吉安感知网项目-前端
chenyao
2026-01-27 a4201c87e9428d230d3778a940c2cbb114efd89a
Merge remote-tracking branch 'origin/master'

# Conflicts:
# applications/task-work-order/src/views/orderView/flyingHand/index.vue
54 files modified
16 files added
2764 ■■■■ changed files
applications/drone-command/env/.env.development 4 ●●●● patch | view | raw | blame | history
applications/drone-command/public/fonts/font_5099981_va3gbv2bkxo.ttf patch | view | raw | blame | history
applications/drone-command/public/fonts/font_5099981_va3gbv2bkxo.woff patch | view | raw | blame | history
applications/drone-command/public/fonts/font_5099981_va3gbv2bkxo.woff2 patch | view | raw | blame | history
applications/drone-command/src/api/dataCockpit/index.js 28 ●●●● patch | view | raw | blame | history
applications/drone-command/src/components/map-container/device-map-container.vue 126 ●●●● patch | view | raw | blame | history
applications/drone-command/src/components/map-container/device-map-materials.js 40 ●●●● patch | view | raw | blame | history
applications/drone-command/src/config/iconList.js 7 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/styles/common.scss 1 ●●●● patch | view | raw | blame | history
applications/drone-command/src/styles/customFont.scss 60 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/api.txt 127 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/deviceStock/index.vue 3 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/LegendBar.vue 8 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/RealWarning.vue 63 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue 30 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue 6 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue 6 ●●●● patch | view | raw | blame | history
applications/mobile-web-view/src/appComponents/workMap/index.vue 2 ●●● patch | view | raw | blame | history
applications/mobile-web-view/src/appPages/work/workDetail/mapWork/index.vue 12 ●●●●● patch | view | raw | blame | history
applications/task-work-order/env/.env 3 ●●●●● patch | view | raw | blame | history
applications/task-work-order/env/.env.development 2 ●●● patch | view | raw | blame | history
applications/task-work-order/public/fonts/font_5099981_va3gbv2bkxo.ttf patch | view | raw | blame | history
applications/task-work-order/public/fonts/font_5099981_va3gbv2bkxo.woff patch | view | raw | blame | history
applications/task-work-order/public/fonts/font_5099981_va3gbv2bkxo.woff2 patch | view | raw | blame | history
applications/task-work-order/src/api/zkxt/index.js 17 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/assets/images/common/checkbox.png patch | view | raw | blame | history
applications/task-work-order/src/assets/images/common/n-checkbox.png patch | view | raw | blame | history
applications/task-work-order/src/assets/images/menuIcon/order-manage.png patch | view | raw | blame | history
applications/task-work-order/src/components/map-container/common-cesium-map.vue 18 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/config/iconList.js 7 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/styles/common.scss 4 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/styles/common/cockpit.scss 391 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/styles/customFont.scss 60 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/styles/tags.scss 13 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/FormDiaLog.vue 4 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue 10 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue 11 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue 14 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/evaluate/FormDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue 8 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/ApplyViewDialog.vue 17 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/FormDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/auditRecord.vue 67 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue 12 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/reasonForRejectionDialog.vue 19 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/DistributeDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue 80 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue 9 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue 8 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue 22 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/RefuseOrderDialog1.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue 136 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue 18 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue 294 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue 152 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue 8 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/organizational/agenciesManagement/FormDiaLog.vue 181 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/organizational/agenciesManagement/agenciesApi.js 66 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue 336 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue 20 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/organizationalMessage/agenciesManagement/agenciesApi.js 66 ●●●●● patch | view | raw | blame | history
pnpm-lock.yaml 72 ●●●● patch | view | raw | blame | history
pnpm-workspace.yaml 4 ●●●● patch | view | raw | blame | history
uniapps/work-app/src/api/map.js 8 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/pages/map/index.vue 10 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/pages/work/index.vue 26 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/store/modules/location.js 34 ●●●● patch | view | raw | blame | history
applications/drone-command/env/.env.development
@@ -2,7 +2,7 @@
 # @Author       : yuan
 # @Date         : 2026-01-07 14:58:30
 # @LastEditors  : yuan
 # @LastEditTime : 2026-01-23 17:51:43
 # @LastEditTime : 2026-01-26 17:29:11
 # @FilePath     : \applications\drone-command\env\.env.development
 # @Description  : 
 # Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -16,7 +16,7 @@
#开发环境代理地址(推荐本地新建文件 .env.development.local 来进行覆盖)
# VITE_APP_URL = https://wrj.shuixiongit.com/api
VITE_APP_URL= http://192.168.1.33
VITE_APP_URL= http://192.168.1.204
#新大屏地址
VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/'
applications/drone-command/public/fonts/font_5099981_va3gbv2bkxo.ttf
Binary files differ
applications/drone-command/public/fonts/font_5099981_va3gbv2bkxo.woff
Binary files differ
applications/drone-command/public/fonts/font_5099981_va3gbv2bkxo.woff2
Binary files differ
applications/drone-command/src/api/dataCockpit/index.js
@@ -2,7 +2,7 @@
 * @Author       : yuan
 * @Date         : 2026-01-09 11:14:04
 * @LastEditors  : yuan
 * @LastEditTime : 2026-01-09 11:35:14
 * @LastEditTime : 2026-01-26 19:02:07
 * @FilePath     : \applications\drone-command\src\api\dataCockpit\index.js
 * @Description  : 
 * Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -53,11 +53,33 @@
    })
}
// ????
export const alarmFavoriteSaveApi = (data) => {
    return request({
        url: '/drone-fw/record/fwAlarmFavorite/save',
        method: 'post',
        data
    })
}
// ??????
export const alarmFavoriteRemoveApi = (ids) => {
    const formattedIds = Array.isArray(ids) ? ids.join(',') : ids
    return request({
        url: '/drone-fw/record/fwAlarmFavorite/cancelFavorite',
        method: 'post',
        params: {
            ids: formattedIds
        }
    })
}
// 数据驾驶舱地图聚合
export const cockpitAggregationApi = () => {
export const cockpitAggregationApi = (params) => {
    return request({
        url: '/drone-fw/device/fwDevice/statisticalDeviceOut',
        method: 'get'
        method: 'get',
        params
    })
}
applications/drone-command/src/components/map-container/device-map-container.vue
@@ -2,8 +2,9 @@
    <div class="map-shell">
        <CommonCesiumMap ref="mapRef" class="command-cesium map-container" :dom-id="props.containerId" :active="true"
            :flat-mode="false" :terrain="true" :layer-mode="4" :contour="false" :boundary="false"
            :show-admin-boundary="true" :zoom-to-boundary="true" :enable-stage-emit="true" :cluster-height="100000"
            @ready="handleMapReady" @stage-change="handleStageChange" />
            :show-admin-boundary="true" :zoom-to-boundary="true" :enable-stage-emit="true"
            :cluster-height="CLUSTER_HEIGHT" :detail-height="DETAIL_HEIGHT" @ready="handleMapReady"
            @stage-change="handleStageChange" />
        <div v-if="props.showLayerControl" class="layer-control-root" :class="{ collapsed: props.leftCollapsed }">
            <div class="layer-control-wrap" ref="layerWrapRef">
                <div class="layer-control" @click="toggleLayerPanel">
@@ -63,6 +64,9 @@
    createRadialGradientMaterial,
    getTexturedVertexFormat,
} from './device-map-materials'
const CLUSTER_HEIGHT = 100000
const DETAIL_HEIGHT = 10000
const props = defineProps({
    onlineDevices: {
@@ -157,6 +161,14 @@
    const latitude = Number(latitudeRaw)
    if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) return null
    return { longitude, latitude }
}
const getDeviceRange = item => {
    if (!item) return null
    const rawRange = item.effectiveRangeKm ?? item.range ?? item.coverRadiusM
    const range = Number(rawRange)
    if (!Number.isFinite(range) || range <= 0) return null
    return range
}
const ensureCockpitPrimitiveLayer = () => {
@@ -305,6 +317,20 @@
    if (aggregationSource) aggregationSource.show = visible
}
const setDroneVisibility = visible => {
    if (droneTrackBillboardCollection) droneTrackBillboardCollection.show = visible
    if (droneTrackPolylineCollection) droneTrackPolylineCollection.show = visible
    if (!visible && selectedTargetType.value === 'drone') {
        closePopup()
    }
}
const getStageByHeight = height => {
    if (height == null) return 'detail'
    if (height >= CLUSTER_HEIGHT) return 'cluster'
    if (height <= DETAIL_HEIGHT) return 'detail'
    return 'mid'
}
const ensureCountyCenterMap = () => {
    if (countyCenterMap.size) return
    const geojson = JSON.parse(jaGeojsonRaw)
@@ -316,24 +342,44 @@
    })
}
const buildSimulatedTrackPoints = base => {
    ensureCountyCenterMap()
    const anchor = base || { longitude: 116.397, latitude: 39.908 }
    const offsets = [
        [0, 0, 120],
        [0.02, 0.012, 150],
        [0.04, 0.006, 180],
        [0.06, -0.008, 200],
        [0.03, -0.02, 160],
        [0.0, -0.015, 140],
        [-0.02, -0.005, 120],
        [-0.01, 0.01, 130],
const buildSimulatedTrackPoints = () => {
    return [
        {
            longitude: 114.963191,
            latitude: 27.136716,
            height: 120
        },
        {
            longitude:114.957308,
            latitude: 27.138452,
            height: 120
        },
        {
            longitude:114.952,
            latitude: 27.136317,
            height: 120
        },
        {
            longitude:114.949293,
            latitude: 27.133864,
            height: 120
        },
        {
            longitude:114.944666,
            latitude: 27.130526,
            height: 120
        },
        {
            longitude:114.945909,
            latitude:27.127845,
            height: 120
        },
        {
            longitude:114.962974,
            latitude:27.136242,
            height: 120
        },
    ]
    return offsets.map(item => ({
        longitude: anchor.longitude + item[0],
        latitude: anchor.latitude + item[1],
        height: item[2],
    }))
}
@@ -422,13 +468,11 @@
const renderSimulatedDroneTrack = () => {
    if (!viewer) return
    clearDroneTrackEntities()
    ensureCountyCenterMap()
    ensureDroneTrackCollections()
    droneTrackBillboardCollection.show = detailVisible.value
    droneTrackPolylineCollection.show = detailVisible.value
    droneTrackRuntime = []
    const centers = Array.from(countyCenterMap.entries())
    const baseCenters = centers.length
        ? centers.slice(0, 4)
        : [['默认区域', { longitude: 116.397, latitude: 39.908 }]]
    const baseCenters = [['默认区域', { longitude:114.958541, latitude: 27.121917 }]]
    const segmentDuration = 6
    const baseTrackColor = Cesium.Color.fromCssColorString('red')
    baseCenters.forEach(([centerName, center], trackIndex) => {
@@ -454,7 +498,7 @@
        })
        const droneId = `drone-track-${trackIndex}`
        const billboard = droneTrackBillboardCollection.add({
            position: positions[0],
            position: positions[positions.length - 1],
            image: droneIcon,
            width: 36,
            height: 36,
@@ -511,7 +555,8 @@
        const position = getDevicePosition(item)
        if (!position) return
        const entityId = `online-device-${item.id ?? index}-${index}`
        addDeviceRings(position, ringFillInstancesByStyle, ringOutlineInstancesByStyle)
        const rangeMeters = getDeviceRange(item)
        addDeviceRings(position, ringFillInstancesByStyle, ringOutlineInstancesByStyle, rangeMeters)
        const billboard = deviceBillboardCollection.add({
            position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, 0),
            image: equipmentIcon,
@@ -528,9 +573,20 @@
    ringFillInstancesByStyle.forEach((instances, index) => {
        if (!instances.length) return
        const ring = RING_STYLES[index]
        const alpha = ring.alpha ?? 0.64
        const innerRatio =
            typeof ring.innerRatio === 'number'
                ? ring.innerRatio
                : ring.inner && ring.outer
                    ? Math.min(Math.max(ring.inner / ring.outer, 0), 0.9)
                    : 0
        const material = createRadialGradientMaterial(
            Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(0.64),
            Cesium.Color.fromCssColorString(ring.gradient[1]).withAlpha(0.64)
            Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(alpha),
            Cesium.Color.fromCssColorString(ring.gradient[1]).withAlpha(alpha),
            {
                gamma: 1.7,
                innerCutoff: innerRatio,
            }
        )
        const primitive = new Cesium.GroundPrimitive({
            geometryInstances: instances,
@@ -629,7 +685,7 @@
const renderDefenseZones = zones => {
    if (!viewer) return
    clearDefenseZoneEntities()
    const result = buildZonePrimitives(zones, '#19D266', '#2AEDBF', '#012B11')
    const result = buildZonePrimitives(zones, '#72F3FF', '#72F3FF', '#0A7C88')
    defenseZonePrimitive = result.primitive
    defenseZoneOutlinePrimitive = result.outlinePrimitive
    if (defenseZonePrimitive) defenseZonePrimitive.show = detailVisible.value
@@ -640,7 +696,7 @@
const renderPartitions = zones => {
    if (!viewer) return
    clearPartitionEntities()
    const result = buildZonePrimitives(zones, '#FFCD2A', '#FFC609', '#583300')
    const result = buildZonePrimitives(zones, '#FFD772', '#FFD772', '#A86B00')
    partitionPrimitive = result.primitive
    partitionOutlinePrimitive = result.outlinePrimitive
    if (partitionPrimitive) partitionPrimitive.show = detailVisible.value
@@ -693,7 +749,7 @@
                width: 66.73,
                height: 43,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
                // disableDepthTestDistance: Number.POSITIVE_INFINITY,
            },
            label: {
                text: `${count}`,
@@ -706,7 +762,6 @@
                pixelOffset: new Cesium.Cartesian2(0, -35),
                disableDepthTestDistance: Number.POSITIVE_INFINITY,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            },
        })
    })
@@ -812,7 +867,9 @@
const loadAggregation = async () => {
    try {
        const res = await cockpitAggregationApi()
        const res = await cockpitAggregationApi({
            effectiveRangeKmIsNotNull: 1
        })
        renderAggregation(res?.data?.data ?? [])
    } catch (error) {
        renderAggregation([])
@@ -853,13 +910,14 @@
    const showCluster = stage === 'cluster'
    setClusterVisibility(showCluster)
    setDetailVisibility(!showCluster)
    setDroneVisibility(!showCluster)
}
const handleMapReady = ({ viewer: mapViewer }) => {
    viewer = mapViewer
    ensureCockpitPrimitiveLayer()
    const height = viewer?.camera?.positionCartographic?.height
    const stage = height != null && height >= 100000 ? 'cluster' : 'detail'
    const stage = getStageByHeight(height)
    updateStageDisplay(stage)
    renderDeviceEntities(props.onlineDevices)
    loadDefenseZones()
applications/drone-command/src/components/map-container/device-map-materials.js
@@ -1,6 +1,15 @@
import * as Cesium from 'cesium'
export const RING_STYLES = [{ inner: 0, outer: 2000, gradient: ['#FF361C', '#360B00'] }]
export const RING_STYLES = [
    {
        inner: 0,
        outer: 2000,
        gradient: ['#FF6A57', '#A11806'],
        alpha: 0.42,
        outlineAlpha: 0.85,
        innerRatio: 0.12,
    },
]
export const MATERIAL_TYPE = 'RadialGradientMaterial'
export const DRONE_TRACK_MATERIAL_TYPE = 'DroneTrackFlowMaterial'
@@ -26,15 +35,25 @@
            uniforms: {
                color1: new Cesium.Color(1.0, 1.0, 1.0, 1.0),
                color2: new Cesium.Color(0.0, 0.0, 0.0, 1.0),
                gamma: 1.7,
                innerCutoff: 0.0,
            },
            source: `
                uniform vec4 color1;
                uniform vec4 color2;
                uniform float gamma;
                uniform float innerCutoff;
                czm_material czm_getMaterial(czm_materialInput materialInput) {
                    czm_material material = czm_getDefaultMaterial(materialInput);
                    vec2 st = materialInput.st - vec2(0.5);
                    float t = clamp(length(st) * 2.0, 0.0, 1.0);
                    vec4 color = mix(color1, color2, t);
                    float ramp = smoothstep(innerCutoff, 1.0, t);
                    float shaped = pow(t, gamma);
                    float alpha = color.a * ramp * shaped;
                    material.diffuse = color.rgb;
                    material.alpha = color.a;
                    material.alpha = alpha;
                    return material;
                }
            `,
@@ -82,9 +101,9 @@
    })
}
export const createRadialGradientMaterial = (color1, color2) => {
export const createRadialGradientMaterial = (color1, color2, options = {}) => {
    registerRadialGradientMaterial()
    return Cesium.Material.fromType(MATERIAL_TYPE, { color1, color2 })
    return Cesium.Material.fromType(MATERIAL_TYPE, { color1, color2, ...(options || {}) })
}
export const createDroneTrackMaterial = options => {
@@ -115,18 +134,19 @@
    return positions
}
export const addDeviceRings = (center, ringFillInstancesByStyle, ringOutlineInstancesByStyle) => {
export const addDeviceRings = (center, ringFillInstancesByStyle, ringOutlineInstancesByStyle, rangeMeters) => {
    if (!ringFillInstancesByStyle) return
    const centerPosition = Cesium.Cartesian3.fromDegrees(center.longitude, center.latitude, 0)
    const vertexFormat = getTexturedVertexFormat()
    RING_STYLES.forEach((ring, index) => {
        if (!ringFillInstancesByStyle[index]) return
        const outer = Number.isFinite(rangeMeters) && rangeMeters > 0 ? rangeMeters : ring.outer
        ringFillInstancesByStyle[index].push(
            new Cesium.GeometryInstance({
                geometry: new Cesium.EllipseGeometry({
                    center: centerPosition,
                    semiMajorAxis: ring.outer,
                    semiMinorAxis: ring.outer,
                    semiMajorAxis: outer,
                    semiMinorAxis: outer,
                    vertexFormat,
                }),
            })
@@ -135,7 +155,9 @@
    if (!ringOutlineInstancesByStyle) return
    RING_STYLES.forEach((ring, index) => {
        if (!ringOutlineInstancesByStyle[index]) return
        const positions = buildCirclePositions(center, ring.outer)
        const outer = Number.isFinite(rangeMeters) && rangeMeters > 0 ? rangeMeters : ring.outer
        const positions = buildCirclePositions(center, outer)
        const outlineAlpha = typeof ring.outlineAlpha === 'number' ? ring.outlineAlpha : 0.8
        ringOutlineInstancesByStyle[index].push(
            new Cesium.GeometryInstance({
                geometry: new Cesium.GroundPolylineGeometry({
@@ -144,7 +166,7 @@
                }),
                attributes: {
                    color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                        Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(0.8)
                        Cesium.Color.fromCssColorString(ring.gradient[0]).withAlpha(outlineAlpha)
                    ),
                },
            })
applications/drone-command/src/config/iconList.js
@@ -113,6 +113,13 @@
      'iconfont icon-msnui-360',
      'iconfont icon-iframe',
      'iconfont icon-huanyingye',
      'iconfont_com icon-a-1',
      'iconfont_com icon-a-4',
      'iconfont_com icon-a-3',
      'iconfont_com icon-a-2',
      'iconfont_com icon-a-6',
      'iconfont_com icon-a-5',
      'iconfont_com icon-Frame',
    ],
  },
];
applications/drone-command/src/styles/common.scss
@@ -9,6 +9,7 @@
@import './mapEdit.scss';
@import './common/cockpit.scss';
@import './customFont.scss';
a {
  text-decoration: none;
applications/drone-command/src/styles/customFont.scss
New file
@@ -0,0 +1,60 @@
@font-face {
    font-family: "iconfont_com";
    /* Project id 5099981 */
    src: url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.woff2?t=1769414361186') format('woff2'),
        url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.woff?t=1769414361186') format('woff'),
        url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.ttf?t=1769414361186') format('truetype'),
        url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.svg?t=1769414361186#iconfont') format('svg');
}
.iconfont_com {
    font-family: "iconfont_com" !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
.icon-a-1:before {
    content: "\e609";
  }
.icon-a-4:before {
    content: "\e604";
}
.icon-a-3:before {
    content: "\e605";
}
.icon-a-2:before {
    content: "\e606";
}
.icon-a-6:before {
    content: "\e607";
}
.icon-a-5:before {
    content: "\e608";
}
.icon-Frame:before {
    content: "\e602";
}
.icon-a-:before {
    content: "\e601";
}
.icon-MenuIcon-biaozhunshujutuisong-heise:before {
    content: "\e611";
}
.icon-MenuIcon-xuncharenwujiankong-heise:before {
    content: "\e614";
}
.icon-MenuIcon-shebeirizhi-heise:before {
    content: "\e615";
}
applications/drone-command/src/views/api.txt
@@ -1,22 +1,32 @@
## 分页
## 重点关注
**接口地址**:`/blade-log/log/operationLog/page`
**接口地址**:`/drone-fw/record/fwAlarmFavorite/save`
**请求方式**:`GET`
**请求方式**:`POST`
**请求数据类型**:`application/x-www-form-urlencoded`
**请求数据类型**:`application/json`
**响应数据类型**:`*/*`
**接口描述**:<p>分页</p>
**接口描述**:<p>传入fwAlarmFavorite</p>
**请求示例**:
```javascript
{
  "alarmRecordId": 0
}
```
**请求参数**:
@@ -27,12 +37,8 @@
| 参数名称 | 参数说明 | 请求类型    | 是否必须 | 数据类型 | schema |
| -------- | -------- | ----- | -------- | -------- | ------ |
|createBy|操作人|query|false|string||
|current|当前页|query|false|integer(int32)||
|endTime|结束时间|query|false|string||
|size|每页的数量|query|false|integer(int32)||
|startTime|开始时间|query|false|string||
|title|日志类型(0菜单/1按钮)|query|false|string||
|fwAlarmFavorite|告警记录关注表|body|true|FwAlarmFavorite对象|FwAlarmFavorite对象|
|&emsp;&emsp;alarmRecordId|告警记录id||false|integer(int64)||
**响应状态**:
@@ -40,7 +46,8 @@
| 状态码 | 说明 | schema |
| -------- | -------- | ----- | 
|200|OK|R«IPage«OperationLogVO»»|
|200|OK|R|
|201|Created||
|401|Unauthorized||
|403|Forbidden||
|404|Not Found||
@@ -52,18 +59,7 @@
| 参数名称 | 参数说明 | 类型 | schema |
| -------- | -------- | ----- |----- | 
|code|状态码|integer(int32)|integer(int32)|
|data|承载数据|IPage«OperationLogVO»|IPage«OperationLogVO»|
|&emsp;&emsp;current||integer(int64)||
|&emsp;&emsp;pages||integer(int64)||
|&emsp;&emsp;records||array|OperationLogVO|
|&emsp;&emsp;&emsp;&emsp;createBy|操作人|string||
|&emsp;&emsp;&emsp;&emsp;remoteIp|客户端IP|string||
|&emsp;&emsp;&emsp;&emsp;requestUri|请求地址|string||
|&emsp;&emsp;&emsp;&emsp;title|日志标题|string||
|&emsp;&emsp;&emsp;&emsp;type|日志类型(0菜单/1按钮)|string||
|&emsp;&emsp;&emsp;&emsp;userAgent|客户端|string||
|&emsp;&emsp;size||integer(int64)||
|&emsp;&emsp;total||integer(int64)||
|data|承载数据|object||
|msg|返回消息|string||
|success|是否成功|boolean||
@@ -72,22 +68,73 @@
```javascript
{
    "code": 0,
    "data": {
        "current": 0,
        "pages": 0,
        "records": [
            {
                "createBy": "",
                "remoteIp": "",
                "requestUri": "",
                "title": "",
                "type": "",
                "userAgent": ""
            }
        ],
        "size": 0,
        "total": 0
    },
    "data": {},
    "msg": "",
    "success": true
}
```
## 取消关注
**接口地址**:`/drone-fw/record/fwAlarmFavorite/remove`
**请求方式**:`POST`
**请求数据类型**:`application/json`
**响应数据类型**:`*/*`
**接口描述**:<p>传入ids</p>
**请求参数**:
**请求参数**:
| 参数名称 | 参数说明 | 请求类型    | 是否必须 | 数据类型 | schema |
| -------- | -------- | ----- | -------- | -------- | ------ |
|ids|主键集合|query|true|string||
**响应状态**:
| 状态码 | 说明 | schema |
| -------- | -------- | ----- |
|200|OK|R|
|201|Created||
|401|Unauthorized||
|403|Forbidden||
|404|Not Found||
**响应参数**:
| 参数名称 | 参数说明 | 类型 | schema |
| -------- | -------- | ----- |----- |
|code|状态码|integer(int32)|integer(int32)|
|data|承载数据|object||
|msg|返回消息|string||
|success|是否成功|boolean||
**响应示例**:
```javascript
{
    "code": 0,
    "data": {},
    "msg": "",
    "success": true
}
applications/drone-command/src/views/basicManage/deviceStock/index.vue
@@ -62,7 +62,6 @@
        <div class="command-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
            <div class="command-table-content command-table-content-bg">
                <el-table class="command-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="deviceName" show-overflow-tooltip width="130" label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip width="130" label="设备类型">
@@ -80,7 +79,7 @@
                    </el-table-column>
                    <el-table-column prop="source" show-overflow-tooltip width="112" label="来源" />
                    <el-table-column prop="purpose" show-overflow-tooltip width="206" label="用途" />
                    <el-table-column prop="belongDeptName" show-overflow-tooltip width="124" label="所属部门" />
                    <el-table-column prop="belongDeptName" show-overflow-tooltip label="所属部门" />
                    <el-table-column prop="charger" show-overflow-tooltip width="100" label="负责人" />
                    <el-table-column prop="yxzt" show-overflow-tooltip width="116" label="运行状态">
                        <template v-slot="{ row }">
applications/drone-command/src/views/dataCockpit/components/LegendBar.vue
@@ -85,13 +85,13 @@
}
.legend-color.defense {
    background: radial-gradient(50% 50% at 50% 50%, #2aedbf 0%, #012b11 100%);
    border: 1px solid #19d266;
    background: radial-gradient(50% 50% at 50% 50%, rgba(114, 243, 255, 0.45) 0%, rgba(10, 124, 136, 0.55) 100%);
    border: 1px solid rgba(114, 243, 255, 0.85);
}
.legend-color.partition {
    background: radial-gradient(50% 50% at 50% 50%, #ffc609 0%, #583300 100%);
    border: 1px solid #ffcd2a;
    background: radial-gradient(50% 50% at 50% 50%, rgba(255, 215, 114, 0.5) 0%, rgba(168, 107, 0, 0.6) 100%);
    border: 1px solid rgba(255, 215, 114, 0.9);
}
.legend-icon {
applications/drone-command/src/views/dataCockpit/components/RealWarning.vue
@@ -2,7 +2,7 @@
 * @Author       : yuan
 * @Date         : 2026-01-08 09:29:07
 * @LastEditors  : yuan
 * @LastEditTime : 2026-01-19 11:31:09
 * @LastEditTime : 2026-01-26 09:59:52
 * @FilePath     : \applications\drone-command\src\views\dataCockpit\components\RealWarning.vue
 * @Description  : 
 * Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -24,7 +24,7 @@
                :data="item"
                @signal="() => handleAction('signal', item)"
                @counter="() => handleAction('counter', item)"
                @favorite="() => console.log('收藏', item.id)"
                @favorite="() => handleFavorite(item)"
            />
        </div>
    </div>
@@ -32,7 +32,12 @@
<script setup>
import RealTemplate from './templateComponents/RealTemplate.vue'
import { alarmLogApi, interferenceAndExpulsionApi } from '@/api/dataCockpit'
import {
    alarmLogApi,
    alarmFavoriteRemoveApi,
    alarmFavoriteSaveApi,
    interferenceAndExpulsionApi
} from '@/api/dataCockpit'
import { onMounted, ref } from 'vue'
import EmptyState from './EmptyState.vue'
import { ElMessage } from 'element-plus'
@@ -46,9 +51,23 @@
    counter: '诱导驱离'
}
const getAlarmRecordId = (item) => item?.alarmRecordId ?? item?.id
const getFavoriteId = (item) =>
    item?.favoriteId ??
    item?.alarmFavoriteId ??
    item?.fwAlarmFavoriteId ??
    item?.favoriteRecordId ??
    getAlarmRecordId(item)
const isFavorited = (item) => {
    const value = item?.favorited ?? item?.isFavorite
    return value === 1 || value === '1' || value === true
}
const buildPayload = (type, item) => ({
    counterWay: type === 'signal' ? 1 : type === 'counter' ? 2 : '',
    alarmRecordId: item?.alarmRecordId ?? item?.id
    alarmRecordId: getAlarmRecordId(item)
})
const handleAction = async (type, item) => {
@@ -56,13 +75,36 @@
    try {
        const res = await interferenceAndExpulsionApi(buildPayload(type, item))
        if (res?.data?.success) {
            ElMessage({ type: 'success', message: `${actionText}成功` })
            ElMessage({ type: 'success', message: actionText + '成功' })
            await fetchRealWarning()
        } else {
            ElMessage({ type: 'error', message: res?.data?.msg || `${actionText}失败` })
            ElMessage({ type: 'error', message: res?.data?.msg || actionText + '失败' })
        }
    } catch (error) {
        ElMessage({ type: 'error', message: `${actionText}失败` })
        ElMessage({ type: 'error', message: actionText + '失败' })
    }
}
const handleFavorite = async (item) => {
    const alarmRecordId = getAlarmRecordId(item)
    if (!alarmRecordId) {
        ElMessage({ type: 'warning', message: '缺少告警记录ID' })
        return
    }
    const isFavorite = isFavorited(item)
    const actionText = isFavorite ? '取消关注' : '关注'
    try {
        const res = isFavorite
            ? await alarmFavoriteRemoveApi(getFavoriteId(item))
            : await alarmFavoriteSaveApi({ alarmRecordId })
        if (res?.data?.success) {
            ElMessage({ type: 'success', message: actionText + '成功' })
            await fetchRealWarning()
        } else {
            ElMessage({ type: 'error', message: res?.data?.msg || actionText + '失败' })
        }
    } catch (error) {
        ElMessage({ type: 'error', message: actionText + '失败' })
    }
}
@@ -73,7 +115,12 @@
        const params = { current: 1, size: 20, alarmType: '1' }
        const res = await alarmLogApi(params)
        const records = res?.data?.data?.records ?? []
        realWarningData.value = records
        realWarningData.value = records.map((record) => ({
            ...record,
            isFavorite:
                record?.isFavorite ??
                (record?.favorited === 1 || record?.favorited === '1')
        }))
    } finally {
        const elapsed = Date.now() - startAt
        if (elapsed < minLoadingMs) {
applications/drone-command/src/views/dataCockpit/components/templateComponents/RealEquipmentTemplate.vue
@@ -67,7 +67,7 @@
                </div>
                <div class="col">
                    <span class="label">有效范围</span>
                    {{ data.effectiveRangeKm }}KM
                    {{ Number(data.effectiveRangeKm).toFixed(0) }}m
                </div>
            </div>
        </div>
applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue
@@ -122,7 +122,8 @@
                            class="command-input"
                            v-model="formData.effectiveRangeKm"
                            :min="0"
                            :precision="2"
                            :precision="0"
                            :step="1"
                            :controls="false"
                            placeholder="请输入"
                        />
@@ -227,7 +228,14 @@
function formatRange(value) {
    if (value == null || value === '') return '-'
    return `${value}`
    const normalized = normalizeRange(value)
    return normalized == null ? '-' : `${normalized}`
}
function normalizeRange(value) {
    const numeric = Number(value)
    if (!Number.isFinite(numeric)) return null
    return Math.trunc(numeric)
}
// 关闭弹框
@@ -242,14 +250,16 @@
    submitting.value = true
    try {
        const {longitude, latitude} = parseDeployLocation(formData.value.deployLocation)
        const normalizedRange = normalizeRange(formData.value.effectiveRangeKm)
        const payload = {
            id: formData.value.id || formData.value.deviceId || undefined,
            effectiveRangeKmIsNotNull: formData.value.effectiveRangeKm ? 1 : 2,
            effectiveRangeKm: formData.value.effectiveRangeKm,
            effectiveRangeKmIsNotNull: normalizedRange != null ? 1 : 2,
            effectiveRangeKm: normalizedRange,
            longitude,
            latitude
        }
        formData.value.effectiveRangeKm = normalizedRange
        delete payload.deviceId
        await detectionRangeSubmitApi(payload)
@@ -280,6 +290,7 @@
        current: 1,
        size: 200,
        effectiveRangeKmIsNotNull: 2,
        isTrack: 1
    })
    const records = res?.data?.data?.records ?? []
    deviceOptions.value = records.map(item => ({
@@ -432,9 +443,18 @@
watch(
    () => formData.value.effectiveRangeKm,
    value => {
        const normalized = normalizeRange(value)
        if (value != null && normalized == null) {
            formData.value.effectiveRangeKm = null
            return
        }
        if (value != null && normalized !== value) {
            formData.value.effectiveRangeKm = normalized
            return
        }
        const parsed = parseDeployLocation(formData.value.deployLocation)
        if (!parsed) return
        updateRangeCircle(parsed.longitude, parsed.latitude, value)
        updateRangeCircle(parsed.longitude, parsed.latitude, normalized)
    }
)
</script>
applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
@@ -204,8 +204,10 @@
function formatRange(row) {
    if (!row) return '-'
    const value = row.effectiveRangeKm ?? row.range
    return value === null || value === undefined || value === '' ? '-' : value
    let value = row.effectiveRangeKm ?? row.range
    return value === null || value === undefined || value === '' ? '-' : Number(value).toFixed(0)
}
function formatDeviceCode(row) {
applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue
@@ -151,7 +151,10 @@
async function getList() {
    loading.value = true
    try {
        const res = await fwDevicePageApi(searchParams.value)
        const res = await fwDevicePageApi({
            ...searchParams.value,
            deviceStatusList: '0,1,2'
        })
        list.value = res?.data?.data?.records ?? []
        total.value = res?.data?.data?.total ?? 0
    } finally {
@@ -176,6 +179,7 @@
function getDictList() {
    getDictionaryByCode('deviceType,deviceStatus,deviceAtt').then(res => {
        dictObj.value = res.data.data
        dictObj.value.deviceStatus = dictObj.value.deviceStatus.filter(item => item.dictKey != 3)
    })
}
applications/mobile-web-view/src/appComponents/workMap/index.vue
@@ -291,7 +291,7 @@
watch(
    () => mapCurrentDetail,
    newVal => {
const newDataMap=JSON.parse(newVal)
const newDataMap=newVal
        // 只有 workNavigationShow 为 true 且有经纬度时才添加标记
        if (workNavigationShow && newDataMap?.longitude && newDataMap?.latitude) {
            addIncidentMarker(newDataMap)
applications/mobile-web-view/src/appPages/work/workDetail/mapWork/index.vue
@@ -7,31 +7,21 @@
            :workNavigationShow="true"
            :mapCurrentDetail="mapCurrentDetail"
        >
<!--            <template #eventNav>-->
<!--                <EventNavigation :mapCurrentDetail="mapCurrentDetail"></EventNavigation>-->
<!--            </template>-->
        </WorkMap>
    </div>
</template>
<script setup>
import { getDeviceRegion } from '@/api/home/aggregation'
import WorkMap from '@/appComponents/workMap/index.vue'
import EventNavigation from '@/appPages/work/workDetail/mapWork/eventNavigation.vue'
import { useRoute } from 'vue-router'
import { showToast } from 'vant'
import { getList } from '/src/api/work/index.js'
import { useStore } from 'vuex'
const store = useStore()
const userInfo = computed(() => store?.state?.user?.userInfo)
const route = useRoute()
const mapCurrentDetail = ref({})
const eventNum = ref('')
onMounted(async () => {
    eventNum.value = route.query.currentItem
    mapCurrentDetail.value = eventNum.value
mapCurrentDetail.value = JSON.parse(decodeURIComponent(route.query.currentItem))
})
</script>
applications/task-work-order/env/.env
@@ -15,3 +15,6 @@
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS=gzip
# xt接口地址
VITE_APP_URL_XT=http://218.202.104.82:8200
applications/task-work-order/env/.env.development
@@ -17,7 +17,7 @@
# VITE_APP_URL = https://wrj.shuixiongit.com/api
VITE_APP_URL= http://192.168.1.204
VITE_APP_URL_XT=http://218.202.104.82:8200
#新大屏地址
VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/'
applications/task-work-order/public/fonts/font_5099981_va3gbv2bkxo.ttf
Binary files differ
applications/task-work-order/public/fonts/font_5099981_va3gbv2bkxo.woff
Binary files differ
applications/task-work-order/public/fonts/font_5099981_va3gbv2bkxo.woff2
Binary files differ
applications/task-work-order/src/api/zkxt/index.js
@@ -28,4 +28,21 @@
    })
}
// 获取航线列表
export const airlineListApi = (data) => {
    return request({
        url: `/webservice/webservice/airline/queryList`,
        method: 'post',
        data: data,
    })
}
// 获取航线详情
export const queryAirById = (id) => {
    return request({
        url: `/webservice/webservice/airline/queryById/${id}`,
        method: 'get',
    })
}
applications/task-work-order/src/assets/images/common/checkbox.png
applications/task-work-order/src/assets/images/common/n-checkbox.png
applications/task-work-order/src/assets/images/menuIcon/order-manage.png
applications/task-work-order/src/components/map-container/common-cesium-map.vue
@@ -66,6 +66,22 @@
let initialized = false
let removeCameraListener = null
const preventDefault = event => {
    event.preventDefault()
    return
}
const cesiumContextMenu = (isAdd = true) => {
    let cesium = document.getElementById(mapId)
    if (!cesium) return
    if (isAdd) {
        cesium.addEventListener('contextmenu', preventDefault)
    } else {
        cesium.removeEventListener('contextmenu', preventDefault)
    }
}
const initMap = async () => {
    if (initialized) return
    initialized = true
@@ -77,6 +93,7 @@
        boundary: props.boundary,
        contour: props.contour,
    })
    cesiumContextMenu(true)
    viewer.value = viewInstance.value.getViewer()
    if (props.showAdminBoundary) {
        adminBoundarySources = await loadJaAdminBoundary(viewer.value, {
@@ -118,6 +135,7 @@
    if (removeCameraListener) removeCameraListener()
    removeJaAdminBoundary(viewer.value, adminBoundarySources)
    viewInstance.value?.viewerDestroy?.()
    cesiumContextMenu(false)
})
const getMap = () => ({ viewer: viewer.value, publicCesium: viewInstance.value })
applications/task-work-order/src/config/iconList.js
@@ -113,6 +113,13 @@
      'iconfont icon-msnui-360',
      'iconfont icon-iframe',
      'iconfont icon-huanyingye',
      'iconfont_com icon-a-1',
      'iconfont_com icon-a-4',
      'iconfont_com icon-a-3',
      'iconfont_com icon-a-2',
      'iconfont_com icon-a-6',
      'iconfont_com icon-a-5',
      'iconfont_com icon-Frame',
    ],
  },
];
applications/task-work-order/src/styles/common.scss
@@ -9,6 +9,7 @@
@import './mapEdit.scss';
@import './common/cockpit.scss';
@import './customFont.scss';
a {
  text-decoration: none;
@@ -17,6 +18,7 @@
* {
  outline: none;
  box-sizing: border-box;
}
.avue-sidebar,
@@ -107,6 +109,7 @@
    height: 100%;
    box-sizing: border-box;
    background: url('@/assets/images/layoutBg.png') repeat;
    background-position: 0 -20px;
    .layer-content-bottom {
      width: 100%;
@@ -270,6 +273,7 @@
}
.gd-cesium {
  position: relative;
  .cesium-viewer {
    height: 100%;
    overflow: hidden;
applications/task-work-order/src/styles/common/cockpit.scss
@@ -4,6 +4,12 @@
$form-bg-gray: #DDE2ED;
$form-tips-gray: #A1A3D4;
$search-item-icon-color: #383874;
$search-item-symbol-color: #383874;
$search-item-symbol-bg: #fff;
$search-item-symbol-txt: #4E5969;
.gd-input {
  --bg: #{$form-bg};
  --tips: #{$form-tips};
@@ -13,12 +19,15 @@
    --tips: #{$form-tips-gray};
  }
  .el-input__wrapper, .el-textarea__inner {
  .el-input__wrapper,
  .el-textarea__inner {
    box-shadow: none !important;
    background: var(--bg);
    border: none;
  }
  .el-input__inner, .el-textarea__inner {
  .el-input__inner,
  .el-textarea__inner {
    &::placeholder {
      color: var(--tips);
    }
@@ -31,7 +40,19 @@
  }
}
.gd-select, {
.gd-button-main {
  --el-button-bg-color: #4C34FF;
  --el-button-text-color: #ffffff;
  --el-button-border-color: #4C34FF;
  --el-button-hover-bg-color: rgb(130, 113, 255);
  --el-button-hover-text-color: #ffffff;
  --el-button-hover-border-color: rgb(130, 113, 255);
  --el-button-active-bg-color: rgb(65, 46, 208);
  --el-button-active-border-color: rgb(65, 46, 208);
  color: #ffffff;
}
.gd-select {
  --bg: #{$form-bg};
  --tips: #{$form-tips};
@@ -45,6 +66,13 @@
    background: var(--bg);
    box-shadow: none !important;
    border: none;
    .el-select__suffix {
      .el-icon {
        color: $search-item-icon-color;
      }
    }
  }
  .el-select__placeholder {
@@ -65,6 +93,14 @@
  &.gray {
    --bg: #{$form-bg-gray};
    --tips: #{$form-tips-gray};
  }
  .el-icon {
    color: $search-item-icon-color;
  }
  .el-range-separator {
    color: $search-item-symbol-color !important;
  }
  box-shadow: none !important;
@@ -114,7 +150,7 @@
      background: none !important;
    }
    .el-tree-node.is-current > .el-tree-node__content {
    .el-tree-node.is-current>.el-tree-node__content {
      color: #479dff !important;
    }
  }
@@ -172,26 +208,26 @@
}
.gd-date-picker-popper {
  background: #DDE2ED !important;
  background: #fff !important;
  border: none !important;
  border-radius: 0px 0px 8px 8px;
  .el-date-picker__prev-btn,
  .el-date-picker__next-btn {
    .el-icon {
      color: #fff !important;
      color: #4E5969 !important;
    }
  }
  .el-date-picker__header-label {
    color: #fff !important;
    color: #4E5969 !important;
  }
  .el-picker-panel {
    .el-picker-panel__body-wrapper {
      .el-picker-panel__body {
        background: #DDE2ED !important;
        color: #fff !important;
        background: #fff !important;
        color: #4E5969 !important;
        .el-date-range-picker__time-header {
          .el-input__wrapper {
@@ -259,7 +295,7 @@
        .el-picker-panel__content {
          .el-date-range-picker__header {
            .el-picker-panel__icon-btn {
              color: #fff !important;
              color: #4E5969 !important;
              &:hover {
                color: var(--el-color-primary) !important;
@@ -272,9 +308,9 @@
              }
            }
            & > div {
            &>div {
              span {
                color: #fff !important;
                color: #4E5969 !important;
              }
            }
          }
@@ -299,14 +335,15 @@
            td.start-date span,
            td.start-date span,
            td.end-date span {
              background-color: #DDE2ED !important;
              color: #fff !important;
              background-color: #354DFF !important;
            }
            td.in-range div,
            td.in-range div:hover,
            &.is-week-mode .el-date-table__row.current div,
            &.is-week-mode .el-date-table__row:hover div {
              background-color: rgba(60, 121, 202) !important;
              background-color: rgba(71, 126, 255, .1) !important;
            }
          }
        }
@@ -380,12 +417,14 @@
.el-overlay-dialog {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
  justify-content: center;
  /* 水平居中 */
  align-items: center;
  /* 垂直居中 */
}
.gd-dialog {
  padding: 30px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  background: #FFFFFF;
@@ -394,6 +433,9 @@
  max-height: 90vh;
  .el-dialog__header {
    padding-bottom: 20px;
    position: relative;
    span {
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-weight: bold;
@@ -403,6 +445,13 @@
      text-align: left;
      font-style: normal;
      text-transform: none;
    }
    &>button {
      width: auto;
      height: auto;
      display: flex;
      align-items: center;
    }
    .el-icon {
@@ -420,6 +469,33 @@
      font-weight: 400;
      font-size: 14px;
      color: #161B2C;
    }
    .detail-container {
      display: flex;
      justify-content: space-between;
      .detail-left {
        margin-right: 20px;
        width: 312px;
        padding: 24px;
        border: 1px solid #E4E4E4;
      }
      .detail-right {
        &>div {
          .detail-title {
            margin: 10px 0;
          }
          &:first-child {
            .detail-title {
              margin-top: 0;
            }
          }
        }
      }
    }
    // 查看
@@ -460,6 +536,13 @@
        }
      }
    }
    .el-upload {
      button {
        background: #4C34FF;
        border: none;
      }
    }
  }
  .el-dialog__footer {
@@ -470,15 +553,10 @@
      margin-left: 16px;
      width: 96px;
      height: 36px;
      color: #161B2C;
      &:first-child {
        margin-left: 0;
      }
    }
    .save-btn {
      color: #FFFFFF;
    }
  }
}
@@ -488,15 +566,14 @@
  flex: 1;
  background: transparent !important;
  .el-table--border .el-table__inner-wrapper:after,
  .el-table--border:after,
  .el-table--border:before,
  .el-table__inner-wrapper:before {
    height: 0;
  }
  tr {
    background: transparent !important;
  }
  tr.el-table__row {
    &:hover {
      background: #F7F8FC !important;
    }
  }
  th.el-table__cell {
@@ -534,17 +611,42 @@
  td.operation-btns .cell {
    display: flex;
    flex-wrap: nowrap;
    gap: 12px;
    /* 按钮间距(推荐) */
    white-space: nowrap;
    /* 双保险 */
    a {
      display: flex;
      align-items: center;
      position: relative;
      margin: 0 10px;
      min-width: 28px;
      color: #0075FF;
      span {
        color: #0075FF;
      }
      &:first-child {
        margin-left: 0;
      }
      &::before {
        content: '';
        position: absolute;
        top: 50%;
        right: -10px;
        width: 1px;
        height: 12px;
        background: #BCC8E3;
        transform: translateY(calc(-50% - 1px));
      }
      &:last-child {
        margin-right: 0;
        &::before {
          display: none;
        }
      }
    }
  }
@@ -554,8 +656,53 @@
    background: transparent !important;
  }
  .el-checkbox {
    width: 16px;
    height: 16px;
    .el-checkbox__input {
      width: 16px;
      height: 16px;
      .el-checkbox__inner {
        width: 16px;
        height: 16px;
        border: none;
        background: url("@/assets/images/common/n-checkbox.png") no-repeat center / 100% 100% !important;
      }
    }
    &.is-checked {
      .el-checkbox__input {
        .el-checkbox__inner {
          border: none;
          background: url("@/assets/images/common/checkbox.png") no-repeat center / 100% 100% !important;
          &::after {
            content: none;
          }
        }
      }
    }
  }
  .fixed-column {
    background-color: #1A1A2A !important;
  }
}
.el-table {
  .el-table--border .el-table__inner-wrapper:after,
  .el-table--border:after,
  .el-table--border:before,
  .el-table__inner-wrapper:before {
    height: 0;
  }
  td.el-table__cell {
    border: none !important;
  }
}
@@ -628,16 +775,16 @@
}
.gd-confirm-custom {
  background: #1A1A2A;
  background: #fff;
  border-radius: 6px;
  border: 1px solid #2E2E46;
  border: none;
  .el-message-box__header {
    .el-message-box__title {
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-weight: bold;
      font-size: 18px;
      color: #FFFFFF;
      color: #383874;
      line-height: 22px;
      text-align: left;
      font-style: normal;
@@ -646,7 +793,7 @@
  }
  .el-message-box__content {
    color: #D4D5D7;
    color: #4E5969;
  }
  .el-message-box__btns {
@@ -666,14 +813,15 @@
}
.gd-confirm-button {
  background: #284FE3 !important;
  border-color: #284FE3 !important;
  background: #4C34FF !important;
  border: none !important;
  color: #fff !important;
}
.gd-confirm-cancel-button {
  background: #2B2B4C !important;
  border-color: #2B2B4C !important;
  color: #FFFFFF !important;
  background: #F2F3F5 !important;
  border: none !important;
  color: #161B2C !important;
}
.gd-search-form {
@@ -790,14 +938,14 @@
.gd-select-popper {
  border: none;
  background: $form-bg !important;
  background: $search-item-symbol-bg !important;
  .el-select-dropdown {
    .el-scrollbar {
      .el-select-dropdown__wrap {
        .el-select-dropdown__list {
          .el-select-dropdown__item {
            color: #4E5969;
            color: $search-item-symbol-txt;
            &.hover {
              background-color: rgba(0, 120, 233, 0.63) !important;
@@ -866,3 +1014,162 @@
    }
  }
}
.gd-tabs {
  .el-tabs__header {
    .el-tabs__item.is-active {
      color: #3247E5;
    }
    .el-tabs__active-bar {
      background: #3247E5;
    }
  }
}
.gd-dialog-table {
  background: transparent !important;
  tr {
    background: transparent !important;
  }
  tr.el-table__row {
    &:hover {
      background: #F7F8FC !important;
    }
  }
  th.el-table__cell {
    height: 40px;
    border-bottom: 1px solid #DBDFF1 !important;
    .cell {
      padding: 0 0 0 16px;
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-weight: 400;
      font-size: 14px;
      color: #9292C1;
      text-align: left;
      font-style: normal;
      text-transform: none;
    }
  }
  td.el-table__cell {
    padding: 9px 0;
    height: 56px;
    .cell {
      padding: 0 0 0 16px;
      font-family: Source Han Sans CN, Source Han Sans CN;
      font-weight: 400;
      font-size: 14px;
      color: #383874;
      text-align: left;
      font-style: normal;
      text-transform: none;
    }
  }
  td.operation-btns .cell {
    display: flex;
    flex-wrap: nowrap;
    /* 按钮间距(推荐) */
    white-space: nowrap;
    /* 双保险 */
    a {
      display: flex;
      align-items: center;
      position: relative;
      margin: 0 10px;
      min-width: 28px;
      span {
        color: #0075FF;
      }
      &:first-child {
        margin-left: 0;
      }
      &::before {
        content: '';
        position: absolute;
        top: 50%;
        right: -10px;
        width: 1px;
        height: 12px;
        background: #BCC8E3;
        transform: translateY(calc(-50% - 1px));
      }
      &:last-child {
        margin-right: 0;
        &::before {
          display: none;
        }
      }
    }
  }
  th.el-table__cell:not(.fixed-column),
  td.el-table__cell:not(.fixed-column) {
    background: transparent !important;
  }
  .el-checkbox {
    width: 16px;
    height: 16px;
    .el-checkbox__input {
      width: 16px;
      height: 16px;
      .el-checkbox__inner {
        width: 16px;
        height: 16px;
        border: none;
        background: url("@/assets/images/common/n-checkbox.png") no-repeat center / 100% 100% !important;
      }
    }
    &.is-checked {
      .el-checkbox__input {
        .el-checkbox__inner {
          border: none;
          background: url("@/assets/images/common/checkbox.png") no-repeat center / 100% 100% !important;
          &::after {
            content: none;
          }
        }
      }
    }
  }
  .fixed-column {
    background-color: #1A1A2A !important;
  }
}
.el-popper {
  .el-menu--popup-container {
    .el-menu {
      .el-menu-item.is-active {
        &::before {
          display: none;
        }
        background: #4C34FF;
        span {
          color: #fff;
        }
      }
    }
  }
}
applications/task-work-order/src/styles/customFont.scss
New file
@@ -0,0 +1,60 @@
@font-face {
    font-family: "iconfont_com";
    /* Project id 5099981 */
    src: url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.woff2?t=1769414361186') format('woff2'),
        url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.woff?t=1769414361186') format('woff'),
        url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.ttf?t=1769414361186') format('truetype'),
        url('//at.alicdn.com/t/c/font_5099981_ysrl5v42ycd.svg?t=1769414361186#iconfont') format('svg');
}
.iconfont_com {
    font-family: "iconfont_com" !important;
    font-size: 16px;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
.icon-a-1:before {
    content: "\e609";
  }
.icon-a-4:before {
    content: "\e604";
}
.icon-a-3:before {
    content: "\e605";
}
.icon-a-2:before {
    content: "\e606";
}
.icon-a-6:before {
    content: "\e607";
}
.icon-a-5:before {
    content: "\e608";
}
.icon-Frame:before {
    content: "\e602";
}
.icon-a-:before {
    content: "\e601";
}
.icon-MenuIcon-biaozhunshujutuisong-heise:before {
    content: "\e611";
}
.icon-MenuIcon-xuncharenwujiankong-heise:before {
    content: "\e614";
}
.icon-MenuIcon-shebeirizhi-heise:before {
    content: "\e615";
}
applications/task-work-order/src/styles/tags.scss
@@ -37,11 +37,20 @@
    border-radius: 3px 3px 3px 3px;
    &:active  {
      color: #FFFFFF !important;
      background: #5B6BFF !important;
      span {
        color: #fff !important;
      }
    }
    &.is-active {
      //padding: 0 !important;
      //padding-left: 20px !important;
      color: #FFFFFF;
      background: #5B6BFF;
      color: #FFFFFF !important;
      background: #5B6BFF !important;
      .is-icon-close {
        //margin: 0 10px;
applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/FormDiaLog.vue
@@ -98,7 +98,7 @@
            <template v-if="!dialogReadonly">
                <el-button color="#F2F3F5" @click="visible = false">取消</el-button>
                <el-button
                    class="save-btn"
                    class=""
                    color="#4C34FF"
                    :loading="submitting"
@@ -111,7 +111,7 @@
            <template v-if="dialogReadonly && innovationDetailsStatus ==='0'">
                <el-button color="#F2F3F5" @click="handleReject">不通过</el-button>
                <el-button
                    class="save-btn"
                    class=""
                    color="#4C34FF"
                    :loading="submitting"
                    :disabled="submitting"
applications/task-work-order/src/views/orderView/orderDataManage/appInnovation/index.vue
@@ -43,7 +43,7 @@
        <div class="gd-table-container" v-loading="loading">
            <div class="gd-table-content gd-table-content-bg">
                <el-table class="gd-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column label="序号" width="60" align="center">
                    <el-table-column label="序号" width="70" align="center">
                        <template #default="{ $index }">
                            {{ formatNumber((searchParams.current - 1) * searchParams.size + $index + 1) }}
                        </template>
@@ -60,11 +60,11 @@
                    <el-table-column prop="resourceName" show-overflow-tooltip label="资源名称" />
                    <el-table-column prop="resourceCode" show-overflow-tooltip label="资源编码" />
                    <el-table-column prop="caseDesc" show-overflow-tooltip label="案例描述" />
                    <el-table-column label="操作" class-name="operation-btns" width="180">
                    <el-table-column label="操作" class-name="operation-btns" width="240">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
<!--                            <el-link @click="openForm('edit', row)">编辑</el-link>-->
                            <el-link @click="handleDelete(row)" v-if="!['1', '2'].includes(row.innovationStatus)">删除</el-link>
                            <el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
<!--                            <el-link  type="primary"  @click="openForm('edit', row)">编辑</el-link>-->
                            <el-link  type="primary"  @click="handleDelete(row)" v-if="!['1', '2'].includes(row.innovationStatus)">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/FormDiaLog.vue
@@ -187,13 +187,13 @@
                >
                    保存
                </el-button>
                <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleApply">申请</el-button>
                <el-button class="" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleApply">申请</el-button>
            </template>
            <template v-if="dialogReadonly && detailObjectionStatus === '1'">
                <el-button color="#F2F3F5" :loading="submitting" :disabled="submitting" @click="visible = false">取消</el-button>
                <el-button
                    class="save-btn"
                    class=""
                    color="#4C34FF"
                    :loading="submitting"
@@ -204,7 +204,7 @@
                    反馈
                </el-button>
                <el-button
                        class="save-btn"
                        class=""
                        color="#4C34FF"
                        :loading="submitting"
@@ -444,7 +444,7 @@
        ElMessage.warning('没有可下载的附件')
        return
    }
    // 遍历所有附件并下载
    attachmentDetailsList.value.forEach(attach => {
        if (attach.link) {
@@ -479,9 +479,6 @@
</script>
<style scoped lang="scss">
.detail-container {
    padding: 20px;
}
.upload-container {
    width: 100%;
}
applications/task-work-order/src/views/orderView/orderDataManage/dataObjection/index.vue
@@ -43,7 +43,7 @@
        <div class="gd-table-container" v-loading="loading">
            <div class="gd-table-content gd-table-content-bg">
                <el-table class="gd-table" :data="list">
                    <el-table-column label="序号" width="60">
                    <el-table-column label="序号" width="70">
                        <template v-slot="{ $index }">
                            {{ String($index + 1).padStart(2, '0') }}
                        </template>
@@ -59,21 +59,21 @@
                            {{ getDictLabel(row.objectionStatus, dictObj.objectionStatus) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="catalogResourceName" width="170" show-overflow-tooltip label="目录/申请资源名称" />
                    <el-table-column prop="catalogResourceName" width="130" show-overflow-tooltip  label="目录/申请资源名称" />
                    <el-table-column prop="otherObjectionDetail" show-overflow-tooltip label="其他异议详情" />
                    <el-table-column prop="submitter" show-overflow-tooltip label="问题提交人" />
                    <el-table-column prop="submitterContact" show-overflow-tooltip width="145" label="提交人联系方式" />
                    <el-table-column prop="submitterContact" show-overflow-tooltip width="120" label="提交人联系方式" />
                    <el-table-column prop="submitUnitName" show-overflow-tooltip label="提交单位" />
                    <el-table-column prop="handleUnit" show-overflow-tooltip label="处理单位" />
                    <el-table-column prop="objectionDesc" show-overflow-tooltip label="异议描述" />
                    <el-table-column prop="objectionBasis" show-overflow-tooltip label="异议依据" />
                    <el-table-column prop="attachName" show-overflow-tooltip label="附件名称" />
                    <el-table-column prop="reviewOpinion" show-overflow-tooltip label="审核意见" />
                    <el-table-column label="操作" class-name="operation-btns" width="180">
                    <el-table-column label="操作" class-name="operation-btns" width="240">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
                            <el-link @click="openForm('edit', row)" v-if="!['1', '2'].includes(row.objectionStatus)">编辑</el-link>
                            <el-link @click="handleDelete(row)" v-if="!['1', '2'].includes(row.objectionStatus)">删除</el-link>
                            <el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
                            <el-link  type="primary"  @click="openForm('edit', row)" v-if="!['1', '2'].includes(row.objectionStatus)">编辑</el-link>
                            <el-link  type="primary"  @click="handleDelete(row)" v-if="!['1', '2'].includes(row.objectionStatus)">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
applications/task-work-order/src/views/orderView/orderDataManage/evaluate/FormDiaLog.vue
@@ -128,7 +128,7 @@
        <template #footer v-if="!dialogReadonly">
            <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
            <el-button
                class="save-btn"
                class=""
                color="#4C34FF"
                :loading="submitting"
applications/task-work-order/src/views/orderView/orderDataManage/evaluate/index.vue
@@ -53,11 +53,11 @@
                        </template>
                    </el-table-column>
                    <el-table-column prop="evaluationContent" show-overflow-tooltip label="评价内容" />
                    <el-table-column label="操作" class-name="operation-btns" width="180">
                    <el-table-column label="操作" class-name="operation-btns" width="240">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
                            <el-link @click="openForm('edit', row)">编辑</el-link>
                            <el-link @click="handleDelete(row)">删除</el-link>
                            <el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
                            <el-link  type="primary"  @click="openForm('edit', row)">编辑</el-link>
                            <el-link  type="primary"  @click="handleDelete(row)">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/ApplyViewDialog.vue
@@ -108,13 +108,13 @@
        <template #footer>
            <template v-if="detailDemandStatus === '1' && !requesterProvider">
                <el-button color="#F2F3F5"  @click="rejectTheApplication">拒绝申请</el-button>
                <el-button class="save-btn" color="#4C34FF" @click="approvedByTheReview">审核通过</el-button>
                <el-button class="" color="#4C34FF" @click="approvedByTheReview">审核通过</el-button>
            </template>
            <template v-if="detailDemandStatus === '2'">
                <el-button class="save-btn" color="#4C34FF" @click="downloadAllFiles">全部下载</el-button>
                <el-button class="" color="#4C34FF" @click="downloadAllFiles">全部下载</el-button>
            </template>
            <template v-if="detailDemandStatus === '3'">
                <el-button class="save-btn" color="#4C34FF" @click="visible =false">关闭</el-button>
                <el-button class="" color="#4C34FF" @click="visible =false">关闭</el-button>
            </template>
        </template>
    </el-dialog>
@@ -419,23 +419,16 @@
</script>
<style scoped lang="scss">
.detail-container {
    padding: 20px;
    display: flex;
    gap: 30px;
    align-items: stretch;
}
/* 左侧步骤条 */
.detail-left {
    width: 25%;
    width: 35%;
    padding-right: 20px;
    border-right: 1px solid #e8e8e8;
}
/* 右侧表单 */
.detail-right {
    width: 75%;
    width: 65%;
    .reject-reason {
        margin-bottom: 20px;
        background: #f2f3f5;
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/FormDiaLog.vue
@@ -194,7 +194,7 @@
            >
                保存
            </el-button>
            <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleApply">申请</el-button>
            <el-button color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleApply">申请</el-button>
        </template>
    </el-dialog>
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/auditRecord.vue
@@ -1,14 +1,25 @@
<template>
  <div class="audit-record-container">
    <div class="label">审批记录</div>
    <el-steps direction="vertical" :active="displayedSteps.length">
      <el-step v-for="step in displayedSteps" :key="step.status" :title="step.title" :description="`${step.person || ''}\n${step.time || ''}`" />
    </el-steps>
    <el-timeline class="gd-timeline">
      <el-timeline-item
        v-for="(step, index) in displayedSteps"
        :key="step.status"
        :icon="Check"
        :type="index === displayedSteps.length - 1 ? 'success' : 'info'"
        :timestamp="step.time"
      >
        <div class="item-content">
          <div class="flowName">{{ step.title }}</div>
          <div >{{ step.person }}</div>
        </div>
      </el-timeline-item>
    </el-timeline>
  </div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { Check } from '@element-plus/icons-vue'
import { gdSupplyDemandAuditListApi } from '@/views/orderView/orderDataManage/supplyAdd/supplyAddApi'
const props = defineProps({
@@ -89,32 +100,32 @@
<style scoped lang="scss">
.audit-record-container {
    height: 95%;
  .label {
    font-weight: 500;
    margin-bottom: 8px;
    color: #333;
width:100%;
    // height: 95%;
}
/* 时间线样式 */
:deep(.gd-timeline) {
 padding-left: 90px;
}
:deep(.el-timeline-item) {
  padding-bottom: 20px;
  .item-content {
     position: relative;
            .flowName {
                width: 80px;
                position: absolute;
                left: -120px;
                top: 0px;
            }
  }
}
/* 步骤条样式 */
:deep(.el-steps) {
  align-items: flex-start;
}
:deep(.el-step) {
  // margin-bottom: 20px;
}
:deep(.el-step__title) {
  font-size: 14px;
  font-weight: 500;
}
:deep(.el-step__description) {
  font-size: 13px;
  color: #666;
  white-space: pre-wrap;
  line-height: 1.4;
:deep(.el-timeline-item__timestamp) {
  font-size: 12px;
  color: #999;
  margin-top: 2px;
}
</style>
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/index.vue
@@ -42,7 +42,7 @@
        <div class="gd-table-container" v-loading="loading">
            <div class="gd-table-content gd-table-content-bg">
                <el-table class="gd-table" :data="list">
                    <el-table-column label="序号" width="60" align="center">
                    <el-table-column label="序号" width="70" align="center">
                        <template #default="scope">
                            {{ ((searchParams.current - 1) * searchParams.size + scope.$index + 1).toString().padStart(2, '0') }}
                        </template>
@@ -54,7 +54,7 @@
                        </template>
                    </el-table-column>
                    <el-table-column prop="contactPerson" show-overflow-tooltip label="需求联系人" />
                    <el-table-column prop="contactPhone" show-overflow-tooltip width="150" label="需求联系人电话" />
                    <el-table-column prop="contactPhone" show-overflow-tooltip width="180" label="需求联系人电话" />
                    <el-table-column prop="contactEmail" show-overflow-tooltip label="需求邮箱" />
                    <el-table-column prop="demandStatus" show-overflow-tooltip label="需求状态">
                        <template v-slot="{ row }">
@@ -76,12 +76,12 @@
                    <el-table-column prop="responsibleDeptName" show-overflow-tooltip label="责任部门" />
                    <el-table-column prop="dataSource" show-overflow-tooltip label="数据来源依据" />
                    <el-table-column prop="demandInfo" show-overflow-tooltip label="需求信息项" />
                    <el-table-column label="操作" class-name="operation-btns" width="180">
                    <el-table-column label="操作" class-name="operation-btns" width="240">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
                            <el-link  type="primary"  @click="openForm('view', row)">查看</el-link>
                            <!-- 只对非审批状态显示编辑和删除按钮 -->
                            <el-link @click="openForm('edit', row)" v-if="!['1', '2', '3'].includes(row.demandStatus)">编辑</el-link>
                            <el-link @click="handleDelete(row)" v-if="!['1', '2', '3'].includes(row.demandStatus)">删除</el-link>
                            <el-link  type="primary"  @click="openForm('edit', row)" v-if="!['1', '2', '3'].includes(row.demandStatus)">编辑</el-link>
                            <el-link  type="primary"  @click="handleDelete(row)" v-if="!['1', '2', '3'].includes(row.demandStatus)">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
applications/task-work-order/src/views/orderView/orderDataManage/supplyAdd/reasonForRejectionDialog.vue
@@ -16,7 +16,7 @@
            </div>
        </div>
        <template #footer>
            <el-button class="save-btn" color="#4C34FF" @click="handleConfirm">确认</el-button>
            <el-button class="" color="#4C34FF" @click="handleConfirm">确认</el-button>
        </template>
    </el-dialog>
</template>
@@ -65,21 +65,4 @@
</script>
<style scoped lang="scss">
.detail-container {
    padding: 20px;
    display: flex;
    align-items: flex-start;
    gap: 30px;
    .detail-cell {
        display: flex;
        justify-content: center;
        .cell-label {
            min-width: 80px;
            flex-shrink: 0;
        }
        :deep(.el-textarea__inner) {
            height: 100px !important;
        }
    }
}
</style>
applications/task-work-order/src/views/orderView/orderManage/clueEvents/DistributeDiaLog.vue
@@ -43,7 +43,7 @@
        </el-form>
        <template #footer>
            <el-button color="#F2F3F5" @click="visible = false">取消</el-button>
            <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleSubmit">
            <el-button class="" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="handleSubmit">
                保存
            </el-button>
        </template>
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
@@ -1,45 +1,45 @@
<template>
    <el-dialog class="gd-dialog" v-model="visible" title="查看" @closed="visible = false" width="1000px" destroy-on-close>
        <div class="gd-table-container" v-loading="loading" style="height: 600px">
            <div class="gd-table-content gd-table-content-bg">
                <el-table class="gd-table" :data="list">
                    <el-table-column label="线索缩略图" width="120">
                        <template v-slot="{ row }">
                            <el-image
                                v-if="row.resultUrl"
                                :src="row.resultUrl"
                                :preview-src-list="[row.resultUrl]"
                                fit="cover"
                                style="width: 80px; height: 60px"
                                preview-teleported
                            />
                            <span v-else>-</span>
                        </template>
                    </el-table-column>
                    <el-table-column prop="resultCode" show-overflow-tooltip label="线索编号" />
                    <el-table-column prop="shootTime" show-overflow-tooltip label="拍摄时间" />
                    <el-table-column label="线索位置" show-overflow-tooltip>
                        <template v-slot="{ row }">
                            {{ formatLocation(row) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="distributeStatus" show-overflow-tooltip label="线索状态">
                        <template v-slot="{ row }">
                            {{ getDistributeStatusLabel(row.distributeStatus) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="distributeDeptName" show-overflow-tooltip label="分发部门" />
                    <el-table-column prop="distributeUserName" show-overflow-tooltip label="分发人员" />
                    <el-table-column label="操作" class-name="operation-btns" width="140">
                        <template v-slot="{ row }">
                            <el-link v-if="row.distributeStatus === 0" @click="openDistributeDialog(row)" :disabled="row.distributeStatus === 1">
                                转为事件并分发
                            </el-link>
                            <div class="disabled-text" v-else>转为事件并分发</div>
                        </template>
                    </el-table-column>
                </el-table>
            </div>
        <div v-loading="loading">
            <el-table :data="list">
                <el-table-column label="线索缩略图" width="120">
                    <template v-slot="{ row }">
                        <el-image
                            v-if="row.resultUrl"
                            :src="row.resultUrl"
                            :preview-src-list="[row.resultUrl]"
                            fit="cover"
                            style="width: 80px; height: 60px"
                            preview-teleported
                        />
                        <span v-else>-</span>
                    </template>
                </el-table-column>
                <el-table-column prop="resultCode" show-overflow-tooltip label="线索编号" />
                <el-table-column prop="shootTime" show-overflow-tooltip label="拍摄时间" />
                <el-table-column label="线索位置" show-overflow-tooltip>
                    <template v-slot="{ row }">
                        {{ formatLocation(row) }}
                    </template>
                </el-table-column>
                <el-table-column prop="distributeStatus" show-overflow-tooltip label="线索状态">
                    <template v-slot="{ row }">
                        {{ getDistributeStatusLabel(row.distributeStatus) }}
                    </template>
                </el-table-column>
                <el-table-column prop="distributeDeptName" show-overflow-tooltip label="分发部门" />
                <el-table-column prop="distributeUserName" show-overflow-tooltip label="分发人员" />
                <el-table-column label="操作" class-name="operation-btns" width="140">
                    <template v-slot="{ row }">
                        <el-link  type="primary"
                                            @click="openDistributeDialog(row)"
                                            :disabled="row.distributeStatus === 1 || currentRow.taskStatus !== '8'"
                        >
                            转为事件并分发
                        </el-link>
                    </template>
                </el-table-column>
            </el-table>
        </div>
        <template #footer>
applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
@@ -92,7 +92,7 @@
                    <el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="viewDiaLogView(row)">查看线索</el-link>
                            <el-link  type="primary"  @click="viewDiaLogView(row)">查看线索</el-link>
                        </template>
                    </el-table-column>
                </el-table>
@@ -159,7 +159,12 @@
    const range = dateRangeFormat(dateRange.value)
    loading.value = true
    try {
        const res = await gdPatrolTaskPageApi({ ...searchParams.value, startTime: range[0], endTime: range[1] })
        const res = await gdPatrolTaskPageApi({
            ...searchParams.value,
            startTime: range[0],
            endTime: range[1],
            taskStatus: 8
        })
        list.value = res?.data?.data?.records ?? []
        total.value = res?.data?.data?.total ?? 0
    } finally {
applications/task-work-order/src/views/orderView/orderManage/inspectionReport/index.vue
@@ -57,9 +57,9 @@
                    </el-table-column>
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="seeOnlineWord(row)">查看</el-link>
                            <el-link @click="openForm(row)">在线编辑</el-link>
                            <el-link @click="handleDelete(row)">删除</el-link>
                            <el-link  type="primary"  @click="seeOnlineWord(row)">查看</el-link>
                            <el-link  type="primary"  @click="openForm(row)">在线编辑</el-link>
                            <el-link  type="primary"  @click="handleDelete(row)">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
@@ -117,7 +117,7 @@
            <template #footer>
                <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button>
                <el-button
                    class="save-btn"
                    class=""
                    color="#4C34FF"
                    :loading="submitting"
                    :disabled="submitting"
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue
@@ -179,7 +179,7 @@
        <template #footer>
            <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
            <el-button
                class="save-btn"
                class=""
                color="#4C34FF"
                v-if="!dialogReadonly"
                :loading="submitting"
@@ -201,6 +201,7 @@
import { gdWorkOrderPageApi } from '../orderManage/orderManageApi'
import { gdManageDeviceListApi } from '../orderManage/gdManageDeviceApi'
import { pxToRem } from '@/utils/rem'
import { airlineListApi } from '@/api/zkxt'
// 初始化任务行
const initTaskRow = () => ({
@@ -220,7 +221,7 @@
const dialogMode = ref('add') // 弹框模式
const submitting = ref(false) // 提交中
const dialogReadonly = computed(() => dialogMode.value === 'view')
const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
const titleEnum = ref({ edit: '新增', view: '查看', add: '新增' })
// 工单相关
const workOrderList = ref([]) // 工单列表
@@ -230,11 +231,7 @@
// 下拉选项
const flyerListMap = ref({}) // 飞手列表,按行索引存储
const deviceList = ref([]) // 设备列表
const routeOptions = ref([
    { name: '航线1', id: '1' },
    { name: '航线2', id: '2' },
    { name: '航线3', id: '3' },
]) // 航线假数据
const routeOptions = inject('routeOptions')
// 子任务列表
const taskList = ref([initTaskRow()])
@@ -273,7 +270,7 @@
// 获取工单列表
async function getWorkOrderList() {
    const res = await gdWorkOrderPageApi({ size: 999, workOrderStatus: '20' })
    const res = await gdWorkOrderPageApi({ size: 999, workOrderStatus: dialogMode.value ==='add' ?  '20' : '' })
    workOrderList.value = res?.data?.data?.records ?? []
}
@@ -297,7 +294,7 @@
// 获取设备列表
async function getDeviceList() {
    const res = await gdManageDeviceListApi({
        deviceIds: selectedWorkOrder.value.recommendDeviceIds,
        deviceIds: selectedWorkOrder.value?.recommendDeviceIds,
    })
    deviceList.value = res?.data?.data ?? []
}
@@ -305,6 +302,7 @@
watch(
    () => selectedWorkOrderId.value,
    () => {
        handleWorkOrderChange(selectedWorkOrderId.value)
        getDeviceList()
    }
)
@@ -367,9 +365,9 @@
// 打开弹框
async function open({ mode = 'add', row } = {}) {
    console.log(row, 'rowrow')
    dialogMode.value = mode
    if (mode === 'add') {
    await getWorkOrderList()
    if (dialogMode.value === 'add') {
        selectedWorkOrderId.value = null
        selectedWorkOrder.value = null
        taskList.value = [initTaskRow()]
@@ -388,7 +386,7 @@
}
onMounted(() => {
    getWorkOrderList()
})
defineExpose({ open })
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/RefuseOrderDialog1.vue
@@ -42,7 +42,7 @@
        <template #footer>
            <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
            <el-button
                class="save-btn"
                class=""
                color="#4C34FF"
                v-if="!dialogReadonly"
                :loading="submitting"
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
@@ -5,6 +5,7 @@
        :title="titleEnum[dialogMode]"
        @closed="visible = false"
        destroy-on-close
        width="auto"
        :close-on-click-modal="false"
    >
        <div class="content" style="display: flex">
@@ -17,10 +18,10 @@
                        :type="index === processList.length - 1 ? 'success' : 'info'"
                        :color="activity.color"
                        :hollow="activity.hollow"
                        :timestamp="activity.flowDesc.split(' ')[1]"
                        :timestamp="activity.createTime"
                    >
                        <div class="item-content">
                            <div>{{ activity.flowDesc.split(' ')[0] }}</div>
                            <div>{{ activity.operator }}</div>
                            <div class="flowName">{{ activity.flowName }}</div>
                        </div>
                    </el-timeline-item>
@@ -45,7 +46,7 @@
                        </el-col>
                        <el-col :span="12">
                            <div class="label">巡查任务航线</div>
                            <div class="val">{{ getRouteName(formData.patrolRouteUrl) }}</div>
                            <div class="val">{{ getAirName(formData.patrolRouteUrl) }}</div>
                        </el-col>
                        <el-col :span="12">
                            <div class="label">推荐飞手</div>
@@ -59,15 +60,17 @@
                            <div class="label">关联工单</div>
                            <div class="val">{{ getWorkOrderName(formData.workOrderId) }}</div>
                        </el-col>
                        <el-col :span="24">
                        <el-col :span="12">
                            <div class="label">巡查任务描述</div>
                            <div class="val">{{ formData.taskDesc }}</div>
                        </el-col>
                    </el-row>
                    <template v-if="['6', '7', '8'].includes(taskStatus)">
                        <div class="detail-title" :style="{ marginTop: pxToRem(10) }">任务成功({{ list.length || 0 }}条)</div>
                        <div class="detail-title" :style="{ marginTop: pxToRem(10) }">
                            任务成果({{ taskResultList.length || 0 }}条)
                        </div>
                        <div class="imgBox">
                            <div v-for="item in list">
                            <div v-for="item in taskResultList">
                                <el-image
                                    v-if="item.resultUrl"
                                    :src="item.resultUrl"
@@ -179,6 +182,7 @@
                    </el-row>
                </el-form>
                <div class="detail-title" :style="{ marginTop: pxToRem(10) }">任务航线</div>
                <!-- 地图组件 -->
                <CommonCesiumMap
                    ref="mapRef"
@@ -189,36 +193,37 @@
                    :layer-mode="4"
                    :boundary="false"
                    :zoomToBoundary="false"
                    @ready="() => mapRef.flyBoundary()"
                    @ready="readyMap"
                />
            </div>
        </div>
        <template #footer>
            <template v-if="requester">
                <el-button v-if="['1', '4'].includes(taskStatus)" @click="viewDescription" color="#F2F3F5">
                    {{ gdStatusObj[taskStatus].reason }}
                </el-button>
                <el-button @click="statusChange(3)" v-if="taskStatus === '3'" color="#4C34FF">撤回任务</el-button>
                <el-button @click="refusalToAccept" v-if="taskStatus === '6'" color="#F2F3F5">拒绝验收</el-button>
                <el-button @click="statusChange(6)" v-if="taskStatus === '6'" color="#4C34FF">验收通过</el-button>
                <el-button
                    v-if="!dialogReadonly || ['1', '4'].includes(taskStatus)"
                    :loading="submitting"
                    :disabled="submitting"
                    color="#4C34FF"
                    @click="handleSubmit"
                >
                    提交
                </el-button>
                <el-button v-if="['1', '4'].includes(taskStatus)" @click="viewDescription">
                    {{ gdStatusObj[taskStatus].reason }}
                </el-button>
                <el-button @click="statusChange(3)" v-if="taskStatus === '3'">撤回任务</el-button>
                <el-button @click="refusalToAccept" v-if="taskStatus === '6'">拒绝验收</el-button>
                <el-button @click="statusChange(6)" v-if="taskStatus === '6'">验收通过</el-button>
            </template>
            <template v-else>
                <el-button v-if="['7'].includes(taskStatus)" @click="viewDescription">
                <el-button v-if="['7'].includes(taskStatus)" @click="viewDescription" color="#F2F3F5">
                    {{ gdStatusObj[taskStatus].reason }}
                </el-button>
                <el-button v-if="taskStatus === '0'" @click="addDescription">拒绝签收</el-button>
                <el-button v-if="taskStatus === '0'" @click="statusChange(1)">签收</el-button>
                <el-button v-if="taskStatus === '3'" @click="addDescription">驳回</el-button>
                <el-button v-if="taskStatus === '3'" @click="statusChange(4)">同意</el-button>
                <el-button v-if="taskStatus === '0'" @click="addDescription" color="#F2F3F5">拒绝签收</el-button>
                <el-button v-if="taskStatus === '0'" @click="statusChange(1)" color="#4C34FF">签收</el-button>
                <el-button v-if="taskStatus === '3'" @click="addDescription" color="#F2F3F5">驳回</el-button>
                <el-button v-if="taskStatus === '3'" @click="statusChange(4)" color="#4C34FF">同意</el-button>
            </template>
        </template>
@@ -234,7 +239,7 @@
<script setup>
import { computed, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { fieldRules, getDictLabel } from '@ztzf/utils'
import { fieldRules, flyVisual, getDictLabel } from '@ztzf/utils'
import { gdPatrolTaskRepublish, gdFlyerPageApi, gdPatrolTaskAuditApi } from './inspectionRequestApi'
import { gdWorkOrderFlowListApi, gdWorkOrderPageApi } from '../orderManage/orderManageApi'
import { gdManageDeviceListApi } from '../orderManage/gdManageDeviceApi'
@@ -244,6 +249,8 @@
import RefuseOrderDialog from '@/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue'
import RefuseOrderDialog1 from '@/views/orderView/orderManage/inspectionRequest/RefuseOrderDialog1.vue'
import { Check } from '@element-plus/icons-vue'
import { queryAirById } from '@/api/zkxt'
import * as Cesium from 'cesium'
// 初始化表单数据
const initForm = () => ({
@@ -277,11 +284,8 @@
const flyerList = ref([])
const deviceList = ref([])
const workOrderList = ref([])
const routeOptions = ref([
    { name: '航线1', id: '1' },
    { name: '航线2', id: '2' },
    { name: '航线3', id: '3' },
])
const routeOptions = inject('routeOptions')
const getAirName = inject('getAirName')
const gdStatusObj = {
    '0': { reason: '拒绝原因', operationType: '2' },
@@ -388,7 +392,7 @@
const processList = ref([])
// 加载时间线list
function loadList() {
    gdWorkOrderFlowListApi({ workOrderId: formData.value.id,type: '1' }).then(res => {
    gdWorkOrderFlowListApi({ workOrderId: formData.value.id, type: '1' }).then(res => {
        processList.value = res.data.data
    })
}
@@ -408,25 +412,82 @@
    }
}
let list = ref([])
let taskResultList = ref([])
// 获取成果列表
async function getList() {
async function getTaskResultList() {
    if (!formData.value?.id) return
    try {
        const res = await gdTaskResultListApi({ patrolTaskId: formData.value.id })
        list.value = res?.data?.data ?? []
        taskResultList.value = res?.data?.data ?? []
    } finally {
    }
}
// 获取航线详情
function getAirDetails() {
    queryAirById(formData.value.patrolRouteUrl).then(res => {
        const list = res.data.data.airlineWaypoints
        if (!list.length) return mapRef.value?.flyBoundary()
        const result = list.map(item => [Number(item.longitude), Number(item.latitude)]).flat()
        viewer.entities.add({
            polyline: {
                positions: Cesium.Cartesian3.fromDegreesArray(result),
                clampToGround: true,
                width: 3,
                material: Cesium.Color.RED,
            },
        })
        // 渲染起点(蓝色)
        const startPoint = list[0]
        viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(
                Number(startPoint.longitude),
                Number(startPoint.latitude),
                startPoint.height || 0
            ),
            point: {
                pixelSize: 12,
                color: Cesium.Color.BLUE,
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            },
        })
        // 渲染终点(红色)
        const endPoint = list[list.length - 1]
        viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(
                Number(endPoint.longitude),
                Number(endPoint.latitude),
                endPoint.height || 0
            ),
            point: {
                pixelSize: 12,
                color: Cesium.Color.RED,
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            },
        })
        flyVisual({
            positionsData: list.map(i => [Number(i.longitude), Number(i.latitude), i.height || 0]),
            viewer,
        })
    })
}
// 打开弹框
async function open({ mode = 'view', row } = {}) {
    dialogMode.value = mode
    formData.value = { ...initForm(), ...row }
    console.log(row)
    ;['6', '7', '8'].includes(row.taskStatus) && getList()
    ;['6', '7', '8'].includes(row.taskStatus) && getTaskResultList()
    loadList()
    initMap()
}
const readyMap = () => {
    // mapRef.value?.flyBoundary()
    getAirDetails()
}
// 初始化地图实例
@@ -449,17 +510,26 @@
.content {
    display: flex;
    gap: 0 20px;
    height: 680px;
    .leftBox {
        width: 920px;
        flex: 1;
        overflow: auto;
        display: flex;
        flex-direction: column;
        .gd-cesium {
            padding-top: 10px;
            width: 100%;
            height: 423px;
            min-height: 380px;
            flex: 1;
        }
    }
    .processBox {
        width: 312px;
        padding: 24px 0;
        border: 1px solid #e4e4e4;
        overflow: auto;
        .item-content {
            position: relative;
            .flowName {
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue
@@ -98,8 +98,7 @@
                    <el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="viewDiaLogView(row)">查看</el-link>
                            <!--                            <el-link @click="openForm('edit', row)">编辑</el-link>-->
                            <el-link  type="primary"  @click="viewDiaLogView(row)">查看</el-link>
                        </template>
                    </el-table-column>
                </el-table>
@@ -137,6 +136,7 @@
import { gdPatrolTaskPageApi, gdPatrolTaskRemoveApi } from './inspectionRequestApi'
import ViewDiaLog from '@/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue'
import { useStore } from 'vuex'
import { airlineListApi } from '@/api/zkxt'
const store = useStore()
const requester = computed(() => store.state.user.userInfo?.role_id === '2014158512610869250')
@@ -232,6 +232,19 @@
    selectedIds.value = rows.map(item => item.id)
}
const routeOptions = ref([])
const getAirName = id => {
    const item = routeOptions.value.find(item => item.id === id)
    return item ? item.name : id
}
provide('routeOptions', routeOptions)
provide('getAirName', getAirName)
function getAirList() {
    airlineListApi({}).then(res => {
        routeOptions.value = res.data.data || []
    })
}
// 获取字典
function getDictList() {
    getDictionaryByCode('patrolTaskType,workOrderType,deviceLoadDemand,taskStatus').then(res => {
@@ -249,6 +262,7 @@
onMounted(() => {
    getList()
    getDictList()
    getAirList()
})
</script>
<style scoped lang="scss"></style>
applications/task-work-order/src/views/orderView/orderManage/operatingIncome/index.vue
@@ -1,81 +1,93 @@
<!-- 运营收益 -->
<template>
  <basic-container>
        <div class="gd-table-toolbar">
            <el-button :icon="Plus" color="#4C34FF" type="primary" @click="handleAdd">新增</el-button>
    <div class="gd-table-toolbar">
      <el-button :icon="Plus" color="#4C34FF" type="primary" @click="handleAdd">新增</el-button>
      <el-button :icon="Delete" color="#4C34FF" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
   <div class="gd-table-container" v-loading="loading">
            <div class="gd-table-content gd-table-content-bg">
        <el-table class="gd-table" :data="tableList" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="46" />
                <el-table-column label="序号" type="index" width="60"></el-table-column>
        <el-table-column prop="operatingIncome" label="营业收入" align="center"></el-table-column>
        <el-table-column prop="totalCost" label="综合总成本费用" align="center"></el-table-column>
        <el-table-column prop="netProfit" label="净利润" align="center"></el-table-column>
        <el-table-column prop="financialIrr" label="财务内部收益率" align="center"></el-table-column>
        <el-table-column prop="marketSpace" label="市场空间" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
        <el-table-column prop="nickName" label="创建人" align="center"></el-table-column>
                <el-table-column label="操作" width="180" align="center">
                    <template #default="scope">
            <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> -->
            <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button>
                        <el-button type="text" @click="handleDelete(scope.row)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
        </div>
    <div class="gd-pagination-parent">
                <el-pagination
                    popper-class="gd-select-popper"
                    v-model:current-page="params.current"
                    v-model:page-size="params.size"
                    layout="total, prev, pager, next, sizes"
                    :total="total"
                    @change="getList"
                />
            </div>
    </div>
  <el-dialog class="gd-dialog" append-to-body v-model="isShowEditView" :title="titleTxt"
        :width="pxToRem(800)" :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose">
    <div class="gd-table-container" v-loading="loading">
      <div class="gd-table-content gd-table-content-bg">
        <el-table class="gd-table" :data="tableList" @selection-change="handleSelectionChange">
          <el-table-column type="selection" width="46" />
          <el-table-column label="序号" type="index" width="60"></el-table-column>
          <el-table-column prop="operatingIncome" label="营业收入" align="center"></el-table-column>
          <el-table-column prop="totalCost" label="综合总成本费用" align="center"></el-table-column>
          <el-table-column prop="netProfit" label="净利润" align="center"></el-table-column>
          <el-table-column prop="financialIrr" label="财务内部收益率" align="center"></el-table-column>
          <el-table-column prop="marketSpace" label="市场空间" align="center" show-overflow-tooltip></el-table-column>
          <el-table-column prop="createTime" label="创建时间" align="center"></el-table-column>
          <el-table-column prop="nickName" label="创建人" align="center"></el-table-column>
          <el-table-column label="操作" width="180" align="center" class-name="operation-btns">
            <template #default="scope">
              <!-- <el-button icon="el-icon-view" type="text" @click="handleDetail(scope.row)">查看</el-button> -->
              <el-link type="primary" @click="handleEdit(scope.row)">编辑</el-link>
              <el-link type="primary" @click="handleDelete(scope.row)">删除</el-link>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="gd-pagination-parent">
        <el-pagination popper-class="gd-select-popper" v-model:current-page="params.current"
          v-model:page-size="params.size" layout="total, prev, pager, next, sizes" :total="total" @change="getList" />
      </div>
    </div>
    <el-dialog class="gd-dialog" append-to-body v-model="isShowEditView" :title="titleTxt" :width="pxToRem(800)"
      :close-on-click-modal="false" :destroy-on-close="true" @close="handleClose">
      <el-form class="gd-dialog-form" ref="ruleFormRef" :model="editParams" :rules="rules" label-width="140px">
        <el-form-item label="营业收入" prop="operatingIncome">
          <el-input class="gd-input" v-model="editParams.operatingIncome" />
        </el-form-item>
        <el-form-item label="综合总成本费用" prop="totalCost">
          <el-input class="gd-input" v-model="editParams.totalCost" />
        </el-form-item>
        <el-form-item label="净利润" prop="netProfit">
          <el-input class="gd-input" v-model="editParams.netProfit" />
        </el-form-item>
        <el-form-item label="财务内部收益率" prop="financialIrr">
          <el-input class="gd-input" v-model="editParams.financialIrr" />
        </el-form-item>
        <el-form-item label="市场空间" prop="marketSpace">
          <el-input class="gd-input" v-model="editParams.marketSpace"  />
        </el-form-item>
        <el-row>
          <el-col span="12">
            <el-form-item label="营业收入" prop="operatingIncome">
              <el-input class="gd-input" v-model="editParams.operatingIncome" />
            </el-form-item>
          </el-col>
          <el-col span="12">
            <el-form-item label="综合总成本费用" prop="totalCost">
              <el-input class="gd-input" v-model="editParams.totalCost" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col span="12">
            <el-form-item label="净利润" prop="netProfit">
              <el-input class="gd-input" v-model="editParams.netProfit" />
            </el-form-item>
          </el-col>
          <el-col span="12">
            <el-form-item label="财务内部收益率" prop="financialIrr">
              <el-input class="gd-input" v-model="editParams.financialIrr" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col span="12">
            <el-form-item label="市场空间" prop="marketSpace">
              <el-input class="gd-input" v-model="editParams.marketSpace" />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    <!-- </div> -->
     <template #footer>
            <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button>
            <el-button class="save-btn" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="submit(ruleFormRef)">
                保存
            </el-button>
        </template>
    </el-dialog>
      <!-- </div> -->
      <template #footer>
        <el-button color="#F2F3F5" @click="isShowEditView = false">取消</el-button>
        <el-button class="" color="#4C34FF" :loading="submitting" :disabled="submitting" @click="submit(ruleFormRef)">
          保存
        </el-button>
      </template>
    </el-dialog>
  </basic-container>
</template>
<script setup>
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { operatingIncomePage, operatingIncomeUpdate, operatingIncomeAdd, operatingIncomeBatchDelete } from './operatingIncomeApi';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import { operatingIncomePage, operatingIncomeUpdate, operatingIncomeAdd, operatingIncomeBatchDelete } from './operatingIncomeApi'
let titleTxt = ref('新增')
const total = ref(0)
const params = ref({
  current: 1,
  size: 10,
});
})
const submitting = ref(false)
const loading = ref(true) // 列表加载中
const selectedIds = ref([]) // 勾选的ID列表
@@ -98,9 +110,9 @@
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
          callback(new Error('请输入有效的数字(整数或小数)'))
        } else {
          callback();
          callback()
        }
      },
      trigger: 'blur'
@@ -111,9 +123,9 @@
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
          callback(new Error('请输入有效的数字(整数或小数)'))
        } else {
          callback();
          callback()
        }
      },
      trigger: 'blur'
@@ -124,9 +136,9 @@
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
          callback(new Error('请输入有效的数字(整数或小数)'))
        } else {
          callback();
          callback()
        }
      },
      trigger: 'blur'
@@ -137,9 +149,9 @@
    {
      validator: (rule, value, callback) => {
        if (!/^\d+(\.\d+)?$/.test(value)) {
          callback(new Error('请输入有效的数字(整数或小数)'));
          callback(new Error('请输入有效的数字(整数或小数)'))
        } else {
          callback();
          callback()
        }
      },
      trigger: 'blur'
@@ -151,11 +163,11 @@
})
// 勾选值设置
function handleSelectionChange(rows) {
    selectedIds.value = rows.map(item => item.id)
function handleSelectionChange (rows) {
  selectedIds.value = rows.map(item => item.id)
}
function getList() {
function getList () {
  loading.value = true
  operatingIncomePage(params.value).then(res => {
    tableList.value = res.data.data.records || []
@@ -164,34 +176,34 @@
    loading.value = false
  })
}
function handleEdit(row) {
function handleEdit (row) {
  titleTxt.value = '编辑'
  isShowEditView.value = true
  editParams.value = { ...row }
}
// 删除
async function handleDelete(row) {
    const tips = row ? '该条' : '选中的项'
    await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', {
        type: 'warning',
        customClass: 'gd-confirm-custom',
        confirmButtonClass: 'gd-confirm-button',
        cancelButtonClass: 'gd-confirm-cancel-button',
    })
    const ids = row ? row.id : selectedIds.value
    await operatingIncomeBatchDelete(ids)
    ElMessage.success('删除成功')
    selectedIds.value = []
    getList()
async function handleDelete (row) {
  const tips = row ? '该条' : '选中的项'
  await ElMessageBox.confirm(`确认删除${tips}吗?`, '提示', {
    type: 'warning',
    customClass: 'gd-confirm-custom',
    confirmButtonClass: 'gd-confirm-button',
    cancelButtonClass: 'gd-confirm-cancel-button',
  })
  const ids = row ? row.id : selectedIds.value
  await operatingIncomeBatchDelete(ids)
  ElMessage.success('删除成功')
  selectedIds.value = []
  getList()
}
function handleAdd() {
function handleAdd () {
  titleTxt.value = '新增'
  isShowEditView.value = true
}
async function submit(formValidate) {
async function submit (formValidate) {
  if (!formValidate) return
  await formValidate.validate((valid, fields) => {
    if (valid) {
@@ -217,7 +229,7 @@
  })
}
function handleClose() {
function handleClose () {
  // 清除表单内容
  editParams.value = {
    id: '',
@@ -234,65 +246,68 @@
})
</script>
<style lang="scss" scoped>
  .operatingIncome {
    height: 0;
    flex: 1;
    margin: 0 10px 10px 10px;
    background-color: #ffffff;
    padding: 10px 20px;
    border-radius: 5px;
    display: flex;
    flex-direction: column;
    .search-box {
      margin-top: 20px;
      height: 40px;
    }
.operatingIncome {
  height: 0;
  flex: 1;
  margin: 0 10px 10px 10px;
  background-color: #ffffff;
  padding: 10px 20px;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
    :deep(.el-input) {
      .el-input__wrapper {
        width: 200px;
      }
    }
  .search-box {
    margin-top: 20px;
    height: 40px;
  }
    // 表格
    .mange-table {
      height: 0;
      flex: 1;
      margin-top: 18px;
      overflow: auto;
    }
    :deep(.el-pagination) {
      display: flex;
      justify-content: right;
    }
    :deep(.el-pagination button) {
      background: center center no-repeat none !important;
      color: #8eb8ea !important;
    }
    :deep(.ztzf-select){
      .el-select__selection {
        width: 200px;
      }
  :deep(.el-input) {
    .el-input__wrapper {
      width: 200px;
    }
  }
 .content {
  // 表格
  .mange-table {
    height: 0;
    flex: 1;
    margin-top: 18px;
    overflow: auto;
  }
  :deep(.el-pagination) {
    display: flex;
    justify-content: right;
  }
  :deep(.el-pagination button) {
    background: center center no-repeat none !important;
    color: #8eb8ea !important;
  }
  :deep(.ztzf-select) {
    .el-select__selection {
      width: 200px;
    }
  }
}
.content {
  padding: 20px;
  .view-table {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #EBEEF5;
    tr {
      &:not(:last-child) {
        border-bottom: 1px solid #EBEEF5;
      }
      td {
        padding: 12px 10px;
        &.label {
          width: 140px;
          text-align: right;
@@ -300,7 +315,7 @@
          // background-color: #F5F7FA;
          border-right: 1px solid #EBEEF5;
        }
        &.value {
          width: 180px;
          // color: #303133;
@@ -309,21 +324,24 @@
    }
  }
}
.content-edit {
  .el-form {
    .el-form-item {
      width: 320px;
      :deep(.el-form-item__label) {
        width: 140px;
      }
    }
    // .el-form-item:last-child {
    //   width: 640px;
    // }
    .btns {
        display: flex;
        justify-content: center
      }
      display: flex;
      justify-content: center
    }
  }
}
</style>
applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue
@@ -18,10 +18,10 @@
                        :type="index === processList.length - 1 ? 'success' : 'info'"
                        :color="activity.color"
                        :hollow="activity.hollow"
                        :timestamp="activity.flowDesc.split(' ')[1]"
                        :timestamp="activity.createTime"
                    >
                        <div class="item-content">
                            <div>{{ activity.flowDesc.split(' ')[0] }}</div>
                            <div>{{ activity.operator }}</div>
                            <div class="flowName">{{ activity.flowName }}</div>
                        </div>
                    </el-timeline-item>
@@ -56,7 +56,7 @@
                        </el-col>
                    </el-row>
                    <div class="detail-title" :style="{ marginTop: pxToRem(20) }">已选设备</div>
                    <el-table class="setHeight" ref="deviceTableRef" :data="deviceList" row-key="id">
                    <el-table class="setHeight gd-dialog-table" ref="deviceTableRef" :data="deviceList" row-key="id">
                        <el-table-column prop="nickname" label="设备名称" />
                        <el-table-column prop="deviceName" label="设备型号" />
                        <el-table-column prop="devicePayload" label="设备负载" />
@@ -164,7 +164,7 @@
                <div class="detail-title" :style="{ marginTop: pxToRem(20) }">工单执行范围</div>
                <CommonCesiumMap
                    ref="mapRef"
                    class="leftMap gd-cesium"
                    class="gd-cesium"
                    :active="visible"
                    :flat-mode="false"
                    :terrain="true"
@@ -195,34 +195,43 @@
        <template #footer>
            <template v-if="requester">
                <template v-if="!suddenlyEdit">
                    <el-button
                        v-if="['11', '21', '23', '24', '25', '31', '60'].includes(gdStatus)"
                        @click="viewDescription"
                        color="#F2F3F5"
                    >
                        {{ gdStatusObj[gdStatus].reason }}
                    </el-button>
                    <el-button @click="addDescription" v-if="['20', '24', '25', '50'].includes(gdStatus)" color="#F2F3F5">
                        {{ gdStatus === '50' ? '结算' : '申请取消' }}
                    </el-button>
                    <el-button color="#4C34FF" @click="requestModification" v-if="['20', '25'].includes(gdStatus)">
                        申请修改
                    </el-button>
                </template>
                <el-button
                    v-if="['11'].includes(gdStatus) || suddenlyEdit || (!dialogReadonly && !formData.id)"
                    :loading="submitting"
                    :disabled="submitting"
                    color="#4C34FF"
                    @click="handleSubmit"
                >
                    {{ gdStatus === '11' || !gdStatus ? '发布' : '提交修改' }}
                </el-button>
                <el-button v-if="['11', '21', '23', '24', '25', '31', '60'].includes(gdStatus)" @click="viewDescription">
                    {{ gdStatusObj[gdStatus].reason }}
                </el-button>
                <el-button @click="addDescription" v-if="['20', '24', '25', '50'].includes(gdStatus)">
                    {{ gdStatus === '50' ? '结算' : '申请取消' }}
                </el-button>
                <el-button @click="requestModification" v-if="['20', '25'].includes(gdStatus)">申请修改</el-button>
            </template>
            <template v-else>
                <el-button v-if="['21', '23'].includes(gdStatus)" @click="viewDescription">
                <el-button v-if="['21', '23'].includes(gdStatus)" @click="viewDescription" color="#F2F3F5">
                    {{ gdStatusObj[gdStatus].reason }}
                </el-button>
                <el-button v-if="gdStatus === '10'" @click="addDescription">拒绝接单</el-button>
                <el-button v-if="gdStatus === '10'" @click="statusChange(1)">接单</el-button>
                <el-button v-if="gdStatus === '22'" @click="statusChange(8)">不同意修改</el-button>
                <el-button v-if="gdStatus === '22'" @click="statusChange(7)">同意修改</el-button>
                <el-button v-if="gdStatus === '21'" @click="addDescription">不同意取消</el-button>
                <el-button v-if="gdStatus === '21'" @click="statusChange(5)">同意取消</el-button>
                <el-button v-if="gdStatus === '30'" @click="addDescription">协商修改</el-button>
                <el-button v-if="gdStatus === '31'" @click="statusChange(10)">同意</el-button>
                <el-button v-if="gdStatus === '10'" @click="addDescription" color="#F2F3F5">拒绝接单</el-button>
                <el-button v-if="gdStatus === '10'" @click="statusChange(1)" color="#4C34FF">接单</el-button>
                <el-button v-if="gdStatus === '22'" @click="addDescription" color="#F2F3F5">不同意修改</el-button>
                <el-button v-if="gdStatus === '22'" @click="statusChange(7)" color="#4C34FF">同意修改</el-button>
                <el-button v-if="gdStatus === '21'" @click="addDescription" color="#F2F3F5">不同意取消</el-button>
                <el-button v-if="gdStatus === '21'" @click="statusChange(5)" color="#4C34FF">同意取消</el-button>
                <el-button v-if="gdStatus === '30'" @click="addDescription" color="#4C34FF">协商修改</el-button>
                <el-button v-if="gdStatus === '31'" @click="statusChange(10)" color="#4C34FF">同意</el-button>
            </template>
        </template>
@@ -292,13 +301,14 @@
const processList = ref([])
let viewPlane
const hasPatrolTaskList = computed(() => ['30', '40', '50', '60'].includes(String(formData.value.workOrderStatus)))
import droneIcon from '@/assets/images/orderView/orderManage/drone.png'
const gdStatusObj = {
    '10': { reason: '拒绝原因', operationType: '2' },
    '11': { reason: '拒绝原因' },
    '20': { reason: '取消原因', operationType: '3' },
    '21': { reason: '原因', operationType: '6' },
    '22': { reason: '驳回原因' },
    '22': { reason: '驳回原因', operationType: '8' },
    '23': { reason: '取消原因' },
    '24': { reason: '驳回原因', operationType: '3' },
    '25': { reason: '驳回原因', operationType: '3' },
@@ -332,9 +342,11 @@
    })
}
function requestModification() {
// 申请修改按钮
async function requestModification() {
    suddenlyEdit.value = true
    dialogMode.value = 'edit'
    await getDeviceList()
    nextTick(() => {
        syncSelection()
        viewPlane && viewer.entities.remove(viewPlane)
@@ -342,6 +354,7 @@
    })
}
// 填写说明弹框回调
function rejectSuccess() {
    visible.value = false
    emit('success')
@@ -378,9 +391,9 @@
        const str = [...pointList.value, pointList.value[0]].map(item => `${item.longitude} ${item.latitude}`).join(',')
        let geom = `POLYGON((${str}))`
        const res = await gdManageDeviceListApi({
            deviceIds: formData.value.recommendDeviceIds,
            devicePayload: dialogMode.value === 'add' ? formData.value.deviceLoadDemand : '',
            geom: dialogMode.value === 'add' ? geom : '',
            deviceIds: dialogMode.value === 'add' ? '' : formData.value.recommendDeviceIds,
            devicePayload: formData.value?.deviceLoadDemand,
            geom: geom,
        })
        deviceList.value = res?.data?.data ?? []
    } catch (error) {
@@ -389,10 +402,10 @@
}
// 设备需求变化
function loadDemandChange() {
async function loadDemandChange() {
    formData.value.recommendDeviceIds = ''
    selectedDevices.value = []
    getDeviceList()
    await getDeviceList()
    syncSelection()
}
@@ -428,18 +441,9 @@
    }
}
watch(
    () => dateRange.value,
    newVal => {
        const range = dateRangeFormat(dateRange.value)
        formData.value.executeStartTime = range[0]
        formData.value.executeEndTime = range[1]
    }
)
// 加载时间线list
function loadList() {
    gdWorkOrderFlowListApi({ workOrderId: formData.value.id,type: '0' }).then(res => {
    gdWorkOrderFlowListApi({ workOrderId: formData.value.id, type: '0' }).then(res => {
        processList.value = res.data.data
    })
}
@@ -508,7 +512,7 @@
    })
}
// 同步关联场景
// 回显选中设备
function syncSelection() {
    if (!deviceTableRef.value) return
    deviceTableRef.value.clearSelection()
@@ -527,25 +531,27 @@
    })
}
function setMapDevice() {
    gdManageDeviceListApi().then(res => {
        renderingDevice(res?.data?.data || [])
    })
}
import droneIcon from '@/assets/images/orderView/orderManage/drone.png'
function renderingDevice(list) {
    // 渲染红点
//  渲染
function renderingAllDevice(list) {
    list.forEach(item => {
        const position = Cesium.Cartesian3.fromDegrees(item.longitude || 115.0, item.latitude || 27.11)
        viewer.entities.add({
            position: position,
            billboard: {
                image: droneIcon,
                width: 40,
                height: 40,
                width: 30,
                height: 30,
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
            },
            label: {
                text: item.nickname,
                font: '12px/1.5 Microsoft YaHei',
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                outlineWidth: 2,
                outlineColor: Cesium.Color.WHITE,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(0, -20),
            },
        })
    })
@@ -554,8 +560,10 @@
// 打开弹框
async function open({ mode = 'add', row } = {}) {
    dialogMode.value = mode
    formData.value = dialogMode.value === 'add' ? initForm() : row
    initMap()
    const allDeviceRes = await gdManageDeviceListApi()
    formData.value = dialogMode.value === 'add' ? initForm() : row
    renderingAllDevice(allDeviceRes?.data?.data || [])
    if (dialogMode.value === 'add') {
        addPolygon()
    } else {
@@ -563,10 +571,11 @@
        hasPatrolTaskList.value && gdPatrolTaskPage()
        dialogMode.value === 'edit' ? editPolygon() : viewPolygon()
    }
    // setMapDevice()
    await nextTick()
    await getDeviceList()
    syncSelection()
    getDeviceList()
    highlightSelectedDevices()
}
// 初始化地图实例
@@ -576,6 +585,34 @@
    viewer = map?.viewer || null
}
// 高亮选中的设备
function highlightSelectedDevices() {
    const selectedIds = (formData.value.recommendDeviceIds || '').split(',').filter(Boolean)
    if (!viewer?.entities) return
    viewer.entities.values.forEach(entity => {
        if (entity.billboard?.image?._value === droneIcon && entity.label) {
            const device = deviceList.value.find(d => d.nickname === entity.label.text._value)
            if (device && selectedIds.includes(String(device.id))) {
                entity.label.fillColor = Cesium.Color.YELLOW
            } else {
                entity.label.fillColor = Cesium.Color.WHITE
            }
        }
    })
}
watch(() => formData.value.recommendDeviceIds, highlightSelectedDevices)
watch(
    () => dateRange.value,
    newVal => {
        const range = dateRangeFormat(dateRange.value)
        formData.value.executeStartTime = range[0]
        formData.value.executeEndTime = range[1]
    }
)
// 地图加载完毕
function mapReady() {
    dialogMode.value === 'add' && mapRef.value.flyBoundary()
}
@@ -587,16 +624,19 @@
.content {
    display: flex;
    gap: 0 20px;
    height: 680px;
    .leftBox {
        width: 0;
        flex: 1;
        display: flex;
        overflow: auto;
        flex-direction: column;
        .gd-cesium {
            width: 100%;
            height: 423px;
            min-height: 380px;
            flex: 1;
        }
    }
@@ -610,7 +650,11 @@
    }
    .processBox {
        padding: 24px 0;
        width: 312px;
        border: 1px solid #e4e4e4;
        overflow: auto;
        .item-content {
            position: relative;
            .flowName {
applications/task-work-order/src/views/orderView/orderManage/orderManage/RefuseOrderDialog.vue
@@ -42,7 +42,7 @@
        <template #footer>
            <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
            <el-button
                class="save-btn"
                class=""
                color="#4C34FF"
                v-if="!dialogReadonly"
                :loading="submitting"
applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue
@@ -112,9 +112,9 @@
                    <el-table-column prop="createTime" show-overflow-tooltip label="工单创建时间" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openFormChange(row)">查看</el-link>
                            <!--<el-link @click="openForm('edit', row)">编辑</el-link>-->
                            <el-link @click="handleDelete(row)" v-if="requester">删除</el-link>
                            <el-link  type="primary"  @click="openFormChange(row)">查看</el-link>
                            <!--<el-link  type="primary"  @click="openForm('edit', row)">编辑</el-link>-->
                            <el-link  type="primary"  @click="handleDelete(row)" v-if="requester">删除</el-link>
                        </template>
                    </el-table-column>
                </el-table>
@@ -236,7 +236,7 @@
function openFormChange(row) {
    dialogVisible.value = true
    nextTick(() => {
        const mode = ['11','25'].includes(row.workOrderStatus) && requester.value ? 'edit' : 'view'
        const mode = ['11'].includes(row.workOrderStatus) && requester.value ? 'edit' : 'view'
        dialogRef.value?.open({ mode, row })
    })
}
applications/task-work-order/src/views/orderView/orderManage/orderManage/orderManageApi.js
@@ -53,6 +53,6 @@
    return request({
        url: `/drone-gd/workOrder/gdWorkOrderFlow/list`,
        method: 'get',
        params,
        params:{ descs: 'create_time', ...params },
    })
}
applications/task-work-order/src/views/orderView/organizational/agenciesManagement/FormDiaLog.vue
New file
@@ -0,0 +1,181 @@
<template>
  <el-dialog
    class="gd-dialog"
    v-model="visible"
    :title="titleEnum[dialogMode]"
    @closed="visible = false"
    destroy-on-close
    :close-on-click-modal="false"
  >
    <el-row class="detail-row-view" v-if="dialogReadonly">
      <el-col :span="12">
        <div class="label">机构名称</div>
        <div class="val">{{ formData.deptName }}</div>
      </el-col>
      <el-col :span="12">
        <div class="label">所属区划</div>
        <div class="val">{{ formData.areaName }}</div>
      </el-col>
      <el-col :span="12">
        <div class="label">机构状态</div>
        <div class="val"> {{ getDictLabel(formData.status, dictObj.institutionStatus) }}</div>
      </el-col>
      <el-col :span="12">
        <div class="label">机构描述</div>
        <div class="val">{{ formData.remark }}</div>
      </el-col>
    </el-row>
    <el-form
      class="gd-dialog-form"
      v-else
      ref="formRef"
      :model="formData"
      :rules="rules"
      :disabled="dialogReadonly"
      label-width="140px"
    >
      <el-row>
        <el-col :span="12">
          <el-form-item label="机构名称" prop="deptName">
            <el-input class="gd-input" v-model="formData.deptName" placeholder="请输入" clearable />
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="所属区划" prop="areaCode">
            <el-select
              class="gd-select"
              popper-class="gd-select-popper"
              v-model="formData.areaCode"
              placeholder="请选择"
              clearable
            >
              <el-option v-for="item in regionOptions" :key="item.value" :label="item.title" :value="item.value" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="机构状态" prop="status">
            <el-select
              class="gd-select"
              popper-class="gd-select-popper"
              v-model="formData.status"
              placeholder="请选择"
              clearable
            >
              <el-option v-for="item in dictObj.institutionStatus" :key="item.dictKey"
                                :label="item.dictValue"
                                :value="item.dictKey" />
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="机构描述" prop="remark">
            <el-input
              class="gd-input"
              v-model="formData.remark"
              placeholder="请输入"
              clearable
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <template #footer v-if="!dialogReadonly">
      <el-button color="#F2F3F5" @click="visible = false">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
      <el-button
        class="save-btn"
        color="#4C34FF"
        :loading="submitting"
        :disabled="submitting"
        @click="handleSubmit"
      >
        保存
      </el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { getDictLabel } from '@ztzf/utils'
import { computed, ref, inject, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { fieldRules } from '@ztzf/utils'
import {
  agenciesSubmitApi,
  agenciesDetailApi,
} from './agenciesApi'
// 初始化表单数据
const initForm = () => ({
  deptName: '',
  areaCode: '',
  status: '',
  remark: '',
  id: null,
})
const dictObj = inject('dictObj')
const regionOptions = inject('regionOptions')
const emit = defineEmits(['success'])
const formRef = ref(null) // 表单实例
const formData = ref(initForm()) // 表单数据
const visible = defineModel() // 弹框显隐
const dialogMode = ref('add') // 弹框模式
const submitting = ref(false) // 提交中
const dialogReadonly = computed(() => dialogMode.value === 'view')
const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
const rules = {
  deptName: fieldRules(true),
  areaCode: fieldRules(true),
  status: fieldRules(true),
  remark: fieldRules(true),
}
// 提交新增/编辑
async function handleSubmit() {
  const isValid = await formRef.value?.validate().catch(() => false)
  if (!isValid) return
  submitting.value = true
  try {
    await agenciesSubmitApi(formData.value)
    ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功')
    visible.value = false
    emit('success')
  } finally {
    submitting.value = false
  }
}
// 加载详情
async function loadDetail() {
  if (!formData.value.id) return
  const res = await agenciesDetailApi({ id: formData.value.id })
  const data = res?.data?.data ?? {}
  // 将 status 转换为字符串类型,与字典中的 dictKey 类型保持一致
  if (data.status !== undefined) {
    data.status = String(data.status)
  }
  // 将 areaCode 转换为字符串类型,与 regionOptions 中的 value 类型保持一致
  if (data.areaCode !== undefined) {
    data.areaCode = String(data.areaCode)
  }
  formData.value = data
}
// 打开弹框
async function open({ mode = 'add', row } = {}) {
  dialogMode.value = mode
  formData.value = dialogMode.value === 'add' ? initForm() : row
  if (dialogMode.value !== 'add') {
    await loadDetail()
  }
}
defineExpose({ open })
</script>
<style scoped lang="scss">
</style>
applications/task-work-order/src/views/orderView/organizational/agenciesManagement/agenciesApi.js
New file
@@ -0,0 +1,66 @@
import request from '@/axios'
// 列表
export const agenciesPageApi = params => {
  return request({
    url: `/blade-system/dept/page`,
    method: 'get',
    params: { ...params },
  })
}
// 新增或编辑
export const agenciesSubmitApi = data => {
  return request({
    url: `/blade-system/dept/submit`,
    method: 'post',
    data,
  })
}
// 删除
export const agenciesRemoveApi = params => {
  return request({
    url: `/blade-system/dept/remove`,
    method: 'post',
    params,
  })
}
// 详情
export const agenciesDetailApi = params => {
  return request({
    url: `/blade-system/dept/detail`,
    method: 'get',
    params,
  })
}
// 导入机构
export const agenciesImportApi = (data,params) => {
  return request({
    url: `/blade-system/dept/import-region`,
    method: 'post',
    data,
    params
  })
}
// 导出机构
export const agenciesExportApi = params => {
  return request({
    url: `/blade-system/dept/export-region`,
    method: 'get',
    params,
    responseType: 'blob',
  })
}
// 懒加载列表
export const regionLazyTreeApi = params => {
  return request({
    url: `/blade-system/region/lazy-tree`,
    method: 'get',
    params,
  })
}
applications/task-work-order/src/views/orderView/organizational/agenciesManagement/index.vue
New file
@@ -0,0 +1,336 @@
<template>
  <basic-container>
    <el-form ref="queryParamsRef" :model="searchParams" class="gd-search-form">
      <el-form-item label="机构名称" prop="deptName">
        <el-input
          class="gd-input gray"
          v-model="searchParams.deptName"
          placeholder="请输入"
          clearable
          @clear="handleSearch"
        />
      </el-form-item>
      <el-form-item label="机构编码" prop="bindCode">
        <el-input
          class="gd-input gray"
          v-model="searchParams.bindCode"
          placeholder="请输入"
          clearable
          @clear="handleSearch"
        />
      </el-form-item>
      <el-form-item label="所属区划" prop="areaCode">
        <el-select
          class="gd-select gray"
          popper-class="gd-select-popper"
          v-model="searchParams.areaCode"
          placeholder="请选择"
          clearable
          @change="handleSearch"
        >
          <el-option v-for="item in regionOptions" :key="item.value" :label="item.title" :value="item.value" />
        </el-select>
      </el-form-item>
      <el-form-item class="gd-search-actions">
        <el-button :icon="RefreshRight" @click="resetForm"></el-button>
        <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button>
      </el-form-item>
    </el-form>
    <div class="gd-table-toolbar">
      <el-button :icon="Plus" color="#4C34FF" type="primary" @click="openForm('add')">新增机构</el-button>
      <el-button :icon="Upload" @click="handleImport">导入机构</el-button>
      <el-button :icon="Download" @click="handleExport">导出机构</el-button>
    </div>
    <div class="gd-table-container" v-loading="loading">
      <div class="gd-table-content gd-table-content-bg">
        <el-table class="gd-table" :data="list">
          <el-table-column label="序号" width="80">
            <template v-slot="{ $index }">
              {{ ((searchParams.current - 1) * searchParams.size + $index + 1).toString().padStart(2, '0') }}
            </template>
          </el-table-column>
          <el-table-column prop="bindCode" show-overflow-tooltip label="机构编码" />
          <el-table-column prop="deptName" show-overflow-tooltip label="机构名称" />
          <el-table-column prop="areaName" show-overflow-tooltip label="所属区划" />
          <el-table-column prop="remark" show-overflow-tooltip label="机构描述" />
          <el-table-column prop="status" show-overflow-tooltip label="机构状态">
            <template v-slot="{ row }">
             {{ getDictLabel(row.status, dictObj.institutionStatus) }}
            </template>
          </el-table-column>
          <el-table-column label="操作" class-name="operation-btns" width="310">
            <template v-slot="{ row }">
              <el-link type="primary" @click="openForm('view', row)">查看</el-link>
              <el-link type="primary"  @click="openForm('edit', row)">编辑</el-link>
              <el-link type="primary" @click="handleDelete(row)">删除</el-link>
              <el-link type="primary" @click="toggleStatus(row)">{{row.status === 1 ? '禁用' : '启用'}}</el-link>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="gd-pagination-parent">
        <el-pagination
          popper-class="gd-select-popper"
          v-model:current-page="searchParams.current"
          v-model:page-size="searchParams.size"
          layout="total, prev, pager, next, sizes"
          :total="total"
          @change="getList"
        />
      </div>
    </div>
    <FormDiaLog ref="dialogRef" @success="getList" v-if="dialogVisible" v-model="dialogVisible" />
    <!-- 导入机构弹框 -->
    <el-dialog
      class="gd-dialog"
      append-to-body
      v-model="isShowImportView"
      title="导入机构"
      :width="pxToRem(600)"
      :close-on-click-modal="false"
      :destroy-on-close="true"
      @close="handleImportClose"
    >
      <el-form class="gd-dialog-form" ref="importFormRef" :model="importParams" :rules="importRules" label-width="140px">
        <el-form-item label="上传文件" prop="file">
          {{ importFileName }}
          <el-upload class="avatar-uploader" action="" :show-file-list="false" :before-upload="onImportFileBefore">
            <el-button size="small" type="primary">点击上传</el-button>
          </el-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button color="#F2F3F5" @click="isShowImportView = false">取消</el-button>
        <el-button
          class=""
          color="#4C34FF"
          :loading="importSubmitting"
          :disabled="importSubmitting"
          @click="submitImport(importFormRef)"
        >
          导入
        </el-button>
      </template>
    </el-dialog>
  </basic-container>
</template>
<script setup>
import { Search, RefreshRight, Plus, Delete, Upload, Download } from '@element-plus/icons-vue'
import { onMounted, ref, provide, nextTick } from 'vue'
import { ElMessage, ElMessageBox, ElUpload } from 'element-plus'
import FormDiaLog from './FormDiaLog.vue'
import {
  agenciesPageApi,
  agenciesRemoveApi,
  agenciesImportApi,
  agenciesExportApi,
  regionLazyTreeApi,
  agenciesSubmitApi
} from './agenciesApi'
import { getDictionaryByCode } from '@/api/system/dictbiz'
import { getDictLabel } from '@ztzf/utils'
import { pxToRem } from '@/utils/rem'
// 初始化查询参数
const initSearchParams = () => ({
  deptName: '', // 机构名称
  bindCode: '', // 机构编码
  areaCode: '', // 所属区划
  current: 1, // 当前页
  size: 10, // 每页大小
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const queryParamsRef = ref(null) // 查询表单实例
const dialogRef = ref(null) // 弹框实例
const dialogVisible = ref(false)
const regionOptions = ref([]) // 区域选项
const dictObj = ref({}) // 字典对象
// 导入机构相关
const isShowImportView = ref(false)
const importFileName = ref('')
const importParams = ref({
  isCovered: '0',
  file: '',
})
const importFormRef = ref()
const importSubmitting = ref(false)
const importRules = ref({
  file: [{ required: true, message: '请上传文件', trigger: ['change'] }],
})
provide('regionOptions', regionOptions)
provide('dictObj', dictObj)
// 获取字典列表
function getDictList() {
  getDictionaryByCode('institutionStatus').then(res => {
            dictObj.value = res.data.data
  })
}
// 获取区域列表
function getRegionList() {
  regionLazyTreeApi({parentCode: '360800000000'}).then(res => {
  console.log('区域列表', res.data.data);
    regionOptions.value = res.data.data || []
  })
}
// 获取列表
async function getList() {
  loading.value = true
  try {
    const res = await agenciesPageApi(searchParams.value)
    list.value = res?.data?.data?.records ?? []
    total.value = res?.data?.data?.total ?? 0
  } finally {
    loading.value = false
  }
}
// 查询
function handleSearch() {
  searchParams.value.current = 1
  getList()
}
// 重置查询
function resetForm() {
  queryParamsRef.value?.resetFields()
  searchParams.value.current = 1
  getList()
}
// 新增/编辑/查看 弹框
function openForm(mode, row) {
  dialogVisible.value = true
  nextTick(() => {
    dialogRef.value?.open({ mode, row })
  })
}
// 删除
async function handleDelete(row) {
  await ElMessageBox.confirm('确认删除该条记录吗?', '提示', {
    type: 'warning',
    customClass: 'gd-confirm-custom',
    confirmButtonClass: 'gd-confirm-button',
    cancelButtonClass: 'gd-confirm-cancel-button',
  })
  await agenciesRemoveApi({ ids: row.id })
  ElMessage.success('删除成功')
  getList()
}
// 切换机构状态
async function toggleStatus(row) {
  // 计算目标状态:当前为1则切换为0,当前为0则切换为1
  const targetStatus = row.status === 1 ? 0 : 1
  const actionText = targetStatus === 0 ? '禁用' : '启用'
  await ElMessageBox.confirm(`确认${actionText}该机构吗?`, '提示', {
    type: 'warning',
    customClass: 'gd-confirm-custom',
    confirmButtonClass: 'gd-confirm-button',
    cancelButtonClass: 'gd-confirm-cancel-button',
  })
  try {
    await agenciesSubmitApi({ ...row, status: targetStatus })
    ElMessage.success(`${actionText}成功`)
    getList()
  } catch (error) {
    ElMessage.error(`${actionText}失败`)
  }
}
// 导入机构
function handleImport() {
  isShowImportView.value = true
}
// 导入机构弹框关闭
function handleImportClose() {
  importFileName.value = ''
  importParams.value = {
    isCovered: '0',
    file: '',
  }
}
// 上传文件前处理
function onImportFileBefore(file) {
  // 执行文件上传
  let data = new FormData()
  data.append('file', file)
  agenciesImportApi(data, { isCovered: importParams.value.isCovered }).then(res => {
    if (res.data.code === 200) {
      ElMessage.success('导入成功')
      // 保存文件名
      importFileName.value = file.name
      importParams.value.file = file
      isShowImportView.value = false
      getList()
    } else {
      ElMessage.error(res.msg || '导入失败')
    }
  })
  return false // 阻止组件的默认上传行为
}
// 提交导入
async function submitImport(formValidate) {
  if (!formValidate) return
  await formValidate.validate(async (valid, fields) => {
    if (valid) {
      importSubmitting.value = true
      try {
        // 这里实际上传文件的逻辑已经在onImportFileBefore中处理了
        // 这里可以添加额外的验证或逻辑
      } finally {
        importSubmitting.value = false
      }
    }
  })
}
// 导出机构
function handleExport() {
  agenciesExportApi(searchParams.value).then(res => {
    const blob = new Blob([res.data])
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = `机构列表${new Date().getTime()}.xlsx`
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
  })
}
onMounted(() => {
  getDictList()
  getRegionList()
  getList()
})
</script>
<style scoped lang="scss">
</style>
applications/task-work-order/src/views/orderView/organizational/zoningManagement/index.vue
New file
@@ -0,0 +1,20 @@
<template>
 <div>
    区划管理
 </div>
</template>
<script setup >
/**
 * @description index
 * @date 2026-01-26 (周一) 10:50:43
 */
defineOptions({
 name: 'index'
})
</script>
<style scoped lang="scss">
</style>
applications/task-work-order/src/views/orderView/organizationalMessage/agenciesManagement/agenciesApi.js
New file
@@ -0,0 +1,66 @@
import request from '@/axios'
// 列表
export const agenciesPageApi = params => {
  return request({
    url: `/blade-system/dept/page`,
    method: 'get',
    params: { ...params },
  })
}
// 新增或编辑
export const agenciesSubmitApi = data => {
  return request({
    url: `/blade-system/dept/submit`,
    method: 'post',
    data,
  })
}
// 删除
export const agenciesRemoveApi = params => {
  return request({
    url: `/blade-system/dept/remove`,
    method: 'post',
    params,
  })
}
// 详情
export const agenciesDetailApi = params => {
  return request({
    url: `/blade-system/dept/detail`,
    method: 'get',
    params,
  })
}
// 导入机构
export const agenciesImportApi = (data,params) => {
  return request({
    url: `/blade-system/dept/import-region`,
    method: 'post',
    data,
    params
  })
}
// 导出机构
export const agenciesExportApi = params => {
  return request({
    url: `/blade-system/dept/export-region`,
    method: 'get',
    params,
    responseType: 'blob',
  })
}
// 懒加载列表
export const regionLazyTreeApi = params => {
  return request({
    url: `/blade-system/region/lazy-tree`,
    method: 'get',
    params,
  })
}
pnpm-lock.yaml
@@ -28,8 +28,8 @@
      specifier: ^1.4.4
      version: 1.6.3
    '@smallwei/avue':
      specifier: ^3.6.2
      version: 3.8.0
      specifier: 3.6.2
      version: 3.6.2
    '@turf/turf':
      specifier: ^6.5.0
      version: 6.5.0
@@ -46,7 +46,7 @@
      specifier: ^4.1.1
      version: 4.1.1
    avue-plugin-ueditor:
      specifier: ^1.0.4
      specifier: 1.0.4
      version: 1.0.4
    axios:
      specifier: ^1.8.3
@@ -232,7 +232,7 @@
        version: 1.6.3
      '@smallwei/avue':
        specifier: 'catalog:'
        version: 3.8.0(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
        version: 3.6.2(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
      '@turf/turf':
        specifier: 'catalog:'
        version: 6.5.0
@@ -443,7 +443,7 @@
        version: 1.6.3
      '@smallwei/avue':
        specifier: 'catalog:'
        version: 3.8.0(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
        version: 3.6.2(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
      '@turf/turf':
        specifier: 'catalog:'
        version: 6.5.0
@@ -651,7 +651,7 @@
        version: 1.6.3
      '@smallwei/avue':
        specifier: 'catalog:'
        version: 3.8.0(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
        version: 3.6.2(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))
      '@turf/turf':
        specifier: 'catalog:'
        version: 6.5.0
@@ -3040,8 +3040,8 @@
  '@sinonjs/fake-timers@8.1.0':
    resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==}
  '@smallwei/avue@3.8.0':
    resolution: {integrity: sha512-htgZsATcTtBVfoHhU7i6fBNnHT222hKGVelGX7IBldNUVPdJHsdnC4gL+FMs6w83Z6GhIeXuWgleoYxllbfAnQ==}
  '@smallwei/avue@3.6.2':
    resolution: {integrity: sha512-Ifkt0o7KLsAMptfoNMG7qYS86OL2pEet761wWZyZGu8e48wuNNPOfqx5jnibGjx2oIoKtYUFh7tFdllOCth2EQ==}
    peerDependencies:
      element-plus: '>=2.2.0'
      vue: '>=3.2.0'
@@ -12065,7 +12065,7 @@
    dependencies:
      '@sinonjs/commons': 1.8.6
  '@smallwei/avue@3.8.0(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))':
  '@smallwei/avue@3.6.2(element-plus@2.9.11(vue@3.5.27(typescript@5.9.3)))(vue@3.5.27(typescript@5.9.3))':
    dependencies:
      '@element-plus/icons-vue': 2.3.2(vue@3.5.27(typescript@5.9.3))
      countup.js: 1.9.3
@@ -13590,30 +13590,30 @@
      - '@vue/composition-api'
      - vue
  '@wangeditor-next/basic-modules@1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/basic-modules@1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
    dependencies:
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      dom7: 4.0.6
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      dom7: 3.0.0
      is-url: 1.2.4
      lodash.throttle: 4.1.1
      nanoid: 5.1.6
      slate: 0.82.1
      nanoid: 3.3.11
      slate: 0.72.8
      snabbdom: 3.6.3
  '@wangeditor-next/code-highlight@1.3.43(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/code-highlight@1.3.43(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)':
    dependencies:
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      dom7: 4.0.6
      prismjs: 1.30.0
      slate: 0.82.1
      snabbdom: 3.6.3
  '@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)':
    dependencies:
      '@types/event-emitter': 0.3.5
      '@uppy/core': 2.3.4
      '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
      dom7: 4.0.6
      dom7: 3.0.0
      event-emitter: 0.3.5
      html-void-elements: 3.0.0
      i18next: 23.16.8
@@ -13624,9 +13624,9 @@
      lodash.foreach: 4.5.0
      lodash.throttle: 4.1.1
      lodash.toarray: 4.4.0
      nanoid: 5.1.6
      nanoid: 3.3.11
      scroll-into-view-if-needed: 3.1.0
      slate: 0.82.1
      slate: 0.72.8
      slate-history: 0.109.0(slate@0.82.1)
      snabbdom: 3.6.3
@@ -13634,13 +13634,13 @@
    dependencies:
      '@uppy/core': 2.3.4
      '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
      '@wangeditor-next/basic-modules': 1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/code-highlight': 1.3.43(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/list-module': 1.1.52(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/table-module': 1.6.60(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/upload-image-module': 1.1.50(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/video-module': 1.3.51(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/basic-modules': 1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      '@wangeditor-next/code-highlight': 1.3.43(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      '@wangeditor-next/list-module': 1.1.52(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/table-module': 1.6.60(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/upload-image-module': 1.1.50(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/video-module': 1.3.51(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      dom7: 4.0.6
      is-hotkey: 0.2.0
      lodash.camelcase: 4.3.0
@@ -13653,16 +13653,16 @@
      slate: 0.82.1
      snabbdom: 3.6.3
  '@wangeditor-next/list-module@1.1.52(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/list-module@1.1.52(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(slate@0.82.1)(snabbdom@3.6.3)':
    dependencies:
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      dom7: 4.0.6
      slate: 0.82.1
      snabbdom: 3.6.3
  '@wangeditor-next/table-module@1.6.60(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/table-module@1.6.60(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.debounce@4.0.8)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)':
    dependencies:
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      dom7: 4.0.6
      lodash.debounce: 4.0.8
      lodash.throttle: 4.1.1
@@ -13670,22 +13670,22 @@
      slate: 0.82.1
      snabbdom: 3.6.3
  '@wangeditor-next/upload-image-module@1.1.50(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/upload-image-module@1.1.50(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/basic-modules@1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.foreach@4.5.0)(slate@0.82.1)(snabbdom@3.6.3)':
    dependencies:
      '@uppy/core': 2.3.4
      '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
      '@wangeditor-next/basic-modules': 1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(lodash.throttle@4.1.1)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/basic-modules': 1.5.47(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@3.0.0)(lodash.throttle@4.1.1)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      dom7: 4.0.6
      lodash.foreach: 4.5.0
      slate: 0.82.1
      snabbdom: 3.6.3
  '@wangeditor-next/video-module@1.3.51(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)':
  '@wangeditor-next/video-module@1.3.51(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(@wangeditor-next/core@1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3))(dom7@4.0.6)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)':
    dependencies:
      '@uppy/core': 2.3.4
      '@uppy/xhr-upload': 2.1.3(@uppy/core@2.3.4)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@4.0.6)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@5.1.6)(slate@0.82.1)(snabbdom@3.6.3)
      '@wangeditor-next/core': 1.7.45(@uppy/core@2.3.4)(@uppy/xhr-upload@2.1.3(@uppy/core@2.3.4))(dom7@3.0.0)(is-hotkey@0.2.0)(lodash.camelcase@4.3.0)(lodash.clonedeep@4.5.0)(lodash.debounce@4.0.8)(lodash.foreach@4.5.0)(lodash.throttle@4.1.1)(lodash.toarray@4.4.0)(nanoid@3.3.11)(slate@0.72.8)(snabbdom@3.6.3)
      dom7: 4.0.6
      nanoid: 5.1.6
      slate: 0.82.1
pnpm-workspace.yaml
@@ -11,10 +11,10 @@
  "@saber/nf-design-base-elp": "^1.3.0"
  "@saber/nf-form-design-elp": "^1.4.1"
  "@saber/nf-form-elp": "^1.4.4"
  "@smallwei/avue": "^3.6.2"
  "@smallwei/avue": "3.6.2"
  "@turf/turf": "^6.5.0"
  "animate.css": "^4.1.1"
  "avue-plugin-ueditor": "^1.0.4"
  "avue-plugin-ueditor": "1.0.4"
  "axios": "^1.8.3"
  "cesium": "1.126.0"
  "codemirror": "^5.65.16"
uniapps/work-app/src/api/map.js
@@ -7,3 +7,11 @@
    data: { hidden_flag: 0, ...data },
  })
}
// 位置上报
export const reportLocationApi = data => {
  return request({
    url: '/webservice/jaUserTrajectory/reportLocation',
    method: 'post',
    data,
  })
}
uniapps/work-app/src/pages/map/index.vue
@@ -1,13 +1,3 @@
<!--
 * @Author       : yuan
 * @Date         : 2025-12-03 14:20:57
 * @LastEditors  : yuan
 * @LastEditTime : 2025-12-20 16:49:02
 * @FilePath     : \src\pages\map\index.vue
 * @Description  :
 * Copyright 2025 OBKoro1, All Rights Reserved.
 * 2025-12-03 14:20:57
-->
<template>
  <view class="page-wrap">
    <WebViewPlus :src="`${viewUrl}`" @webMessage="onPostMessage" />
uniapps/work-app/src/pages/work/index.vue
@@ -2,7 +2,7 @@
  <div class="eventTickets" :style="{ paddingTop: topMargin + 'px' }">
    <div class="searchTop">
      <up-search placeholder="请输入关键字搜索"  :animation="true"  v-model="listParams.keyword" :show-action="false" @search="handleSearch"></up-search>
      <up-search placeholder="请输入关键字搜索"  :animation="true"  v-model="listParams.keyword" :show-action="false" @search="handleSearch" @clear="handleClear"></up-search>
    </div>
    <div class="listBox">
      <div class="tabs-container">
@@ -18,6 +18,11 @@
              <div class="itemContent">{{formatDate(item.createTime) }}</div>
            </div>
          </div>
        </div>
        <!-- 暂无数据提示 -->
        <div class="noData" v-if="!loading && dataList.length === 0">
          <text>暂无数据</text>
        </div>
        <!-- 加载提示 -->
@@ -151,6 +156,15 @@
// 搜索功能
const handleSearch = () => {
  listParams.value.current = 1
  hasMore.value = true
  dataList.value = []
  getDataList()
  getstatusCountData()
}
// 清除搜索
const handleClear = () => {
  listParams.value.keyword = ''
  listParams.value.current = 1
  hasMore.value = true
  dataList.value = []
@@ -295,5 +309,15 @@
    color: #999;
    width: 100%;
  }
  .noData {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 300rpx;
    font-size: 28rpx;
    color: #999;
    width: 100%;
  }
}
</style>
uniapps/work-app/src/store/modules/location.js
@@ -1,5 +1,6 @@
import { defineStore } from 'pinia'
import locationUtil from '@/utils/location.js'
import { reportLocationApi } from '@/api/map.js'
const useLocationStore = defineStore('location', {
  state: () => ({
@@ -12,7 +13,9 @@
    // 位置更新间隔(毫秒)
    updateInterval: 5000,
    // 位置监听器ID
    watcherId: null
    watcherId: null,
    // 上次位置上报时间
    lastReportTime: 0
  }),
  getters: {
@@ -115,13 +118,32 @@
    },
    /**
     * 位置信息上报(可根据实际需求实现)
     * 位置信息上报
     * @param {Object} location 位置信息
     */
    reportLocation(location) {
      // 这里可以添加位置信息上报到服务器的逻辑
      // 例如:api.uploadLocation(location)
      // console.log('位置上报:', location);
    async reportLocation(location) {
      try {
        const now = Date.now();
        // 检查是否达到上报时间间隔(1分钟)
        if (now - this.lastReportTime >= 60000) {
          // 构造请求参数
           const params = {
            longitude: location.longitude,
            latitude: location.latitude,
            // reportTime: new Date().toISOString()
          };
          // 调用位置上报接口
          const result = await reportLocationApi(params);
          console.log('位置上报成功:', result);
          // 更新上次上报时间
          this.lastReportTime = now;
        }
      } catch (error) {
        console.error('位置上报失败:', error);
      }
    },
    /**