15 files modified
1 files added
| | |
| | | - 文件与目录保持 kebabCase,遵循现有应用与包的命名风格。 |
| | | |
| | | ## 测试指南 |
| | | - 当前未配置测试框架(`pnpm test` 会直接退出)。 |
| | | - 若新增测试,请在对应应用 `README.md` 说明测试框架,并补充根目录脚本。 |
| | | - 无需任何测试 |
| | | |
| | | ## 提交与合并请求规范 |
| | | - 提交历史使用简短的约定式主题(如 `feat: ...`)。 |
| | |
| | | Prefer minimal changes. |
| | | - 未被明确要求时,禁止大规模重构。 |
| | | Avoid large refactors unless requested. |
| | | - 修改完不需要走打包编译校验 |
| | |
| | | </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> |
| | |
| | | const titleEnum = ref({ view: '查看' }) |
| | | const dictObj = inject('dictObj') |
| | | |
| | | console.log(formData.value, '9090') |
| | | console.log(dictObj.value, '8080') |
| | | |
| | | // 关闭弹框 |
| | | function handleCancel() { |
| | | visible.value = false |
| | |
| | | </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> |
| | |
| | | }); |
| | | }; |
| | | |
| | | export const getDeptTree = tenantId => { |
| | | export const getDeptTree = id => { |
| | | return request({ |
| | | url: '/blade-system/dept/getTree', |
| | | method: 'get', |
| | | params: { |
| | | tenantId, |
| | | id, |
| | | }, |
| | | }); |
| | | }; |
| | |
| | | }) |
| | | } |
| | | |
| | | // 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', |
| | | }) |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | .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; |
| | |
| | | <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 |
| | |
| | | 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 |
| | |
| | | </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"> |
| | |
| | | <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="巡查任务状态"> |
| | |
| | | <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> |
| | |
| | | </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 = () => ({ |
| | |
| | | workOrderType: [], // 巡查任务类型 |
| | | taskStatus: [], // 巡查任务状态 |
| | | }) |
| | | const workOrderTypeXT = ref([]) |
| | | |
| | | provide('dictObj', dictObj) |
| | | provide('workOrderTypeXT', workOrderTypeXT) |
| | | provide('deptTree', deptTree) |
| | | provide('treeProps', treeProps) |
| | | |
| | |
| | | ...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 |
| | |
| | | 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 |
| | | }) |
| | | } |
| | |
| | | :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> |
| | |
| | | <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> |
| | |
| | | <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> |
| | | 巡查任务名称 |
| | |
| | | /> |
| | | </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> |
| | | 任务执行时间 |
| | |
| | | <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" |
| | |
| | | /> |
| | | </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> |
| | | 巡查任务航线 |
| | |
| | | </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> |
| | | 推荐飞手 |
| | |
| | | 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 显示红星号 --> |
| | |
| | | </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> |
| | | 选择设备 |
| | |
| | | </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> |
| | |
| | | </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') |
| | |
| | | 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()]) |
| | |
| | | // 将工单类型赋值给所有子任务行 |
| | | 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 { |
| | |
| | | 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) |
| | |
| | | // 处理巡查任务类型变化 |
| | | async function handlePatrolTaskTypeChange(index, skilledTaskType) { |
| | | // 清空该行已选择的飞手 |
| | | taskList.value[index].recommendFlyerName = '' |
| | | taskList.value[index].deviceFlyerId = '' |
| | | // 获取对应的飞手列表 |
| | | await getFlyerList(index, skilledTaskType) |
| | | } |
| | | |
| | | |
| | | |
| | | import * as turf from '@turf/turf' |
| | | |
| | |
| | | |
| | | // 获取飞手列表 |
| | | 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 || '', |
| | | }) |
| | |
| | | |
| | | // 判断一行是否已填写(至少填写了任务名称) |
| | | 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 |
| | | } |
| | | |
| | | // 提交新增 |
| | |
| | | ElMessage.warning(`第${i + 1}行: 请输入巡查任务名称`) |
| | | return |
| | | } |
| | | if (!task.patrolTaskType) { |
| | | if (!hasTaskTypeValue(task.patrolTaskType)) { |
| | | ElMessage.warning(`第${i + 1}行: 请选择巡查任务类型`) |
| | | return |
| | | } |
| | |
| | | ElMessage.warning(`第${i + 1}行: 请选择巡查任务航线`) |
| | | return |
| | | } |
| | | if (!task.recommendFlyerName) { |
| | | if (!task.deviceFlyerId) { |
| | | ElMessage.warning(`第${i + 1}行: 请选择推荐飞手`) |
| | | return |
| | | } |
| | |
| | | // 只提交已填写的任务行 |
| | | const dataList = filledTasks.map(item => ({ |
| | | ...item, |
| | | patrolTaskType: toTaskTypeRequestValue(item.patrolTaskType), |
| | | workOrderId: selectedWorkOrderId.value, |
| | | id: undefined, |
| | | })) |
| | |
| | | async function open({ mode = 'add', row } = {}) { |
| | | dialogMode.value = mode |
| | | await getWorkOrderList() |
| | | getAlgorithmList() |
| | | |
| | | if (dialogMode.value === 'add') { |
| | | selectedWorkOrderId.value = null |
| | | selectedWorkOrder.value = null |
| | |
| | | // 编辑/查看模式 - 加载已有数据 |
| | | 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) |
| | | } |
| | | } |
| | | } |
| | |
| | | </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> |
| | |
| | | </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> |
| | |
| | | <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)"> |
| | |
| | | </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"> |
| | |
| | | </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> |
| | |
| | | <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"> |
| | |
| | | </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> |
| | |
| | | </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 { |
| | |
| | | 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, |
| | | }) |
| | |
| | | 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) |
| | |
| | | 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 = { |
| | |
| | | patrolTaskType: fieldRules(true), |
| | | executeTime: fieldRules(true), |
| | | patrolRouteUrl: fieldRules(true), |
| | | recommendFlyerName: fieldRules(true), |
| | | deviceFlyerId: fieldRules(true), |
| | | deviceId: fieldRules(true), |
| | | } |
| | | |
| | |
| | | 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 |
| | | } |
| | | |
| | | // 获取工单名称 |
| | |
| | | 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') |
| | |
| | | |
| | | // 打开弹框 |
| | | 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() |
| | |
| | | </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"> |
| | |
| | | <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="巡查任务状态"> |
| | |
| | | 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) |
| | |
| | | deviceLoadDemand: [], // 设备负载需求 |
| | | taskStatus: [], // 巡查任务状态 |
| | | }) |
| | | const workOrderTypeXT = ref([]) |
| | | const activeName = ref('all') |
| | | provide('dictObj', dictObj) |
| | | provide('workOrderTypeXT', workOrderTypeXT) |
| | | |
| | | const colors = { |
| | | 0: '#F6A000',//0待签收 |
| | |
| | | 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) { |
| | |
| | | <template> |
| | | <el-dialog |
| | | class="gd-dialog" |
| | | class="gd-dialog orderManageFormDlg" |
| | | v-model="visible" |
| | | :title="titleEnum[dialogMode]" |
| | | @closed="visible = false" |
| | |
| | | </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> |
| | |
| | | <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="任务状态"> |
| | |
| | | </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"> |
| | |
| | | </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> |
| | |
| | | </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> |
| | |
| | | </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 { |
| | |
| | | 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') |
| | |
| | | // 初始化表单数据 |
| | | const initForm = () => ({ |
| | | workOrderName: '', |
| | | workOrderType: '', |
| | | workOrderType: [], |
| | | executeStartTime: '', |
| | | executeEndTime: '', |
| | | deviceLoadDemand: '', |
| | |
| | | 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']) |
| | |
| | | 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([]) // 设备列表 |
| | |
| | | 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') |
| | |
| | | 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] |
| | | } |
| | | |
| | |
| | | |
| | | // 打开弹框 |
| | | async function open({ mode = 'add', row } = {}) { |
| | | detailLoaded.value = false |
| | | dialogMode.value = mode |
| | | getPayloadList() |
| | | initMap() |
| | |
| | | hasPatrolTaskList.value && gdPatrolTaskPage() |
| | | dialogMode.value === 'edit' ? editPolygon() : viewPolygon() |
| | | } |
| | | detailLoaded.value = true |
| | | |
| | | await nextTick() |
| | | await getDeviceList() |
| | |
| | | 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; |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | .content { |
| | | display: flex; |
| | | gap: 0 20px; |
| | | height: 630px; |
| | | //height: 630px; |
| | | |
| | | .leftBox { |
| | | width: 0; |
| | |
| | | |
| | | .gd-cesium { |
| | | position: relative; |
| | | overflow: hidden; |
| | | //overflow: hidden; |
| | | width: 100%; |
| | | min-height: 360px; |
| | | flex: 1; |
| | | height: 390px; |
| | | } |
| | | } |
| | | |
| | |
| | | </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"> |
| | |
| | | <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="阶段状态"> |
| | |
| | | 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' |
| | |
| | | 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') |
| | |
| | | workOrderType: [], // 工单类型 |
| | | workOrderStatus: [], // 工单状态 |
| | | }) |
| | | const workOrderTypeXT = ref([]) |
| | | provide('dictObj', dictObj) |
| | | provide('workOrderTypeXT', workOrderTypeXT) |
| | | |
| | | // 获取列表 |
| | | async function getList () { |
| | |
| | | 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的总条数 |
| New file |
| | |
| | | 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, |
| | | } |
| | |
| | | .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] |
| | |
| | | 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: "", |