Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard
13 files modified
3 files deleted
2 files added
| | |
| | | let liveVideoRef = ref(null); |
| | | |
| | | const play = (url) => { |
| | | pause(); |
| | | webrtcPlayer = new window.ZLMRTCClient.Endpoint({ |
| | | element: liveVideoRef.value, // video 标签 |
| | | debug: true, // 是否打印日志 |
| | |
| | | ) |
| | | }; |
| | | |
| | | // 销毁 |
| | | const pause = () => { |
| | | if (webrtcPlayer) { |
| | | webrtcPlayer.close(); |
| | |
| | | (newValue) => { |
| | | if (!newValue) return; |
| | | nextTick(() => { |
| | | pause(); |
| | | play(newValue); |
| | | }); |
| | | }, |
| | |
| | | immediate: true |
| | | } |
| | | ); |
| | | |
| | | onBeforeUnmount(() => { |
| | | pause() |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | if (props.videoUrl) { |
| | |
| | | object-fit: cover; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | color: var(--text-color); |
| | | } |
| | | .el-select__wrapper { |
| | | background-color: transparent; |
| | | background-color: #021022; |
| | | box-shadow: none; |
| | | border: var(--border); |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | // 弹框-dialog |
| | | .ztzf-dialog { |
| | | |
| | | background: #0f1929; |
| | | box-shadow: inset 0px -50px 50px 0px rgba(27, 148, 255, 0.13); |
| | | border-radius: 20px 0px 0px 0px; |
| | | border: 2px solid; |
| | | padding: 0 !important; |
| | | |
| | | border-image: linear-gradient( |
| | | 180deg, |
| | | rgba(81, 168, 255, 0), |
| | | rgba(48, 111, 202, 1), |
| | | rgba(255, 255, 255, 1), |
| | | rgba(27, 148, 255, 1) |
| | | ) |
| | | 2 2; |
| | | // 头部 |
| | | .el-dialog__header { |
| | | width: 100%; |
| | | height: 47px; |
| | | margin-bottom: 14px; |
| | | background: url('/src/assets/images/home/homeLeft/inspection-vector.png') no-repeat center; |
| | | background-size: 100% 100%; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | line-height: 47px; |
| | | } |
| | | .el-dialog__title { |
| | | width: 112px; |
| | | height: 19px; |
| | | font-family: Segoe UI, Segoe UI; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | line-height: 16px; |
| | | text-shadow: 0px 0px 5px rgba(154, 218, 255, 0.6); |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | background: linear-gradient(90deg, #fbfdff 0%, #86d4ff 100%); |
| | | margin-left: 16px; |
| | | -webkit-background-clip: text; /* 背景被裁剪成文字的前景色 */ |
| | | -webkit-text-fill-color: transparent; /* 文字填充颜色变透明 */ |
| | | } |
| | | .el-dialog .el-dialog__header { |
| | | /* margin: 0px !important; */ |
| | | padding: 0px !important; |
| | | padding-left: 0px !important; |
| | | } |
| | | .el-scrollbar__thumb { |
| | | background: #13c6ff !important; |
| | | } |
| | | } |
| | | |
| | |
| | | return true |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 飞到中心点并且所有点在可视范围 |
| | | * @param lngLatArr |
| | | * @param viewer |
| | | * @param rangeMultiple 范围倍数越大飞的越高默认2 |
| | | */ |
| | | export function flyVisual(lngLatArr,viewer,rangeMultiple = 2) { |
| | | if (!Array.isArray(lngLatArr) || lngLatArr.length === 0) return |
| | | const positions = lngLatArr.map(([lon, lat]) => |
| | | Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | ) |
| | | // 计算包围盒 BoundingSphere(所有点的外接球) |
| | | const boundingSphere = Cesium.BoundingSphere.fromPoints(positions) |
| | | viewer.camera.flyToBoundingSphere(boundingSphere, { |
| | | duration: 0, |
| | | offset: new Cesium.HeadingPitchRange(0, 0, boundingSphere.radius * rangeMultiple), |
| | | }) |
| | | } |
| | |
| | | <div class="eventListItem" v-for="item in list"> |
| | | <img |
| | | class="eventListItemImg" |
| | | :src=" |
| | | item.photo_url |
| | | ? item.photo_url.substring(0, item.photo_url.lastIndexOf('.')) + |
| | | '_small' + |
| | | item.photo_url.substring(item.photo_url.lastIndexOf('.')) |
| | | : '' |
| | | " |
| | | :src="getSmallImg(item.photo_url)" |
| | | alt="" |
| | | /> |
| | | <div class="eventListItemPosition" :title="item.address" @click="positioning(item)"> |
| | |
| | | current: 1, |
| | | size: 8, |
| | | }) |
| | | |
| | | const getSmallImg = (url) => { |
| | | return url ? url.substring(0, url.lastIndexOf('.')) + '_small' + url.substring(url.lastIndexOf('.')) : '' |
| | | } |
| | | |
| | | const isMore = ref(false) |
| | | const leftArrowFun = () => { |
| | |
| | | } |
| | | getEventPage(params.value, pageParams).then(res => { |
| | | const resData = res.data.data |
| | | list.value = resData?.records || [] |
| | | list.value = (resData?.records || []) |
| | | total.value = resData.total |
| | | }) |
| | | } |
| | |
| | | |
| | | .leftArrow { |
| | | position: absolute; |
| | | left: 0; |
| | | left: -11px; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | cursor: pointer; |
| | |
| | | <div class="name">机巢总数</div> |
| | | </div> |
| | | <div class="status"> |
| | | <div class="item" v-for="(item, index) in listNum"> |
| | | <div class="item" v-for="(item, index) in listNum" > |
| | | <div> |
| | | <div :style="{ color: item.color }" class="value">{{ item.value }}</div> |
| | | <div class="name">{{ item.name }}</div> |
| | |
| | | <template> |
| | | <div class="ai-chat"> |
| | | <el-popover |
| | | placement="bottom" |
| | | :visible="visible" |
| | | :width="200" |
| | | trigger="click" |
| | | > |
| | | <template #reference> |
| | | <div class="chat" id="chatID" v-drag:chatID @mousedown="handleMouseDown" |
| | | @mouseup="handleMouseUp"/> |
| | | </template> |
| | | <div> |
| | | 快和我对话吧 |
| | | <el-input/> |
| | | </div> |
| | | </el-popover> |
| | | <img class="chat-bottom" src="../../assets/images/chat-bottom.png" alt=""> |
| | | </div> |
| | | <div class="r-side"> |
| | | <img v-for="(item, index) in images" |
| | | :key="index" :class="item.class" |
| | | :src="activeIndex === index ? item.activeSrc : item.src" alt="" |
| | | @click="activeChange(index)" |
| | | @mouseenter="enterHover(index)" |
| | | @mouseleave="logIndex=3" |
| | | > |
| | | </div> |
| | | <div v-if="logIndex===0" class="r-side-positioning">返回当前位置</div> |
| | | <div v-if="logIndex===1" class="r-side-measuring">量尺</div> |
| | | <div v-if="logIndex===2" class="r-side-layer">切换地图模式</div> |
| | | <MeasuringDistance v-if="activeIndex === 1"/> |
| | | <div class="ai-chat"> |
| | | <el-popover placement="bottom" :visible="visible" :width="200" trigger="click"> |
| | | <template #reference> |
| | | <div class="chat" id="chatID" v-drag:chatID @mousedown="handleMouseDown" @mouseup="handleMouseUp" /> |
| | | </template> |
| | | <div> |
| | | 快和我对话吧 |
| | | <el-input /> |
| | | </div> |
| | | </el-popover> |
| | | <img class="chat-bottom" src="../../assets/images/chat-bottom.png" alt="" /> |
| | | </div> |
| | | <div class="r-side"> |
| | | <img |
| | | v-for="(item, index) in images" |
| | | :key="index" |
| | | :class="item.class" |
| | | :src="activeIndex === index ? item.activeSrc : item.src" |
| | | alt="" |
| | | @click="activeChange(index)" |
| | | @mouseenter="enterHover(index)" |
| | | @mouseleave="logIndex = 3" |
| | | /> |
| | | </div> |
| | | <div v-if="logIndex === 0" class="r-side-positioning">返回当前位置</div> |
| | | <div v-if="logIndex === 1" class="r-side-measuring">量尺</div> |
| | | <div v-if="logIndex === 2" class="r-side-layer">切换地图模式</div> |
| | | <MeasuringDistance v-if="activeIndex === 1" /> |
| | | |
| | | </template> |
| | | |
| | | <script setup> |
| | |
| | | import tc1 from '@/assets/images/rSide/tc1.png' |
| | | import cesiumOperation from '@/utils/cesium-tsa' |
| | | |
| | | let logIndex = ref(3); |
| | | const enterHover = (value) => { |
| | | logIndex.value = value; |
| | | let logIndex = ref(3) |
| | | const enterHover = value => { |
| | | logIndex.value = value |
| | | } |
| | | const { flyTo } = cesiumOperation() |
| | | |
| | | const store = useStore(); |
| | | const currentAreaPosition = computed(() => store.state.home.currentAreaPosition); |
| | | const store = useStore() |
| | | const currentAreaPosition = computed(() => store.state.home.currentAreaPosition) |
| | | |
| | | let activeIndex = ref(null); |
| | | const activeChange = (value) => { |
| | | if(value === 0) { |
| | | let activeIndex = ref(null) |
| | | const activeChange = value => { |
| | | if (value === 0) { |
| | | flyTo(currentAreaPosition.value, 0, currentAreaPosition.value.height) |
| | | } |
| | | if (value === 1){ |
| | | activeIndex.value = activeIndex.value === 1 ? null : value; |
| | | if (value === 1) { |
| | | activeIndex.value = activeIndex.value === 1 ? null : value |
| | | } |
| | | if (value === 2) { |
| | | activeIndex.value = activeIndex.value === 2 ? null : value |
| | | } |
| | | } |
| | | const visible = ref(false); |
| | | let pressStart = 0; |
| | | const visible = ref(false) |
| | | let pressStart = 0 |
| | | |
| | | const handleMouseDown = () => { |
| | | pressStart = Date.now(); // 记录按下时间 |
| | | }; |
| | | pressStart = Date.now() // 记录按下时间 |
| | | } |
| | | |
| | | const handleMouseUp = () => { |
| | | const pressDuration = Date.now() - pressStart; // 计算按下时长 |
| | | if (pressDuration < 150) { |
| | | // 如果按下时间小于200ms,认为是点击 |
| | | visible.value = !visible.value; |
| | | } |
| | | }; |
| | | const pressDuration = Date.now() - pressStart // 计算按下时长 |
| | | if (pressDuration < 150) { |
| | | // 如果按下时间小于200ms,认为是点击 |
| | | visible.value = !visible.value |
| | | } |
| | | } |
| | | |
| | | // 添加: 定义图片数组 |
| | | const images = [ |
| | | { class: 'positioning', src: dw,activeSrc:dw1 }, |
| | | { class: 'measuring-scale', src: lc,activeSrc:lc1 }, |
| | | { class: 'layer', src: tc,activeSrc:tc1 } |
| | | ]; |
| | | { class: 'positioning', src: dw, activeSrc: dw1 }, |
| | | { class: 'measuring-scale', src: lc, activeSrc: lc1 }, |
| | | { class: 'layer', src: tc, activeSrc: tc1 }, |
| | | ] |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | } |
| | | } |
| | | .r-side { |
| | | position: absolute; |
| | | bottom: 122px; |
| | | right: 463px; |
| | | cursor: pointer; |
| | | img { |
| | | display: block; |
| | | width: 48px; |
| | | height: 48px; |
| | | } |
| | | .positioning { |
| | | position: relative; |
| | | bottom: 24px; |
| | | } |
| | | .measuring-scale { |
| | | position: relative; |
| | | bottom: 12px; |
| | | } |
| | | position: absolute; |
| | | bottom: 122px; |
| | | right: 463px; |
| | | cursor: pointer; |
| | | img { |
| | | display: block; |
| | | width: 48px; |
| | | height: 48px; |
| | | } |
| | | .positioning { |
| | | position: relative; |
| | | bottom: 24px; |
| | | } |
| | | .measuring-scale { |
| | | position: relative; |
| | | bottom: 12px; |
| | | } |
| | | } |
| | | .r-side-positioning, .r-side-measuring, .r-side-layer { |
| | | position: absolute; |
| | | right: 514px; |
| | | width: 130px; |
| | | height: 48px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #FFFFFF; |
| | | line-height: 48px; |
| | | text-align: center; |
| | | background: url('@/assets/images/cursor.png'); |
| | | .r-side-positioning, |
| | | .r-side-measuring, |
| | | .r-side-layer { |
| | | position: absolute; |
| | | right: 514px; |
| | | width: 130px; |
| | | height: 48px; |
| | | font-family: Source Han Sans CN, Source Han Sans CN; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #ffffff; |
| | | line-height: 48px; |
| | | text-align: center; |
| | | background: url('@/assets/images/cursor.png'); |
| | | } |
| | | .r-side-positioning { |
| | | bottom: 242px; |
| | | bottom: 242px; |
| | | } |
| | | .r-side-measuring { |
| | | bottom: 182px; |
| | | bottom: 182px; |
| | | } |
| | | .r-side-layer { |
| | | bottom: 122px; |
| | | bottom: 122px; |
| | | } |
| | | </style> |
| | | |
| | |
| | | justify-content: space-between; |
| | | padding: 12px 10px 0; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | </el-table-column> |
| | | <el-table-column prop="id" label="事件编号" /> |
| | | <el-table-column prop="event_name" label="事件名称" /> |
| | | <el-table-column prop="event_name" label="所属单位 " /> |
| | | <el-table-column show-overflow-tooltip prop="media_type" label="事件内容" /> |
| | | <el-table-column prop="create_user" label="所属单位 " /> |
| | | <el-table-column show-overflow-tooltip prop="remark" label="事件内容" /> |
| | | <el-table-column show-overflow-tooltip prop="ai_types" label="关联算法" /> |
| | | <el-table-column prop="status" label="事件状态"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="scope.row.status === 0" type="info">待处理</el-tag> |
| | | <el-tag v-if="scope.row.status === 1" type="success">待分拨</el-tag> |
| | | <el-tag v-if="scope.row.status === 2" type="warning">待处理</el-tag> |
| | | <el-tag v-if="scope.row.status === 3" type="success">处理中</el-tag> |
| | | <el-tag v-if="scope.row.status === 4" type="success">已完成</el-tag> |
| | | <el-tag v-if="scope.row.status === 5" type="success">已完结</el-tag> |
| | | <div class="pending" v-if="scope.row.status === 0">待处理</div> |
| | | <div class="reviewed" v-if="scope.row.status === 2">待审核</div> |
| | | <div class="processing" v-if="scope.row.status === 3">处理中</div> |
| | | <div class="done" v-if="scope.row.status === 4">已完成</div> |
| | | <div class="ended" v-if="scope.row.status === 5">已完结</div> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="操作" width="80"> |
| | | <template #default="scope"> |
| | | <div class="ztzf-view" @click="distribution(scope.row)">查看</div> |
| | | </template> |
| | | <!-- <template #default="scope" > |
| | | <el-button type="success" link @click="examine(scope.row)">审核</el-button> |
| | | <el-button type="primary" link @click="distribution(scope.row)">查看</el-button> |
| | | </template> --> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | |
| | | :page-sizes="[10, 20, 30, 50]" |
| | | v-model:current-page="sizeParams.current" |
| | | v-model:page-size="sizeParams.size" |
| | | layout="prev, pager, next, jumper" |
| | | layout="prev, pager, next,sizes, jumper" |
| | | :total="total" |
| | | @change="pageChange" |
| | | /> |
| | |
| | | background: center center no-repeat none !important; |
| | | color: #8eb8ea !important; |
| | | } |
| | | |
| | | :deep(.el-tag){ |
| | | background: none !important; |
| | | border:none !important |
| | | // 待处理 |
| | | .pending{ |
| | | color: #FF7411; |
| | | } |
| | | |
| | | // 待审核 |
| | | .reviewed{ |
| | | color: #8CFEA7; |
| | | } |
| | | // 处理中 |
| | | .processing{ |
| | | color: #FFC398; |
| | | } |
| | | // 已完成 |
| | | .done{ |
| | | color: #AFD9FB; |
| | | } |
| | | // 已完结 |
| | | .ended{ |
| | | color: #11C4FF; |
| | | } |
| | | </style> |
| | |
| | | <el-table-column label="操作" width="80"> |
| | | <template #default="scope"> |
| | | <div class="ztzf-view" @click="viewJob(scope.row)">查看</div> |
| | | <!-- <el-button type="warning" link @click="viewJob(scope.row)">查看</el-button> --> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | :page-sizes="[10, 20, 30, 50]" |
| | | v-model:current-page="sizeParams.current" |
| | | v-model:page-size="sizeParams.size" |
| | | layout=" prev, pager, next, jumper" |
| | | layout=" prev, pager, next,sizes, jumper" |
| | | :total="total" |
| | | @change="pageChange" |
| | | /> |
| | |
| | | getList() |
| | | }) |
| | | </script> |
| | | <style lang="scss"> |
| | | .devicejob-container { |
| | | // 表格 |
| | | |
| | | } |
| | | </style> |
| | | <style scoped lang="scss"> |
| | | // 标题 |
| | | .machineTableDetailsTitle { |
| | |
| | | import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' |
| | | 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 rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png' |
| | | import endPointImg from '@/assets/images/EndPointicon.png' |
| | | import { addBlueFilter } from '@/utils/cesium/common' |
| | | import { flyVisual } from '@/utils/cesium/mapUtil' |
| | | |
| | | const props = defineProps(['detailsData']) |
| | | |
| | | |
| | | const filterLayer = (options,viewer) => { |
| | | const { bInvertColor, bFilterColor, filterColor } = options |
| | | const color = new Cesium.Color.fromCssColorString(filterColor) |
| | | const filterRGB = [ |
| | | Math.round(color.red * 255), |
| | | Math.round(color.green * 255), |
| | | Math.round(color.blue * 255) |
| | | ] |
| | | let fragShader = viewer.scene.globe._surfaceShaderSet.baseFragmentShaderSource.sources |
| | | for (let i = 0; i < fragShader.length; i++) { |
| | | const strS = 'color = czm_saturation(color, textureSaturation);\n#endif\n' |
| | | let strT = 'color = czm_saturation(color, textureSaturation);\n#endif\n' |
| | | if (bInvertColor) { |
| | | strT += ` |
| | | color.r = 1.0 - color.r; |
| | | color.g = 1.0 - color.g; |
| | | color.b = 1.0 - color.b; |
| | | ` |
| | | } |
| | | if (bFilterColor) { |
| | | strT += ` |
| | | color.r = color.r * ${filterRGB[0]}.0/255.0; |
| | | color.g = color.g * ${filterRGB[1]}.0/255.0; |
| | | color.b = color.b * ${filterRGB[2]}.0/255.0; |
| | | ` |
| | | } |
| | | fragShader[i] = fragShader[i].replace(strS, strT) |
| | | } |
| | | } |
| | | |
| | | |
| | | const imageryProvider_ammapSL = new Cesium.UrlTemplateImageryProvider({ |
| | | url: 'https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', |
| | |
| | | }) |
| | | } |
| | | |
| | | // 飞到中心点 |
| | | function flyToPoints(lngLatArr) { |
| | | if (!Array.isArray(lngLatArr) || lngLatArr.length === 0) return |
| | | const positions = lngLatArr.map(([lon, lat]) => |
| | | Cesium.Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | ) |
| | | // 计算包围盒 BoundingSphere(所有点的外接球) |
| | | const boundingSphere = Cesium.BoundingSphere.fromPoints(positions) |
| | | viewer.camera.flyToBoundingSphere(boundingSphere, { |
| | | duration: 0, |
| | | offset: new Cesium.HeadingPitchRange(0, 0, boundingSphere.radius * 2), |
| | | }) |
| | | } |
| | | |
| | | // 异步解析kmz文件 |
| | | const analysis = async url => { |
| | | return new Promise(async resolve => { |
| | |
| | | const drawLine = async () => { |
| | | const res = await Promise.all(props.detailsData.way_lines.map(item => analysis(item.url))) |
| | | res.map(item => renderingLine(item)) |
| | | console.log(res,'jiexi') |
| | | const allPoint = res |
| | | .flatMap(item => item.Placemark) |
| | | .map(item => item.Point.coordinates.split(',')) |
| | | flyToPoints(allPoint) |
| | | flyVisual(allPoint,viewer) |
| | | } |
| | | |
| | | const removeMap = () => { |
| | |
| | | <!-- 机巢列表详情 --> |
| | | <template> |
| | | <el-dialog |
| | | class="machineTableDetails" |
| | | class="machineTableDetails ztzf-dialog" |
| | | v-model="isShowDetails" |
| | | :width="pxToRem(1500)" |
| | | :close-on-click-modal="false" |
| | | :destroy-on-close="true" |
| | | |
| | | > |
| | | <template #header="{ titleId, titleClass }"> |
| | | <div class="my-header"> |
| | |
| | | <div class="machineTableDetailsTitle"><span>详情</span></div> |
| | | <div class="infoBox"> |
| | | <div class="itemBox" v-for="(item, index) in infoList" :key="index"> |
| | | <div class="itemTitle">{{ item.name }} : </div> |
| | | <div class="itemTitle">{{ item.name }} :</div> |
| | | <div v-if="item.name == '任务成果'" class="missionOutcomes"> |
| | | <span>{{item.value ? item.value :0}}</span> |
| | | 个 |
| | | </div> |
| | | <div |
| | | v-if="item.name == '机巢状态'" |
| | | :class="{ |
| | | active: item.value === 'WORKING', |
| | | freetime: item.value === 'LEISURE', |
| | | offine: item.value === 'OFFLINE', |
| | | }" |
| | | v-if="item.name == '机巢状态'" |
| | | > |
| | | {{ item.value === 'OFFLINE' ? '离线中' : item.value === 'WORKING' ? '作业中' : '空闲中' }} |
| | | </div> |
| | | <div class="itemValue" v-else> {{ item.value }}</div> |
| | | <div class="itemValue" v-else>{{ item.value }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <DeviceJob v-if="isShowDetails" /> |
| | | <DeviceEvent v-if="isShowDetails" /> |
| | | </el-dialog> |
| | | |
| | | </template> |
| | | |
| | | <script setup> |
| | |
| | | |
| | | <style lang="scss"> |
| | | .machineTableDetails { |
| | | width: 1270px; |
| | | width: 1270px; |
| | | height: 856px; |
| | | background: #0f1929; |
| | | box-shadow: inset 0px -50px 50px 0px rgba(27, 148, 255, 0.13); |
| | | border-radius: 20px 0px 0px 0px; |
| | | border: 2px solid; |
| | | padding: 0 !important; |
| | | |
| | | border-image: linear-gradient( |
| | | 180deg, |
| | | rgba(81, 168, 255, 0), |
| | | rgba(48, 111, 202, 1), |
| | | rgba(255, 255, 255, 1), |
| | | rgba(27, 148, 255, 1) |
| | | ) |
| | | 2 2; |
| | | .el-pagination { |
| | | text-align: left; |
| | | padding: 20px 20px 0 20px; |
| | |
| | | vertical-align: middle; |
| | | margin-left: 12px; |
| | | } |
| | | |
| | | /* 头部 */ |
| | | .el-dialog__header { |
| | | width: 1270px; |
| | | height: 47px; |
| | | margin-bottom: 14px; |
| | | background: url('/src/assets/images/home/homeLeft/inspection-vector.png') no-repeat center; |
| | | background-size: 100% 100%; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | line-height: 47px; |
| | | } |
| | | |
| | | .el-dialog .el-dialog__header { |
| | | /* margin: 0px !important; */ |
| | | padding: 0px !important; |
| | | padding-left: 0px !important; |
| | | } |
| | | /* 头部 */ |
| | | .el-dialog__title { |
| | | width: 112px; |
| | | height: 19px; |
| | | font-family: Segoe UI, Segoe UI; |
| | | font-weight: bold; |
| | | font-size: 16px; |
| | | line-height: 16px; |
| | | text-shadow: 0px 0px 5px rgba(154, 218, 255, 0.6); |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | background: linear-gradient(90deg, #fbfdff 0%, #86d4ff 100%); |
| | | margin-left: 16px; |
| | | -webkit-background-clip: text; /* 背景被裁剪成文字的前景色 */ |
| | | -webkit-text-fill-color: transparent; /* 文字填充颜色变透明 */ |
| | | } |
| | | } |
| | | </style> |
| | | |
| | | <style lang="scss" scoped> |
| | | |
| | | .infoBox { |
| | | display: flex; |
| | | justify-content: space-between; |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | .itemTitle { |
| | | margin-right: 5px; |
| | | margin-right: 5px; |
| | | } |
| | | } |
| | | |
| | |
| | | margin-bottom: 8px; |
| | | } |
| | | } |
| | | .missionOutcomes { |
| | | span { |
| | | color: #ffa500; |
| | | font-size: 14px; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | // 离线中 |
| | | .offine { |
| | | width: 53px; |
| | |
| | | <script setup> |
| | | import MachineLeft from '@/views/SignMachineNest/MachineLeft/MachineLeft.vue' |
| | | import MachineRight from '@/views/SignMachineNest/MachineRight/MachineRight.vue'; |
| | | import { useConnectWebSocket } from '../../utils/websocket/connect-websocket'; |
| | | import { useConnectWebSocket } from '@/utils/websocket/connect-websocket'; |
| | | import { getWebsocketUrl } from '@/websocket/util/config'; |
| | | import { EBizCode } from '@/utils/staticData/enums.js'; |
| | | import { EModeCode } from '@/utils/staticData/device.js'; |
| New file |
| | |
| | | <!--当前任务详情--> |
| | | <template> |
| | | <el-dialog |
| | | modal-class="current-task-details" |
| | | v-model="isShow" |
| | | title="当前任务详情" |
| | | :width="pxToRem(1500)" |
| | | :close-on-click-modal="false" |
| | | :destroy-on-close="true"> |
| | | <div class="content-container" v-if="isShow"> |
| | | <!-- 视频直播 --> |
| | | <div class="video-container"> |
| | | <LiveVideo :videoUrl="machineNestUrl"/> |
| | | </div> |
| | | <!-- 展示地图 --> |
| | | <RealTimeMap /> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { pxToRem } from '@/utils/rem'; |
| | | import LiveVideo from '@/components/LiveVideo.vue'; |
| | | import { liveStart } from '@/api/home/machineNest'; |
| | | import { getJobDetails } from '@/api/home/task'; |
| | | |
| | | import RealTimeMap from '@/views/TaskManage/TaskIntermediateContent/CurrentTaskDetails/RealTimeMap.vue' |
| | | import { getWebsocketUrl } from '@/websocket/util/config' |
| | | import { useConnectWebSocket } from '@/utils/websocket/connect-websocket' |
| | | |
| | | |
| | | const isShow = defineModel('show'); |
| | | const props = defineProps({ |
| | | rowData: { // 任务列表row数据 |
| | | type: Object, |
| | | default: () => ({}) |
| | | } |
| | | }); |
| | | let taskDetails = ref({}) |
| | | const machineNestUrl = ref(''); |
| | | provide('taskDetails', taskDetails); |
| | | |
| | | // 获取机巢直播地址 |
| | | const getVideoUrl = (deviceSn) => { |
| | | liveStart(deviceSn).then(res => { |
| | | if (res.data.code !== 0) return; |
| | | machineNestUrl.value = res.data.data.rtcs_url; |
| | | }); |
| | | }; |
| | | // 获取任务详情获取航线文件 |
| | | const getTaskDetails = () => { |
| | | getJobDetails({ wayLineJobInfoId: props.rowData.id }).then(res => { |
| | | taskDetails.value = res.data.data |
| | | getVideoUrl(taskDetails.value.device_sns[0]); |
| | | console.log('taskDetails', taskDetails.value) |
| | | createWsConnect(taskDetails.value.way_lines[0].workspace_id) |
| | | }) |
| | | } |
| | | const messageHandler = (result) => { |
| | | let payload = JSON.parse(result) // 为了兼容聊天消息 |
| | | console.log('result,6666666', payload) |
| | | } |
| | | let connectWs |
| | | const createWsConnect = (workspaceId) => { |
| | | let webSocketUrl = getWebsocketUrl() + '&workspace-id=' + workspaceId; |
| | | // 监听ws 消息 |
| | | connectWs = useConnectWebSocket(messageHandler, webSocketUrl); |
| | | }; |
| | | |
| | | |
| | | // 监听 rowData 变化 |
| | | watch(isShow, (newVal) => { |
| | | if (newVal) { |
| | | getTaskDetails(); |
| | | }else{ |
| | | connectWs?.close(); |
| | | } |
| | | }); |
| | | |
| | | onBeforeUnmount(() => { |
| | | connectWs?.close(); |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .current-task-details { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | .content-container { |
| | | display: flex; |
| | | // gap: 20px; |
| | | height: 600px; |
| | | |
| | | .video-container { |
| | | width: 50%; |
| | | padding-right: 10px; |
| | | } |
| | | } |
| | | |
| | | } |
| | | </style> |
| New file |
| | |
| | | |
| | | |
| | | <template> |
| | | <div id="currentTaskMap"> |
| | | |
| | | |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | |
| | | import * as Cesium from 'cesium' |
| | | import AmapMercatorTilingScheme from '@/utils/cesium/AmapMercatorTilingScheme' |
| | | import { Cartesian3, Terrain, Viewer } from 'cesium' |
| | | import endPointImg from '@/assets/images/EndPointicon.png' |
| | | import startPointImg from '@/assets/images/Startingpointicon.png' |
| | | import { addBlueFilter } from '@/utils/cesium/common' |
| | | import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz' |
| | | import rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png' |
| | | import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial' |
| | | import lineImg from '@/assets/images/arrow-right-blue.png' |
| | | import { flyVisual } from '@/utils/cesium/mapUtil' |
| | | |
| | | const imageryProvider_ammapSL = new Cesium.UrlTemplateImageryProvider({ |
| | | url: 'https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', |
| | | layer: 'tdtVecBasicLayer', |
| | | style: 'default', |
| | | format: 'image/png', |
| | | tileMatrixSetID: 'GoogleMapsCompatible', |
| | | subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], |
| | | maximumLevel: 18, |
| | | tilingScheme: new AmapMercatorTilingScheme(), |
| | | credit: 'amap_SL', |
| | | }) |
| | | let viewer = null |
| | | const initMap = () => { |
| | | viewer = new Viewer('currentTaskMap', { |
| | | terrain: Terrain.fromWorldTerrain(), |
| | | infoBox: false, // 禁用沙箱,解决控制台报错 |
| | | animation: false, // 左下角的动画仪表盘 |
| | | baseLayerPicker: false, // 右上角的图层选择按钮 |
| | | geocoder: false, // 搜索框 |
| | | homeButton: false, // home按钮 |
| | | sceneModePicker: false, // 模式切换按钮 |
| | | timeline: false, // 底部的时间轴 |
| | | navigationHelpButton: false, // 右上角的帮助按钮, |
| | | selectionIndicator: false, // 是否显示选择指示器 |
| | | baseLayer: false, |
| | | fullscreenButton: false, |
| | | }) |
| | | const gdLayer = viewer.imageryLayers.addImageryProvider(imageryProvider_ammapSL) |
| | | const options = { |
| | | bInvertColor: true, |
| | | bFilterColor: true, |
| | | filterColor: '#4e70a6' |
| | | } |
| | | // 添加蓝色滤镜 |
| | | addBlueFilter(options,viewer,gdLayer) |
| | | viewer.scene.morphTo2D(0) |
| | | //设置默认点 |
| | | viewer.camera.setView({ |
| | | destination: Cartesian3.fromDegrees(115.763819, 28.787374,5000), |
| | | }) |
| | | } |
| | | |
| | | |
| | | const drawWayline = lineObj => { |
| | | const positions = lineObj.Placemark.map(item => { |
| | | const [lon, lat] = item.Point.coordinates.split(',') |
| | | return Cartesian3.fromDegrees(Number(lon), Number(lat)) |
| | | }) |
| | | // 起点 |
| | | viewer.entities.add({ |
| | | position: positions[0], |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(rwqfdImg), |
| | | width: 70, |
| | | height: 70, |
| | | }, |
| | | }) |
| | | // 终点 |
| | | viewer.entities.add({ |
| | | position: positions[positions.length-1], |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(endPointImg), |
| | | width: 30, |
| | | height: 30, |
| | | verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐 |
| | | }, |
| | | }) |
| | | // 路径线 |
| | | viewer.entities.add({ |
| | | polyline: { |
| | | width: 4, |
| | | positions: positions, |
| | | 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, |
| | | }, |
| | | }) |
| | | } |
| | | |
| | | |
| | | // 解析kmz文件 |
| | | const parsingFiles = async (url) => { |
| | | const res = await analyzeKmzFile(`${url}?_t=${new Date().getTime()}`) |
| | | const waylinesXML = await res.fileInfoObj['wpmz/waylines.wpml'] |
| | | const waylinesXMLJSON = XMLToJSON(waylinesXML)?.['Document']; |
| | | const waylinesXMLObj = removeTextKey(waylinesXMLJSON.Folder) |
| | | if (!waylinesXMLObj.Placemark.length) return; |
| | | const allPoint = waylinesXMLObj.Placemark.map(item => item.Point.coordinates.split(',')) |
| | | flyVisual(allPoint,viewer) |
| | | drawWayline(waylinesXMLObj) |
| | | }; |
| | | |
| | | const removeMap = () => { |
| | | viewer.entities.removeAll() |
| | | viewer.destroy() |
| | | } |
| | | |
| | | const taskDetails = inject('taskDetails') |
| | | |
| | | watch(taskDetails, () => { |
| | | if (taskDetails.value.way_lines.length){ |
| | | parsingFiles(taskDetails.value.way_lines[0].url) |
| | | } |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | removeMap() |
| | | }) |
| | | |
| | | onMounted(() => { |
| | | nextTick(() => { |
| | | initMap() |
| | | }) |
| | | }) |
| | | |
| | | </script> |
| | | <style scoped lang="scss"> |
| | | #currentTaskMap { |
| | | width: 50%; |
| | | padding-left: 10px; |
| | | height: 100%; |
| | | :deep() { |
| | | .cesium-viewer { |
| | | width: 100%; |
| | | height: 100%; |
| | | overflow: hidden; |
| | | |
| | | .cesium-viewer-cesiumWidgetContainer { |
| | | width: 100%; |
| | | height: 100%; |
| | | |
| | | .cesium-widget { |
| | | width: 100%; |
| | | height: 100%; |
| | | |
| | | canvas { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .cesium-viewer-bottom { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <el-table-column prop="ai_type_str" label="关联算法" show-overflow-tooltip /> |
| | | <el-table-column label="任务状态" > |
| | | <template #default="scope"> |
| | | <span :style="{ |
| | | color: scope.row.status === 1 ? '#e36913' : |
| | | scope.row.status === 2 ? '#ffc398' : |
| | | <span :style="{ |
| | | color: scope.row.status === 1 ? '#e36913' : |
| | | scope.row.status === 2 ? '#ffc398' : |
| | | scope.row.status === 3 ? '#afd9fb' : |
| | | scope.row.status === 4 ? '#11c4ff' : '8cfea7' |
| | | }"> |
| | |
| | | <script setup> |
| | | import SearchBox from '../SearchBox.vue'; |
| | | import AddTask from './AddTask.vue'; |
| | | import CurrentTaskDetails from './CurrentTaskDetails.vue'; |
| | | import CurrentTaskDetails from './CurrentTaskDetails/CurrentTaskDetails.vue'; |
| | | import { jobList } from '@/api/home/task'; |
| | | import { ElMessage } from 'element-plus' |
| | | |
| | | const jobListParams = reactive({ |
| | | current: 1, |
| | |
| | | let isShowCurrentTaskDetails = ref(false); |
| | | let rowData = ref({}); |
| | | const handleDetail = (row) => { |
| | | isShowCurrentTaskDetails.value = true; |
| | | rowData.value = row? row : {}; |
| | | if (row.device_sns.length === 1){ |
| | | isShowCurrentTaskDetails.value = true; |
| | | rowData.value = row? row : {}; |
| | | }else{ |
| | | ElMessage.warning('即将跳转到集群调度'); |
| | | } |
| | | }; |
| | | |
| | | // 分页大小改变 |