吉安感知网项目-前端
15 files modified
1 files added
650 ■■■■ changed files
AGENTS.md 4 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/areaStatistics/FormDiaLog.vue 5 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/FormDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/task-work-order/src/api/system/dept.js 4 ●●●● 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/styles/common/cockpit.scss 16 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue 85 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue 34 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue 148 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue 118 ●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue 17 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue 64 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue 17 ●●●●● patch | view | raw | blame | history
applications/task-work-order/src/views/orderView/orderManage/taskTypeOptions.js 105 ●●●●● patch | view | raw | blame | history
packages/utils/common/index.js 10 ●●●●● patch | view | raw | blame | history
uniapps/work-app/src/pages/login/index.vue 4 ●●●● patch | view | raw | blame | history
AGENTS.md
@@ -30,8 +30,7 @@
- 文件与目录保持 kebabCase,遵循现有应用与包的命名风格。
## 测试指南
- 当前未配置测试框架(`pnpm test` 会直接退出)。
- 若新增测试,请在对应应用 `README.md` 说明测试框架,并补充根目录脚本。
- 无需任何测试
## 提交与合并请求规范
- 提交历史使用简短的约定式主题(如 `feat: ...`)。
@@ -54,3 +53,4 @@
  Prefer minimal changes.
- 未被明确要求时,禁止大规模重构。
  Avoid large refactors unless requested.
- 修改完不需要走打包编译校验
applications/drone-command/src/views/areaManage/areaStatistics/FormDiaLog.vue
@@ -9,7 +9,7 @@
                </el-col>
                <el-col :span="12">
                    <div class="label">区域类型</div>
                    <div class="val">{{ getDictLabel(formData.areaType, dictObj.areaType) }}</div>
                    <div class="val">{{ getDictLabel(formData.areaTypeKeys, dictObj.areaType) }}</div>
                </el-col>
                <el-col :span="12">
                    <div class="label">关联场景</div>
@@ -72,6 +72,9 @@
const titleEnum = ref({ view: '查看' })
const dictObj = inject('dictObj')
console.log(formData.value, '9090')
console.log(dictObj.value, '8080')
// 关闭弹框
function handleCancel() {
    visible.value = false
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/FormDiaLog.vue
@@ -14,7 +14,7 @@
                </el-col>
                <el-col :span="12">
                    <div class="label">无人机类型</div>
                    <div class="val">{{ formData.droneType || '-' }}</div>
                    <div class="val">{{ getDeviceTypeLabel(formData.droneType) || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div class="label">设备编码</div>
applications/task-work-order/src/api/system/dept.js
@@ -67,12 +67,12 @@
  });
};
export const getDeptTree = tenantId => {
export const getDeptTree = id => {
  return request({
    url: '/blade-system/dept/getTree',
    method: 'get',
    params: {
      tenantId,
            id,
    },
  });
};
applications/task-work-order/src/api/zkxt/index.js
@@ -53,4 +53,21 @@
    })
}
// ai算法
export const algorithmGroupedApi = (params) => {
    return request({
        url: `/webservice/webservice/algorithm/grouped`,
        method: 'get',
        params,
    })
}
// 获取字典下拉 task_inspection_type
export const getDictListApi = (str) => {
    return request({
        url: `/system/dict/data/type/${str}`,
        method: 'get',
    })
}
applications/task-work-order/src/styles/common/cockpit.scss
@@ -1223,22 +1223,6 @@
}
.gd-dialog-form {
  // 最后一排不需要设置 margin-bottom
  // border: 1px solid red;
  // 倒数第二个也设置为0
  // .el-col:nth-last-child(2) {
  //   margin-bottom: 0;
  // }
  // .el-col:nth-last-child(1) {
  //   margin-bottom: 0;
  // }
  // .el-form-item:nth-last-child(2) {
  //   margin-bottom: 0;
  // }
  //  .el-form-item:nth-last-child(1) {
  //   margin-bottom: 0;
  // }
  .gd-select {
    .el-select__wrapper {
      height: 36px;
applications/task-work-order/src/views/orderView/orderManage/clueEvents/ViewDiaLog.vue
@@ -5,9 +5,9 @@
                <el-table-column label="线索缩略图" width="120">
                    <template v-slot="{ row }">
                        <el-image
                            v-if="row.resultUrl"
                            :src="row.resultUrl"
                            :preview-src-list="[row.resultUrl]"
                            v-if="row.aiImg || row.resultUrl"
                            :src="row.aiImg || row.resultUrl"
                            :preview-src-list="[row.aiImg || row.resultUrl]"
                            fit="cover"
                            style="width: 80px; height: 60px"
                            preview-teleported
@@ -101,11 +101,90 @@
    try {
        const res = await gdTaskResultListApi({ patrolTaskId: currentRow.value.id })
        list.value = res?.data?.data ?? []
        list.value = await Promise.all(list.value.map(async i => {
            const aiImg = await getAiImg(i.resultUrl)
            return { ...i, aiImg }
        }))
    } finally {
        loading.value = false
    }
}
const aiFrame = [
    "{\"score\":0.91357421875,\"bbox\":{\"x_cen\":1246.0,\"y_cen\":209.0,\"width\":166.0,\"height\":334.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}",
    "{\"score\":0.89697265625,\"bbox\":{\"x_cen\":370.0,\"y_cen\":694.5,\"width\":162.0,\"height\":331.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}",
    "{\"score\":0.89501953125,\"bbox\":{\"x_cen\":396.0,\"y_cen\":343.0,\"width\":168.0,\"height\":330.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}",
    "{\"score\":0.79296875,\"bbox\":{\"x_cen\":409.5,\"y_cen\":52.5,\"width\":167.0,\"height\":105.0},\"class_name\":\"car\",\"algorithmId\":\"e71116098eeb1d60cfebd04d30653b151\"}"
]
function getAiImg(url) {
    if (!url) return ''
    const img = new Image()
    img.crossOrigin = 'anonymous';
    return new Promise(resolve => {
        img.onload = () => {
            if (!img.naturalWidth || !img.naturalHeight) {
                resolve('')
                return
            }
            const canvas = document.createElement('canvas')
            const ctx = canvas.getContext('2d')
            if (!ctx) {
                resolve('')
                return
            }
            canvas.width = img.naturalWidth
            canvas.height = img.naturalHeight
            ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
            aiFrame.forEach(item => {
                let target = item
                try {
                    target = typeof item === 'string' ? JSON.parse(item) : item
                } catch (error) {
                    return
                }
                const { x_cen, y_cen, width, height } = target.bbox || {}
                if ([x_cen, y_cen, width, height].some(value => typeof value !== 'number')) return
                const x = x_cen - width / 2
                const y = y_cen - height / 2
                const label = target.class_name || ''
                const fontSize = Math.max(18, Math.round(canvas.width / 80))
                const labelHeight = fontSize + 10
                const labelY = y - labelHeight >= 0 ? y - labelHeight : y
                ctx.strokeStyle = '#FF3B30'
                ctx.lineWidth = Math.max(3, Math.round(canvas.width / 640))
                ctx.strokeRect(x, y, width, height)
                if (label) {
                    ctx.font = `${fontSize}px Arial`
                    const labelWidth = ctx.measureText(label).width + 16
                    ctx.fillStyle = '#FF3B30'
                    ctx.fillRect(x, labelY, labelWidth, labelHeight)
                    ctx.fillStyle = '#FFFFFF'
                    ctx.textBaseline = 'middle'
                    ctx.fillText(label, x + 8, labelY + labelHeight / 2)
                }
            })
            try {
                resolve(canvas.toDataURL('image/jpeg', 0.92))
            } catch (error) {
                console.log(error)
                resolve('')
            }
        }
        img.onerror = () => resolve('')
        img.src = url
    })
}
// 打开分发弹框
function openDistributeDialog(row) {
    distributeDialogVisible.value = true
applications/task-work-order/src/views/orderView/orderManage/clueEvents/index.vue
@@ -13,21 +13,16 @@
            </el-form-item>
            <el-form-item label="巡查任务类型" prop="patrolTaskType">
                <el-select
                <el-cascader
                    class="gd-select gray"
                    popper-class="gd-select-popper"
                    v-model="searchParams.patrolTaskType"
                    :options="workOrderTypeXT"
                    :props="taskTypeFilterCascaderProps"
                    placeholder="请选择"
                    clearable
                    @change="handleSearch"
                >
                    <el-option
                        v-for="item in dictObj.workOrderType"
                        :key="item.dictKey"
                        :label="item.dictValue"
                        :value="item.dictKey"
                    />
                </el-select>
                />
            </el-form-item>
            <!-- <el-form-item label="任务状态" prop="taskStatus">
@@ -76,7 +71,7 @@
                    <el-table-column prop="taskNo" show-overflow-tooltip label="巡查任务编号" />
                    <el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
                            {{ getTaskTypeLabel(row.patrolTaskType, workOrderTypeXT) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="taskStatus" show-overflow-tooltip label="巡查任务状态">
@@ -92,7 +87,7 @@
                    <el-table-column prop="taskDesc" show-overflow-tooltip label="巡查任务描述" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link  type="primary"  @click="viewDiaLogView(row)">查看线索</el-link>
                            <el-link type="primary" @click="viewDiaLogView(row)">查看线索</el-link>
                        </template>
                    </el-table-column>
                </el-table>
@@ -115,12 +110,15 @@
</template>
<script setup>
import { Search, RefreshRight } from '@element-plus/icons-vue'
import { onMounted, ref } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { getDictionaryByCode } from '@/api/system/dictbiz'
import { dateRangeFormat, getDictLabel } from '@ztzf/utils'
import { getDictListApi } from '@/api/zkxt'
import { gdPatrolTaskPageApi } from '../inspectionRequest/inspectionRequestApi'
import { getDeptTree } from '@/api/system/dept'
import ViewDiaLog from './ViewDiaLog.vue'
import { useStore } from 'vuex'
import { getTaskTypeLabel, normalizeTaskTypeOptions, taskTypeFilterCascaderProps } from '../taskTypeOptions'
// 初始化查询参数
const initSearchParams = () => ({
@@ -149,8 +147,10 @@
    workOrderType: [], // 巡查任务类型
    taskStatus: [], // 巡查任务状态
})
const workOrderTypeXT = ref([])
provide('dictObj', dictObj)
provide('workOrderTypeXT', workOrderTypeXT)
provide('deptTree', deptTree)
provide('treeProps', treeProps)
@@ -163,7 +163,7 @@
            ...searchParams.value,
            startTime: range[0],
            endTime: range[1],
            taskStatus: 8
            taskStatus: 8,
        })
        list.value = res?.data?.data?.records ?? []
        total.value = res?.data?.data?.total ?? 0
@@ -199,11 +199,17 @@
    getDictionaryByCode('workOrderType,taskStatus').then(res => {
        dictObj.value = res.data.data
    })
    getDictListApi('task_inspection_type').then(res => {
        workOrderTypeXT.value = normalizeTaskTypeOptions(res.data.data || [])
    })
}
const store = useStore()
const userInfo = computed(() => store.state.user.userInfo)
// 获取部门树
function getDeptTreeFun() {
    getDeptTree().then(res => {
    getDeptTree(userInfo.value.dept_id).then(res => {
        deptTree.value = res.data.data
    })
}
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/FormDiaLog.vue
@@ -5,10 +5,10 @@
        :title="titleEnum[dialogMode]"
        @closed="visible = false"
        destroy-on-close
        width="75%"
        width="90%"
        :close-on-click-modal="false"
    >
        <div class="gd-dialog-form">
        <div>
            <!-- 关联工单选择 -->
            <div class="work-order-section">
                <div class="detail-title" :style="{ marginBottom: 0, marginRight: pxToRem(10) }">选择工单</div>
@@ -33,7 +33,7 @@
                        <div class="info-item">
                            <span class="label">工单类型</span>
                            <span class="val" v-if="selectedWorkOrder">
                                {{ getDictLabel(selectedWorkOrder.workOrderType, dictObj.workOrderType) }}
                                {{ getTaskTypeLabel(selectedWorkOrder.workOrderType, workOrderTypeXT) }}
                            </span>
                            <span class="val grayText" v-else>选择工单后自动带出</span>
                        </div>
@@ -78,7 +78,7 @@
                        <el-table-column width="50" label="">
                            <template v-slot="{ $index }">{{ $index + 1 }}</template>
                        </el-table-column>
                        <el-table-column prop="patrolTaskName" min-width="120">
                        <el-table-column prop="patrolTaskName" min-width="100">
                            <template #header>
                                <span class="required-star">*</span>
                                巡查任务名称
@@ -92,29 +92,24 @@
                                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="patrolTaskType" min-width="140">
                        <el-table-column prop="patrolTaskType" min-width="100">
                            <template #header>
                                <span class="required-star">*</span>
                                巡查任务类型
                            </template>
                            <template v-slot="{ row, $index }">
                                <el-select
                                <el-cascader
                                    class="gd-select"
                                    popper-class="gd-select-popper"
                                    v-model="row.patrolTaskType"
                                    :options="workOrderTypeXT"
                                    :props="taskTypeCascaderProps"
                                    placeholder="请选择"
                                    @change="handlePatrolTaskTypeChange($index, $event)"
                                >
                                    <el-option
                                        v-for="item in dictObj.workOrderType"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="executeTime" min-width="180">
                        <el-table-column prop="executeTime" width="200">
                            <template #header>
                                <span class="required-star">*</span>
                                任务执行时间
@@ -122,7 +117,7 @@
                            <template v-slot="{ row }">
                                <!--                                gd-date-picker-popper-->
                                <el-date-picker
                                    :style="{width: pxToRem(160)}"
                                    :style="{width: pxToRem(165)}"
                                    class="gd-date-picker"
                                    popper-class=""
                                    v-model="row.executeTime"
@@ -133,7 +128,7 @@
                                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="patrolRouteUrl" min-width="120">
                        <el-table-column prop="patrolRouteUrl" min-width="100">
                            <template #header>
                                <span class="required-star">*</span>
                                巡查任务航线
@@ -152,7 +147,7 @@
                                </el-select>
                            </template>
                        </el-table-column>
                        <el-table-column prop="recommendFlyerName" min-width="120">
                        <el-table-column prop="deviceFlyerId" min-width="100">
                            <template #header>
                                <span class="required-star">*</span>
                                推荐飞手
@@ -162,16 +157,17 @@
                                    no-data-text="暂无推荐飞手"
                                    class="gd-select"
                                    popper-class="gd-select-popper"
                                    v-model="row.recommendFlyerName"
                                    v-model="row.deviceFlyerId"
                                    placeholder="请选择"
                                    filterable
                                    :disabled="dialogReadonly || !taskList[$index].patrolTaskType"
                                    :disabled="dialogReadonly || !hasTaskTypeValue(taskList[$index].patrolTaskType)"
                                >
                                    <el-option
                                        v-for="item in flyerListMap[$index] || []"
                                        :key="item.id"
                                        :key="item.flyerId"
                                        :label="item.flyerName"
                                        :value="item.flyerName"
                                        :value="item.flyerId"
                                    >
                                        <template #default>
                                        <!-- 匹配区域=1 显示红星号 -->
@@ -182,7 +178,7 @@
                                    </el-select>
                            </template>
                        </el-table-column>
                        <el-table-column prop="deviceId" min-width="120">
                        <el-table-column prop="deviceId" min-width="100">
                            <template #header>
                                <span class="required-star">*</span>
                                选择设备
@@ -200,7 +196,31 @@
                                </el-select>
                            </template>
                        </el-table-column>
                        <el-table-column prop="taskDesc" label="巡查任务描述" min-width="120">
                        <el-table-column prop="algorithmIds" min-width="160">
                            <template #header>
                                算法
                            </template>
                            <template v-slot="{ row }">
                                <el-tree-select
                                    class="gd-select"
                                    popper-class="gd-tree-select-popper"
                                    v-model="row.algorithmIds"
                                    :data="algorithmTreeData"
                                    :props="{ label: 'name', children: 'children', value: 'id' }"
                                    node-key="id"
                                    multiple
                                    collapse-tags
                                    collapse-tags-tooltip
                                    check-strictly
                                    filterable
                                    placeholder="请选择"
                                    :disabled="dialogReadonly"
                                />
                            </template>
                        </el-table-column>
                        <el-table-column prop="taskDesc" label="巡查任务描述">
                            <template v-slot="{ row }">
                                <el-input class="gd-input" v-model="row.taskDesc" placeholder="请输入" :disabled="dialogReadonly" />
                            </template>
@@ -240,24 +260,33 @@
</template>
<script setup>
import { computed, ref, onMounted } from 'vue'
import { computed, ref, onMounted, inject } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import { geomAnalysis, getDictLabel } from '@ztzf/utils'
import { gdPatrolTaskSaveApi, gdFlyerPageApi, gdPatrolTaskAuditApi } from './inspectionRequestApi'
import { gdWorkOrderPageApi } from '../orderManage/orderManageApi'
import { gdManageDeviceListApi } from '../orderManage/gdManageDeviceApi'
import { pxToRem } from '@/utils/rem'
import { airlineListApi } from '@/api/zkxt'
import { airlineListApi, algorithmGroupedApi } from '@/api/zkxt'
import {
    getTaskTypeLabel,
    getTaskTypeLeafValues,
    taskTypeCascaderProps,
    toTaskTypeCascaderValue,
    toTaskTypeRequestValue,
} from '../taskTypeOptions'
// 初始化任务行
const initTaskRow = () => ({
    patrolTaskName: '',
    patrolTaskType: '',
    patrolTaskType: [],
    executeTime: '',
    patrolRouteUrl: '',
    recommendFlyerName: '',
    deviceFlyerId: '',
    deviceId: null,
    algorithmIds: [],
    taskDesc: '',
})
const dictObj = inject('dictObj')
@@ -278,6 +307,27 @@
const deviceList = ref([]) // 设备列表
const routeOptions = ref([]) // 航线选项(根据工单范围获取)
const routeLoading = ref(false) // 航线加载中
const algorithmTreeData = ref([]) // 算法树形数据
const workOrderTypeXT = inject('workOrderTypeXT', ref([]))
// 获取算法分组数据
async function getAlgorithmList() {
    try {
        const res = await algorithmGroupedApi()
        const list = res?.data?.data ?? []
        algorithmTreeData.value = list.map(group => ({
            id: 'group_' + group.type,
            name: group.type,
            disabled: true,
            children: (group.algorithms || []).map(alg => ({
                id: alg.id,
                name: alg.name,
            }))
        }))
    } catch (e) {
        console.error('获取算法列表失败', e)
    }
}
// 子任务列表
const taskList = ref([initTaskRow()])
@@ -291,13 +341,14 @@
        // 将工单类型赋值给所有子任务行
        const workOrderType = selectedWorkOrder.value?.workOrderType
        if (workOrderType) {
            const patrolTaskType = toTaskTypeCascaderValue(workOrderType)
            taskList.value.forEach((task, index) => {
                taskList.value[index] = {
                    ...initTaskRow(),
                    patrolTaskType: workOrderType,
                    patrolTaskType,
                }
                // 获取对应的飞手列表
                getFlyerList(index, workOrderType)
                getFlyerList(index, patrolTaskType)
            })
        }
    } else {
@@ -325,7 +376,7 @@
    const newTask = initTaskRow()
    // 如果已选择工单,自动填充工单类型
    if (selectedWorkOrder.value?.workOrderType) {
        newTask.patrolTaskType = selectedWorkOrder.value.workOrderType
        newTask.patrolTaskType = toTaskTypeCascaderValue(selectedWorkOrder.value.workOrderType)
    }
    const newIndex = taskList.value.length
    taskList.value.push(newTask)
@@ -369,10 +420,12 @@
// 处理巡查任务类型变化
async function handlePatrolTaskTypeChange(index, skilledTaskType) {
    // 清空该行已选择的飞手
    taskList.value[index].recommendFlyerName = ''
    taskList.value[index].deviceFlyerId = ''
    // 获取对应的飞手列表
    await getFlyerList(index, skilledTaskType)
}
import * as turf from '@turf/turf'
@@ -387,11 +440,16 @@
// 获取飞手列表
async function getFlyerList(index, skilledTaskType) {
    const leafValues = getTaskTypeLeafValues(skilledTaskType)
    if (!leafValues.length) {
        flyerListMap.value[index] = []
        return
    }
    const obj = getPolygonCenter(geomAnalysis(selectedWorkOrder.value.geom))
    const res = await gdFlyerPageApi({
        size: 999,
        current: 1,
        skilledTaskType,
        skilledTaskType: leafValues.join(','),
        // longitude: obj.longitude || '',
        // latitude: obj.latitude || '',
    })
@@ -416,7 +474,18 @@
// 判断一行是否已填写(至少填写了任务名称)
function isTaskRowFilled(task) {
    return !!(task.patrolTaskName || task.executeTime || task.patrolRouteUrl || task.recommendFlyerName || task.deviceId)
    return !!(
        task.patrolTaskName ||
        hasTaskTypeValue(task.patrolTaskType) ||
        task.executeTime ||
        task.patrolRouteUrl ||
        task.deviceFlyerId ||
        task.deviceId
    )
}
function hasTaskTypeValue(value) {
    return !!toTaskTypeRequestValue(value).length
}
// 提交新增
@@ -441,7 +510,7 @@
            ElMessage.warning(`第${i + 1}行: 请输入巡查任务名称`)
            return
        }
        if (!task.patrolTaskType) {
        if (!hasTaskTypeValue(task.patrolTaskType)) {
            ElMessage.warning(`第${i + 1}行: 请选择巡查任务类型`)
            return
        }
@@ -453,7 +522,7 @@
            ElMessage.warning(`第${i + 1}行: 请选择巡查任务航线`)
            return
        }
        if (!task.recommendFlyerName) {
        if (!task.deviceFlyerId) {
            ElMessage.warning(`第${i + 1}行: 请选择推荐飞手`)
            return
        }
@@ -468,6 +537,7 @@
        // 只提交已填写的任务行
        const dataList = filledTasks.map(item => ({
            ...item,
            patrolTaskType: toTaskTypeRequestValue(item.patrolTaskType),
            workOrderId: selectedWorkOrderId.value,
            id: undefined,
        }))
@@ -485,6 +555,8 @@
async function open({ mode = 'add', row } = {}) {
    dialogMode.value = mode
    await getWorkOrderList()
    getAlgorithmList()
    if (dialogMode.value === 'add') {
        selectedWorkOrderId.value = null
        selectedWorkOrder.value = null
@@ -494,11 +566,11 @@
        // 编辑/查看模式 - 加载已有数据
        selectedWorkOrderId.value = row?.workOrderId
        handleWorkOrderChange(row?.workOrderId)
        taskList.value = [{ ...row }]
        taskList.value = [{ ...row, patrolTaskType: toTaskTypeCascaderValue(row?.patrolTaskType) }]
        flyerListMap.value = {}
        // 如果有巡查类型,加载对应的飞手列表
        if (row?.patrolTaskType) {
            getFlyerList(0, row.patrolTaskType)
            getFlyerList(0, taskList.value[0].patrolTaskType)
        }
    }
}
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue
@@ -42,7 +42,7 @@
                        </el-col>
                        <el-col :span="12">
                            <div class="label">巡查任务类型</div>
                            <div class="val">{{ getDictLabel(formData.patrolTaskType, dictObj.workOrderType) }}</div>
                            <div class="val">{{ getTaskTypeLabel(formData.patrolTaskType, workOrderTypeXT) }}</div>
                        </el-col>
                        <el-col :span="12">
                            <div class="label">任务执行时间</div>
@@ -58,7 +58,7 @@
                        </el-col>
                        <el-col :span="12">
                            <div class="label">推荐飞手</div>
                            <div class="val">{{ formData.recommendFlyerName }}</div>
                            <div class="val">{{ getFlyerName(formData.deviceFlyerId) }}</div>
                        </el-col>
                        <el-col :span="12">
                            <div class="label">选择设备</div>
@@ -71,6 +71,10 @@
                        <el-col :span="12">
                            <div class="label">巡查任务描述</div>
                            <div class="val">{{ formData.taskDesc }}</div>
                        </el-col>
                        <el-col :span="12">
                            <div class="label">算法</div>
                            <div class="val">{{ getAlgorithmNames(formData.algorithmIds) }}</div>
                        </el-col>
                    </el-row>
                    <template v-if="['6', '7', '8'].includes(taskStatus)">
@@ -107,20 +111,15 @@
                        </el-col>
                        <el-col :span="12">
                            <el-form-item label="巡查任务类型" prop="patrolTaskType">
                                <el-select
                                <el-cascader
                                    class="gd-select"
                                    popper-class="gd-select-popper"
                                    v-model="formData.patrolTaskType"
                                    :options="workOrderTypeXT"
                                    :props="taskTypeCascaderProps"
                                    placeholder="请选择"
                                    clearable
                                >
                                    <el-option
                                        v-for="item in dictObj.workOrderType"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                                />
                            </el-form-item>
                        </el-col>
                        <el-col :span="12">
@@ -149,16 +148,16 @@
                            </el-form-item>
                        </el-col>
                        <el-col :span="12">
                            <el-form-item label="推荐飞手" prop="recommendFlyerName">
                            <el-form-item label="推荐飞手" prop="deviceFlyerId">
                                <el-select
                                    class="gd-select"
                                    popper-class="gd-select-popper"
                                    v-model="formData.recommendFlyerName"
                                    v-model="formData.deviceFlyerId"
                                    placeholder="请选择"
                                    filterable
                                    clearable
                                >
                                    <el-option v-for="item in flyerList" :key="item.id" :label="item.flyerName" :value="item.flyerName" />
                                    <el-option v-for="item in flyerList" :key="item.id" :label="item.flyerName" :value="item.flyerId" />
                                </el-select>
                            </el-form-item>
                        </el-col>
@@ -179,6 +178,26 @@
                        <el-col :span="12">
                            <el-form-item label="关联工单">
                                <span>{{ getWorkOrderName(formData.workOrderId) }}</span>
                            </el-form-item>
                        </el-col>
                        <!-- 算法下拉 -->
                        <el-col :span="12">
                            <el-form-item label="算法" prop="algorithmIds">
                                <el-tree-select
                                    class="gd-select"
                                    popper-class="gd-tree-select-popper"
                                    v-model="formData.algorithmIds"
                                    :data="algorithmTreeData"
                                    :props="{ label: 'name', children: 'children', value: 'id' }"
                                    node-key="id"
                                    multiple
                                    collapse-tags
                                    collapse-tags-tooltip
                                    check-strictly
                                    filterable
                                    clearable
                                    placeholder="请选择"
                                />
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
@@ -212,7 +231,7 @@
            </div>
        </div>
        <template #footer>
        <template #footer v-if="detailLoaded">
            <el-button v-if="['1', '4', '7'].includes(taskStatus)" @click="viewDescription" color="#F2F3F5">
                {{ gdStatusObj[taskStatus].reason }}
            </el-button>
@@ -260,7 +279,7 @@
</template>
<script setup>
import { computed, ref, onMounted } from 'vue'
import { computed, ref, onMounted, inject } from 'vue'
import { ElMessage } from 'element-plus'
import { fieldRules, flyVisual, getDictLabel, geomAnalysis } from '@ztzf/utils'
import {
@@ -276,19 +295,21 @@
import { gdTaskResultListApi } from '@/views/orderView/orderManage/clueEvents/achievementApi'
import RefuseOrderDialog1 from '@/views/orderView/orderManage/inspectionRequest/RefuseOrderDialog1.vue'
import { Check } from '@element-plus/icons-vue'
import { queryAirById, airlineListApi } from '@/api/zkxt'
import { queryAirById, airlineListApi, algorithmGroupedApi } from '@/api/zkxt'
import * as Cesium from 'cesium'
import { useStore } from 'vuex'
import { getTaskTypeLabel, taskTypeCascaderProps, toTaskTypeCascaderValue, toTaskTypeRequestValue } from '../taskTypeOptions'
// 初始化表单数据
const initForm = () => ({
    id: null,
    patrolTaskName: '',
    patrolTaskType: '',
    patrolTaskType: [],
    executeTime: '',
    patrolRouteUrl: '',
    recommendFlyerName: '',
    deviceFlyerId: null,
    deviceId: null,
    algorithmIds: [],
    taskDesc: '',
    workOrderId: null,
})
@@ -304,6 +325,7 @@
const visible = defineModel()
const dialogMode = ref('view')
const submitting = ref(false)
const detailLoaded = ref(false)
const dialogReadonly = computed(() => dialogMode.value === 'view')
const titleEnum = ref({ edit: '编辑', view: '查看' })
const taskStatus = computed(() => formData.value.taskStatus)
@@ -316,6 +338,38 @@
const getAirName = id => {
    const item = routeOptions.value.find(item => item.id === id)
    return item ? item.name : id
}
const algorithmTreeData = ref([]) // 算法树形数据
const workOrderTypeXT = inject('workOrderTypeXT', ref([]))
// 获取算法分组数据
async function getAlgorithmList() {
    try {
        const res = await algorithmGroupedApi()
        const list = res?.data?.data ?? []
        algorithmTreeData.value = list.map(group => ({
            id: 'group_' + group.type,
            name: group.type,
            disabled: true,
            children: (group.algorithms || []).map(alg => ({
                id: alg.id,
                name: alg.name,
            }))
        }))
    } catch (e) {
        console.error('获取算法列表失败', e)
    }
}
// 根据 algorithmIds 数组获取算法名称,逗号分割回显
function getAlgorithmNames(algorithmIds) {
    if (!algorithmIds || !algorithmIds.length) return ''
    const allAlgorithms = algorithmTreeData.value.flatMap(group => group.children || [])
    return algorithmIds.map(id => {
        const item = allAlgorithms.find(alg => alg.id === id)
        return item ? item.name : id
    }).join(', ')
}
const gdStatusObj = {
@@ -338,7 +392,7 @@
    patrolTaskType: fieldRules(true),
    executeTime: fieldRules(true),
    patrolRouteUrl: fieldRules(true),
    recommendFlyerName: fieldRules(true),
    deviceFlyerId: fieldRules(true),
    deviceId: fieldRules(true),
}
@@ -382,6 +436,12 @@
function getDeviceName(id) {
    const item = deviceList.value.find(item => item.id === id)
    return item ? item.nickname : id
}
// 获取飞手名称
function getFlyerName(id) {
    const item = flyerList.value.find(item => item.flyerId === id)
    return item ? item.flyerName : id
}
// 获取工单名称
@@ -429,7 +489,11 @@
    if (!isValid) return
    submitting.value = true
    try {
        await gdPatrolTaskRepublish(formData.value)
        const payload = {
            ...formData.value,
            patrolTaskType: toTaskTypeRequestValue(formData.value.patrolTaskType),
        }
        await gdPatrolTaskRepublish(payload)
        ElMessage.success('更新成功')
        visible.value = false
        emit('success')
@@ -515,9 +579,21 @@
// 打开弹框
async function open({ mode = 'view', row } = {}) {
    detailLoaded.value = false
    dialogMode.value = mode
    const res = await gdPatrolTaskDetailApi({ id: row.id })
    formData.value = { ...initForm(), ...res.data.data }
    formData.value.patrolTaskType = toTaskTypeCascaderValue(formData.value.patrolTaskType)
    // 确保 algorithmIds 是数组
    if (formData.value.algorithmIds && typeof formData.value.algorithmIds === 'string') {
        formData.value.algorithmIds = formData.value.algorithmIds.split(',').filter(Boolean)
    } else if (!formData.value.algorithmIds) {
        formData.value.algorithmIds = []
    }
    detailLoaded.value = true
    // 获取算法列表
    getAlgorithmList()
    // 获取工单详情并根据geom范围获取航线列表
    await getWorkOrderDetail(formData.value.workOrderId)
    ;['6', '7', '8'].includes(row.taskStatus) && await getTaskResultList()
applications/task-work-order/src/views/orderView/orderManage/inspectionRequest/index.vue
@@ -11,11 +11,9 @@
            </el-form-item>
            <el-form-item label="任务类型" prop="patrolTaskType">
                <el-select class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.patrolTaskType"
                    placeholder="请选择" clearable @change="handleSearch">
                    <el-option v-for="item in dictObj.workOrderType" :key="item.dictKey" :label="item.dictValue"
                        :value="item.dictKey" />
                </el-select>
                <el-cascader class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.patrolTaskType"
                    :options="workOrderTypeXT" :props="taskTypeFilterCascaderProps" placeholder="请选择" clearable
                    @change="handleSearch" />
            </el-form-item>
            <el-form-item label="任务状态" prop="taskStatus">
@@ -55,7 +53,7 @@
                    <el-table-column prop="taskNo" show-overflow-tooltip label="巡查任务编号" />
                    <el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
                            {{ getTaskTypeLabel(row.patrolTaskType, workOrderTypeXT) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="taskStatus" show-overflow-tooltip label="巡查任务状态">
@@ -94,10 +92,12 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { getDictionaryByCode } from '@/api/system/dictbiz'
import { dateRangeFormat, getDictLabel } from '@ztzf/utils'
import { getDictListApi } from '@/api/zkxt'
import FormDiaLog from './FormDiaLog.vue'
import { gdPatrolTaskPageApi, gdPatrolTaskRemoveApi } from './inspectionRequestApi'
import ViewDiaLog from '@/views/orderView/orderManage/inspectionRequest/ViewDiaLog.vue'
import { useStore } from 'vuex'
import { getTaskTypeLabel, normalizeTaskTypeOptions, taskTypeFilterCascaderProps } from '../taskTypeOptions'
const store = useStore()
const permission = computed(() => store.state.user.permission)
@@ -130,8 +130,10 @@
    deviceLoadDemand: [], // 设备负载需求
    taskStatus: [], // 巡查任务状态
})
const workOrderTypeXT = ref([])
const activeName = ref('all')
provide('dictObj', dictObj)
provide('workOrderTypeXT', workOrderTypeXT)
const colors = {
    0: '#F6A000',//0待签收
@@ -213,6 +215,9 @@
    getDictionaryByCode('workOrderType,deviceLoadDemand,taskStatus').then(res => {
        dictObj.value = res.data.data
    })
    getDictListApi('task_inspection_type').then(res => {
        workOrderTypeXT.value = normalizeTaskTypeOptions(res.data.data || [])
    })
}
function refusalAccept (row) {
applications/task-work-order/src/views/orderView/orderManage/orderManage/FormDiaLog.vue
@@ -1,6 +1,6 @@
<template>
    <el-dialog
        class="gd-dialog"
        class="gd-dialog orderManageFormDlg"
        v-model="visible"
        :title="titleEnum[dialogMode]"
        @closed="visible = false"
@@ -31,7 +31,7 @@
                        </el-col>
                        <el-col :span="12">
                            <div class="label">工单类型</div>
                            <div class="val">{{ getDictLabel(formData.workOrderType, dictObj.workOrderType) }}</div>
                            <div class="val">{{ getTaskTypeLabel(formData.workOrderType, workOrderTypeXT) }}</div>
                        </el-col>
                        <el-col :span="12">
                            <div class="label">执行时间范围</div>
@@ -62,7 +62,7 @@
                            <el-table-column prop="patrolTaskName" show-overflow-tooltip label="巡查任务名称" />
                            <el-table-column prop="patrolTaskType" show-overflow-tooltip label="巡查任务类型">
                                <template v-slot="{ row }">
                                    {{ getDictLabel(row.patrolTaskType, dictObj.workOrderType) }}
                                    {{ getTaskTypeLabel(row.patrolTaskType, workOrderTypeXT) }}
                                </template>
                            </el-table-column>
                            <el-table-column prop="taskStatus" show-overflow-tooltip label="任务状态">
@@ -94,20 +94,15 @@
                        </el-col>
                        <el-col :span="12">
                            <el-form-item label="工单类型" prop="workOrderType">
                                <el-select
                                <el-cascader
                                    class="gd-select"
                                    popper-class="gd-select-popper"
                                    v-model="formData.workOrderType"
                                    :options="workOrderTypeXT"
                                    :props="taskTypeCascaderProps"
                                    placeholder="请选择"
                                    clearable
                                >
                                    <el-option
                                        v-for="item in dictObj.workOrderType"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                                />
                            </el-form-item>
                        </el-col>
                        <el-col :span="12">
@@ -156,7 +151,7 @@
                        </el-col>
                    </el-row>
                </el-form>
                <div class="detail-title" :style="{ marginTop: pxToRem(20) }">
                <div class="detail-title" :style="{ marginTop: pxToRem(10) }">
                    <span class="required-star" v-if="!dialogReadonly">*</span>
                    工单执行范围
                </div>
@@ -195,7 +190,7 @@
            </div>
        </div>
        <template #footer v-if="activeName === 'basic'">
        <template #footer v-if="activeName === 'basic' && detailLoaded">
            <el-button v-if="['11', '21', '23', '31', '60'].includes(gdStatus)" @click="viewDescription" color="#F2F3F5">
                {{ gdStatusObj[gdStatus]?.reason }}
            </el-button>
@@ -262,7 +257,7 @@
</template>
<script setup>
import { computed, ref, nextTick } from 'vue'
import { computed, ref, nextTick, inject } from 'vue'
import { ElMessage } from 'element-plus'
import { dateRangeFormat, fieldRules, flyVisual, geomAnalysis, getDictLabel } from '@ztzf/utils'
import {
@@ -286,6 +281,8 @@
import { useStore } from 'vuex'
import OrderStepBar from '@/views/orderView/orderManage/orderManage/OrderStepBar.vue'
import OutcomeData from './outcomeData.vue'
import { getDictListApi } from '@/api/zkxt'
import { getTaskTypeLabel, taskTypeCascaderProps, toTaskTypeCascaderValue, toTaskTypeRequestValue } from '../taskTypeOptions'
const store = useStore()
const permission = computed(() => store.state.user.permission)
const activeName = ref('basic')
@@ -293,7 +290,7 @@
// 初始化表单数据
const initForm = () => ({
    workOrderName: '',
    workOrderType: '',
    workOrderType: [],
    executeStartTime: '',
    executeEndTime: '',
    deviceLoadDemand: '',
@@ -305,6 +302,7 @@
const mapRef = ref(null)
const rejectVisible = ref(false)
const dictObj = inject('dictObj')
const workOrderTypeXT = inject('workOrderTypeXT', ref([]))
const dateRange = ref([])
const patrolTaskList = ref([])
const emit = defineEmits(['success'])
@@ -313,6 +311,7 @@
const visible = defineModel() // 弹框显隐
const dialogMode = ref('add') // 弹框模式
const submitting = ref(false) // 提交中
const detailLoaded = ref(false) // 详情加载完成
const dialogReadonly = computed(() => dialogMode.value === 'view')
const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
const deviceList = ref([]) // 设备列表
@@ -454,7 +453,11 @@
        if (!formData.value.id) {
            formData.value.workOrderStatus = '10'
        }
        await gdWorkOrderSaveApi(formData.value)
        const payload = {
            ...formData.value,
            workOrderType: toTaskTypeRequestValue(formData.value.workOrderType),
        }
        await gdWorkOrderSaveApi(payload)
        ElMessage.success(dialogMode.value === 'add' ? '新增成功' : '更新成功')
        visible.value = false
        emit('success')
@@ -476,6 +479,7 @@
    loadList()
    const res = await gdWorkOrderDetailApi({ id: formData.value.id })
    formData.value = res?.data?.data ?? {}
    formData.value.workOrderType = toTaskTypeCascaderValue(formData.value.workOrderType)
    dateRange.value = [formData.value.executeStartTime, formData.value.executeEndTime]
}
@@ -631,6 +635,7 @@
// 打开弹框
async function open({ mode = 'add', row } = {}) {
    detailLoaded.value = false
    dialogMode.value = mode
    getPayloadList()
    initMap()
@@ -645,6 +650,7 @@
        hasPatrolTaskList.value && gdPatrolTaskPage()
        dialogMode.value === 'edit' ? editPolygon() : viewPolygon()
    }
    detailLoaded.value = true
    await nextTick()
    await getDeviceList()
@@ -691,7 +697,20 @@
defineExpose({ open })
</script>
<style lang="scss" scoped>
<style lang="scss">
.orderManageFormDlg{
        .el-dialog__body{
            display: flex;
            flex-direction: column;
            .content{
                height: 0;
                flex: 1;
            }
        }
}
</style>
<style scoped lang="scss">
.separateTable {
    height: 0;
    flex: 1;
@@ -704,10 +723,12 @@
        }
    }
}
.content {
    display: flex;
    gap: 0 20px;
    height: 630px;
    //height: 630px;
    .leftBox {
        width: 0;
@@ -718,10 +739,9 @@
        .gd-cesium {
            position: relative;
            overflow: hidden;
            //overflow: hidden;
            width: 100%;
            min-height: 360px;
            flex: 1;
            height: 390px;
        }
    }
applications/task-work-order/src/views/orderView/orderManage/orderManage/index.vue
@@ -11,11 +11,9 @@
            </el-form-item>
            <el-form-item label="工单类型" prop="workOrderType">
                <el-select class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.workOrderType"
                    placeholder="请选择" clearable @change="handleSearch">
                    <el-option v-for="item in dictObj.workOrderType" :key="item.dictKey" :label="item.dictValue"
                        :value="item.dictKey" />
                </el-select>
                <el-cascader class="gd-select gray" popper-class="gd-select-popper" v-model="searchParams.workOrderType"
                    :options="workOrderTypeXT" :props="taskTypeFilterCascaderProps" placeholder="请选择" clearable
                    @change="handleSearch" />
            </el-form-item>
            <el-form-item label="工单状态" prop="workOrderStatus">
@@ -53,7 +51,7 @@
                    <el-table-column prop="workOrderCode" show-overflow-tooltip label="工单编号" />
                    <el-table-column prop="workOrderType" show-overflow-tooltip label="工单类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.workOrderType, dictObj.workOrderType) }}
                            {{ getTaskTypeLabel(row.workOrderType, workOrderTypeXT) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="status" show-overflow-tooltip label="阶段状态">
@@ -103,6 +101,7 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { getDictionaryByCode } from '@/api/system/dictbiz'
import { dateRangeFormat, getDictLabel } from '@ztzf/utils'
import { getDictListApi } from '@/api/zkxt'
import FormDiaLog from './FormDiaLog.vue'
import { gdWorkOrderPageApi, gdWorkOrderRemoveApi } from './orderManageApi'
import dayjs from 'dayjs'
@@ -110,6 +109,7 @@
import testDock from '@/assets/docx/testDocx.docx'
import testPdf from '@/assets/pdf/testPdf.pdf'
import { useStore } from 'vuex'
import { getTaskTypeLabel, normalizeTaskTypeOptions, taskTypeFilterCascaderProps } from '../taskTypeOptions'
const store = useStore()
const activeName = ref('all')
@@ -143,7 +143,9 @@
    workOrderType: [], // 工单类型
    workOrderStatus: [], // 工单状态
})
const workOrderTypeXT = ref([])
provide('dictObj', dictObj)
provide('workOrderTypeXT', workOrderTypeXT)
// 获取列表
async function getList () {
@@ -246,6 +248,9 @@
    getDictionaryByCode('deviceLoadDemand,workOrderType,workOrderStatus,taskStatus').then(res => {
        dictObj.value = res.data.data
    })
    getDictListApi('task_inspection_type').then(res => {
        workOrderTypeXT.value = normalizeTaskTypeOptions(res.data.data || [])
    })
}
// 获取两个tab的总条数
applications/task-work-order/src/views/orderView/orderManage/taskTypeOptions.js
New file
@@ -0,0 +1,105 @@
function parseRemarkOptions(remark) {
    if (Array.isArray(remark)) return remark
    if (!remark || typeof remark !== 'string') return []
    try {
        const options = JSON.parse(remark)
        return Array.isArray(options) ? options : []
    } catch (error) {
        return []
    }
}
export function normalizeTaskTypeOptions(list = []) {
    return list.map(item => {
        const remarkOptions = parseRemarkOptions(item.remark)
            .map(option => ({
                ...option,
                dictLabel: option.label,
                dictValue: option.value,
            }))
            .sort((a, b) => (a.sort ?? 0) - (b.sort ?? 0))
        return {
            ...item,
            remarkOptions,
            children: remarkOptions,
        }
    })
}
function isValidPath(value) {
    return (
        Array.isArray(value) &&
        value.length === 2 &&
        value.every(item => item !== undefined && item !== null && item !== '' && !Array.isArray(item) && typeof item !== 'object')
    )
}
function parseTaskTypeValue(value) {
    if (typeof value !== 'string') return value
    try {
        const result = JSON.parse(value)
        return Array.isArray(result) ? result : value
    } catch (error) {
        return value
    }
}
export function toTaskTypeCascaderValue(value) {
    value = parseTaskTypeValue(value)
    if (!value) return []
    if (typeof value === 'string') return []
    if (!Array.isArray(value)) return []
    if (isValidPath(value)) return [value]
    if (value.length === 1 && Array.isArray(value[0]) && !isValidPath(value[0])) {
        value = value[0]
    }
    return value.filter(isValidPath)
}
export function toTaskTypeRequestValue(value) {
    return toTaskTypeCascaderValue(value).map(item => [item[0], item[1]])
}
export function getTaskTypeLeafValues(value) {
    return toTaskTypeRequestValue(value).map(item => item[1])
}
export function getTaskTypeLabel(value, options = []) {
    const paths = toTaskTypeCascaderValue(value)
    if (paths.length) {
        return paths
            .map(path => {
                const parent = options.find(item => item.dictValue === path[0])
                const child = (parent?.children || []).find(item => item.dictValue === path[1])
                return child?.dictLabel || path[1]
            })
            .join('、')
    }
    if (!value) return ''
    for (const item of options) {
        if (item.dictValue === value) return item.dictLabel
        const child = (item.children || []).find(option => option.dictValue === value)
        if (child) return child.dictLabel
    }
    return value
}
export const taskTypeCascaderProps = {
    label: 'dictLabel',
    value: 'dictValue',
    children: 'children',
    multiple: true,
    emitPath: true,
    checkStrictly: false,
}
export const taskTypeFilterCascaderProps = {
    label: 'dictLabel',
    value: 'dictValue',
    children: 'children',
    emitPath: false,
    checkStrictly: false,
}
packages/utils/common/index.js
@@ -38,6 +38,16 @@
        .join(',');
}
// id转label xt
export function getDictLabelXT(value, dictList = []) {
    if (value === null || value === undefined || value === '') return '';
    const values = String(value).split(',');
    return dictList
        .filter(item => values.includes(String(item.dictValue)))
        .map(item => item.dictLabel)
        .join(',');
}
export function blobDownload(res) {
    const disposition = res.headers?.['content-disposition'] || res.headers?.['Content-Disposition']
    const encodedName = disposition.split('filename=')[1]
uniapps/work-app/src/pages/login/index.vue
@@ -201,8 +201,8 @@
    tenantId: "000000",
    deptId: "",
    roleId: "",
    username: loginFormGd.value.username,
    password: loginFormGd.value.password,
    username: loginForm.value.username,
    password: loginForm.value.username === 'admin' ? 'admin' : 'jadk@2026',
    type: "account",
    code: "",
    key: "",