Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard
9 files modified
1 files added
| | |
| | | * @LastEditors: shuishen 1109946754@qq.com |
| | | * @LastEditTime: 2025-04-03 12:01:58 |
| | | * @FilePath: \command-center-dashboard\src\store\modules\common.js |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2025 by shuishen, All Rights Reserved. |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2025 by shuishen, All Rights Reserved. |
| | | */ |
| | | import { setStore, getStore, removeStore } from 'utils/store' |
| | | import website from '@/config/website' |
| | | import cesiumOptions from '@/utils/cesium-tsa' |
| | | |
| | | const { loadLAYER } = cesiumOptions() |
| | | const common = { |
| | | state: { |
| | | language: getStore({ name: 'language' }) || 'zh-cn', |
| | |
| | | }, |
| | | }, |
| | | mutations: { |
| | | setMapSetting: (state, data) => { |
| | | state.mapSetting = data |
| | | loadLAYER() |
| | | }, |
| | | SET_LANGUAGE: (state, language) => { |
| | | state.language = language |
| | | setStore({ |
| | |
| | | import { set } from 'lodash' |
| | | import { EDeviceTypeName } from '@/utils/staticData/enums' |
| | | import { getStore, setStore } from '@/utils/store' |
| | | |
| | | const home = { |
| | | state: { |
| | | machineNestDetail: false, // 机巢详情 |
| | | machineNestDetail: false, // 机巢长列表 |
| | | isEventOverviewDetail: false,//是事件概述详情 |
| | | // 用户行政区划中心点 |
| | | userAreaPosition: getStore({ name: 'userAreaPosition' }) || {}, |
| | | // 用户切换后行政区划中心点 |
| | | currentAreaPosition:getStore({ name: 'currentAreaPosition' }) || {}, |
| | | singleUavHome: {}, |
| | | footActiveIndex: 0, |
| | | isEventOverviewDetail: false,//是事件概述详情 |
| | | singleTotal: {}, // 统计单个机巢数据 |
| | | // 项目id |
| | | selectedWorkSpaceId: window.localStorage.getItem('bs_workspace_id'), |
| New file |
| | |
| | | <template> |
| | | <div class="AINowFly"> |
| | | <div>智引即飞</div> |
| | | <div> |
| | | 任务名称 |
| | | <el-input type="text" v-model="params.taskName" /> |
| | | </div> |
| | | <div> |
| | | 关联算法: |
| | | <el-select v-model="params.ai_types" placeholder="请选择"> |
| | | <el-option v-for="item in taskAlgorithm" :key="item.id" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </div> |
| | | <div> |
| | | 地址: |
| | | <el-input type="text" v-model="params.dz" /> |
| | | </div> |
| | | <el-table :data="list"> |
| | | <el-table-column type="index" label="序号" /> |
| | | <el-table-column prop="nickname" label="机巢名称" /> |
| | | <el-table-column prop="minute" label="预计飞行时长(分钟)" /> |
| | | <el-table-column prop="exe_distance" label="预计飞行距离(m)" /> |
| | | </el-table> |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | import { getMultipleDictionary } from '@/api/system/dictbiz' |
| | | import * as Cesium from 'cesium' |
| | | import { getFlyingNestBy } from '@/api/home/task' |
| | | import { cartesian3Convert } from '@/utils/cesium/mapUtil' |
| | | import { Cartesian3 } from 'cesium' |
| | | import uavImg from '@/assets/images/home/useUavHome/uavImg.png' |
| | | import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial' |
| | | import lineImg from '@/assets/images/arrow-right-blue.png' |
| | | import _ from 'lodash' |
| | | import { ElMessage } from 'element-plus' |
| | | |
| | | const params = ref({ |
| | | taskName: '', |
| | | ai_types: '', |
| | | dz: '', |
| | | }) |
| | | let handler = null |
| | | const taskAlgorithm = ref([]) |
| | | |
| | | let viewer |
| | | const list = ref([]) |
| | | let eventPoint = {} |
| | | |
| | | const renderingLine = () => { |
| | | const { longitude, latitude } = eventPoint |
| | | list.value.forEach((item, index) => { |
| | | const start = Cartesian3.fromDegrees(Number(item.longitude), Number(item.latitude)) |
| | | const end = Cartesian3.fromDegrees(Number(longitude), Number(latitude)) |
| | | const positionsList = [start, end] |
| | | // 线 |
| | | viewer.entities.add({ |
| | | id: `AINow-line-${index}`, |
| | | polyline: { |
| | | width: 4, |
| | | positions: positionsList, |
| | | material: new ImageTrailMaterial({ |
| | | color: { alpha: 1, blue: 1, green: 1, red: 1 }, |
| | | speed: 20, |
| | | image: lineImg, |
| | | repeat: { x: Math.floor(40), y: 1 }, |
| | | }), |
| | | clampToGround: false, |
| | | }, |
| | | }) |
| | | // 点 |
| | | viewer.entities.add({ |
| | | id: `AINow-point-${index}`, |
| | | position: start, |
| | | label: { |
| | | text: item.nickname, |
| | | font: '12pt Source Han Sans CN', |
| | | fillColor: Cesium.Color.WHITE, |
| | | outlineColor: Cesium.Color.BLACK, |
| | | outlineWidth: 2, |
| | | style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
| | | verticalOrigin: Cesium.VerticalOrigin.BOTTOM, |
| | | pixelOffset: new Cesium.Cartesian2(0, -9), |
| | | }, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(uavImg), |
| | | width: 24, |
| | | height: 24, |
| | | }, |
| | | properties: { |
| | | customData: { |
| | | data: item, |
| | | }, |
| | | }, |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | const removeEntities = () => { |
| | | const entitiesIDs = viewer.entities.values.map(i => i.id) |
| | | entitiesIDs.forEach(item => { |
| | | item.includes('AINow-') && viewer.entities.removeById(item) |
| | | }) |
| | | } |
| | | |
| | | // 单击事件 |
| | | const singleClickEvent = click => { |
| | | removeEntities() |
| | | const earthPosition = viewer.scene.pickPosition(click.position) |
| | | viewer.entities.add({ |
| | | position: earthPosition, |
| | | id: `AINow-event-0`, |
| | | point: { |
| | | pixelSize: 10, |
| | | color: Cesium.Color.RED, |
| | | outlineColor: Cesium.Color.WHITE, |
| | | outlineWidth: 2, |
| | | }, |
| | | }) |
| | | const { longitude, latitude } = cartesian3Convert(earthPosition, viewer) |
| | | eventPoint = { longitude, latitude } |
| | | getFJList() |
| | | } |
| | | |
| | | // 请求字典字段 |
| | | const requestDictionary = () => { |
| | | getMultipleDictionary('SF').then(res => { |
| | | if (res.code !== 0) { |
| | | taskAlgorithm.value = res.data.data['SF'] |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 获取飞机列表 |
| | | const getFJList = async () => { |
| | | const params = { ...eventPoint, page: 1, limit: 9999, type: 1 } |
| | | const res = await getFlyingNestBy(params) |
| | | list.value = (res.data?.data || []).map(item => ({ |
| | | ...item, |
| | | minute: _.round(item.estimated_arrival_time / 60, 0), |
| | | })) |
| | | if (!list.value.length) ElMessage.warning('附近暂无可用无人机') |
| | | renderingLine() |
| | | } |
| | | |
| | | const initMap = () => { |
| | | handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas) |
| | | handler.setInputAction(singleClickEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | } |
| | | |
| | | const removeAll = () => { |
| | | removeEntities() |
| | | handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | handler?.destroy() |
| | | handler = null |
| | | } |
| | | |
| | | onBeforeUnmount(() => { |
| | | removeAll() |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | requestDictionary() |
| | | viewer = window.$viewer |
| | | initMap() |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .AINowFly { |
| | | position: absolute; |
| | | top: 200px; |
| | | right: 0; |
| | | width: 400px; |
| | | height: 700px; |
| | | background: white; |
| | | color: black; |
| | | font-size: 20px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="footer"> |
| | | <img |
| | | v-for="item in list" |
| | | v-for="(item,index) in list.filter(i => !i.disable)" |
| | | :class="item.className" |
| | | :src="item.active ? item.activeImg : item.img" |
| | | alt="" |
| | | @click="imgClick(item)" |
| | | @click="footAction(item,index)" |
| | | /> |
| | | </div> |
| | | <div class="intelligent-introduction-flying"> |
| | | <img class="orthophoto" src="@/assets/images/intelligent-introduction-flying.png" alt="" /> |
| | | <img |
| | | class="orthophoto" |
| | | src="@/assets/images/intelligent-introduction-flying.png" |
| | | alt="" |
| | | @click="footAction(list[5],5)" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | |
| | | import { useMapAggregation } from '@/views/Home/useMapAggregation/useMapAggregation' |
| | | import { useStore } from 'vuex' |
| | | import func from '@/utils/func' |
| | | |
| | | const store = useStore() |
| | | const footActiveIndex = computed(() => store.state.home.footActiveIndex) |
| | | |
| | | // 机巢聚合 |
| | | const { init, removeAll } = useMapAggregation('device') |
| | |
| | | |
| | | const list = ref([ |
| | | { |
| | | name: 'event1', |
| | | name: 'jc', |
| | | img: img1, |
| | | activeImg: activeImg1, |
| | | active: true, |
| | |
| | | removeAll: removeAll, |
| | | }, |
| | | { |
| | | name: 'event2', |
| | | name: 'sj', |
| | | img: img2, |
| | | activeImg: activeImg2, |
| | | active: false, |
| | |
| | | init: eventInit, |
| | | removeAll: eventRemove, |
| | | }, |
| | | { name: 'event3', img: img3, activeImg: activeImg3, active: false, className: 'panorama' }, |
| | | { name: 'event4', img: img4, activeImg: activeImg4, active: false, className: 'threeD' }, |
| | | { name: 'event5', img: img5, activeImg: activeImg5, active: false, className: 'orthophoto' }, |
| | | { name: 'qj', img: img3, activeImg: activeImg3, active: false, className: 'panorama' }, |
| | | { name: 'sw', img: img4, activeImg: activeImg4, active: false, className: 'threeD' }, |
| | | { name: 'zs', img: img5, activeImg: activeImg5, active: false, className: 'orthophoto' }, |
| | | { name: 'zyjf', active: false, disable: true }, |
| | | ]) |
| | | const store = useStore() |
| | | const imgClick = (toItem,index) => { |
| | | index !== undefined && store.commit('setFootActiveIndex',index) |
| | | const fromItem = list.value.find(item => item.active) |
| | | if (fromItem.name === toItem.name) return |
| | | |
| | | const footAction = (toItem, index) => { |
| | | const fromItem = list.value.find(item => item.active) //上一个激活item |
| | | if (fromItem.name === toItem?.name) return //是重复点击 |
| | | index !== undefined && store.commit('setFootActiveIndex', index) //是按钮点击得动作 |
| | | fromItem?.removeAll?.() |
| | | nextTick(() => { |
| | | toItem?.init?.() |
| | | }) |
| | | list.value = list.value.map(item => ({ ...item, active: item.name === toItem.name })) |
| | | nextTick(() => toItem?.init?.()) |
| | | list.value = list.value.map(item => ({ ...item, active: item.name === toItem?.name })) |
| | | } |
| | | |
| | | const footActiveIndex = computed(() => store.state.home.footActiveIndex) |
| | | watch(footActiveIndex, val => { |
| | | console.log(6666666) |
| | | imgClick(list.value[val]) |
| | | },{deep:true}) |
| | | watch( |
| | | footActiveIndex, |
| | | val => { |
| | | footAction(list.value[val]) |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | |
| | | // 销毁前钩子 |
| | | onBeforeUnmount(() => { |
| | |
| | | bottom: 23px; |
| | | |
| | | img { |
| | | cursor: pointer; |
| | | width: 146px; |
| | | height: 54px; |
| | | } |
| | |
| | | <template> |
| | | <template v-if="singleUavHome?.device_sn"> |
| | | <SignMachineNest /> |
| | | </template> |
| | | <!-- 单个机巢页面--> |
| | | <SignMachineNest v-if="singleUavHome?.device_sn" /> |
| | | <!-- 事件概述详细信息页面--> |
| | | <EventOverviewDetail v-else-if="isEventOverviewDetail" /> |
| | | |
| | | <AINowFly v-else-if="isAINowFly" /> |
| | | <!-- 首页默认的页面--> |
| | | <template v-else> |
| | | <EventOverviewDetail v-if="isEventOverviewDetail" /> |
| | | <template v-else> |
| | | <SearchBox /> |
| | | <HomeLeft /> |
| | | <HomeRight /> |
| | | </template> |
| | | <HomeLeft /> |
| | | <HomeRight /> |
| | | </template> |
| | | |
| | | <SearchBox /> |
| | | <RSide /> |
| | | <Footer /> |
| | | </template> |
| | |
| | | import { onMounted } from 'vue' |
| | | import cesiumOperation from '@/utils/cesium-tsa' |
| | | import EventOverviewDetail from '@/views/Home/EventOverviewDetail/EventOverviewDetail.vue' |
| | | import AINowFly from '@/views/Home/AINowFly.vue' |
| | | |
| | | const store = useStore() |
| | | const { _init, viewerDestory } = cesiumOperation() |
| | | |
| | | const singleUavHome = computed(() => store.state.home.singleUavHome) |
| | | const isEventOverviewDetail = computed(() => store.state.home.isEventOverviewDetail) |
| | | const isAINowFly = computed(() => store.state.home.footActiveIndex === 5) |
| | | |
| | | onUnmounted(() => { |
| | | store.commit('setSingleUavHome', null) |
| | | console.log('home销毁') |
| | | store.commit('setIsEventOverviewDetail', false) |
| | | store.commit('setFootActiveIndex', 0) |
| | | viewerDestory() |
| | | }) |
| | | |
| | |
| | | <CommonDateTime :style="{ top: pxToRem(19) }" v-model="newTime" @change="getData" /> |
| | | <div class="chart-container" ref="chartRef"></div> |
| | | </div> |
| | | <InspectionRaskDetailsDialog v-model:show="isShowDetailsDialog"></InspectionRaskDetailsDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | |
| | | import CommonDateTime from '@/components/CommonDateTime.vue' |
| | | import { getJobNumBar, getJobStatistics, getTotalJobNum } from '@/api/home' |
| | | import dayjs from 'dayjs' |
| | | |
| | | import InspectionRaskDetailsDialog from '@/views/Home/HomeLeft/InspectionRaskDetails/InspectionRaskDetailsDialog.vue' |
| | | const currenDate = dayjs().format('YYYY-MM-DD') |
| | | const newTime = ref([currenDate, currenDate]) |
| | | const list = ref([ |
| | |
| | | }, |
| | | }, |
| | | } |
| | | |
| | | // 是否展示巡检任务详情 |
| | | const isShowDetailsDialog = ref(false) |
| | | const detailsFun = () => { |
| | | console.log('details') |
| | | console.log(isShowDetailsDialog.value) |
| | | isShowDetailsDialog.value = true |
| | | |
| | | } |
| | | |
| | | let chart = null |
| | |
| | | opacity: 0.85; |
| | | |
| | | .inspection-num { |
| | | background: url('@/assets/images/home/homeLeft/inspection-num.png') no-repeat center / 100% |
| | | 100%; |
| | | background: url('@/assets/images/home/homeLeft/inspection-num.png') no-repeat center / 100% 100%; |
| | | width: 360px; |
| | | height: 118px; |
| | | position: relative; |
| | |
| | | <!-- 巡检任务情况-详情 --> |
| | | <template> |
| | | |
| | | <el-dialog |
| | | v-model="isShowDetailsDialog" |
| | | title="巡检任务详情" |
| | | :width="pxToRem(1000)" |
| | | :close-on-click-modal="false" |
| | | :destroy-on-close="true" |
| | | > |
| | | <!-- 搜索 --> |
| | | <el-form :model="searchForm" inline> |
| | | <div class="search-row"> |
| | | <el-form-item> |
| | | <el-input v-model="searchForm.key_word" placeholder="请输入任务/机巢名称" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="关联算法"> |
| | | <el-select v-model="searchForm.ai_types" placeholder="请选择"> |
| | | <el-option v-for="item in taskAlgorithm" :key="item.id" :label="item.dictValue" :value="item.dictKey" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="任务状态"> |
| | | <el-select v-model="searchForm.status" placeholder="请选择" clearable> |
| | | <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </div> |
| | | <div class="search-row"> |
| | | <el-form-item label="选择机巢"> |
| | | <el-select v-model="searchForm.device_sn" placeholder="请选择"> |
| | | <el-option |
| | | v-for="item in deviceList" |
| | | :label="item.nickname" |
| | | :value="item.device_sn" |
| | | :key="item.device_sn" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-date-picker |
| | | v-model="dateRange" |
| | | type="daterange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | value-format="YYYY-MM-DD" |
| | | @change="changeselect" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button @click="handleReset">重置</el-button> |
| | | <el-button type="primary" @click="handleSearch">查询</el-button> |
| | | </el-form-item> |
| | | </div> |
| | | </el-form> |
| | | <!-- 表格 --> |
| | | <el-table :data="taskDetailData" style="width: 100%"> |
| | | <el-table-column label="序号" width="60"> |
| | | <template #default="scope"> |
| | | {{ (taskDetailParams.page - 1) * taskDetailParams.limit + scope.$index + 1 }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="job_info_num" label="任务编号" /> |
| | | <el-table-column prop="name" label="任务名称" /> |
| | | <el-table-column prop="device_names" label="所属机巢" /> |
| | | <el-table-column prop="ai_type_str" label="关联算法" /> |
| | | <el-table-column prop="status" label="任务状态" /> |
| | | <el-table-column prop="industry_type_str" label="任务类型" /> |
| | | <el-table-column prop="begin_time" label="任务时间" /> |
| | | <el-table-column prop="name" label="关联事件" /> |
| | | <el-table-column label="操作"> <el-button link type="primary" size="small">查看</el-button></el-table-column> |
| | | </el-table> |
| | | <!-- 分页 --> |
| | | <div class="pagination"> |
| | | <el-pagination |
| | | v-model:current-page="pageParams.page" |
| | | v-model:page-size="pageParams.limit" |
| | | :page-sizes="[10, 20, 30, 50]" |
| | | background |
| | | :disabled="disabled" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :total="total" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | | <script setup> |
| | | import { pxToRem } from '@/utils/rem' |
| | | import { jobList } from '@/api/home/task' |
| | | import { getDictionary } from '@/api/system/dict' |
| | | import { selectDevicePage } from '@/api/home/machineNest' |
| | | import { getMultipleDictionary } from '@/api/system/dictbiz' |
| | | const isShowDetailsDialog = defineModel('show') |
| | | const dateRange = ref('') |
| | | const searchForm = reactive({ |
| | | key_word: '', // 模糊搜索关键词(匹配名称/昵称/设备sn) |
| | | ai_types: [], // 算法类型 |
| | | device_sn: '', // 设备编号 |
| | | end_date: null, // 结束时间 |
| | | start_date: null, // 开始时间 |
| | | status: '', // 作业状态 |
| | | }) |
| | | const statusOptions = [ |
| | | { label: '待执行', value: 1 }, |
| | | { label: '执行中', value: 2 }, |
| | | { label: '已完成', value: 3 }, |
| | | { label: '已取消', value: 4 }, |
| | | { label: '执行失败', value: 5 }, |
| | | ] |
| | | // 设备页面参数 |
| | | const devicePageParams = ref({ |
| | | current: 1, |
| | | size: 10, |
| | | total: 0, |
| | | nickname: '', |
| | | }) |
| | | const deviceList = ref([]) |
| | | // 表格 |
| | | const taskDetailData = ref([]) |
| | | // 表格参数 |
| | | const taskDetailParams = reactive({ |
| | | page: 1, |
| | | limit: 10, |
| | | searchParams: {}, |
| | | }) |
| | | // 分页 |
| | | const total = ref(0) |
| | | // 分页参数 |
| | | let pageParams = reactive({ |
| | | page: 1, |
| | | limit: 10, |
| | | }) |
| | | // 日期选择 |
| | | const changeselect = () => { |
| | | searchForm.start_date = dateRange.value.length ? `${dateRange.value[0]} 00:00:00` : null |
| | | searchForm.end_date = dateRange.value.length ? `${dateRange.value[1]} 00:00:00` : null |
| | | } |
| | | |
| | | // 重置 |
| | | const handleReset = () => { |
| | | dateRange.value = null |
| | | Object.keys(searchForm).forEach(key => { |
| | | if (key == 'start_date' || key == 'end_date') { |
| | | searchForm[key] = null |
| | | } else if (key == 'ai_types') { |
| | | searchForm[key] = [] |
| | | } else { |
| | | searchForm[key] = '' |
| | | } |
| | | }) |
| | | |
| | | handleSearch() |
| | | } |
| | | // 查询 |
| | | const handleSearch = () => { |
| | | taskDetailParams.page = 1 |
| | | taskDetailParams.limit = 10 |
| | | taskDetailParams.searchParams = searchForm |
| | | console.log('taskDetailParams.value', taskDetailParams) |
| | | getJobList() |
| | | } |
| | | // 分页大小改变 |
| | | const handleSizeChange = val => { |
| | | pageParams.limit = val |
| | | getJobList() |
| | | } |
| | | // 页码改变 |
| | | const handleCurrentChange = val => { |
| | | pageParams.page = val |
| | | getJobList() |
| | | } |
| | | // 获取任务列表 |
| | | const getJobList = () => { |
| | | jobList(taskDetailParams).then(res => { |
| | | if (res.data.code !== 0) return |
| | | taskDetailData.value = res.data.data.records |
| | | total.value = res.data.data.total |
| | | }) |
| | | } |
| | | // 机巢列表数据 |
| | | const getDeviceList = async () => { |
| | | const res = await selectDevicePage({ current: 1, size: 99999, type: 1 }) |
| | | deviceList.value = res.data?.data?.records || [] |
| | | } |
| | | // 关联算法 |
| | | |
| | | let taskBusiness = ref([]) |
| | | let taskAlgorithm = ref([]) |
| | | // 请求字典字段 |
| | | const requestDictionary = () => { |
| | | getMultipleDictionary('SF,HYLB').then(res => { |
| | | if (res.code !== 0) { |
| | | // 处理数据 |
| | | taskAlgorithm.value = res.data.data['SF'] |
| | | taskBusiness.value = res.data.data['HYLB'] |
| | | } |
| | | }) |
| | | } |
| | | const algorithmChange = val => { |
| | | searchForm.ai_types = val |
| | | } |
| | | onMounted(() => { |
| | | requestDictionary() |
| | | getJobList() |
| | | getDeviceList() |
| | | }) |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | .search-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | .el-form-item { |
| | | flex: 1; |
| | | } |
| | | } |
| | | :deep(.el-form) { |
| | | .el-form-item { |
| | | margin-bottom: 0; |
| | | margin-right: 20px; |
| | | .el-form-item__label { |
| | | color: #fff; |
| | | } |
| | | |
| | | .el-input, |
| | | .el-select, |
| | | .el-date-editor { |
| | | width: 200px; |
| | | --el-input-bg-color: transparent; |
| | | --el-input-border-color: rgba(255, 255, 255, 0.3); |
| | | --el-input-text-color: #fff; |
| | | --el-input-placeholder-color: rgba(255, 255, 255, 0.5); |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep() { |
| | | .el-date-editor.el-input, |
| | | .el-date-editor.el-input__wrapper { |
| | | height: var(--el-input-height, var(--el-component-size)); |
| | | width: 0 !important; |
| | | } |
| | | } |
| | | .pagination { |
| | | margin-top: 20px; |
| | | } |
| | | </style> |
| | |
| | | <!-- 机巢概况 --> |
| | | <template> |
| | | <common-title :style="{ marginLeft: pxToRem(14) }" @details="detailsFun"></common-title> |
| | | <common-title title="机巢概况" :style="{ marginLeft: pxToRem(14) }" @details="detailsFun"></common-title> |
| | | <div class="overview-next"> |
| | | <MachineNestTotal @searchNickName="handleSearch" /> |
| | | <div class="table-list"> |
| | |
| | | border-radius: 0px 0px 0px 0px; |
| | | opacity: 0.85; |
| | | margin-bottom: 10px; |
| | | |
| | | |
| | | .table-list { |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | margin: 16px; |
| | |
| | | scalingJudgment.forEach(item => item.show && (item.outline = outlineGJson)) |
| | | const [longitude, latitude] = outlineGJson.features[0].properties.centroid |
| | | const height = scalingJudgment[(hierarchy.length - 3) * (-1)].height |
| | | setCenterPosition({longitude, latitude,height}) |
| | | setCenterPosition({ longitude, latitude, height }) |
| | | flyTo({ longitude, latitude }, 0, height) |
| | | } |
| | | |
| | | const userAreaPosition = computed(() => store.state.home.userAreaPosition); |
| | | const userAreaPosition = computed(() => store.state.home.userAreaPosition) |
| | | |
| | | const setCenterPosition = (position) => { |
| | | store.commit('setCurrentAreaPosition', position) |
| | | if (!userAreaPosition.value.longitude){ |
| | | store.commit('setUserAreaPosition', position) |
| | | } |
| | | if (!userAreaPosition.value.longitude) { |
| | | store.commit('setUserAreaPosition', position) |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | id: `aggregation-splashed-${index}`, |
| | | position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude), |
| | | label: { |
| | | // 随机整数 |
| | | text: item.nickname, |
| | | font: '12pt Source Han Sans CN', |
| | | fillColor: Cesium.Color.WHITE, |
| | |
| | | // 渲染轮廓 |
| | | const renderOutline = item => { |
| | | item.outline && |
| | | Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => { |
| | | viewer.dataSources.add(dataSource) |
| | | const entities = dataSource.entities.values |
| | | entities.forEach(entity => { |
| | | // 隐藏多边形填充 |
| | | entity.polygon.material = Cesium.Color.TRANSPARENT |
| | | entity.polygon.outline = false // 关闭原生轮廓 |
| | | // 创建独立折线作为轮廓 |
| | | const positions = entity.polygon.hierarchy.getValue().positions |
| | | viewer.entities.add({ |
| | | polyline: { |
| | | positions: positions, |
| | | width: 5, // 直接设置宽度 |
| | | material: new Cesium.PolylineGlowMaterialProperty({ |
| | | glowPower: 0.5, |
| | | color: Cesium.Color.AQUA, |
| | | }), |
| | | clampToGround: true, // 贴地显示 |
| | | }, |
| | | Cesium.GeoJsonDataSource.load(item.outline).then(dataSource => { |
| | | const entities = dataSource.entities.values |
| | | entities.forEach((entity, index) => { |
| | | // 创建独立折线作为轮廓 |
| | | const positions = entity.polygon.hierarchy.getValue().positions |
| | | viewer.entities.add({ |
| | | id: `aggregation-outline-${index}`, |
| | | polyline: { |
| | | positions: positions, |
| | | width: 5, // 直接设置宽度 |
| | | material: new Cesium.PolylineGlowMaterialProperty({ |
| | | glowPower: 0.5, |
| | | color: Cesium.Color.AQUA, |
| | | }), |
| | | }, |
| | | }) |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 聚合机巢 |
| | |
| | | // 遍历特征并添加实体 |
| | | featuresList.forEach((feature, index) => { |
| | | if (!feature.position) return |
| | | const position = Cesium.Cartesian3.fromDegrees(feature.position[0], feature.position[1]) |
| | | const position = Cesium.Cartesian3.fromDegrees(feature.position[0], feature.position[1], 12000) |
| | | viewer.entities.add({ |
| | | position: position, |
| | | id: `aggregation-name-${index}`, |
| | |
| | | return arrColor[++index % arrColor.length] |
| | | } |
| | | |
| | | // 加载新的 GeoJSON 数据 |
| | | // 加载边界 |
| | | Cesium.GeoJsonDataSource.load(item.gJson).then(dataSource => { |
| | | console.log(dataSource, item.gJson) |
| | | |
| | | viewer.dataSources.add(dataSource) |
| | | item.dataSource = dataSource // 保存数据源以便后续删除 |
| | | item.BJDataSource = dataSource // 保存数据源以便后续删除 |
| | | // 获取数据源中的实体 |
| | | const entities = dataSource.entities.values |
| | | |
| | |
| | | alphaPower: 1.3 |
| | | }) |
| | | |
| | | entity.polygon.extrudedHeight = (entity.propertyNames.length || 1) * 500 |
| | | entity.polygon.extrudedHeight = (entity.properties.childrenNum._value || 1) * 500 |
| | | |
| | | entity.polygon.material = material |
| | | entity.polygon.outline = false // 显示边框 |
| | | }) |
| | | |
| | | needFly && viewer.flyTo(dataSource, { |
| | | offset: new Cesium.HeadingPitchRange( |
| | | 0, // heading: 0 (朝向不变) |
| | | Cesium.Math.toRadians(-60), // pitch: -90° (垂直向下) |
| | | 0 // range: 0 (默认距离) |
| | | ), |
| | | offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0), |
| | | duration: 0.5, |
| | | }) |
| | | needFly = false |
| | |
| | | // 左键单机事件 |
| | | const singleMachineEvent = async click => { |
| | | const pickedObject = viewer.scene.pick(click.position) |
| | | if (Cesium.defined(pickedObject) && pickedObject.id) { |
| | | const entity = pickedObject.id |
| | | currentEntity = entity |
| | | positionC3 = entity?.position?._value |
| | | if (!positionC3) return |
| | | removeLabel() |
| | | const customData = entity.properties.customData._value.data |
| | | console.log('customData', customData) |
| | | switch (customData.type) { |
| | | case 'deviceAggregation': |
| | | viewer.scene.postRender.addEventListener(labelBoxRender) |
| | | break |
| | | // todo 待对接 |
| | | case 'device': |
| | | store.commit('setSingleUavHome', { id: '123' }) |
| | | break |
| | | case 'eventAggregation': |
| | | break |
| | | case 'event': |
| | | viewer.scene.postRender.addEventListener(labelBoxRender) |
| | | break |
| | | default: |
| | | break |
| | | } |
| | | if (!(Cesium.defined(pickedObject) && pickedObject.id)) return |
| | | const entity = pickedObject.id |
| | | currentEntity = entity |
| | | const entityPosition = entity?.position?._value |
| | | if (!entityPosition) return |
| | | if (entityPosition) { |
| | | positionC3 = entityPosition |
| | | } |
| | | removeLabel() |
| | | const customData = entity?.properties?.customData?._value?.data |
| | | if (!customData) return |
| | | console.log('customData', customData) |
| | | switch (customData.type) { |
| | | case 'deviceAggregation': |
| | | viewer.scene.postRender.addEventListener(labelBoxRender) |
| | | break |
| | | // todo 待对接 |
| | | case 'device': |
| | | store.commit('setSingleUavHome', { id: '123' }) |
| | | break |
| | | case 'eventAggregation': |
| | | break |
| | | case 'event': |
| | | viewer.scene.postRender.addEventListener(labelBoxRender) |
| | | break |
| | | default: |
| | | break |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | // 移除 点 和 gjson 实体 |
| | | const removeEntities = () => { |
| | | viewer.dataSources?.removeAll(true) |
| | | // viewer.entities?.removeAll(); |
| | | // dataSources移除 |
| | | scalingJudgment.forEach(item => { |
| | | item.BJDataSource && viewer.dataSources.remove(item.BJDataSource) |
| | | item.BJDataSource = null |
| | | }) |
| | | // entities移除 |
| | | const entitiesIDs = viewer.entities.values.map(i => i.id) |
| | | entitiesIDs.forEach(item => { |
| | | item.includes('aggregation-') && viewer.entities.removeById(item) |
| | |
| | | import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial' |
| | | import lineImg from '@/assets/images/arrow-right-blue.png' |
| | | import uavImg from '@/assets/images/home/useUavHome/uavImg.png' |
| | | import { getCenterPoint } from '@/utils/cesium/mapUtil' |
| | | |
| | | const props = defineProps(['detailsData']) |
| | | |