吉安感知网项目-前端
张含笑
2026-02-03 91bb9f7781ce95e3a7acde3602eeae0c1c3613ff
Merge remote-tracking branch 'origin/master'
22 files modified
473 ■■■■ changed files
applications/drone-command/env/.env 12 ●●●●● patch | view | raw | blame | history
applications/drone-command/env/.env.development 4 ●●● patch | view | raw | blame | history
applications/drone-command/env/.env.production 3 ●●●●● patch | view | raw | blame | history
applications/drone-command/env/.env.test 3 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/styles/common/cockpit.scss 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/api.txt 90 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue 48 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue 55 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/sceneConfig/index.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/deviceStock/DeviceTrackDiaLog.vue 4 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/permissionManage/permissionDept/FormDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/permissionManage/permissionDept/index.vue 58 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue 26 ●●●● patch | view | raw | blame | history
applications/task-work-order/env/.env 4 ●●●● patch | view | raw | blame | history
applications/task-work-order/env/.env.production 3 ●●●●● patch | view | raw | blame | history
applications/task-work-order/env/.env.test 24 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/styles/theme/white.scss 4 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue 35 ●●●● patch | view | raw | blame | history
uniapps/work-wx/src/subPackages/deviceRegistration/add.vue 6 ●●●● patch | view | raw | blame | history
uniapps/work-wx/src/subPackages/deviceRegistration/details.vue 31 ●●●● patch | view | raw | blame | history
uniapps/work-wx/src/subPackages/flightApplication/add.vue 56 ●●●● patch | view | raw | blame | history
uniapps/work-wx/src/subPackages/userDetail/password/index.vue 1 ●●●● patch | view | raw | blame | history
applications/drone-command/env/.env
@@ -1,3 +1,13 @@
/*
 * @Author       : yuan
 * @Date         : 2026-01-07 14:58:30
 * @LastEditors  : yuan
 * @LastEditTime : 2026-02-03 15:43:33
 * @FilePath     : \applications\drone-command\env\.env
 * @Description  :
 * Copyright 2026 OBKoro1, All Rights Reserved.
 * 2026-01-07 14:58:30
 */
#接口地址
VITE_APP_API=/api
@@ -12,3 +22,5 @@
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS=gzip
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_c_uas/
applications/drone-command/env/.env.development
@@ -2,7 +2,7 @@
 # @Author       : yuan
 # @Date         : 2026-01-31 14:34:31
 # @LastEditors  : yuan
 # @LastEditTime : 2026-02-03 09:34:48
 # @LastEditTime : 2026-02-03 15:52:27
 # @FilePath     : \applications\drone-command\env\.env.development
 # @Description  : 
 # Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -30,8 +30,6 @@
# 航线文件地址
VITE_APP_AIRLINE_URL=https://wrj.shuixiongit.com/minio/cloud-bucket
# 地形存放
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_c_uas/
# 行政区划存放地址
VITE_APP_REGION_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_region
# 算法仓库图片地址
applications/drone-command/env/.env.production
@@ -19,9 +19,6 @@
# 航线文件地址
VITE_APP_AIRLINE_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket
# 图片存放地址
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_terrain/
# 算法仓库图片地址
VITE_APP_PICTURE_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket
applications/drone-command/env/.env.test
@@ -18,9 +18,6 @@
# 航线文件地址
VITE_APP_AIRLINE_URL = https://wrj.shuixiongit.com/minio/cloud-bucket
# 图片存放地址
VITE_APP_TERRAIN_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_terrain/
# 算法仓库图片地址
VITE_APP_PICTURE_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket
applications/drone-command/src/styles/common/cockpit.scss
@@ -1316,7 +1316,7 @@
                    align-items: center;
                    .label {
                        width: 88px;
                        min-width: 88px;
                        font-family: Source Han Sans CN, Source Han Sans CN;
                        font-weight: 500;
                        font-size: 14px;
applications/drone-command/src/views/api.txt
@@ -3,7 +3,7 @@
## 列表
**接口地址**:`/area/fwPoliceStation/list`
**接口地址**:`/device/fwDevice/list`
**请求方式**:`GET`
@@ -15,7 +15,7 @@
**响应数据类型**:`*/*`
**接口描述**:<p>获取全部派出所</p>
**接口描述**:<p>传入isAreaSelect、areaId、areaIds(多个用,隔开获取对应区域绑定设备数据)、status</p>
@@ -25,7 +25,13 @@
**请求参数**:
暂无
| 参数名称 | 参数说明 | 请求类型    | 是否必须 | 数据类型 | schema |
| -------- | -------- | ----- | -------- | -------- | ------ |
|areaId|areaId|query|false|integer(int64)||
|areaIds|areaIds(多个用,隔开)|query|false|string||
|isAreaSelect|isAreaSelect|query|false|integer(int32)||
|isTrack|isTrack|query|false|integer(int32)||
|status|status|query|false|integer(int32)||
**响应状态**:
@@ -33,7 +39,7 @@
| 状态码 | 说明 | schema |
| -------- | -------- | ----- | 
|200|OK|R«List«FwPoliceStationVO»»|
|200|OK|R«List«FwDeviceVO»»|
|401|Unauthorized||
|403|Forbidden||
|404|Not Found||
@@ -45,21 +51,41 @@
| 参数名称 | 参数说明 | 类型 | schema |
| -------- | -------- | ----- |----- | 
|code|状态码|integer(int32)|integer(int32)|
|data|承载数据|array|FwPoliceStationVO|
|&emsp;&emsp;address|派出所地址|string||
|&emsp;&emsp;areaCode|区域编码|string||
|&emsp;&emsp;contactPerson|联系人|string||
|&emsp;&emsp;contactPhone|联系方式|string||
|data|承载数据|array|FwDeviceVO|
|&emsp;&emsp;azimuth|方位角 0-360°|integer(int32)||
|&emsp;&emsp;batteryPct|电量百分比 0-100|integer(int32)||
|&emsp;&emsp;belongDept|所属部门id|integer(int64)||
|&emsp;&emsp;belongDeptName|所属部门名称|string||
|&emsp;&emsp;charger|负责人|string||
|&emsp;&emsp;contactPhone|联系电话|string||
|&emsp;&emsp;createDept|创建部门|integer(int64)||
|&emsp;&emsp;createTime|创建时间|string(date-time)||
|&emsp;&emsp;createUser|创建人|integer(int64)||
|&emsp;&emsp;id|主键id|integer(int64)||
|&emsp;&emsp;latitude|纬度|number(double)||
|&emsp;&emsp;longitude|经度|number(double)||
|&emsp;&emsp;stationName|派出所名称|string||
|&emsp;&emsp;status|状态(0正常 1停用)|integer(int32)||
|&emsp;&emsp;detectTargetCnt|侦测目标数量|integer(int32)||
|&emsp;&emsp;deviceAtt|设备属性(无线电/光电/雷达)|string||
|&emsp;&emsp;deviceModel|型号|string||
|&emsp;&emsp;deviceName|设备名称|string||
|&emsp;&emsp;deviceSn|设备sn|string||
|&emsp;&emsp;deviceSpecification|规格|string||
|&emsp;&emsp;deviceType|设备类型(察打一体/便捷侦测箱/反制枪)|string||
|&emsp;&emsp;effectiveRangeKm|有效范围 km|number||
|&emsp;&emsp;elevation|俯仰角 -90-+90°|integer(int32)||
|&emsp;&emsp;id|主键|integer(int64)||
|&emsp;&emsp;isShared|是否被共享给当前机构|boolean||
|&emsp;&emsp;latitude|纬度|string||
|&emsp;&emsp;longitude|经度|string||
|&emsp;&emsp;manufacturer|生产厂商|string||
|&emsp;&emsp;outTarget|出库去向|string||
|&emsp;&emsp;purpose|用途|string||
|&emsp;&emsp;remark|备注|string||
|&emsp;&emsp;sceneName|场景名称|string||
|&emsp;&emsp;shareId|共享记录ID|integer(int64)||
|&emsp;&emsp;source|来源|string||
|&emsp;&emsp;status|运行状态(0:在线/1:离线/2:故障/3:报废)|integer(int32)||
|&emsp;&emsp;trackStatus|设备出入库状态 0未出库1已出库|integer(int32)||
|&emsp;&emsp;updateTime|更新时间|string(date-time)||
|&emsp;&emsp;updateUser|更新人|integer(int64)||
|&emsp;&emsp;workMode|工作模式:1.侦测中/2.信号干扰中/3.诱导驱离中/4.待机|string||
|msg|返回消息|string||
|success|是否成功|boolean||
@@ -70,23 +96,43 @@
    "code": 0,
    "data": [
        {
            "address": "",
            "areaCode": "",
            "contactPerson": "",
            "azimuth": 0,
            "batteryPct": 0,
            "belongDept": 0,
            "belongDeptName": "",
            "charger": "",
            "contactPhone": "",
            "createDept": 0,
            "createTime": "",
            "createUser": 0,
            "detectTargetCnt": 0,
            "deviceAtt": "",
            "deviceModel": "",
            "deviceName": "",
            "deviceSn": "",
            "deviceSpecification": "",
            "deviceType": "",
            "effectiveRangeKm": 0,
            "elevation": 0,
            "id": 0,
            "latitude": 0,
            "longitude": 0,
            "stationName": "",
            "isShared": true,
            "latitude": "",
            "longitude": "",
            "manufacturer": "",
            "outTarget": "",
            "purpose": "",
            "remark": "",
            "sceneName": "",
            "shareId": 0,
            "source": "",
            "status": 0,
            "trackStatus": 0,
            "updateTime": "",
            "updateUser": 0
            "updateUser": 0,
            "workMode": ""
        }
    ],
    "msg": "",
    "success": true
}
```
```
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -260,6 +260,7 @@
import ellipseIcon from '@/assets/images/areaMap/ellipse.png'
import bufferIcon from '@/assets/images/areaMap/buffer.png'
import trashIcon from '@/assets/images/areaMap/trash.png'
import equipmentIcon from '@/assets/images/dataCockpit/map/equipment.png'
const initForm = () => ({
    areaName: '', // 区域名称
@@ -314,6 +315,7 @@
let viewEntity
let shapeDisplaySource
const deviceRangePrimitiveMap = new Map()
const deviceIconEntityMap = new Map()
const activeToolMode = ref('')
const suppressDeviceFly = ref(false)
const isDialogInitializing = ref(false)
@@ -437,6 +439,7 @@
            hideTypePanel()
            clearShapeDisplay()
            clearDeviceRangePrimitives()
            clearDeviceIconEntities()
        }
    }
)
@@ -504,10 +507,20 @@
    deviceRangePrimitiveMap.clear()
}
function clearDeviceIconEntities () {
    if (!viewer || !deviceIconEntityMap.size) return
    for (const entity of deviceIconEntityMap.values()) {
        viewer.entities.remove(entity)
    }
    deviceIconEntityMap.clear()
}
function clearDeviceListState () {
    deviceOptions.value = []
    selectedDeviceRows.value = []
    formData.value.deviceIds = ''
    clearDeviceRangePrimitives()
    clearDeviceIconEntities()
    if (deviceTableRef.value) {
        deviceTableRef.value.clearSelection()
    }
@@ -599,8 +612,10 @@
async function renderDeviceRangeSingle (device) {
    if (!viewer) return
    clearDeviceRangePrimitives()
    clearDeviceIconEntities()
    const position = getDeviceLngLat(device)
    if (!position) return
    addDeviceIconEntity(device, position)
    const rangeMeters = normalizeDeviceRange(device.effectiveRangeKm)
    const primitive = await createDeviceRangePrimitive(viewer, position, rangeMeters)
    if (!primitive) return
@@ -620,6 +635,12 @@
            deviceRangePrimitiveMap.delete(id)
        }
    }
    for (const [id, entity] of deviceIconEntityMap.entries()) {
        if (!nextIds.has(id)) {
            viewer.entities.remove(entity)
            deviceIconEntityMap.delete(id)
        }
    }
    const pendingRows = selectedRows.filter(row => {
        const id = String(row?.id)
        return id && !deviceRangePrimitiveMap.has(id)
@@ -628,14 +649,17 @@
    const primitives = await Promise.all(
        pendingRows.map(async row => {
            const position = getDeviceLngLat(row)
            if (!position) return { row, primitive: null }
            if (!position) return { row, primitive: null, position: null }
            const rangeMeters = normalizeDeviceRange(row.effectiveRangeKm)
            const primitive = await createDeviceRangePrimitive(viewer, position, rangeMeters)
            return { row, primitive }
            return { row, primitive, position }
        })
    )
    if (renderToken !== deviceRangeRenderToken) return
    primitives.forEach(({ row, primitive }) => {
    primitives.forEach(({ row, primitive, position }) => {
        if (position) {
            addDeviceIconEntity(row, position)
        }
        if (!primitive) return
        const id = String(row?.id)
        if (!nextIds.has(id)) return
@@ -665,6 +689,23 @@
function clearShapeDisplay () {
    if (!shapeDisplaySource) return
    shapeDisplaySource.entities.removeAll()
}
function addDeviceIconEntity (device, position) {
    if (!viewer || !position) return
    const id = String(device?.id ?? '')
    if (!id || deviceIconEntityMap.has(id)) return
    const entity = viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(position.lng, position.lat, position.height || 0),
        billboard: {
            image: equipmentIcon,
            width: 28,
            height: 38,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        },
    })
    deviceIconEntityMap.set(id, entity)
}
function normalizeShapePoint (point) {
@@ -1357,6 +1398,7 @@
    initMap()
    clearShapeDisplay()
    clearDeviceRangePrimitives()
    clearDeviceIconEntities()
    viewEntity && viewer?.entities?.remove(viewEntity)
    viewEntity = null
    clearActiveTool()
applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue
@@ -50,6 +50,20 @@
                            </el-table>
                        </div>
                    </div>
                    <div class="detail-title">设备列表</div>
                    <div class="command-table-container">
                        <div class="command-table-content">
                            <el-table
                                class="command-table"
                                :data="deviceList"
                                :loading="deviceLoading"
                                row-key="id"
                            >
                                <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                                <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型" />
                            </el-table>
                        </div>
                    </div>
                </div>
                <el-form
@@ -128,6 +142,21 @@
                            </el-table>
                        </el-form-item>
                    </div>
                    <div class="detail-title">设备列表</div>
                    <div class="command-table-container">
                        <div class="command-table-content">
                            <el-table
                                class="command-table"
                                :data="deviceList"
                                :loading="deviceLoading"
                                row-key="id"
                            >
                                <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                                <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型" />
                            </el-table>
                        </div>
                    </div>
                </el-form>
                <div class="footer">
@@ -160,6 +189,7 @@
import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
import * as Cesium from 'cesium'
import { fwAreaDivideDetailApi, fwAreaDivideListApi } from '../partition/partitionApi'
import { fwDeviceListApi } from '@/views/basicManage/deviceStock/fwDevice'
import {
    addBufferRadiusLabelEntity,
    buildEllipsePositions,
@@ -189,6 +219,8 @@
const searchName = ref('')
const areaList = ref([]) // 关联区域列表
const selectedAreaRows = ref([]) //选中列表
const deviceList = ref([]) // 设备列表
const deviceLoading = ref(false)
const dictObj = inject('dictObj')
const mapRef = ref(null)
const route = useRoute()
@@ -242,6 +274,20 @@
    if (areaList.value.length) return
    const res = await fwAreaDivideListApi({ filterSelected: 1, sceneId: formData.value.id })
    areaList.value = res?.data?.data ?? []
}
async function loadDeviceListByAreaIds(areaIdsKey) {
    if (!areaIdsKey) {
        deviceList.value = []
        return
    }
    deviceLoading.value = true
    try {
        const res = await fwDeviceListApi({ areaIds: areaIdsKey })
        deviceList.value = res?.data?.data ?? []
    } finally {
        deviceLoading.value = false
    }
}
// 关联区域变更
@@ -514,6 +560,15 @@
}
watch(() => selectedAreaRows.value, renderSelectedAreas)
const deviceAreaIdsKey = computed(() =>
    selectedAreaRows.value.map(item => item?.id).filter(Boolean).join(',')
)
watch(
    () => deviceAreaIdsKey.value,
    val => {
        loadDeviceListByAreaIds(val)
    }
)
watch(
    () => visible.value,
    val => {
applications/drone-command/src/views/areaManage/sceneConfig/index.vue
@@ -54,7 +54,7 @@
                    </el-table-column>
                    <el-table-column prop="areaCount" show-overflow-tooltip label="区域数量" />
                    <el-table-column prop="counterDeviceCount" show-overflow-tooltip label="反制设备数量" />
                    <el-table-column prop="detectDeviceCount" show-overflow-tooltip label="探测设备数量" />
                    <el-table-column prop="detectDeviceCount" show-overflow-tooltip label="侦测设备数量" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
applications/drone-command/src/views/basicManage/deviceStock/DeviceTrackDiaLog.vue
@@ -24,7 +24,7 @@
                            placeholder="请选择"
                            clearable
                        >
                            <el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.label" />
                            <el-option v-for="item in areaOptions" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </el-form-item>
                </el-col>
@@ -137,9 +137,11 @@
    submitting.value = true
    try {
        const selected = areaOptions.value.find(item => item.value === formData.value.outTarget)
        const payload = {
            ...formData.value,
            outTarget: selected?.label ?? formData.value.outTarget,
            outTargetCode: formData.value.outTarget
        }
        await fwDeviceTrackSubmitApi(payload)
        saveOperationLog({
applications/drone-command/src/views/permissionManage/permissionDept/FormDiaLog.vue
@@ -258,7 +258,7 @@
        })
        ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功')
        visible.value = false
        emit('success')
        emit('success', { parentId: formData.value.parentId || null, mode: dialogMode.value, isAddChild: isAddChild.value })
    } finally {
        submitting.value = false
    }
applications/drone-command/src/views/permissionManage/permissionDept/index.vue
@@ -87,7 +87,7 @@
            </div>
        </div>
        <FormDiaLog ref="dialogRef" @success="getList" v-model="visible" v-if="visible" />
        <FormDiaLog ref="dialogRef" @success="handleFormSuccess" v-model="visible" v-if="visible" />
        <ShareDiaLog ref="shareDialogRef" @success="getList" v-model="shareVisible" v-if="shareVisible" />
    </basic-container>
</template>
@@ -123,6 +123,8 @@
const list = ref([])
const total = ref(0)
const selectedIds = ref([])
const selectedRows = ref([])
const lastActionParentRow = ref(null)
const queryParamsRef = ref(null)
const dialogRef = ref(null)
const shareDialogRef = ref(null)
@@ -133,6 +135,7 @@
})
const deptTree = ref([])
const route = useRoute()
const treeResolveMap = new Map()
provide('dictObj', dictObj)
provide('deptTree', deptTree)
@@ -167,6 +170,7 @@
}
function handleAddChild(row) {
    lastActionParentRow.value = row
    visible.value = true
    nextTick(() => {
        dialogRef.value?.open({ mode: 'add', parent: row })
@@ -203,6 +207,7 @@
        cancelButtonClass: 'command-message-box-cancel',
    })
    const ids = row ? row.id : selectedIds.value.join(',')
    const rows = row ? [row] : selectedRows.value
    await remove(ids)
    saveOperationLog({
        requestUri: route.path,
@@ -211,11 +216,18 @@
    })
    ElMessage.success('删除成功')
    selectedIds.value = []
    getList()
    selectedRows.value = []
    const parentIds = Array.from(new Set(rows.map(item => item.parentId).filter(Boolean)))
    const hasRoot = rows.some(item => !item.parentId)
    if (hasRoot) {
        getList()
    }
    parentIds.forEach(parentId => refreshChildNodes(parentId))
}
function handleSelectionChange(rows) {
    selectedIds.value = rows.map(item => item.id)
    selectedRows.value = rows
}
function getDictList() {
@@ -236,11 +248,49 @@
}
function loadChildren(row, treeNode, resolve) {
    treeResolveMap.set(row.id, { resolve, row })
    getChildLazyTree({ parentId: row.id })
        .then(res => {
            resolve(res?.data?.data ?? [])
            const children = res?.data?.data ?? []
            row.hasChildren = children.length > 0
            resolve(children)
        })
        .catch(() => resolve([]))
        .catch(() => {
            row.hasChildren = false
            resolve([])
        })
}
function refreshChildNodes(parentId) {
    const cache = treeResolveMap.get(parentId)
    if (!cache?.resolve) return
    getChildLazyTree({ parentId })
        .then(res => {
            const children = res?.data?.data ?? []
            if (cache.row) {
                cache.row.hasChildren = children.length > 0
            }
            cache.resolve(children)
        })
        .catch(() => {
            if (cache.row) {
                cache.row.hasChildren = false
            }
            cache.resolve([])
        })
}
function handleFormSuccess(payload = {}) {
    if (payload?.parentId) {
        refreshChildNodes(payload.parentId)
        if (payload.isAddChild && lastActionParentRow.value?.id === payload.parentId) {
            lastActionParentRow.value.hasChildren = true
        }
        lastActionParentRow.value = null
        return
    }
    lastActionParentRow.value = null
    getList()
}
onMounted(() => {
applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue
@@ -9,7 +9,15 @@
    >
        <div class="dialog-container">
            <div class="left-container">
                <div class="leftMap command-cesium" id="leftMapContainer"></div>
                <CommonCesiumMap
                    ref="mapRef"
                    class="leftMap command-cesium"
                    :active="visible"
                    :flat-mode="false"
                    :terrain="true"
                    :layer-mode="4"
                    :boundary="false"
                />
            </div>
            <div class="right-container">
                <div class="header">
@@ -67,11 +75,10 @@
import { Close } from '@element-plus/icons-vue'
import { computed, nextTick, ref } from 'vue'
import CommonCesiumMap from '@/components/map-container/common-cesium-map.vue'
import { fwDroneFlightRecordDetailApi } from '@/views/recordManage/historyTracks/fwDroneFlightRecord'
import { fwDroneFlightRecordDetailPageApi } from '@/views/recordManage/historyTracks/flyTrajectory'
import { PublicCesium } from '@/utils/cesium/publicCesium'
import * as Cesium from 'cesium'
import { flyVisual } from '@ztzf/utils'
import { ArrowLineMaterialProperty } from '@/utils/cesium/Material'
import droneIcon from '@/assets/images/dataCockpit/map/drone.png'
@@ -83,11 +90,11 @@
    stayDuration: '',
})
let list = ref([])
const emit = defineEmits(['success'])
const formData = ref(initForm()) // 表单数据
const visible = ref(false) // 弹框显隐
const dialogMode = ref('add') // 弹框模式
const dialogReadonly = computed(() => dialogMode.value === 'view')
const mapRef = ref(null)
const dialogTitle = computed(() => {
    if (dialogMode.value === 'edit') {
        return '编辑'
@@ -170,14 +177,9 @@
let viewer, geometricSource, droneLineEntity, startDroneEntity
function initMap() {
    if (viewer) return
    const publicCesiumInstance = new PublicCesium({
        dom: 'leftMapContainer',
        flatMode: false,
        terrain: true,
        layerMode: 4,
        boundary: false,
    })
    viewer = publicCesiumInstance.getViewer()
    const map = mapRef.value?.getMap?.()
    if (!map?.viewer) return
    viewer = map.viewer
    geometricSource = new Cesium.CustomDataSource('geometricSource')
    viewer.dataSources.add(geometricSource)
}
applications/task-work-order/env/.env
@@ -20,6 +20,6 @@
VITE_BUILD_COMPRESS=gzip
# 预览地址 previewURL
VITE_APP_PREVIEW_URL=http://192.168.1.204:8012
VITE_APP_PREVIEW_URL=http://192.168.1.36:8012
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_c_uas/
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_c_uas/
applications/task-work-order/env/.env.production
@@ -16,8 +16,5 @@
# 航线文件地址
VITE_APP_AIRLINE_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket
# 图片存放地址
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_terrain/
# 行政区划存放地址
VITE_APP_REGION_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_region
applications/task-work-order/env/.env.test
@@ -1,3 +1,23 @@
###
 # @Author       : yuan
 # @Date         : 2026-02-03 13:46:08
 # @LastEditors  : yuan
 # @LastEditTime : 2026-02-03 15:44:11
 # @FilePath     : \applications\task-work-order\env\.env.test
 # @Description  :
 # Copyright 2026 OBKoro1, All Rights Reserved.
 # 2026-02-03 13:46:08
###
###
 # @Author       : yuan
 # @Date         : 2026-02-03 13:46:08
 # @LastEditors  : yuan
 # @LastEditTime : 2026-02-03 15:44:01
 # @FilePath     : \applications\task-work-order\env\.env.test
 # @Description  :
 # Copyright 2026 OBKoro1, All Rights Reserved.
 # 2026-02-03 13:46:08
###
NODE_ENV='test'
#开发环境配置
@@ -14,10 +34,6 @@
# 航线文件地址
VITE_APP_AIRLINE_URL=https://wrj.shuixiongit.com/minio/cloud-bucket
# 图片存放地址
VITE_APP_TERRAIN_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_terrain/
# 行政区划存放地址
VITE_APP_REGION_URL=https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_region
applications/task-work-order/src/styles/theme/white.scss
@@ -88,6 +88,10 @@
        color: #666
      }
      .iconfont{
        font-size: 14px;
      }
      &:hover {
        background: transparent;
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
@@ -450,49 +450,46 @@
})
// 获取航线详情
function getAirDetails() {
    console.log(formData.value)
    const dockHeight = formData.value.height
    queryAirById(formData.value.patrolRouteUrl).then(res => {
        const list = res.data.data.airlineWaypoints
        const {airlineWaypoints,airlineSetting:{globalAirlineHeight,airlineHeightMode}} = res.data.data
        const relative = airlineHeightMode === 'relativeToStartPoint'
        const list = airlineWaypoints
        if (!list.length) return mapRef.value?.flyBoundary()
        const result = list.map(item => [Number(item.longitude), Number(item.latitude)]).flat()
        const result = list.map(item => {
            let height = item?.globalHeight || globalAirlineHeight
            if (relative){
                height = height + Number(dockHeight)
            }
            return [Number(item.longitude), Number(item.latitude),height || 0]
        })
        viewer.entities.add({
            polyline: {
                positions: Cesium.Cartesian3.fromDegreesArray(result),
                clampToGround: true,
                positions: Cesium.Cartesian3.fromDegreesArrayHeights(result.flat()),
                width: 4,
                material: arrowLineMaterialProperty,
            },
        })
        // 渲染起点(蓝色)
        const startPoint = list[0]
        const startPoint = result[0]
        viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(
                Number(startPoint.longitude),
                Number(startPoint.latitude),
                startPoint.height || 0
            ),
            position: Cesium.Cartesian3.fromDegrees(Number(startPoint[0]), Number(startPoint[1]), startPoint[2]),
            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]
        const endPoint = result[result.length - 1]
        viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(
                Number(endPoint.longitude),
                Number(endPoint.latitude),
                endPoint.height || 0
            ),
            position: Cesium.Cartesian3.fromDegrees(Number(endPoint[0]), Number(endPoint[1]), endPoint[2]),
            point: {
                pixelSize: 12,
                color: Cesium.Color.RED,
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            },
        })
        flyVisual({
uniapps/work-wx/src/subPackages/deviceRegistration/add.vue
@@ -258,7 +258,7 @@
            </view>
                <u-radio-group
                v-if="!loadingManufacturer"
                    v-model="formParams.spacecraftId"
                    v-model="formParams.manufacturer"
                    placement="column"
                    @change="radioChange"
                >
@@ -426,7 +426,7 @@
    formParams.value.region = e[2] || '' // 用逗号分隔的区域码
    // 通过arrRegion的数组值为[36,3608,360824] 从areaData里面反查出名称
    const regionNames = findRegionNamesByCodes(e, areaData.value)
    formParams.value.regionText = regionNames.join('-') || '' // 用连字符连接的区域名称
    formParams.value.regionText = regionNames.join(',') || '' // 用连字符连接的区域名称
    isShowRegion.value = false
}
// 是否有保险
@@ -671,7 +671,7 @@
    // 检查响应
    if (response.statusCode === 200) {
        areaData.value = response.data
        console.log('请求成功:', data)
        // console.log('请求成功:', data)
        // 处理数据
    } else {
        console.error('请求失败:', response)
uniapps/work-wx/src/subPackages/deviceRegistration/details.vue
@@ -313,12 +313,6 @@
        current: 1,
        size: 1000,
    }).then(res => {
        // manufacturerList.value = res.data.data.records.map(item => ({
        //     ...item,
        //     label: item.unitName,
        //     value: item.id,
        // }))
        console.log(formParams.value.manufacturer, res.data.data.records.find(item => item.id === formParams.value.manufacturer))
        formParams.value.manufacturerText = res.data.data.records.find(item => item.id === formParams.value.manufacturer)?.unitName || ''
    })
}
@@ -329,7 +323,9 @@
        formParams.value.hasInsurance = res.data.data.hasInsurance === '1' ? '有' : '无'
        // formParams.value.manufacturer = manufacturerList.value.find(item => item.value === res.data.data.manufacturer)?.label || ''
        formParams.value.type = typeList.value.find(item => item.value === res.data.data.type)?.label || ''
        formParams.value.region = res.data.data.region
        // formParams.value.region = res.data.data.region
        // 360824 截取留前两位 3608 截取留前四位
        formParams.value.region = findRegionNamesByCodes([res.data.data.region.slice(0,2),res.data.data.region.slice(0,4),res.data.data.region], areaData.value)
        getManufacturerInfoApi()
    })
    
@@ -339,8 +335,25 @@
    // getManufacturerInfoApi()
    getProTypeApi()
    // 动态导入xzqhData,确保在使用前已初始化
    const { xzqhData } = await import('@/static/xzqh/index')
    areaData.value = xzqhData
    // const { xzqhData } = await import('@/static/xzqh/index')
    // areaData.value = xzqhData
    const response = await uni.request({
        url: 'https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ja-app-wx/xzqh/index.json',
        method: 'GET',
        timeout: 10000, // 10秒超时
        dataType: 'json'
    })
    // 检查响应
    if (response.statusCode === 200) {
        areaData.value = response.data
        // console.log('请求成功:', data)
        // 处理数据
    } else {
        console.error('请求失败:', response)
        throw new Error(`请求失败: ${response.statusCode}`)
    }
})
</script>
<style scoped lang="scss">
uniapps/work-wx/src/subPackages/flightApplication/add.vue
@@ -360,32 +360,30 @@
    <u-popup
    :show="isShowAircraftInfo"
    mode="bottom"
    round="20"
    round="0"
    @close="isShowAircraftInfo = false"
  >
  <scroll-view scroll-y>
    <view class="select-header">
        <view>请选择飞行器</view>
        <view class="select-header-btn">
            <view class="cancel-btn" @click="isShowAircraftInfo = false">取消</view>
            <view @click="onPickerAircraftInfo">确定</view>
        </view>
        <!-- <view>请选择飞行器</view> -->
        <view class="cancel-btn" @click="isShowAircraftInfo = false">取消</view>
        <view class="confirm-btn" @click="onPickerAircraftInfo">确定</view>
    </view>
    <view class="select-content">
          <up-checkbox-group
          <u-checkbox-group
            v-model="formParams.spacecraftId"
            placement="column"
            @change="checkboxChange"
        >
            <up-checkbox
            <u-checkbox
                :customStyle="{marginBottom: '8px'}"
                v-for="(item, index) in aircraftInfoList"
                :key="item.id"
                :label="item.label"
                :name="item.value"
            >
            </up-checkbox>
        </up-checkbox-group>
            </u-checkbox>
        </u-checkbox-group>
    </view>
    </scroll-view>
  </u-popup>
@@ -400,32 +398,30 @@
    <u-popup
    :show="isShowPilotInfo"
    mode="bottom"
    round="20"
    round="0"
    @close="isShowPilotInfo = false"
  >
  <scroll-view scroll-y>
    <view class="select-header">
        <view>请选择飞手</view>
        <view class="select-header-btn">
            <view class="cancel-btn" @click="isShowPilotInfo = false">取消</view>
            <view @click="onPickerPilotInfo">确定</view>
        </view>
        <!-- <view>请选择飞手</view> -->
        <view class="cancel-btn" @click="isShowPilotInfo = false">取消</view>
        <view class="confirm-btn" @click="onPickerPilotInfo">确定</view>
    </view>
    <view class="select-content">
          <up-checkbox-group
          <u-checkbox-group
            v-model="formParams.pilotId"
            placement="column"
            @change="checkboxPilotChange"
        >
            <up-checkbox
            <u-checkbox
                :customStyle="{marginBottom: '8px'}"
                v-for="(item, index) in pilotInfoList"
                :key="item.id"
                :label="item.label"
                :name="item.value"
            >
            </up-checkbox>
        </up-checkbox-group>
            </u-checkbox>
        </u-checkbox-group>
    </view>
    </scroll-view>
  </u-popup>
@@ -645,7 +641,7 @@
//   isShowAircraftInfo.value = false
// }
function checkboxChange(val) {
    formParams.value.spacecraftId = val.join(',')
    formParams.value.spacecraftId = val
    formParams.value.spacecraftText = aircraftInfoList.value.filter(item => val.includes(item.value)).map(item => item.label).join(',')
}
const onPickerAircraftInfo = () => {
@@ -666,7 +662,7 @@
    })
}
function checkboxPilotChange(val) {
    formParams.value.pilotId = val.join(',')
    formParams.value.pilotId = val
    formParams.value.pilotText = pilotInfoList.value.filter(item => val.includes(item.value)).map(item => item.label).join(',')
}
const onPickerPilotInfo = (e) => {
@@ -775,6 +771,8 @@
const submitForm = async () => {
  await formRef.value.validate()
  isSubmitDisabled.value = true
  formParams.value.pilotId = formParams.value.pilotId.join(',')
  formParams.value.spacecraftId = formParams.value.spacecraftId.join(',')
  flightPlanSaveApi(formParams.value).then(res => {
    if (res.data.code === 200) {
        isSubmitDisabled.value = true
@@ -953,19 +951,17 @@
        padding: 20rpx 20rpx;
        font-size: 32rpx;
        color: #222324;
        .select-header-btn {
            display: flex;
            font-size: 28rpx;
        .cancel-btn {
            color: #86909C;
            margin-right: 20rpx;
        }
        .confirm-btn {
            color: #1D6FE9;
            .cancel-btn {
                color: #86909C;
                margin-right: 20rpx;
            }
        }
    }
    .select-content {
        height: 600rpx;
        height: 480rpx;
        text-align: center;
        padding: 20rpx 20rpx;
    }
uniapps/work-wx/src/subPackages/userDetail/password/index.vue
@@ -287,6 +287,7 @@
                .rowTitle {
                    width: 160rpx;
                    font-family: Source Han Sans CN, Source Han Sans CN;
                    font-weight: 400;
                    font-size: 30rpx;