forked from drone/command-center-dashboard

chenyao
2025-04-19 bdbc09270be8590d9b5a4837501074dfc338d34b
Merge branch 'master' of http://139.196.74.78:10010/r/drone/command-center-dashboard
23 files modified
3 files added
7793 ■■■■ changed files
index.html 2 ●●● patch | view | raw | blame | history
pnpm-lock.yaml 6968 ●●●● patch | view | raw | blame | history
public/favicon.png patch | view | raw | blame | history
src/api/payload.js 28 ●●●●● patch | view | raw | blame | history
src/assets/images/home/useEventOperate/Ellipse_2412.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/eventClosed.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/eventCompleted.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/eventPending.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/eventProcessing.png patch | view | raw | blame | history
src/assets/images/home/useEventOperate/eventWaitAudit.png patch | view | raw | blame | history
src/components/CurrentTaskDetails/ControlPanel/BaseControl.vue 1 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue 16 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/CurrentTaskDetails.vue 81 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/RealTimeMap.vue 67 ●●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/TaskDetailsHead.vue 4 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/TaskDetailsLeft.vue 26 ●●●● patch | view | raw | blame | history
src/components/CurrentTaskDetails/TaskDetailsRight.vue 6 ●●●●● patch | view | raw | blame | history
src/hooks/components/DevicePopUpBox.vue 2 ●●● patch | view | raw | blame | history
src/hooks/useTaskDetails/useTaskDetails.js 27 ●●●●● patch | view | raw | blame | history
src/hooks/useTaskViewInfo/useTaskViewInfo.js 81 ●●●●● patch | view | raw | blame | history
src/hooks/useTaskWayline/useTaskWayline.js 103 ●●●●● patch | view | raw | blame | history
src/views/Home/HomeRight/EventOverview.vue 2 ●●● patch | view | raw | blame | history
src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue 11 ●●●● patch | view | raw | blame | history
src/views/SignMachineNest/MachineRight/InspectionRaskList.vue 334 ●●●● patch | view | raw | blame | history
src/views/TaskManage/TaskIntermediateContent/AddTask.vue 27 ●●●●● patch | view | raw | blame | history
src/views/TaskManage/TaskIntermediateContent/TaskIntermediateContent.vue 7 ●●●● patch | view | raw | blame | history
index.html
@@ -11,7 +11,7 @@
  <meta name='apple-mobile-web-app-capable' content='yes'>
  <meta name='apple-mobile-web-app-status-bar-style' content='black'>
  <meta name='format-detection' content='telephone=no'>
  <link rel='icon' href='/favicon.png' />
  <link rel="icon"  href='/favicon.png' />
  <link rel='stylesheet' href='/fonts/font.css'>
  <link rel='stylesheet' href='/iconfont/index.css'>
  <link rel='stylesheet' href='/iconfont/avue/iconfont.css'>
pnpm-lock.yaml
Diff too large
public/favicon.png

src/api/payload.js
@@ -24,8 +24,8 @@
}
// 获得有效载荷控制
export async function getPayloadControlApi(params) {
  return await request({
export function getPayloadControlApi(params) {
  return request({
    url:`${API_PREFIX}/devices/payload-control/requests`,
    method:'get',
    params
@@ -33,8 +33,8 @@
}
// 云台控制api
export async function ptzControlApi(key,params) {
  return await request({
export function ptzControlApi(key,params) {
  return request({
    url:`${API_PREFIX}/devices/payload-control/payload/${key}`,
    method:'get',
    params
@@ -42,8 +42,8 @@
}
// 拍照和录像
export async function callPhotoAndVideoCmd(sn, type) {
  return await request({
export function callPhotoAndVideoCmd(sn, type) {
  return request({
    url:`${API_PREFIX}/devices/${sn}/payload/photoAndVideoCmd/${type}`,
    method:'get',
  })
@@ -51,17 +51,25 @@
// 相机参数调整
export async function cameraParamsChangeApi(data) {
  return await request({
export function cameraParamsChangeApi(data) {
  return request({
    url:`${API_PREFIX}/devices/payload-control/payload/zoom/level`,
    method:'post',
    data
  })
}
export function getLiveCapacityApi(workspace_id,params) {
  return request({
    url:`/drone-device-core/manage/api/v1/live/capacity${workspace_id}`,
    method:'get',
    params
  })
}
// 云台重置
export async function ptzResetModeApi(params) {
  return await request({
export function ptzResetModeApi(params) {
  return request({
    url:`${API_PREFIX}/devices/payload-control/payload/reset`,
    method:'get',
    params
src/assets/images/home/useEventOperate/Ellipse_2412.png

src/assets/images/home/useEventOperate/eventClosed.png

src/assets/images/home/useEventOperate/eventCompleted.png

src/assets/images/home/useEventOperate/eventPending.png

src/assets/images/home/useEventOperate/eventProcessing.png

src/assets/images/home/useEventOperate/eventWaitAudit.png

src/components/CurrentTaskDetails/ControlPanel/BaseControl.vue
@@ -89,6 +89,7 @@
            &:hover {
                cursor: pointer;
                //background: radial-gradient(circle, #5d5c5e 0%, #514f52 50%, #3d3b3d 100%);
                box-shadow: 0 0 20px 5px rgba(0, 0, 0, 0.3);
            }
        }
src/components/CurrentTaskDetails/ControlPanel/ControlPanel.vue
@@ -34,7 +34,7 @@
            </div>
            <div class="speed">
                <el-icon class="btnIcon" @click="speed = speed + 1">
                <el-icon class="btnIcon" @click="speed = speed === 15 ? 15 : speed + 1">
                    <Plus />
                </el-icon>
                <div>
@@ -42,7 +42,7 @@
                    <br />
                    m/s
                </div>
                <el-icon class="btnIcon" @click="speed = speed - 1">
                <el-icon class="btnIcon" @click="speed = speed === 0 ? 0 : speed - 1">
                    <Minus />
                </el-icon>
            </div>
@@ -181,7 +181,7 @@
let timer = null
let totalSeconds = 0
const workspace_id = computed(() => taskDetails?.value?.workspace_id)
const workspace_id = inject('workspace_id')
const list1 = [
    { key: KeyCode.KEY_Q, text: 'Q', icon: RefreshLeft },
    { key: KeyCode.KEY_W, text: 'W', icon: ArrowUp },
@@ -406,8 +406,7 @@
    speed: speed.value,
}))
watch(
    () => workspace_id.value,
watch(workspace_id,
    async () => {
        if (workspace_id.value && mqttState === null && client_id.value === '') {
            await createConnect()
@@ -465,7 +464,7 @@
    right: 0;
    width: 1400px;
    height: 217px;
    background: linear-gradient(196deg, rgba(23, 23, 23, 0.11) 0%, rgba(6, 6, 6, 0.11) 100%);
    background: rgba(31, 31, 31, 0.15);
    backdrop-filter: blur(5px);
    border-radius: 40px 0px 40px 40px;
    display: flex;
@@ -519,10 +518,11 @@
            box-shadow: 2px 4px 6px 0px rgba(0, 13, 26, 0.42);
            border-radius: 8px 8px 8px 8px;
            text-align: center;
            padding: 5px 0;
            padding: 10px 0;
            .btnIcon {
                font-size: 20px;
                cursor: pointer;
            }
        }
    }
@@ -631,7 +631,7 @@
        .divider {
            position: absolute;
            transform: translateX(90px);
            transform: translateX(95px);
            width: 0;
            height: 137px;
            border: 1px solid rgba(255, 255, 255, 0.07);
src/components/CurrentTaskDetails/CurrentTaskDetails.vue
@@ -1,3 +1,13 @@
<!--
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2025-04-19 13:13:15
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2025-04-19 15:07:04
 * @FilePath: \command-center-dashboard\src\components\CurrentTaskDetails\CurrentTaskDetails.vue
 * @Description:
 *
 * Copyright (c) 2025 by shuishen, All Rights Reserved.
-->
<!--当前任务详情-->
<template>
    <el-dialog
@@ -10,7 +20,7 @@
    >
        <div class="content-container" v-if="isShow">
            <!-- 视频直播 -->
            <div :class="`${isMaxMap ? 'minBox' : 'maxBox'}`">
            <div :class="`${isMaxMap ? 'minBox' : 'maxBox'} centerPoint`">
                <LiveVideo :videoUrl="currentLiveUrl" :controls="false" />
            </div>
            <!-- 展示地图 -->
@@ -20,9 +30,7 @@
                <TaskDetailsHead />
                <TaskDetailsLeft />
            </template>
            <!--    控制面板,里面有方法需要立即执行,不可用v-if        -->
            <!--            <ControlPanel />-->
            <ControlPanel v-show="!isAutoControl" />
            <img alt="" :src="amplifyImg" class="amplify" @click="isMaxMap = !isMaxMap" />
        </div>
@@ -44,14 +52,14 @@
import { ElMessage } from 'element-plus'
import EventBus from '@/event-bus'
import { updateDroneQualityApi } from '@/api/drc'
import { getLiveAiLinkApi } from '@/api/payload'
import { getLiveAiLinkApi, getLiveCapacityApi } from '@/api/payload'
import { CURRENT_CONFIG } from '@/utils/http/config'
import { useDroneWS } from '@/hooks/useDroneWS'
import { useTaskDetails } from '@/hooks/useTaskDetails/useTaskDetails'
const isAutoControl = ref(true) //是否自动控制
const lineQuality = ref(1) //1流畅,2标清
const taskDetailsViewer = ref(null) //地图实例
let taskDetails = ref({}) //任务详情
const deviceOsdInfo = computed(() => wsInfo.value?.device_osd)
const dockSn = computed(() => taskDetails?.value?.device_sns?.[0])
const droneSn = computed(() => deviceOsdInfo?.value?.data?.sn)
@@ -64,9 +72,27 @@
const isTakeOff = ref(false) // 是在飞行中
const isMaxMap = ref(false) //是大地图
const client_id = ref('') //是大地图
const workspace_id = ref('')
// 获取机巢直播
const getDeviceLiveUrl = async () => {
    const res = await liveStart(dockSn.value, 2)
    currentLiveUrl.value = res.data.data.rtcs_url
}
//获取相机能力
async function getLiveCapacity() {
    const res = await getLiveCapacityApi(workspace_id.value,{ sn: dockSn.value})
}
const useTaskDetailsCallBack = () => {
    console.log(workspace_id.value,66666666)
    getDeviceLiveUrl()
}
let { taskDetails, workspace_id, getTaskDetails } = useTaskDetails(useTaskDetailsCallBack)
let { wsInfo, removeWS } = useDroneWS(workspace_id) //ws信息,是一个ref对象
provide('wsInfo', wsInfo)
provide('workspace_id', workspace_id)
provide('deviceOsdInfo', deviceOsdInfo)
provide('dockOsdInfo', wsInfo?.value?.dock_osd)
provide('dockSn', dockSn)
@@ -80,6 +106,14 @@
provide('video_id', video_id)
provide('client_id', client_id)
let once = true
watch(deviceOsdInfo,()=>{
    if (once){
        // getLiveCapacity()
        once =false
    }
})
watch(
    wsInfo,
    () => {
@@ -88,12 +122,6 @@
    },
    { deep: true }
)
// 获取机巢直播
const getDeviceLiveUrl = async () => {
    const res = await liveStart(dockSn.value, 2)
    currentLiveUrl.value = res.data.data.rtcs_url
}
const getAiLiveUrl = async () => {
    const res = await getLiveAiLinkApi({
@@ -132,19 +160,9 @@
    isTakeOff.value = currentIsTakeOff
    isTakeOff.value ? await getDroneLiveUrl() : await getDeviceLiveUrl()
}
// 获取任务详情获取航线文件
const getTaskDetails = () => {
    if (!props.id) ElMessage.warning('请检查是否传入id')
    getJobDetails({ wayLineJobInfoId: props.id }).then(async res => {
        taskDetails.value = res.data.data
        await getDeviceLiveUrl()
        taskDetails.value.workspace_id = taskDetails.value.way_lines[0]?.workspace_id
        workspace_id.value = taskDetails.value.workspace_id
    })
}
onMounted(() => {
    getTaskDetails()
    getTaskDetails(props?.id)
    EventBus.on('CurrentTaskDetails-timeStop', changeLineQuality)
    EventBus.on('CurrentTaskDetails-getAiLiveUrl', getAiLiveUrl)
    EventBus.on('CurrentTaskDetails-getDroneLiveUrl', getDroneLiveUrl)
@@ -201,6 +219,21 @@
    border-radius: 4rem;
    overflow: hidden;
    .centerPoint {
        &:before {
            content: '+';
            font-size: 30px;
            color: white;
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            pointer-events: none;
            font-weight: bold;
            text-shadow: -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black, 1px 1px 0 black; /* 四方向描边 */
        }
    }
    .maxBox {
        width: 100%;
        height: 100%;
@@ -222,6 +255,8 @@
        position: absolute;
        left: 340px;
        bottom: 183px;
        width: 22px;
        height: 22px;
    }
}
</style>
src/components/CurrentTaskDetails/RealTimeMap.vue
@@ -5,15 +5,10 @@
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 { 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'
import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum'
import aircraftGltf from '@/assets/gltf/aircraft.gltf'
import { useTaskWayline } from '@/hooks/useTaskWayline/useTaskWayline'
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}',
@@ -61,59 +56,6 @@
        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))
    })
    // 起点
    taskDetailsViewer?.value.entities.add({
        position: positions[0],
        billboard: {
            image: new Cesium.ConstantProperty(rwqfdImg),
            width: 70,
            height: 70,
        },
    })
    // 终点
    taskDetailsViewer?.value.entities.add({
        position: positions[positions.length - 1],
        billboard: {
            image: new Cesium.ConstantProperty(endPointImg),
            width: 30,
            height: 30,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐
        },
    })
    // 路径线
    taskDetailsViewer?.value.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, taskDetailsViewer?.value)
    drawWayline(waylinesXMLObj)
}
let viewInfoFrustum
// 设置视椎
@@ -165,11 +107,8 @@
    setCreateFrustum()
    setAircraftGltf()
})
watch(taskDetails, () => {
    if (taskDetails.value.way_lines.length) {
        parsingFiles(taskDetails.value.way_lines[0].url)
    }
})
useTaskWayline(taskDetailsViewer, taskDetails)
const removeMap = () => {
    taskDetailsViewer?.value.entities.removeAll()
src/components/CurrentTaskDetails/TaskDetailsHead.vue
@@ -44,8 +44,8 @@
    { index: 4, title: '经度', value: 0, unit: '°' },
    { index: 5, title: '纬度', value: 0, unit: '°' },
    { index: 6, title: '风速', value: 0, unit: 'M/s' },
    { index: 7, title: '4G信号', value: 0, unit: '' },
    { index: 8, title: 'SDR信号', value: 0, unit: '' },
    { index: 7, title: '4G信号', value: '-', unit: '' },
    { index: 8, title: 'SDR信号', value: '-', unit: '' },
    { index: 9, title: 'GPS搜星数', value: 0, unit: '' },
    { index: 10, title: 'RTK搜星数', value: 0, unit: '' },
    { index: 11, title: '距离机场', value: 0, unit: 'M' },
src/components/CurrentTaskDetails/TaskDetailsLeft.vue
@@ -21,7 +21,7 @@
            <div @click="takePictures">拍照</div>
            <div @click="recordFun">{{ isRecording ? '录像中...' : '录像' }}</div>
        </div>
        <div class="multiCol">
        <div class="multiCol" v-if="wsInfo?.psdk_widget_values">
            <div @click="shoutFun">{{ isRecordShouting ? '喊话' : '停止喊话' }}</div>
            <div @click="broadcastFun">广播</div>
        </div>
@@ -36,6 +36,7 @@
                :max="cameraParams.camera_type === 'ir' ? 200 : 200"
                @change="sliderChange"
            />
            <div class="cameraZoomText">{{cameraParams.zoom_factor}}X</div>
        </div>
    </div>
    <!-- 广播列表 -->
@@ -101,9 +102,9 @@
import Recorder from 'js-audio-recorder';
import dayjs from 'dayjs'
const wsInfo = inject('wsInfo')
// 初始化喊话
let globalShout = null
const isRecording = ref(false)
const list1 = ref([
@@ -345,7 +346,7 @@
    top: 50%;
    transform: translateY(-60%);
    width: 178px;
    height: 416px;
    padding: 20px 0;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(5px);
    border-radius: 20px 20px 20px 20px;
@@ -363,16 +364,27 @@
    .cameraZoom {
        position: absolute;
        padding: 16px 0;
        padding: 20px 0 15px 0;
        left: 1600px;
        top: -59px;
        width: 112px;
        width: 90px;
        height: 490px;
        background: rgba(64, 64, 64, 0.15);
        background: rgba(0, 0, 0, 0.4);
        backdrop-filter: blur(5rem);
        border-radius: 20px 20px 20px 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
        .el-slider {
            height: 100%;
            flex: 1;
        }
        .cameraZoomText{
            font-family: Segoe UI, Segoe UI;
            font-weight: 400;
            font-size: 22px;
            color: #ffffff;
            margin-top: 20px;
        }
    }
src/components/CurrentTaskDetails/TaskDetailsRight.vue
@@ -11,7 +11,7 @@
            </div>
        </div>
        <BaseControl v-if="taskDetails.workspace_id" />
        <BaseControl v-if="workspace_id" />
    </div>
</template>
<script setup>
@@ -19,6 +19,7 @@
import BaseControl from '@/components/CurrentTaskDetails/ControlPanel/BaseControl.vue'
const taskDetails = inject('taskDetails')
const workspace_id = inject('workspace_id')
const list = ref([
    { name: '任务编号', value: '', field: 'job_info_num' },
@@ -58,7 +59,8 @@
    top: 0;
    width: 297px;
    height: 1002px;
    background: rgba(31, 31, 31, 0.15);
    background: rgba(31, 31, 31, 0.5);
    backdrop-filter: blur(0.5rem);
    border-radius: 0px 40px 40px 0px;
    display: flex;
    flex-direction: column;
src/hooks/components/DevicePopUpBox.vue
@@ -55,7 +55,7 @@
  const areaCode = props.data.region_code;
  dataObj.value.region_name = props.data.region_name;
  const res = await getDeviceInfoNum({ areaCode });
  console.log('首页地图弹框',res);
  
  const resJob = await getTotalJobNum({ areaCode });
  dataObj.value.jobNum = resJob.data.data;
src/hooks/useTaskDetails/useTaskDetails.js
New file
@@ -0,0 +1,27 @@
import { ElMessage } from 'element-plus'
import { getJobDetails } from '@/api/home/task'
export function useTaskDetails (cb) {
  const taskDetails = ref({})
  const workspace_id = ref('')
  const getTaskDetails = async (id) => {
    if (!id) ElMessage.warning('请检查是否传入id')
    try {
      const res = await getJobDetails({ wayLineJobInfoId: id })
      taskDetails.value = res.data.data
      cb && await cb()
      workspace_id.value = taskDetails.value.way_lines[0]?.workspace_id
      return taskDetails.value
    } catch (error) {
      ElMessage.warning('获取任务详情失败')
      throw error
    }
  }
  return {
    taskDetails,
    workspace_id,
    getTaskDetails
  }
}
src/hooks/useTaskViewInfo/useTaskViewInfo.js
New file
@@ -0,0 +1,81 @@
import * as Cesium from 'cesium'
import aircraftGltf from '@/assets/gltf/aircraft.gltf'
import CreateFrustum from '@/utils/cesium/frustum/CreateFrustum'
export function useTaskViewInfo (viewer, wsInfo, removeEntitys) {
  const newViewer = unref(viewer)
  let viewInfoFrustum
  // 设置视椎
  const setCreateFrustum = (host) => {
    if (!host) return
    viewInfoFrustum?.clear()
    const attitude_head = 180 + host.attitude_head
    const gimbal_pitch = 90 - Number(host?.payloads[0]?.gimbal_pitch) || 0
    viewInfoFrustum = new CreateFrustum(newViewer, {
      position: {
        longitude: host.longitude,
        latitude: host.latitude,
        altitude: host.height,
      },
      width: 30,
      height: 30,
      fov: 20.0,
      near: 3.0,
      far: 250.0,
      roll: gimbal_pitch,
      pitch: 0,
      heading: attitude_head,
    })
  }
  function setAircraftGltf () {
    const host = deviceOsdInfo.value?.data?.host
    const aircraftEntity = newViewer.entities.getById('aircraftGltf')
    const position = Cesium.Cartesian3.fromDegrees(host.longitude, host.latitude, host.height)
    if (aircraftEntity) {
      aircraftEntity.position = new Cesium.ConstantPositionProperty(position)
      return
    }
    newViewer.entities.add({
      id: 'aircraftGltf',
      position,
      model: {
        uri: aircraftGltf, // 或 .glb
        scale: 1.0, // 缩放比例
        minimumPixelSize: 64, // 最小像素尺寸(保证模型远处可见)
        maximumScale: 128, // 最大缩放(可选)
      },
    })
  }
  // 视椎加载处理
  const deviceOsdInfo = computed(() => wsInfo.value?.device_osd)
  watch(deviceOsdInfo, () => {
    const host = deviceOsdInfo.value?.data?.host
    if ([14, 0].includes(host.mode_code)) {
      mapEntityRemove()
      return
    }
    setCreateFrustum(host)
    setAircraftGltf()
  })
  const mapEntityRemove = () => {
    viewInfoFrustum?.clear()
    newViewer.entities.removeById('aircraftGltf')
    removeEntitys && removeEntitys()
  }
  onUnmounted(() => {
    mapEntityRemove()
  })
}
src/hooks/useTaskWayline/useTaskWayline.js
New file
@@ -0,0 +1,103 @@
/*
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2025-04-19 14:24:34
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2025-04-19 15:23:57
 * @FilePath: \command-center-dashboard\src\hooks\useTaskWayline\useTaskWayline.js
 * @Description:
 *
 * Copyright (c) 2025 by shuishen, All Rights Reserved.
 */
import lineImg from '@/assets/images/arrow-right-blue.png'
import rwqfdImg from '@/assets/images/signMachineNest/rwqfd.png'
import endPointImg from '@/assets/images/EndPointicon.png'
import { analyzeKmzFile, removeTextKey, XMLToJSON } from '@/utils/cesium/kmz'
import { flyVisual } from '@/utils/cesium/mapUtil'
import ImageTrailMaterial from '@/utils/cesium/ImageTrailMaterial'
import * as Cesium from 'cesium'
import { Cartesian3 } from 'cesium'
export function useTaskWayline (viewer, taskDetails) {
  const newViewer = unref(viewer)
  // 解析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, newViewer)
    drawWayline(waylinesXMLObj)
  }
  const drawWayline = lineObj => {
    const positions = lineObj.Placemark.map(item => {
      const [lon, lat] = item.Point.coordinates.split(',')
      return Cartesian3.fromDegrees(Number(lon), Number(lat))
    })
    // 起点
    newViewer.entities.add({
      id: 'drone-job-wayline-start',
      position: positions[0],
      billboard: {
        image: new Cesium.ConstantProperty(rwqfdImg),
        width: 70,
        height: 70,
      },
    })
    // 终点
    newViewer.entities.add({
      id: 'drone-job-wayline-end',
      position: positions[positions.length - 1],
      billboard: {
        image: new Cesium.ConstantProperty(endPointImg),
        width: 30,
        height: 30,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 底部对齐
      },
    })
    // 路径线
    newViewer.entities.add({
      id: 'drone-job-wayline-polyline',
      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,
      },
    })
  }
  watch(taskDetails, () => {
    if (taskDetails.value?.way_lines?.length) {
      parsingFiles(taskDetails.value.way_lines[0].url)
    }
  }, { immediate: true })
  const removeEntitys = () => {
    const entitiesIDs = newViewer?.entities.values.map(i => i.id)
    entitiesIDs.forEach(item => {
      item.includes('drone-job-wayline-') && newViewer?.entities.removeById(item)
    })
  }
  onBeforeUnmount(() => {
    removeEntitys()
  })
  return {
    removeEntitys
  }
}
src/views/Home/HomeRight/EventOverview.vue
@@ -144,7 +144,7 @@
const today = dayjs().format('YYYY-MM-DD')
const timeArr = ref([today, today])
const completionRateSeries = {
    name: '完成率',
    name: '完结率',
    type: 'line',
    itemStyle: {
        color: '#0CEBF7', // 设置颜色
src/views/SignMachineNest/MachineLeft/InspectionRaskDetails.vue
@@ -162,12 +162,13 @@
                color: '#fff',
            },
            data: [
                { value: 0, name: '待审核', itemStyle: { color: '#1860EC' } },
                { value: 0, name: '待处理', itemStyle: { color: '#47D107' } },
                { value: 0, name: '已完成', itemStyle: { color: '#F29509' } },
                { value: 0, name: '待审核', itemStyle: { color: '#8CFEA7' } },
                { value: 0, name: '待处理', itemStyle: { color: '#FF7411' } },
                { value: 0, name: '处理中', itemStyle: { color: '#FFC398' } },
                { value: 0, name: '已完成', itemStyle: { color: '#AFD9FB' } },
                // { value: 0, name: '待分拨', itemStyle: { color: '#E9C81A' } },
                { value: 0, name: '处理中', itemStyle: { color: '#0FC1E8' } },
                { value: 0, name: '已完结', itemStyle: { color: '#FE577F' } },
                { value: 0, name: '已完结', itemStyle: { color: '#11C4FF' } },
            ],
        },
    ],
src/views/SignMachineNest/MachineRight/InspectionRaskList.vue
@@ -16,31 +16,38 @@
          </el-input>
        </div>
      </div>
      <div class="table-list" v-if="tableList.length > 0"
            <div
                class="table-list"
                v-if="tableList.length > 0"
        infinite-scroll-distance="6"
        v-infinite-scroll="loadMore"
        :infinite-scroll-disabled="busy"
        infinite-scroll-immediate="true">>
                infinite-scroll-immediate="true"
            >
                >
        <div class="item" v-for="(item,index) in tableList">
          <div class="left" @click="taskClick(item)">
            <div class="left-t">
              <span>{{ index+1 }}.</span>{{ item.name }}
                            <span>{{ index + 1 }}.</span>
                            {{ item.name }}
              <span class="status" :class="item.status===2?'active':''">
                {{ getStatusText(item.status) }}
              </span>
            </div>
            <div class="left-b">
              <img src="../../../assets/images/signMachineNest/machineRight/date.png" alt="" />{{ item.begin_time }}
              <img src="../../../assets/images/signMachineNest/machineRight/name.png" alt="" />{{ item.creator_name || '' }}
                            <img src="../../../assets/images/signMachineNest/machineRight/date.png" alt="" />
                            {{ item.begin_time }}
                            <img src="../../../assets/images/signMachineNest/machineRight/name.png" alt="" />
                            {{ item.creator_name || '' }}
            </div>
          </div>
          <div class="right" v-if="tabIndex===1" @click="reExecute(item.dock_sn)">
            <span>立即返航</span>
            <img src="../../../assets/images/signMachineNest/machineRight/return-fly.png" alt="">
                        <img src="../../../assets/images/signMachineNest/machineRight/return-fly.png" alt="" />
          </div>
          <div class="right" v-else @click="returnImmediately(item.job_id)">
            <span>再次执行</span>
            <img src="../../../assets/images/signMachineNest/machineRight/return-fly.png" alt="">
                        <img src="../../../assets/images/signMachineNest/machineRight/return-fly.png" alt="" />
          </div>
        </div>
      </div>
@@ -52,74 +59,80 @@
    </div>
  </div>
  <!-- 当前任务详情 -->
  <CurrentTaskDetails
        v-if="isShowCurrentTaskDetails"
        v-model:show="isShowCurrentTaskDetails"
        :id="currentInfoId"/>
    <CurrentTaskDetails v-if="isShowCurrentTaskDetails" v-model:show="isShowCurrentTaskDetails" :id="currentInfoId" />
    <!-- 历史任务详情 -->
  <DeviceJobDetails
        v-if="isShowDeviceJobDetails"
        v-model:show="isShowDeviceJobDetails"
        :wayLineJodInfoId="wayLineJodInfoId"/>
        :wayLineJodInfoId="wayLineJodInfoId"
    />
</template>
<script setup>
import { Search } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import CommonTitle from '@/components/CommonTitle.vue';
import CurrentTaskDetails from '@/components/CurrentTaskDetails/CurrentTaskDetails.vue';
import { Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import CommonTitle from '@/components/CommonTitle.vue'
import CurrentTaskDetails from '@/components/CurrentTaskDetails/CurrentTaskDetails.vue'
import DeviceJobDetails from '@/components/DeviceJobDetails/DeviceJobDetails.vue'
import { getBeforeJob, getTodayJob, flyByJobId, returnHome } from '@/api/home';
import { useStore } from 'vuex';
import { getBeforeJob, getTodayJob, flyByJobId, returnHome } from '@/api/home'
import { useStore } from 'vuex'
import { useTaskWayline } from '@/hooks/useTaskWayline/useTaskWayline'
import { useTaskDetails } from '@/hooks/useTaskDetails/useTaskDetails'
import { useTaskViewInfo } from '@/hooks/useTaskViewInfo/useTaskViewInfo'
import { useDroneWS } from '@/hooks/useDroneWS'
let viewer = null
const store = useStore();
let { taskDetails, workspace_id, getTaskDetails } = useTaskDetails()
let { wsInfo, removeWS } = useDroneWS(workspace_id) //ws信息,是一个ref对象
const store = useStore()
// 设备任务详情
let currentInfoId = ref('');
let isShowCurrentTaskDetails = ref(false);
let wayLineJodInfoId = ref('');
let isShowDeviceJobDetails = ref(false);
let currentInfoId = ref('')
let isShowCurrentTaskDetails = ref(false)
let wayLineJodInfoId = ref('')
let isShowDeviceJobDetails = ref(false)
// 单个机巢信息
const singleUavHome = computed(() => store.state.home.singleUavHome);
const singleUavHome = computed(() => store.state.home.singleUavHome)
const isMore = ref(true);
const isMore = ref(true)
// 控制加载状态
const busy = ref(false);
const busy = ref(false)
let searchText = ref('')
const tableList = ref([]);
const tableList = ref([])
// 分页
const pageParams = ref({
  current: 1,
  size: 5,
  total: 0
});
    total: 0,
})
// 当前任务和历史任务切换
let tabIndex = ref(1);
const tabClick = (value) => {
  tabIndex.value = value;
  clearData();
};
let tabIndex = ref(1)
const tabClick = value => {
    tabIndex.value = value
    clearData()
}
// 状态文字判断
const getStatusText = (status) => {
const getStatusText = status => {
  switch (status) {
    case 1:
      return '待执行';
            return '待执行'
    case 2:
      return '执行中';
            return '执行中'
    case 3:
      return '完成';
            return '完成'
    case 4:
      return '取消';
            return '取消'
    case 5:
      return '失败';
            return '失败'
    default:
      return '未知';
            return '未知'
  }
};
}
// 获取历史巡检任务列表
const getJobList = async () => {
@@ -130,89 +143,217 @@
    current: pageParams.value.current,
    size: pageParams.value.size,
  }
  let result = null;
    let result = null
  if (tabIndex.value === 1) {
    result = await getTodayJob(params)
  } else {
    result = await getBeforeJob(params)
  }
  if (result.data.code !== 0) return;
  if (result.data.data.records.length === 0) return (isMore.value = false);
  pageParams.value.current += 1;
  tableList.value = [...tableList.value, ...result.data.data.records];
  busy.value = false;
    if (result.data.code !== 0) return
    if (result.data.data.records.length === 0) return (isMore.value = false)
    pageParams.value.current += 1
    tableList.value = [...tableList.value, ...result.data.data.records]
    busy.value = false
}
// 清除数据
const clearData = () => {
  tableList.value = [];
  pageParams.value.current = 1;
  isMore.value = true;
  getJobList();
};
    tableList.value = []
    pageParams.value.current = 1
    isMore.value = true
    getJobList()
}
// 加载更多数据
const loadMore = async () => {
    busy.value = true;
    if (!isMore.value) return;
    getJobList();
};
    busy.value = true
    if (!isMore.value) return
    getJobList()
}
// 搜索数据
const searchNickName = () => {
  clearData();
};
    clearData()
}
// 立即返航
const returnImmediately = (id) => {
const returnImmediately = id => {
  flyByJobId(id).then(result => {
    if (result.data.code === 0) {
      ElMessage.success('执行成功');
            ElMessage.success('执行成功')
    } else {
      ElMessage.error(result.data.message);
            ElMessage.error(result.data.message)
    }
  });
};
    })
}
// 重新执行
const reExecute = (dock_sn) => {
const reExecute = dock_sn => {
  returnHome(dock_sn).then(result => {
    if (result.data.code === 0) {
      ElMessage.success('返航成功');
            ElMessage.success('返航成功')
    } else {
      ElMessage.error(result.data.message);
            ElMessage.error(result.data.message)
    }
  });
};
    })
}
// 点击当前任务显示当前任务详情
const taskClick = (item) => {
const taskClick = item => {
  if (tabIndex.value === 1) {
    // 展示当前任务详情
    currentInfoId.value = item.wayline_job_info_id;
    isShowCurrentTaskDetails.value = true;
        currentInfoId.value = item.wayline_job_info_id
        isShowCurrentTaskDetails.value = true
  } else {
    // 展示历史任务详情
    wayLineJodInfoId.value = item.wayline_job_info_id;
    isShowDeviceJobDetails.value = true;
        wayLineJodInfoId.value = item.wayline_job_info_id
        isShowDeviceJobDetails.value = true
    }
  }
  
};
onMounted(async () => {
    viewer = window.$viewer
onMounted(() => {
  getJobList();
});
    await getJobList()
    // tableList.value = [
    //     {
    //         id: 11563,
    //         status: 5,
    //         begin_time: '2025/04/19 05:46:25',
    //         end_time: '2025/04/19 05:46:25',
    //         create_time: '2025-04-19T05:46:36.032+00:00',
    //         name: '智引即飞202504191252',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 340,
    //         job_id: '484a7846-60e0-4ec3-b9fb-272a055c6938',
    //     },
    //     {
    //         id: 11559,
    //         status: 5,
    //         begin_time: '2025/04/19 05:39:42',
    //         end_time: '2025/04/19 05:39:42',
    //         create_time: '2025-04-19T05:39:52.022+00:00',
    //         name: '智引即飞202504191252',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 340,
    //         job_id: 'b8c58bfb-4352-47c5-ba33-242eec8df188',
    //     },
    //     {
    //         id: 11558,
    //         status: 3,
    //         begin_time: '2025/04/19 05:39:17',
    //         end_time: '2025/04/19 05:39:17',
    //         create_time: '2025-04-19T05:39:27.407+00:00',
    //         name: '智引即飞202504191252',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 340,
    //         job_id: '839773ce-bd46-4947-a2ef-d859eaea82f6',
    //     },
    //     {
    //         id: 11557,
    //         status: 5,
    //         begin_time: '2025/04/19 04:52:04',
    //         end_time: '2025/04/19 04:52:04',
    //         create_time: '2025-04-19T04:52:14.503+00:00',
    //         name: '智引即飞202504191252',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 340,
    //         job_id: '58366fd4-8361-456f-8ad9-3b881f933620',
    //     },
    //     {
    //         id: 11556,
    //         status: 5,
    //         begin_time: '2025/04/19 03:45:06',
    //         end_time: '2025/04/19 03:45:06',
    //         create_time: '2025-04-19T03:45:16.522+00:00',
    //         name: '智引即飞202504191145',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 338,
    //         job_id: '39c60fb8-e5c4-4474-912a-c3af3f1b9054',
    //     },
    //     {
    //         id: 11555,
    //         status: 5,
    //         begin_time: '2025/04/19 03:27:55',
    //         end_time: '2025/04/19 03:27:55',
    //         create_time: '2025-04-19T03:28:05.196+00:00',
    //         name: '智引即飞202504191127',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 336,
    //         job_id: '78c42532-45e4-4a01-b698-69bca19286ff',
    //     },
    //     {
    //         id: 11554,
    //         status: 5,
    //         begin_time: '2025/04/19 02:58:53',
    //         end_time: '2025/04/19 02:58:53',
    //         create_time: '2025-04-19T02:59:03.602+00:00',
    //         name: '智引即飞202504191058',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 335,
    //         job_id: 'd3b25edc-ec23-4ad6-800a-0f659a72bff3',
    //     },
    //     {
    //         id: 11553,
    //         status: 5,
    //         begin_time: '2025/04/19 02:52:21',
    //         end_time: '2025/04/19 02:52:21',
    //         create_time: '2025-04-19T02:52:31.415+00:00',
    //         name: '智引即飞202504191052',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 334,
    //         job_id: 'e27090f1-e740-4ae4-8d4d-301354eb0bbc',
    //     },
    //     {
    //         id: 11548,
    //         status: 5,
    //         begin_time: '2025/04/19 02:23:06',
    //         end_time: '2025/04/19 02:23:06',
    //         create_time: '2025-04-19T02:23:16.151+00:00',
    //         name: '智引即飞202504191023',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 332,
    //         job_id: '9e1f7283-fe34-4cfd-b468-cd2b34a96d34',
    //     },
    //     {
    //         id: 11547,
    //         status: 3,
    //         begin_time: '2025/04/19 02:18:24',
    //         end_time: '2025/04/19 02:18:24',
    //         create_time: '2025-04-19T02:18:34.590+00:00',
    //         name: '智引即飞202504191018',
    //         event_number: 0,
    //         dock_sn: '7CTDLCR00BQBM2',
    //         wayline_job_info_id: 331,
    //         job_id: '7aa5222c-2f8b-401e-b6ba-d6a550398829',
    //     },
    // ]
    if (tableList.value.length > 0) {
        await getTaskDetails(tableList.value[0].wayline_job_info_id)
    }
})
const { removeEntitys } = useTaskWayline(viewer || window.$viewer, taskDetails)
useTaskViewInfo(viewer || window.$viewer, wsInfo, removeEntitys)
</script>
<style lang="scss" scoped>
  .inspection-rask-list {
    width: 390px;
    height: 325px;
    background: linear-gradient(
      270deg,
      #1f3e7a 0%,
      rgba(31, 62, 122, 0.35) 79%,
      rgba(31, 62, 122, 0) 100%
    );
    background: linear-gradient(270deg, #1f3e7a 0%, rgba(31, 62, 122, 0.35) 79%, rgba(31, 62, 122, 0) 100%);
    opacity: 0.85;
    margin: 2px 0 13 0;
    padding: 11px 27px 0;
@@ -227,12 +368,12 @@
        div {
          width: 104px;
          height: 32px;
          background: #0E2042;
          border: 1px solid #8EA3D1;
                background: #0e2042;
                border: 1px solid #8ea3d1;
          font-family: Source Han Sans CN, Source Han Sans CN;
          font-weight: 400;
          font-size: 16px;
          color: #8EA3D1;
                color: #8ea3d1;
          line-height: 32px;
          text-align: center;
          cursor: pointer;
@@ -284,7 +425,12 @@
        color: #fff;
        display: flex;
        justify-content: space-between;
        background: linear-gradient( 90deg, rgba(71,157,255,0) 0%, rgba(71, 157, 255, 0.12) 50%, rgba(71,157,255,0) 100%);
            background: linear-gradient(
                90deg,
                rgba(71, 157, 255, 0) 0%,
                rgba(71, 157, 255, 0.12) 50%,
                rgba(71, 157, 255, 0) 100%
            );
        .left {
          cursor: pointer;
          .left-t {
@@ -299,13 +445,13 @@
              height: 20px;
              background: rgba(76,166,255,0.08);
              border-radius: 4px 4px 4px 4px;
              border: 1px solid #4CA6FF;
              color: #4CA6FF;
                        border: 1px solid #4ca6ff;
                        color: #4ca6ff;
              margin-left: 10px;
            }
            .active {
              border: 1px solid #04F0D1;
              color: #04F0D1;
                        border: 1px solid #04f0d1;
                        color: #04f0d1;
            }
          }
          .left-b {
@@ -333,11 +479,11 @@
            line-height: 12px;
            font-size: 12px;
            font-family: YouSheBiaoTiHei, YouSheBiaoTiHei, serif;
            color: rgb(4,18,44)
                    color: rgb(4, 18, 44);
          }
          img {
            width: 46px;
            height: 46px
                    height: 46px;
          }
        }
      }
src/views/TaskManage/TaskIntermediateContent/AddTask.vue
@@ -19,6 +19,7 @@
                    </div>
                    <div class="item">
                        <el-date-picker
                            popper-class="custom-date-picker"
                            class="ztzf-date-picker"
                            v-model="taskData"
                            type="daterange"
@@ -31,6 +32,7 @@
                    <div class="item">
                        <div class="itemchild">任务时间:</div>
                        <el-time-picker
                         popper-class="custom-time-picker"
                            class="ztzf-date-picker tasktimer"
                            v-model="timeSlot"
                            placeholder="请选择"
@@ -42,6 +44,7 @@
                        <div class="itemchild">选择航线:</div>
                        
                        <el-select
                            :teleported="false"
                            class="ztzf-select"
                            v-model="searchForm.file_id"
                            @change="getWayLineFile"
@@ -57,12 +60,10 @@
                        </el-select>
                    </div>
                    <div class="item">
                        <div class="itemchild">关联算法:</div>
                        <TaskAlgorithmBusiness  :setWidth="200" :showAlgorithm="true" @algorithmChange="algorithmChange" />
                    </div>
                    <div class="item">
                        <div class="itemchild">任务描述:</div>
                        <el-input class="ztzf-input" v-model="searchForm.remark" placeholder="请输入任务名称"></el-input>
                    </div>
@@ -94,9 +95,8 @@
                    @update:selected="handleSelected"
                />
                <div class="btn">
                    <img @click="cancel" style="margin-right:23px" src="@/assets/images/task/cancel.png" alt="">
                    <img @click="submitClick" src="@/assets/images/task/publish.png" alt="">
                    <img @click="cancel" style="margin-right: 23px" src="@/assets/images/task/cancel.png" alt="" />
                    <img @click="submitClick" src="@/assets/images/task/publish.png" alt="" />
                </div>
            </div>
        </div>
@@ -181,7 +181,7 @@
    waylineType.value = 0
    waylineId.value = val
    const currentRoute = routeOptions.value.find(item => item.wayline_id === val)
    wayLineFile.value = currentRoute?.object_key || '';
    wayLineFile.value = currentRoute?.object_key || ''
}
// 获取选中机场列表数据,并且发布
@@ -253,7 +253,7 @@
    
    searchForm.begin_time = `${taskData.value[0]} 00:00:00`
    searchForm.end_time = `${taskData.value[1]} 23:59:59`
    searchForm.execute_time_arr = timeSlot.value ? [timeSlot.value] : [];
    searchForm.execute_time_arr = timeSlot.value ? [timeSlot.value] : []
    createTask(searchForm).then(res => {
        if (res.data.code === 0) {
            ElMessage.success('任务创建成功')
@@ -294,6 +294,12 @@
        padding: 20px;
    }
}
/* 修改日期单元格背景色 */
.custom-date-picker .el-picker-panel__body {
    background: #012350 !important;
    color: #fff !important;
}
</style>
<style lang="scss" scoped>
@@ -323,7 +329,6 @@
                :deep(.el-date-editor.el-input__wrapper) {
                    width: 200px; // 调整日期选择器宽度
                }
            }
        }
    }
@@ -342,13 +347,11 @@
            height: 32px;
            cursor: pointer;
            }
        }
    }
    :deep(.tasktimer .el-input__wrapper) {
        background: none !important;
        color: #8ac3fd !important;
    }
    :deep(.el-input__inner) {
        color: #8ac3fd !important;
@@ -358,13 +361,13 @@
    }
    :deep(.el-radio__inner){
    background: none !important;
    border: 1px solid #1B5D9A !important;
        border: 1px solid #1b5d9a !important;
    }
    :deep(.el-radio__label){
    color: #fff !important;
    }
    :deep(.el-radio__inner:after ){
    background: #65B5FF !important;
        background: #65b5ff !important;
    }
}
</style>
src/views/TaskManage/TaskIntermediateContent/TaskIntermediateContent.vue
@@ -67,7 +67,7 @@
  <DeviceJobDetails
        v-if="isShowDeviceJobDetails"
        v-model:show="isShowDeviceJobDetails"
        :wayLineJodInfoId="wayLineJodInfoId"/>
        :wayLineJodInfoId="rowData.id"/>
</template>
<script setup>
@@ -85,7 +85,6 @@
});
const jobListData = ref([]);
const total = ref(0);
let wayLineJodInfoId = ref('')
let isShowDeviceJobDetails = ref(false);
let isShowCurrentTaskDetails = ref(false);
@@ -113,12 +112,10 @@
let rowData = ref({});
const handleDetail = (row) => {
    if (row.device_sns.length === 1){
        console.log(row)
        if (row.status === 2 || row.status === 1){
            rowData.value = row? row : {};
        if (row.status === 2 || row.status === 1){
            isShowCurrentTaskDetails.value = true;
        } else{
            wayLineJodInfoId.value = row.id
            isShowDeviceJobDetails.value = true
        }
    }else{