无人机管理后台前端(已迁走)
张含笑
2025-09-23 aa978b64011a887fdad0cf98ccce904f4b25d6b5
Merge branch 'refs/heads/feature/v6.0/6.0.3' into feature/v6.0/6.0.4
33 files modified
1 files added
1348 ■■■■■ changed files
.env.production 2 ●●●●● patch | view | raw | blame | history
src/api/device/device.js 12 ●●●● patch | view | raw | blame | history
src/api/home/aggregation.js 14 ●●●● patch | view | raw | blame | history
src/api/job/task.js 8 ●●●● patch | view | raw | blame | history
src/components/commonDialog.vue 48 ●●●●● patch | view | raw | blame | history
src/option/system/dict.js 2 ●●● patch | view | raw | blame | history
src/option/system/dictbiz.js 2 ●●● patch | view | raw | blame | history
src/page/index/tags.vue 2 ●●● patch | view | raw | blame | history
src/styles/common.scss 1 ●●●● patch | view | raw | blame | history
src/styles/element-ui.scss 70 ●●●●● patch | view | raw | blame | history
src/utils/cesium/createRouteLine.js 35 ●●●●● patch | view | raw | blame | history
src/views/algorithmMange/algorithmMange.vue 153 ●●●●● patch | view | raw | blame | history
src/views/dataCenter/components/dataCenterMap.vue 3 ●●●● patch | view | raw | blame | history
src/views/dataCenter/dataCenter.vue 2 ●●●●● patch | view | raw | blame | history
src/views/device/addDevice.vue 75 ●●●● patch | view | raw | blame | history
src/views/device/airport.vue 218 ●●●● patch | view | raw | blame | history
src/views/device/components/DockControlPanel.vue 1 ●●●● patch | view | raw | blame | history
src/views/device/components/devicePerShare.vue 44 ●●●● patch | view | raw | blame | history
src/views/device/components/firmwareManage.vue 14 ●●●●● patch | view | raw | blame | history
src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue 9 ●●●● patch | view | raw | blame | history
src/views/job/components/TaskTop/TaskEvent.vue 5 ●●●● patch | view | raw | blame | history
src/views/job/components/TaskTop/TaskIndustry.vue 16 ●●●●● patch | view | raw | blame | history
src/views/job/components/TaskTop/TaskTime.vue 16 ●●●● patch | view | raw | blame | history
src/views/license/license.vue 15 ●●●● patch | view | raw | blame | history
src/views/resource/components/DrawPolygon.vue 5 ●●●●● patch | view | raw | blame | history
src/views/resource/components/spotDetails.vue 266 ●●●● patch | view | raw | blame | history
src/views/resource/patchManagement.vue 21 ●●●● patch | view | raw | blame | history
src/views/resource/patchTypeManagement.vue 17 ●●●● patch | view | raw | blame | history
src/views/system/param.vue 1 ●●●● patch | view | raw | blame | history
src/views/system/userinfo.vue 18 ●●●● patch | view | raw | blame | history
src/views/tickets/orderLog.vue 143 ●●●● patch | view | raw | blame | history
src/views/tickets/ticket.vue 66 ●●●●● patch | view | raw | blame | history
src/views/wel/components/backlog.vue 20 ●●●●● patch | view | raw | blame | history
src/views/wel/components/proportionStatic.vue 24 ●●●● patch | view | raw | blame | history
.env.production
@@ -33,6 +33,8 @@
# 算法仓库图片地址
VITE_APP_PICTURE_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket
# 行政区划存放地址
VITE_APP_REGION_URL = https://wrj.shuixiongit.com/aiskyminio/cloud-bucket/ztzf_region
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
src/api/device/device.js
@@ -145,9 +145,9 @@
}
// 注销
export const deviceOffline = (dockSn) => {
export const deviceOffline = (dockSn, deleteFlag) => {
  return request({
    url: `/drone-device-core/manage/api/v1/devices/deviceOffline?dockSn=${dockSn}`,
    url: `/drone-device-core/manage/api/v1/devices/deviceOffline?dockSn=${dockSn}&deleteFlag=${deleteFlag}`,
    method: 'get',
  })
}
@@ -159,4 +159,12 @@
    method: 'post',
    data: param
  })
}
export const devicesUpAndDown = (param) => {
  return request({
    url: `/drone-device-core/manage/api/v1/devices/upAndDown`,
    method: 'post',
    data: param
  })
}
src/api/home/aggregation.js
@@ -8,19 +8,11 @@
    })
}
export const getDeviceRegion = params => {
export const getDeviceRegion = data => {
    return request({
        url: '/drone-device-core/manage/api/v1/devices/getDeviceRegion',
        method: 'get',
        params,
    })
}
export const getDeviceRegionByPost = data => {
    return request({
        url: '/drone-device-core/manage/api/v1/devices/getDeviceRegion',
        method: 'post',
        data,
    method: 'post',
    data:{ hidden_flag:0, ...data },
    })
}
src/api/job/task.js
@@ -190,11 +190,11 @@
    })
}
export const getDeviceRegion = params => {
export const getDeviceRegion = data => {
    return request({
        url: '/drone-device-core/manage/api/v1/devices/getDeviceRegion',
        method: 'get',
        params,
        method: 'post',
        data:{ hidden_flag:0, ...data },
    })
}
@@ -255,4 +255,4 @@
        method: 'post',
        data: data,
    })
}
}
src/components/commonDialog.vue
New file
@@ -0,0 +1,48 @@
<template>
  <el-dialog class="ztzf-dialog-mange" append-to-body v-model="props.isShowView" :title="props.title"
             :width="props.width" :close-on-click-modal="false" :destroy-on-close="true" @close="cancel">
    <slot name="default" />
    <template #footer v-if="props.addEditView !== 'view'">
      <div class="dialog-footer">
        <el-button v-if="props.addEditView === 'add'" type="primary" @click="submit" :icon="CirclePlus">保存</el-button>
        <el-button v-else type="primary" @click="submit" :icon="CircleCheck">确认</el-button>
        <el-button @click="cancel"  :icon="CircleClose">取消</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { Delete, Search, CircleCheck, CircleClose, CirclePlus } from '@element-plus/icons-vue'
import { defineEmits } from 'vue';
const emit = defineEmits(['cancel', 'confirm']);
const props = defineProps({
  width: {
    type: String,
    default: '800'
  },
  isShowView: {
    type: Boolean,
    default: false
  },
  addEditView: {
    type: String,
    default: 'add'
  },
  title:{
    type: String,
    default: ''
  }
})
function submit() {
  emit('submit')
}
function cancel() {
  emit('cancel')
}
</script>
<style scoped lang="scss">
</style>
src/option/system/dict.js
@@ -6,7 +6,7 @@
  index: true,
  selection: true,
  viewBtn: true,
  menuWidth: 250,
  menuWidth: 280,
  dialogWidth: 880,
  dialogClickModal: false,
src/option/system/dictbiz.js
@@ -6,7 +6,7 @@
  index: true,
  selection: true,
  viewBtn: true,
  menuWidth: 250,
  menuWidth: 280,
  dialogWidth: 880,
  dialogClickModal: false,
src/page/index/tags.vue
@@ -23,7 +23,7 @@
      <el-dropdown class="avue-tags__menu">
        <el-button type="primary" style="background: #409eff;border-color: #409eff">
          {{ $t('tagsView.menu') }}
          <i class="el-icon-arrow-down el-icon--right"></i>
          <!-- <i class="el-icon-arrow-down el-icon--right"></i> -->
        </el-button>
        <template #dropdown>
          <el-dropdown-menu>
src/styles/common.scss
@@ -2,6 +2,7 @@
@import './variables.scss';
@import './base.scss';
@import './tool.scss';
@import './element-ui.scss';
a {
  text-decoration: none;
  color: #333;
src/styles/element-ui.scss
@@ -138,4 +138,74 @@
      }
    }
  }
}
//======以下针对表格功能 增删查改样式和弹窗=========
.ztzf-dialog-mange {
  .el-dialog__body {
    padding: 2rem 2rem 4rem;
    flex: 1;
    overflow: scroll;
    border-top: 0.1rem solid #f0f0f0;
  }
  .el-dialog__footer {
    z-index: 2;
    display: block;
    padding: 1rem 1.6rem;
    box-sizing: border-box;
    border-top: 0.1rem solid #f0f0f0;
    width: 100%;
    position: absolute;
    left: 0;
    bottom: 0;
    background-color: #fff;
    text-align: right;
  }
}
.ztzf-search-mange {
  height: 40px;
  .search-contain {
    display: flex;justify-content: space-between;
  }
}
.ztzf-form-mange {
  .el-form-item {
    width: 300px;
    :deep(.el-form-item__label) {
      width: 120px;
    }
  }
}
.ztzf-table-mange {
  th.el-table__cell  {
    color: rgba(0, 0, 0, .85);
    background-color: #fafafa;
  }
}
.table-view-mange {
  width: 100%;
  border-top: 0.1rem solid #ebeef5;
  border-left: 0.1rem solid #ebeef5;
  margin-left: 0;
  margin-right: 0;
  .el-col {
    padding-left: 0;
    padding-right: 0;
    margin-bottom: 0;
    height: 32px;
    line-height: 32px;
    border-right: 0.1rem solid #ebeef5;
    text-align: center;
    align-items: center;
    .el-input__wrapper {
      box-shadow: none !important;
      border-bottom: 0.1rem solid #ebeef5;
    }
  }
  .label {
    color: #909399;
    box-sizing: border-box;
    background: #fafafa;
  }
}
src/utils/cesium/createRouteLine.js
@@ -36,6 +36,34 @@
    speed: 5
})
let arrowLineMaterialPropertyOrange = new ArrowLineMaterialProperty({
    color: new Cesium.Color(255 / 255, 185 / 255, 58 / 255, 1),
    directionColor: new Cesium.Color(1, 1, 1, 1),
    outlineColor: new Cesium.Color(1, 1, 1, 1),
    outlineWidth: 0,
    speed: 5,
})
let arrowLineMaterialPropertyGreen = new ArrowLineMaterialProperty({
    color: new Cesium.Color(6 / 255, 217 / 255, 87 / 255, 1),
    directionColor: new Cesium.Color(1, 1, 1, 1),
    outlineColor: new Cesium.Color(1, 1, 1, 1),
    outlineWidth: 0,
    speed: 5,
})
// 记录index
let indexLog = 0
// 颜色
function getLineColor(lineNumber) {
    // 颜色顺序: 蓝(0), 黄(1), 绿(2)
    const colors = [arrowLineMaterialProperty, arrowLineMaterialPropertyOrange, arrowLineMaterialPropertyGreen]
    // 计算颜色索引 (从0开始)
    const colorIndex = (lineNumber - 1) % 3
    // 返回对应颜色
    return colors[colorIndex]
}
let runningLineMaterial = new LineTrailMaterial({
    color: Cesium.Color.fromCssColorString('#1FFF69'),
    opacity: 1,
@@ -94,6 +122,7 @@
     * @param {*} viewer 
     */
    initCreateRoute (viewer) {
        indexLog = 0
        this.viewer = viewer
    }
@@ -469,7 +498,7 @@
     */
    async drawPointRoute (lineObj, missionConfig, dronePosition, data, startPoint, isShowDock, isShowPointBillboard, wayline_type) {
        const { positionArray, filePositions } = this.disposeData(lineObj, missionConfig, dronePosition, data, startPoint, wayline_type)
        const droneTransformPosition = Cesium.Cartesian3.fromDegrees(
            Number(dronePosition.longitude),
            Number(dronePosition.latitude),
@@ -478,6 +507,7 @@
        // 路径线
        let polyline
        if (this.type === 'clusterScheduling') {
            filePositions.forEach((item, index) => {
@@ -630,7 +660,7 @@
                polyline: {
                    width: 4,
                    positions: positionArray,
                    material: arrowLineMaterialProperty,
                    material: getLineColor(indexLog),
                    clampToGround: false,
                },
@@ -681,6 +711,7 @@
     * @returns {} {positionArray: 带拼接点位置, filePositions:光航线点位置}
     */
    disposeData (lineObj, missionConfig, dronePosition, data, startPoint, wayline_type) {
        indexLog = indexLog + 1
        const { device_sn } = data
        const executeHeightMode = lineObj.executeHeightMode === "WGS84"
src/views/algorithmMange/algorithmMange.vue
@@ -1,30 +1,27 @@
<template>
  <div class="algorithmMange">
    <div class="search-box">
    <div class="ztzf-search-mange">
      <el-form :model="params" inline>
       <div style="display: flex;justify-content: space-between;">
       <div class="search-contain">
        <div>
          <el-form-item label="算法名称:">
          <el-input v-model="params.algName" placeholder="请输入算法名称" clearable />
        </el-form-item>
        <el-form-item label="算法类型:">
          <el-select class="ztzf-select" :teleported="false" v-model="params.algTypeCode" placeholder="请选择算法类型" clearable>
            <el-option v-for="item in sfTypes" :key="item.id" :label="item.dictValue" :value="item.dictKey" ></el-option>
          </el-select>
        </el-form-item>
        </div>
        <div>
          <el-form-item  class="btns">
            <el-button type="primary" @click="getList">搜索</el-button>
            <el-button @click="cancelSearch">清空</el-button>
            <el-input v-model="params.algName" placeholder="请输入算法名称" clearable />
          </el-form-item>
          <el-form-item label="算法类型:">
            <el-select class="ztzf-select" :teleported="false" v-model="params.algTypeCode" placeholder="请选择算法类型" clearable>
              <el-option v-for="item in sfTypes" :key="item.id" :label="item.dictValue" :value="item.dictKey" ></el-option>
            </el-select>
          </el-form-item>
        </div>
        <div class="btns">
            <el-button type="primary" @click="getList" :icon="Search">搜索</el-button>
            <el-button @click="cancelSearch" :icon="Delete">清空</el-button>
        </div>
       </div>
      </el-form>
    </div>
    <div class="mange-table">
            <el-table border :data="tableList" class="custom-header">
            <el-table border :data="tableList" class="ztzf-table-mange">
                <el-table-column label="序号" type="index" width="60"></el-table-column>
        <el-table-column prop="model_name" label="算法名称" align="center" show-overflow-tooltip></el-table-column>
        <el-table-column prop="alg_type" label="算法类型" align="center"></el-table-column>
@@ -60,40 +57,42 @@
        </div>
        <div class="pagination">
            <el-pagination class="ztzf-pagination" popper-class="custom-pagination-dropdown" background
                :page-sizes="[10, 20, 30, 40, 50, 100]" :size="size" v-model:current-page="params.current"
                :page-sizes="[10, 20, 30, 40, 50, 100]" :size="params.size" v-model:current-page="params.current"
                v-model:page-size="params.size" layout="total, sizes, prev, pager, next, jumper" :total="total"
                @size-change="handleSizeChange" @current-change="handleCurrentChange" />
        </div>
  </div>
  <el-dialog class="ztzf-dialog" append-to-body v-model="isShowView" title="查看"
        :width="pxToRem(600)" :close-on-click-modal="false" :destroy-on-close="true">
        <div class="content">
      <table class="view-table" border>
        <tr>
          <td class="label">算法名称</td>
          <td class="value">{{ rowView.model_name }}</td>
          <td class="label">算法类型</td>
          <td class="value">{{ rowView.alg_type }}</td>
        </tr>
        <tr>
          <td class="label">最低准确率</td>
          <td class="value">{{ rowView.qua_rate }}</td>
          <td class="label">最高准确率</td>
          <td class="value">{{ rowView.pass_rate }}</td>
        </tr>
        <tr>
          <td class="label">事件生成类型</td>
          <td class="value">{{ rowView.event_type == 0 ? '常规类' : '紧急类' }}</td>
          <td class="label">算法描述</td>
          <td class="value">{{ rowView.remark }}</td>
        </tr>
      </table>
    </div>
    </el-dialog>
  <el-dialog class="ztzf-dialog" append-to-body v-model="isShowEditView" title="编辑"
        :width="pxToRem(800)" :close-on-click-modal="false" :destroy-on-close="true">
        <div class="content-edit">
      <el-form ref="ruleFormRef" :model="editParams" :rules="rules" inline>
  <commonDialog :isShowView="isShowViewTest" width="1000" title="查看" addEditView="view" @cancel="isShowViewTest = false">
    <template #default>
      <el-row :gutter="0" class="table-view-mange">
        <el-col :span="6" class="label">算法名称</el-col>
        <el-col :span="6">{{ rowView.model_name }}</el-col>
        <el-col :span="6" class="label">算法类型</el-col>
        <el-col :span="6">{{ rowView.alg_type }}</el-col>
      </el-row>
      <el-row :gutter="0" class="table-view-mange">
        <el-col :span="6" class="label">最低准确率</el-col>
        <el-col :span="6">{{ rowView.qua_rate }}</el-col>
        <el-col :span="6" class="label">最高准确率</el-col>
        <el-col :span="6">{{ rowView.pass_rate }}</el-col>
      </el-row>
      <el-row :gutter="0" class="table-view-mange">
        <el-col :span="6" class="label">事件生成类型</el-col>
        <el-col :span="6">{{ rowView.event_type == 0 ? '常规类' : '紧急类' }}</el-col>
        <el-col :span="6" class="label"></el-col>
        <el-col :span="6"></el-col>
      </el-row>
      <el-row :gutter="0" class="table-view-mange">
        <el-col :span="6" class="label">算法描述</el-col>
        <el-col :span="18">
          <el-input v-model="rowView.remark"></el-input>
        </el-col>
      </el-row>
    </template>
  </commonDialog>
  <commonDialog :isShowView="isShowEditView" title="编辑"  addEditView="edit"  @submit="submit(ruleFormRef)" @cancel="isShowEditView = false">
    <template #default>
      <el-form class="ztzf-form-mange" ref="ruleFormRef" :model="editParams" :rules="rules" inline>
        <el-form-item label="算法名称">
          <el-input v-model="editParams.model_name" disabled />
        </el-form-item>
@@ -117,18 +116,16 @@
        <el-form-item label="算法描述">
          <el-input v-model="editParams.remark" placeholder="请输入算法描述" clearable />
        </el-form-item>
        <div class="btns">
          <el-button type="primary" @click="submit(ruleFormRef)">确认</el-button>
          <el-button @click="isShowEditView = false">取消</el-button>
        </div>
      </el-form>
    </div>
    </el-dialog>
    </template>
  </commonDialog>
</template>
<script setup>
import { getAlgorithmManageList, algorithmManageEdit } from '@/api/algorithmMange/algorithmMange';
import { getDictionaryByCode } from '@/api/system/dictbiz';
import commonDialog from '@/components/commonDialog.vue'
import { ElMessage } from 'element-plus';
import { Delete, Search } from '@element-plus/icons-vue'
const total = ref(0)
const params = ref({
@@ -140,7 +137,7 @@
let tableList = ref([])
let isShowView = ref(false)
let isShowViewTest = ref(false)
let rowView = ref({})
@@ -219,7 +216,7 @@
  });
}
function handleDetail(row) {
  isShowView.value = true
  isShowViewTest.value = true
  rowView.value = row
}
function handleEdit(row) {
@@ -302,52 +299,4 @@
      }
    }
  }
 .content {
  padding: 20px;
  .view-table {
    width: 100%;
    border-collapse: collapse;
    border: 1px solid #EBEEF5;
    tr {
      &:not(:last-child) {
        border-bottom: 1px solid #EBEEF5;
      }
      td {
        padding: 12px 10px;
        &.label {
          width: 140px;
          text-align: right;
          // color: #909399;
          // background-color: #F5F7FA;
          border-right: 1px solid #EBEEF5;
        }
        &.value {
          width: 180px;
          // color: #303133;
        }
      }
    }
  }
}
.content-edit {
  .el-form {
    .el-form-item {
      width: 300px;
      :deep(.el-form-item__label) {
        width: 120px;
      }
    }
    .btns {
        display: flex;
        justify-content: center
      }
  }
}
</style>
src/views/dataCenter/components/dataCenterMap.vue
@@ -1,5 +1,5 @@
<template>
  <el-dialog modal-class="mapDialog"  v-model="isShow" width="80%">
  <el-dialog modal-class="mapDialog"  v-model="isShow" width="80%" class="ztzf-dialog-mange">
     <template #header="{ titleId, titleClass }">
          <div class="my-header">
            <h4 :id="titleId" :class="titleClass">定位</h4>
@@ -312,6 +312,7 @@
<style scoped lang="scss">
.mapBox {
  margin-top: 10px;
  z-index: 2;
  height: 650px;
  width: 98%;
src/views/dataCenter/dataCenter.vue
@@ -184,6 +184,7 @@
      <!-- 查看弹框 -->
      <el-dialog
        v-model="dialogVisible"
        class="ztzf-dialog-mange"
        width="60%"
        append-to-body
        @close="dialogClose"
@@ -292,6 +293,7 @@
      <!-- 视频预览 -->
      <el-dialog
        :title="currentVideoTitle"
        class="ztzf-dialog-mange"
        modal-class="videoDialog"
        append-to-body
        width="54%"
src/views/device/addDevice.vue
@@ -11,7 +11,7 @@
                    @click.stop="copyInfo(scope.row, scope.index)" v-if="userInfo.role_name.includes('admin')">复制
                </el-button>
            </template>
        </avue-crud>
        </avue-crud>F
    </basic-container>
</template>
@@ -181,17 +181,16 @@
                        label: '设备类型',
                        editDisplay: false,
                        prop: 'type',
                        type: 'radio',
                        labelWidth: 130,
                        value: 0,
                        type: 'select',
                        dicData: [
                            {
                                label: '机场',
                                label: '机巢',
                                value: 0
                            },
                            {
                                label: '遥控器',
                                label: '控制器',
                                value: 1
                            }
                        ],
@@ -277,36 +276,6 @@
                        },
                    },
                    {
                        label: '设备描述', // '工作空间描述',
                        prop: 'workspace_desc',
                        labelWidth: 130,
                        searchSpan: 4,
                        rules: [
                            {
                                required: true,
                                message: '请输入设备描述',
                                trigger: 'blur',
                            },
                            {
                                max: 30,
                                message: '设备描述不能超过30个字',
                                trigger: 'blur',
                            },
                            // 如果需要更严格的校验(如中文字符计算),可以使用 validator
                            {
                                validator: (rule, value, callback) => {
                                    if (value && value.length > 30) {
                                        callback(new Error('设备描述不能超过30个字'));
                                    } else {
                                        callback();
                                    }
                                },
                                trigger: 'blur',
                            },
                        ],
                    },
                    {
                        label: '创建时间',
                        prop: 'create_time',
                        addDisplay: false,
@@ -318,6 +287,44 @@
                        format: 'YYYY-MM-DD HH:mm:ss',
                    },
                    {
                        label: '设备描述', // '工作空间描述',
                        prop: 'workspace_desc',
                        type: 'textarea',
                        labelWidth: 130,
                        searchSpan: 4,
                        overHidden: true,
                        minRows: 3,
                        maxRows: 5,
                        maxlength: 250,
                        span: 24,
                        showWordLimit: true,
                        rules: [
                            {
                                required: true,
                                message: '请输入设备描述不能超过250个字',
                                trigger: 'blur',
                            },
                            {
                                max: 250,
                                message: '设备描述不能超过250个字',
                                trigger: 'blur',
                            },
                            // 如果需要更严格的校验(如中文字符计算),可以使用 validator
                            {
                                validator: (rule, value, callback) => {
                                    if (value && value.length > 250) {
                                        callback(new Error('设备描述不能超过250个字'));
                                    } else {
                                        callback();
                                    }
                                },
                                trigger: 'blur',
                            },
                        ],
                    },
                    
                ],
src/views/device/airport.vue
@@ -57,7 +57,7 @@
      </template>
      <template #menu="scope">
        <el-dropdown>
              <el-button type="primary" text v-if="permission.oss_set"><el-icon><MoreFilled /></el-icon>更多</el-button>
          <el-button type="primary" text v-if="permission.oss_set"><el-icon><MoreFilled /></el-icon>更多</el-button>
              <template #dropdown v-if="scope.row.domain == 3">
                <el-dropdown-menu teleported>
                  <el-dropdown-item command="a">
@@ -74,9 +74,9 @@
                  <el-dropdown-item command="d"><el-button type="primary" text icon="el-icon-collection" v-if="permission.fly_device_offline"
                        @click.stop="rollFirmware(scope.row)">固件版本管理</el-button>
                  </el-dropdown-item>
                  <el-dropdown-item command="d">
                    <el-button type="primary" text icon="el-icon-collection" v-if="!scope.row.status" @click.stop="dockNotLine(scope.row)">
                      {{ scope.row.hidden_flag == 1 ? '设备上线' : '设备下线'}}
                 <el-dropdown-item command="d" v-if="!scope.row.status">
                    <el-button type="primary" text icon="el-icon-collection" @click.stop="dockNotLine(scope.row)">
                      {{ scope.row.hidden_flag === 1 ? '设备上线' : '设备下线'}}
                    </el-button>
                  </el-dropdown-item>
                  <el-dropdown-item command="e"><el-button type="primary" text icon="el-icon-document-delete" v-if="permission.fly_device_offline"
@@ -86,17 +86,19 @@
              </template>
              <template #dropdown v-else>
                <el-dropdown-menu teleported>
                  <el-dropdown-item command="a">
                  <!-- <el-dropdown-item command="a">
                    <el-button type="primary" text icon="el-icon-circle-close" @click.stop="rowDel(scope.row, scope.index)">删除</el-button>
                  </el-dropdown-item>
                  <el-dropdown-item command="a">
                  </el-dropdown-item> -->
                  <!-- <el-dropdown-item command="a">
                    <el-button type="primary" text icon="el-icon-key" v-if="permission.operate_password_set" @click.stop="handleOperatePassword(scope.row, scope.index)">操控密码设置</el-button>
                  </el-dropdown-item> -->
                  <el-dropdown-item command="d"><el-button type="primary" text icon="el-icon-collection"  @click.stop="rollFirmware(scope.row)">固件版本管理</el-button>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
      </template>
      <!-- 添加行政区划显示模板 -->
      <template #area_code="{ row }">
        <span>{{ row.area_name }}</span>
@@ -122,6 +124,20 @@
    <el-dialog title="操控密码查看" append-to-body v-model="operatePasswordViewBox" width="455px">
      <el-input v-model="operate_password" disabled></el-input>
    </el-dialog>
    <el-dialog title="注销" class="zx-cancel" append-to-body v-model="cancenOperate" width="460px">
      <div style="display: flex;justify-content: center;margin-bottom: 10px;">注销
        <span style="color:cornflowerblue;font-weight: bolder;margin: 0px 4px;">
          {{ cancelSNName }}
        </span> 设备可能会影响相关数据,确认注销吗?</div>
        <div style="display: flex;justify-content: center;color:red;font-size: 12px;">*删除相关图片、视频、事件</div>
      <template #footer>
        <span class="dialog-footer" style="display: flex;justify-content: center;">
          <el-button @click="cancenOperate = false">取 消</el-button>
          <el-button type="primary" @click="cancenOperateDo">确 定</el-button>
        </span>
      </template>
    </el-dialog>
    <el-dialog title="固件升级" append-to-body v-model="firmwareBox" width="455px">
@@ -196,7 +212,8 @@
  getDeviceFirmwareList,
  getDevices,
  deviceOffline,
  devicesUpdate
  devicesUpdate,
  devicesUpAndDown
} from '@/api/device/device'
import { deleteByOssId, addOrUpdate as addOrUpdateOssBind } from '@/api/device/ossBind'
import { getListPage as getOssList } from '@/api/resource/oss'
@@ -232,10 +249,15 @@
      }
    }
    return {
      treeResolveMap: new Map(),
      rules: {
        password: [{ required: true, validator: validatePass, trigger: 'blur' }],
        password2: [{ required: true, validator: validatePass2, trigger: 'blur' }],
      },
      cancelSNName: '',
      cancenOperate: false,
      cancenOperateRow: {},
      deleteFlag: false,
      passwordForm: {
        id: '',
        password: '',
@@ -341,13 +363,6 @@
            searchSpan: 4,
            labelWidth: 145,
            width: 120,
            // rules: [
            //   {
            //     required: true,
            //     message: '请输入设备型号',
            //     trigger: 'blur',
            //   },
            // ],
          },
          {
            label: '设备SN',
@@ -358,27 +373,8 @@
            searchSpan: 4,
            // editDisabled: true,
            editDisplay: false, //编辑显示
            // rules: [
            //   {
            //     required: true,
            //     message: '请输入设备SN',
            //     trigger: 'blur',
            //   },
            // ],
          },
          // {
          //   label: '机巢编号',
          //   prop: 'machine_nest_sn',
          //   labelWidth: 145,
          //   editDisabled: true,
          //   rules: [
          //     {
          //       required: false,
          //       message: '请输入机巢编号',
          //       trigger: 'blur',
          //     },
          //   ],
          // },
          {
            label: '设备位置',// '行政区划',
            prop: 'area_name',
@@ -468,21 +464,24 @@
              },
            ],
          },
          // {
          //   label: '设备位置',
          //   prop: 'address',
          //   labelWidth: 145,
          //   width: 100,
          //   overHidden: true,
          //   rules: [
          //     {
          //       required: true,
          //       message: '请输入设备位置',
          //       trigger: 'blur',
          //     },
          //   ],
          // },
          {
            label: '是否激活',
            prop: 'esim_activate_state',
            labelWidth: 145,
            width: 160,
            overHidden: true,
            editDisplay: false, //编辑显示
            viewDisplay: false,
            align: 'center',
            formatter: (row, column, cellValue) => {
              const statusMap = {
                0: '未知',
                1: '未激活',
                2: '已激活'
              };
              return statusMap[cellValue] || '/';
            }
          },
          {
            label: '负载设备',
@@ -491,14 +490,7 @@
            width: 160,
            overHidden: true,
            editDisplay: false, //编辑显示
            // editDisabled: true,
            // rules: [
            //   {
            //     required: true,
            //     message: '请输入负载设备',
            //     trigger: 'blur',
            //   },
            // ],
          },
          {
            // hide: true,
@@ -508,16 +500,20 @@
            width: 200,
            type: 'daterange',
            format: 'YYYY-MM-DD',
            valueFormat: 'YYYY-MM-DD HH:mm:ss',
            valueFormat: 'YYYY-MM-DD',
            startPlaceholder: '保险开始日期',
            endPlaceholder: '保险结束日期',
            align: 'center',
            rules: [
              {
                required: true,
                required: false,
                message: '请选择保险有效期',
                trigger: 'blur',
              },
            ],
            formatter: (row, value) => {
              return value[0]? `${this.$dayjs(value[0]).format('YYYY-MM-DD')}~${this.$dayjs(value[1]).format('YYYY-MM-DD')}` : '/';
            },
          },
          // {
          //   label: '保险有效期',
@@ -555,14 +551,6 @@
            type: 'date',
            format: 'YYYY-MM-DD',
            editDisplay: false, //编辑显示
            // editDisabled: true,
            // rules: [
            //   {
            //     required: true,
            //     message: '请输入流量到期时间',
            //     trigger: 'blur',
            //   },
            // ],
          },
          {
            label: '固件版本',
@@ -570,14 +558,6 @@
            labelWidth: 145,
            width: 110,
            editDisplay: false, //编辑显示
            // editDisabled: true,
            // rules: [
            //   {
            //     required: true,
            //     message: '请输入固件版本',
            //     trigger: 'blur',
            //   },
            // ],
          },
          {
            label: '固件升级',
@@ -588,16 +568,8 @@
            viewDisabled: true,
            addDisabled: true,
            editDisplay: false, //编辑显示
            // editDisabled: true,
            addDisplay: false,
            viewDisplay: false,
            // rules: [
            //   {
            //     required: true,
            //     message: '请输入固件升级',
            //     trigger: 'blur',
            //   },
            // ],
          },
          {
            label: '所属单位',
@@ -657,7 +629,7 @@
          // },
          {
            label: '在线时间',
@@ -830,6 +802,7 @@
    },
  },
  destroyed () {
    this.treeResolveMap.clear()
    this.websocketMap.forEach((k, v) => {
      if (null != v) {
        v.close()
@@ -934,25 +907,24 @@
      this.operateTitle = row.nickname + ' - ' + row.device_sn
    },
    // 设备下线
    // 设备注销
    handleDeviceOffline (row) {
      ElMessageBox.confirm('确定注销该设备吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => {
          deviceOffline(row.device_sn)
            .then(res => {
              ElMessage.success('注销成功')
      this.cancenOperate = true
      this.cancelSNName = row.nickname
      this.cancenOperateRow = row
    },
              this.init()
            })
            .catch(error => {
              ElMessage.error('注销失败')
            })
        })
        .catch(() => { })
    cancenOperateDo () {
      this.cancenOperate = false
      this.deleteFlag = false
      deviceOffline(this.cancenOperateRow.device_sn, true).then(res => {
        ElMessage.success('注销成功')
        this.init()
      }).catch(error => {
        ElMessage.error('注销失败')
      })
    },
    // 打开存储对象配置页面
@@ -989,9 +961,9 @@
      })
        .then(() => {
          let hidden_flag = row.hidden_flag === 1?0:1
          devicesUpdate({id:row.id, hidden_flag:hidden_flag})
          devicesUpAndDown({id:row.id, hidden_flag:hidden_flag})
            .then(res => {
              ElMessage.success('下线成功')
              ElMessage.success(`${txt}成功`)
              this.init()
            })
            .catch(error => {
@@ -1275,8 +1247,8 @@
      const submitData = {
        ...row,
        area_code: row.area_code.split(',').pop(),
        insure_start_time: row.duration_of_insurance[0],
        insure_expired_time: row.duration_of_insurance[1],
        insure_start_time: row.duration_of_insurance[0] || null,
        insure_expired_time: row.duration_of_insurance[1] || null,
        deptId: row.dept_id,
        areaCode: row.area_code.split(',').pop(),
      }
@@ -1287,7 +1259,25 @@
      update(submitData).then(
        () => {
          this.onLoad(this.page)
          if (row.domain === 0) {
            // 获取保存的 resolve 函数
            const resolve = this.treeResolveMap.get(row.device_sn)
            if (resolve) {
              // 重新加载子节点数据
              var params = {
                childSn: row.device_sn,
              }
              getList(1, 10, params).then(res => {
                const data = res.data.data.records
                data.forEach(e => {
                  e.duration_of_insurance = [e.insure_start_time || '', e.insure_expired_time || '']
                })
                resolve(data)
              })
            }
          } else {
            this.onLoad(this.page)
          }
          this.$message({
            type: 'success',
            message: '操作成功!',
@@ -1384,7 +1374,6 @@
            area_code: await this.getFullAreaCode(data.area_code),
            area_name: this.form.area_name,
            cnmode_code: this.getDockModeText(this.form.mode_code),
            // domain: data.domain === 0 ? '无人机' : data.domain === 3 ? '机巢' : '未知',
            domainTxt: data.domain === 0 ? '无人机' : data.domain === 3 ? '机巢' : '未知',
            cnstatus: this.form.status === false ? '离线' : '在线',
            duration_of_insurance: [data?.insure_start_time || '', data?.insure_expired_time || ''],
@@ -1439,11 +1428,16 @@
      })
    },
    treeLoad (tree, treeNode, resolve) {
      // 保存resolve
      this.treeResolveMap.set(tree.child_sn, resolve)
      var params = {
        childSn: tree.child_sn,
      }
      getList(1, 10, params).then(res => {
        const data = res.data.data.records
        data.forEach(e => {
          e.duration_of_insurance = [e.insure_start_time || '', e.insure_expired_time || '']
        })
        resolve(data)
      })
    },
@@ -1582,5 +1576,11 @@
  right: 0;
}
:deep(.avue-crud__pagination) {
  position: fixed;
  bottom: 10px;
  right: 30px;
}
</style>
src/views/device/components/DockControlPanel.vue
@@ -233,6 +233,7 @@
watch(
  () => Store.getters.deviceState,
  value => {
    console.log(value, '测试')
    // console.log('设备状态变化', value.deviceInfo[props.deviceInfo.child_sn])
    if (props.sn && (value.currentSn === props.deviceInfo.child_sn || value.currentSn === props.deviceInfo.device_sn)) {
      debugStatus.value = value.dockInfo[props.deviceInfo.device_sn]?.basic_osd?.mode_code === EDockModeCode.Remote_Debugging
src/views/device/components/devicePerShare.vue
@@ -89,28 +89,28 @@
              },
            ],
          },
          {
            label: '授权功能',
            prop: 'devicePerMenuId',
            labelWidth: 130,
            type: 'tree',
            dicUrl: '/blade-system/manage/api/v1/devicePerMenu/selectDeviceList',
            props: {
              label: 'name',
              value: 'id',
            },
            multiple: true,
            dataType: 'string',
            span: 24,
            row: true,
            rules: [
              {
                required: true,
                message: '请输入授权功能',
                trigger: 'blur',
              },
            ],
          },
          // {
          //   label: '授权功能',
          //   prop: 'devicePerMenuId',
          //   labelWidth: 130,
          //   type: 'tree',
          //   dicUrl: '/blade-system/manage/api/v1/devicePerMenu/selectDeviceList',
          //   props: {
          //     label: 'name',
          //     value: 'id',
          //   },
          //   multiple: true,
          //   dataType: 'string',
          //   span: 24,
          //   row: true,
          //   rules: [
          //     {
          //       required: true,
          //       message: '请输入授权功能',
          //       trigger: 'blur',
          //     },
          //   ],
          // },
          {
            label: '授权时间',
            prop: 'createTime',
src/views/device/components/firmwareManage.vue
@@ -25,12 +25,12 @@
        </el-button>
      </template>
    </avue-crud>
    <el-dialog title="固件上传" append-to-body v-model="firmwareUploadBox" width="40%" height="60%">
    <el-dialog title="固件上传" class="ztzf-dialog-mange" append-to-body v-model="firmwareUploadBox" width="40%" height="60%">
      <el-form
        ref="form"
        class="ztzf-form-mange"
        :model="importForm"
        v-loading="loadingForm"
        label-width="80px"
        style="width: 80%; margin-left: 10%"
        :rules="rules"
      >
@@ -62,11 +62,13 @@
        <el-form-item label="说明" label-width="80px" prop="release_note">
          <el-input type="textarea" v-model="importForm.release_note" clearable></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="onConfirm">确定</el-button>
          <el-button @click="onCancel">取消</el-button>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
        <el-button type="primary" @click="onConfirm">确定</el-button>
        <el-button @click="onCancel">取消</el-button>
        </div>
      </template>
    </el-dialog>
  </basic-container>
</template>
src/views/job/components/TaskIntermediateContent/TaskIntermediateContent.vue
@@ -169,9 +169,14 @@
const jobId = ref('')
const handleDetail = row => {
    if (!row.device_sns.length) return ElMessage.warning('没有device_sns')
    if (row.device_sns.length !== 1) return ElMessage.success('即将跳转到集群调度')
    rowData.value = row ? row : {}
jobId.value = rowData.value?.job_id
    if (row.device_sns.length > 1 && (row.status === 2 || row.status === 1)) {
        const adminUrl = `${import.meta.env.VITE_APP_AREA_NAME}/command-center-dashboard/#/clusterScheduling`
        const targetPath = `taskNo=${encodeURIComponent(rowData.value.job_info_num)}`
        window.open(`${adminUrl}?${targetPath}`, '_blank')
        return
    }
    jobId.value = rowData.value?.job_id
    if (row.status === 2 || row.status === 1) {
        // isShowCurrentTaskDetails.value = true
        // 跳转大屏当前任务详情
src/views/job/components/TaskTop/TaskEvent.vue
@@ -52,10 +52,7 @@
        type: 'category',
        // data: ['1月', '2月', '3月', '4月', '5月', '6月'],
        axisLine: {
            show: false, // 隐藏轴线
        },
        axisLine: {
            show: false, // 隐藏轴线
            show: true, // 隐藏轴线
        },
        axisLabel: {
            color: '#5B5B5D',
src/views/job/components/TaskTop/TaskIndustry.vue
@@ -22,15 +22,15 @@
        formatter: '{b}: {c} ({d}%)',
    },
    legend: {
        orient: 'horizontal',
        left: 'center',
        bottom: '2%',
    orient: 'vertical',
    top: 'center',
    right: '20',
        textStyle: {
            color: '#363636',
            fontSize: 12,
        },
        itemWidth: 2, // 减小图例标记的宽度
        itemHeight: 3, // 减小图例标记的高度
        itemHeight: 6, // 减小图例标记的高度
        itemGap: 8, // 减小图例项之间的间距
        formatter: '{name}', // 简化图例文本
    },
@@ -39,10 +39,8 @@
            name: '机巢事件统计',
            type: 'pie',
            // roseType: 'radius',
            radius: ['36%', '60%'],
            // center: ['50%', '45%'],
            // radius: '70%', // 设置饼图的半径
            center: ['50%', '36%'], // 调整饼图位置
      radius: ['20%', '70%'],
      center: ['30%', '50%'],
            data: [],
            label: {
                show: true,
@@ -94,7 +92,7 @@
<style lang="scss" scoped>
.task-industry {
    width: 276px;
    width: 300px;
    height: 100%;
    background: #FFFFFF;
    border-radius: 8px 8px 8px 8px;
src/views/job/components/TaskTop/TaskTime.vue
@@ -63,15 +63,15 @@
        type: 'category',
        data: ['1'],
        axisLine: {
            show: false, // 隐藏轴线
            show: true, // 隐藏轴线
        },
        axisTick: {
            show: true,
            length: 2,
            lineStyle: {
                color: '#363636',
            },
        },
        // axisTick: {
        //     show: true,
        //     length: 2,
        //     lineStyle: {
        //         color: 'red',
        //     },
        // },
        axisLabel: {
            color: '#363636',
            margin: 8,
src/views/license/license.vue
@@ -41,7 +41,7 @@
        </avue-crud>
        <!-- 新增弹窗 -->
        <el-dialog title="新增 License" v-model="addDialogVisible" width="70%" :close-on-click-modal="false"
        <el-dialog class="ztzf-dialog-mange" title="新增 License" v-model="addDialogVisible" width="70%" :close-on-click-modal="false"
            @close="resetForm">
            <el-form :model="newLicense" ref="licenseForm" label-width="120px">
                <el-form-item label="机构ID" prop="licenseId">
@@ -50,7 +50,7 @@
                <el-form-item label="机构名称" prop="licenseName" required>
                    <el-input v-model="newLicense.licenseName" />
                </el-form-item>
                <el-form-item label="是否验证过期时间类型" prop="licenseType" required>
                <el-form-item label="过期时间类型" prop="licenseType" required>
                    <el-select v-model="newLicense.licenseType" placeholder="请选择">
                        <el-option label="不验证过期时间" :value="1" />
                        <el-option label="验证过期时间" :value="2" />
@@ -79,8 +79,8 @@
            </el-form>
            <template #footer>
                <div class="dialog-footer">
                    <el-button @click="addDialogVisible = false">取消</el-button>
                    <el-button type="primary" @click="createLicense">保存</el-button>
                  <el-button type="primary" @click="createLicense" :icon="CircleCheck">保存</el-button>
                  <el-button @click="addDialogVisible = false"  :icon="CircleClose">取消</el-button>
                </div>
            </template>
@@ -91,6 +91,7 @@
<script>
import { getList, add } from '@/api/license/license'
import { mapGetters } from 'vuex'
import { CircleCheck, CircleClose } from '@element-plus/icons-vue';
export default {
    data () {
@@ -269,6 +270,12 @@
        }
    },
    computed: {
      CircleClose() {
        return CircleClose
      },
      CircleCheck() {
        return CircleCheck
      },
        ...mapGetters(['userInfo', 'permission']),
        permissionList () {
            return {
src/views/resource/components/DrawPolygon.vue
@@ -214,7 +214,7 @@
  viewInstance.value.removeMouseHandler('drawCustomPolygon');
}
const emit = defineEmits(['upDateDrawState']);
const emit = defineEmits(['upDateDrawState',]);
function updatePolygon() {
  let polygon = savePolygonPosition.reduce((pre, cur) => {
@@ -222,7 +222,7 @@
    return pre;
  }, []);
  polygon.push(polygon[0]);
  console.log('绘制', `POLYGON((${polygon.join(',')}))`);
  // 接口
  sdfwUpdate({
      ids: selectionIds.value,
@@ -244,6 +244,7 @@
      })
}
function cancel() {
  remove();
  removeMenuPanel();
src/views/resource/components/spotDetails.vue
@@ -1,10 +1,11 @@
<template>
  <el-dialog
    class="spotDialog"
    class="spotDialog ztzf-dialog-mange"
    :title="props.title"
    v-model="uploadPatchDialog"
    width="78%"
    align-center
  >
    <div class="container">
      <!-- 信息展示区 -->
@@ -65,14 +66,12 @@
              :row-class-name="tableRowClassName"
              :data="tableData"
              @row-click="handleLocationPolygon"
              @current-change="handleTableRowChange"
            >
              <el-table-column type="index" align="center" :width="pxToRemNum(30)" label="序号">
                <template #default="{ $index }">
                  {{
                    ($index + 1 + (params.page - 1) * params.pageSize).toString().padStart(2, '0')
                  }}
                </template>
               <template #default="{ $index }">
                {{ ($index + 1).toString().padStart(2, '0') }}
              </template>
              </el-table-column>
              <el-table-column prop="dkbh" align="center"  label="图斑名称" show-overflow-tooltip />
              <el-table-column prop="is_exception" :width="pxToRemNum(50)" align="center" label="图斑状态">
@@ -93,20 +92,7 @@
                </template>
              </el-table-column>
            </el-table>
            <div class="pagination-container">
              <el-pagination
                :current-page="params.page"
                :page-size="params.pageSize"
                background
                layout="prev, pager, next, ..."
                :pager-count="3"
                prev-text="上一页"
                next-text="下一页"
                :total="total"
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
              />
            </div>
          </div>
        </div>
        <!--绘制按钮-->
@@ -115,6 +101,7 @@
          ref="drawPolygonRef"
          v-if="isEditing"
          @upDateDrawState="handleUpDateDrawState"
        />
        <!-- 完成/取消 -->
        <div class="btnGroups" v-if="props.title === '图斑编辑'">
@@ -129,6 +116,7 @@
</template>
<script setup>
import { flyVisual } from '@/utils/cesium/mapUtil'
import { pxToRem, pxToRemNum } from '@/utils/rem'
import DrawPolygon from '@/views/resource/components/DrawPolygon.vue';
import { ElMessage, ElMessageBox } from 'element-plus';
@@ -251,59 +239,30 @@
  page: 1,
  pageSize: 10,
});
const isInit = ref(true);
// 图斑管理表格
const getTableList = () => {
  const requestParams = {
    patchesInfoId: props.detailid,
    page: params.value.page,
    pageSize: params.value.pageSize,
  };
  tableMapListApi(requestParams).then(res => {
    tableData.value = res.data.data.records?.map(item => ({
  AlltableMapListApi(requestParams).then(res => {
    tableData.value = res.data.data?.map(item => ({
      ...item,
      dkfw: item.sdfw && item.is_exception == 1 ? item.sdfw : item.dkfw,
    }));
    total.value = res.data.data.total || res.data.data.length;
    tbJwdList = [];
    viewer?.entities.removeAll();
    if (!AlltableData.value) {
    if (!tableData.value) {
      viewInstance.value?.flyToContour();
    } else {
      entitiesAddSpot();
    }
  });
};
// 所有图斑数据
const getAlltableMapListApi = () => {
  loading.value = true;
  const requestParams = {
    patchesInfoId: props.detailid,
  };
  AlltableMapListApi(requestParams).then(res => {
    AlltableData.value = res.data.data?.map(item => ({
      ...item,
      dkfw: item.sdfw && item.is_exception == 1 ? item.sdfw : item.dkfw,
    }));
    tbJwdList = [];
    viewer?.entities.removeAll();
    if (AlltableData.value.length < 1) {
      viewInstance.value?.flyToContour();
    } else {
      entitiesAddSpot();
    }
    loading.value = false;
  });
};
const handleSizeChange = val => {
  params.value.pageSize = val;
  params.value.page = 1;
  getTableList();
};
const handleCurrentChange = val => {
  params.value.page = val;
  getTableList();
};
// 地图
const initMap = () => {
@@ -323,35 +282,52 @@
  viewer.scene.globe.depthTestAgainstTerrain = true;
  viewInstance.value.switchContour(true);
};
// 仅弹框初始化时执行的定位逻辑
const initMapLocation = () => {
  if (tbJwdList.length === 0 || !homeViewer.value) return;
  // 计算所有图斑的包围球(用于初始化定位)
  const allPositions = tbJwdList.flatMap(item =>
    Cesium.Cartesian3.fromDegreesArray(item.grouped)
  );
  const boundingSphere = Cesium.BoundingSphere.fromPoints(allPositions);
  // 初始化定位(仅执行一次)
  homeViewer.value.camera.flyToBoundingSphere(boundingSphere, {
    duration: 0,
    offset: new Cesium.HeadingPitchRange(
      Cesium.Math.toRadians(0),
      Cesium.Math.toRadians(-90)
    ),
  });
};
// 初始化所有图斑
const entitiesAddSpot = () => {
  viewer?.entities.removeAll();
  AlltableData.value.forEach(item => {
    // 取出当中经纬度
  tbJwdList = []; // 重置经纬度列表
  tableData.value.forEach(item => {
    const numbersWithCommas = item.dkfw.match(/\d+(\.\d+)?/g);
    if (!numbersWithCommas) return;
    // 绘制图斑
    const grouped = numbersWithCommas.map(item => Number(item));
    // 为框选存储对比值
    tbJwdList.push({
      ...item,
      grouped: grouped,
    });
    viewInstance.value.removeById('polygon_dk' + item.id);
    // 根据 is_exception 设置颜色
    const color =
      item.is_exception == 2 ? Cesium.Color.RED.withAlpha(0.5) : Cesium.Color.YELLOW.withAlpha(0.5);
    const outlineColor = item.is_exception == 2 ? Cesium.Color.RED : Cesium.Color.YELLOW;
    const grouped = numbersWithCommas.map(Number);
    tbJwdList.push({ ...item, grouped }); // 存储经纬度用于后续操作
    // 绘制图斑(保留原有逻辑,仅移除定位相关代码)
    const fillColor = item.is_exception === 2
      ? Cesium.Color.RED.withAlpha(0.5)
      : Cesium.Color.YELLOW.withAlpha(0.5);
    const outlineColor = item.is_exception === 2
      ? Cesium.Color.RED
      : Cesium.Color.YELLOW;
    homeViewer.value?.entities?.add({
      id: 'polygon_dk' + item.id,
      id: `polygon_dk${item.id}`,
      customType: 'pattern_spot_polygon',
      customInfo: {
        ...item,
      },
      customInfo: item,
      polygon: {
        hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(grouped)),
        material: color,
        material: fillColor,
        outline: true,
        outlineColor: outlineColor,
        outlineWidth: 2,
@@ -361,23 +337,22 @@
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray(grouped),
        width: 2,
        material: color,
        material: outlineColor,
        clampToGround: true,
      },
      zIndex: 99,
    });
    if (tbJwdList.length > 0) {
      const positions = tbJwdList.flatMap(item => Cesium.Cartesian3.fromDegreesArray(item.grouped));
      const boundingSphere = Cesium.BoundingSphere.fromPoints(positions);
      homeViewer.value?.camera.flyToBoundingSphere(boundingSphere, {
        duration: 0,
        offset: new Cesium.HeadingPitchRange(Cesium.Math.toRadians(0), Cesium.Math.toRadians(-90)),
      });
    }
    viewInstance.value?.removeLeftClickEvent('spotHighlighting');
    viewInstance.value?.addLeftClickEvent(null, spotHighlighting, 'spotHighlighting');
  });
  // 仅在初始化阶段执行定位(关键:通过isInit控制)
  if (isInit.value) {
    initMapLocation();
    isInit.value = false; // 初始化完成,后续不再执行定位
  }
  // 保留图斑点击高亮事件(原有逻辑不变)
  viewInstance.value?.removeLeftClickEvent('spotHighlighting');
  viewInstance.value?.addLeftClickEvent(null, spotHighlighting, 'spotHighlighting');
};
// 高亮当前选中图斑,并定位
@@ -440,16 +415,12 @@
  updateMapSpotInfo(nowEntity);
}
// 更新上一个和这一个信息
function updateMapSpotInfo(nowEntity) {
  const nowData = nowEntity.customInfo;
  if (!nowEntity) return;
  if (nowEntity.customInfo.id === lastEntity?.customInfo.id) return;
  // 设置新的
  nowEntity.polygon.material = Cesium.Color.RED.withAlpha(0);
  nowEntity.polyline.material = Cesium.Color.RED;
  // 重置上一个
  if (lastEntity) {
    const lastData = lastEntity.customInfo;
    const originalFillColor =
@@ -458,7 +429,6 @@
        : Cesium.Color.YELLOW.withAlpha(0.5);
    const originalOutlineColor =
      lastData.is_exception == 2 ? Cesium.Color.RED : Cesium.Color.YELLOW;
    lastEntity.polygon.material = originalFillColor;
    lastEntity.polygon.outlineColor = originalOutlineColor;
    lastEntity.polyline.material = originalOutlineColor;
@@ -466,23 +436,20 @@
  lastEntity = nowEntity;
  const numbersWithCommas = nowData.dkfw.match(/\d+(\.\d+)?/g);
  if (numbersWithCommas) {
    // 解析经纬度数组
    const groupedArr = numbersWithCommas.reduce((acc, val, index, src) => {
      if (index % 2 === 0) acc.push(src.slice(index, index + 2));
      return acc;
    }, []);
    const polygonCenter = getCenterPoint(groupedArr);
    // 相机定位
    homeViewer.value.scene.camera.setView({
      destination: Cesium.Cartesian3.fromDegrees(
        Number(polygonCenter.lng),
        Number(polygonCenter.lat),
        1500
      ),
      zIndex: 100,
    const positionsData = [];
    for (let i = 0; i < numbersWithCommas.length; i += 2) {
      const lon = Number(numbersWithCommas[i]);
      const lat = Number(numbersWithCommas[i + 1]);
      positionsData.push([lon, lat, 10]);
    }
    flyVisual({
      positionsData: positionsData,
      viewer: homeViewer.value,
      multiple: 15,
    });
  }
  // flyMapSpot(nowEntity?.customInfo)
}
// 清空选中的数据
const clearSelect = () => {
@@ -491,26 +458,31 @@
  viewer?.entities.removeAll();
};
// 编辑
const handleSelectionChange = row => {
  let curRowIsSelect = row;
  curRowIsSelect && handleLocationPolygon(row);
  // 如果是同一个图斑且正在编辑,则取消编辑
  if (selectionIds.value === row.id && isEditing.value) {
    isEditing.value = false;
    handleUpDateDrawState(false);
    selectionIds.value = null;
    selectionList.value = [];
    return;
  }
  // 定位到选中的图斑
  handleLocationPolygon(row);
  // 仅异常图斑可编辑
  if (row.is_exception !== 2) {
    ElMessage.warning('仅异常图斑支持编辑绘制');
    return;
  }
  // 设置编辑状态
  selectionIds.value = row.id;
  selectionList.value = row;
  if (isEditing.value) {
    //当前已编辑 → 取消编辑(关闭绘制、重置状态)
    isEditing.value = false;
    handleUpDateDrawState(false); // 通知DrawPolygon取消绘制
  } else {
    // 当前未编辑 → 开启编辑(仅异常图斑可编辑)
    if (row.is_exception === 2 && curRowIsSelect) {
      isEditing.value = true;
      handleUpDateDrawState(true); // 通知DrawPolygon开启绘制
    } else {
      ElMessage.warning('仅异常图斑支持编辑绘制');
      isEditing.value = false;
    }
  }
  isEditing.value = true;
  handleUpDateDrawState(true);
};
const handleUpDateDrawState = show => {
  isEditing.value = show; // 同步编辑状态
@@ -521,7 +493,7 @@
  }
};
// 删除
const handleDelete = row => {
const handleDelete = (row) => {
  ElMessageBox.confirm('确认删除当前行图斑?', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
@@ -530,9 +502,27 @@
    deletePatches({ ids: row.id }).then(res => {
      if (res.data.code !== 0) return ElMessage.warning('删除失败');
      ElMessage.success('删除成功');
      getTableList();
      getspotManagementTableApi();
      getAlltableMapListApi();
      tableData.value = tableData.value.filter(item => item.id !== row.id);
      //从地图上移除对应的图斑实体
      const entityId = `polygon_dk${row.id}`;
      viewer?.entities.removeById(entityId);
      const exceptionCountItem = infoList.value.find(item => item.name === '异常图斑数量');
      if (exceptionCountItem && row.is_exception === 2) {
        exceptionCountItem.value = Math.max(0, parseInt(exceptionCountItem.value) - 1);
      }
      const totalCountItem = infoList.value.find(item => item.name === '图斑数量');
      if (totalCountItem) {
        totalCountItem.value = Math.max(0, parseInt(totalCountItem.value) - 1);
      }
      // 清除选中状态
      if (selectionIds.value === row.id) {
        selectionIds.value = null;
        selectionList.value = [];
        isEditing.value = false;
        handleUpDateDrawState(false);
      }
    });
  });
};
@@ -601,18 +591,23 @@
  publicCesiumInstance = null;
};
watch(uploadPatchDialog, newVal => {
  if (newVal) {
    isInit.value = true;
    setTimeout(() => {
      initMap();
      getTableList();
      getAlltableMapListApi();
      initMap();
      getTableList();
      getspotManagementTableApi();
    }, 0);
  } else {
 tableData.value = [];
    isEditing.value = false;
    handleUpDateDrawState(false);
    destroyMap();
    isInit.value = false;
    clearSelect();
  }
  refreshonload();
});
@@ -633,6 +628,10 @@
  font-size: 16px !important;
  color: #363636 !important;
}
:global(.spotDialog .el-dialog__body) {
    padding: 2rem 2rem 0 !important;
  }
.container {
  display: flex;
  flex-direction: column;
@@ -793,7 +792,7 @@
    // 表格主体
    .el-table__body {
      tr:hover > td {
        background-color: rgba(0, 0, 0, 0.6) !important;
        background-color: rgba(64, 158, 255,0.3) !important;
      }
      td {
@@ -803,7 +802,8 @@
    // 选中行
    .current-row td {
      background-color: rgba(0, 0, 0, 0.6) !important;
      background-color: rgba(64, 158, 255,0.3) !important;
    }
  }
  :deep(.el-table__body) {
src/views/resource/patchManagement.vue
@@ -35,13 +35,13 @@
        <el-button type="primary" text icon="el-icon-edit" @click="uploadPatch(scope.row, 'edit')"
          >编辑
        </el-button>
        <el-button type="primary" text icon="el-icon-delete" @click="rowDel(scope.row)"
        <el-button :disabled="scope.row.patches_type_desc==='综合类'" type="primary" text icon="el-icon-delete" @click="rowDel(scope.row)"
          >删除
        </el-button>
      </template>
    </avue-crud>
    <el-dialog title="上传图斑" append-to-body align-center v-model="box" width="550px">
    <el-dialog title="上传图斑" class="ztzf-dialog-mange" append-to-body align-center v-model="box" width="550px">
      <el-form
        ref="ruleFormRef"
        style="max-width: 600px"
@@ -89,7 +89,7 @@
  </basic-container>
</template>
<script setup>
import {findAreaName} from '@/utils/areaUtils'
import { findAreaName } from '@/utils/areaUtils';
import {
  spotManagementTableApi,
  searchManagementApi,
@@ -161,7 +161,7 @@
  border: true,
  index: true,
  indexLabel: '序号',
   indexWidth: 60,
  indexWidth: 60,
  selection: true,
  grid: false,
  menuWidth: 240,
@@ -468,7 +468,7 @@
    data.value = d.records.map(i => ({
      ...i,
      dataFrom: i.date_from === 0 ? '本地上传' : '国土调查云',
      areaName: findAreaName(i.area_code, regionalData.value, true)
      areaName: findAreaName(i.area_code, regionalData.value, true),
    }));
    loading.value = false;
    selectionClear();
@@ -510,12 +510,14 @@
};
// 图斑上传
const uploadFlightFile = (file, t) => {
loading.value = true
  loading.value = true;
  const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1);
  if (!['kmz', 'kml', 'zip'].includes(fileSuffix)) {
    return ElMessage.error('请上传zip/kmz/kml格式的文件');
  }
  if (file) {
    box.value = false;
  }
  let data = new FormData();
  let type = t === '3' ? '' : t;
  const params = {
@@ -535,15 +537,14 @@
    ElMessage.success('上传成功');
    box.value = false;
    loading.value = false;
    ruleForm.name = '';
    ruleForm.region = '';
    if (ruleFormRef.value) {
      ruleFormRef.value.resetFields();
    }
loading.value = true
    searchReset();
  });
};
src/views/resource/patchTypeManagement.vue
@@ -29,6 +29,17 @@
      <template #category="{ row }">
        <el-tag>{{ row.categoryName }}</el-tag>
      </template>
        <template #menu="{ row }">
        <el-button
          :disabled="row.patches_type === '综合类'"
          type="primary"
          text
          icon="el-icon-delete"
          @click="rowDel(row)"
        >
          删除
        </el-button>
      </template>
    </avue-crud>
  </basic-container>
</template>
@@ -76,8 +87,8 @@
  selection: true,
  grid: false,
  menuWidth: 180,
  labelWidth: 100,
  dialogWidth: 880,
  labelWidth: 90,
  dialogWidth: 600,
  dialogClickModal: false,
  height: 'auto',
  calcHeight: 20,
@@ -85,12 +96,14 @@
  gridBtn: false,
  searchShowBtn: false,
  columnBtn: false,
  delBtn: false,
  column: [
    {
      label: '类型名称',
      prop: 'patches_type',
      search: true,
      searchSpan: 4,
      span: 24,
      rules: [{ required: true, message: '请输入类型名称', trigger: 'blur' }],
    },
    {
src/views/system/param.vue
@@ -125,6 +125,7 @@
      </el-row>
      <!-- 表单模块 -->
      <el-dialog
        class="ztzf-dialog-mange"
        :title="title"
        v-model="box"
        width="50%"
src/views/system/userinfo.vue
@@ -44,7 +44,7 @@
            <el-form-item label="姓名:">
              <el-input
                class="ztzf-input"
                :style="{ width: pxToRem(230) }"
                :style="{ width: pxToRem(350) }"
                v-model="userInfo.realName"
                disabled
              />
@@ -300,6 +300,7 @@
  margin: 16px;
  padding: 10px;
  background-color: #ffffff;
  height: 100%;
}
.titleBoxs {
  margin: 0 24px;
@@ -319,26 +320,25 @@
:deep(.el-form-item__label) {
  color: #000 !important;
}
:deep(.el-button) {
  width: 150px !important;
}
// :deep(.el-button) {
//   width: 150px !important;
// }
.info {
  display: flex;
  justify-content: space-between;
  justify-content: center;
  align-items: center;
  padding: 0 80px 0 50px;
  .section:first-child{
  margin-right: 50px;}
}
.password {
  padding: 0 120px 0 50px;
}
.butn {
  // position: absolute;
  // bottom: 20px;
  // left: 50%;
  // transform: translate(-50%);
  display: flex;
  justify-content: center;
  cursor: pointer;
  img {
    width: 96px;
    height: 32px;
src/views/tickets/orderLog.vue
@@ -262,6 +262,7 @@
    <!-- 新建工单对话框 -->
    <el-dialog
      class="ztzf-dialog-mange"
      v-model="dialogVisible"
      title="新建工单"
      width="70%"
@@ -384,18 +385,26 @@
          </el-col>
        </el-row>
        <el-row>
          <div class="add-box-btns">
            <el-button type="danger" @click="submitForm(1)">发起</el-button>
            <el-button type="primary" @click="submitForm(0)">存草稿</el-button>
            <el-button @click="dialogVisible = false">取消</el-button>
          </div>
        </el-row>
<!--        <el-row>-->
<!--          <div class="add-box-btns">-->
<!--            <el-button type="danger" @click="submitForm(1)">发起</el-button>-->
<!--            <el-button type="primary" @click="submitForm(0)">存草稿</el-button>-->
<!--            <el-button @click="dialogVisible = false">取消</el-button>-->
<!--          </div>-->
<!--        </el-row>-->
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="danger" @click="submitForm(1)">发起</el-button>
          <el-button type="primary" @click="submitForm(0)">存草稿</el-button>
          <el-button @click="dialogVisible = false" :icon="CircleClose">取消</el-button>
        </div>
      </template>
    </el-dialog>
    <!-- 工单详情对话框 -->
    <el-dialog
      class="ztzf-dialog-mange"
      align-center
      v-model="detailVisible"
      :title="detailTitle"
@@ -573,43 +582,43 @@
            <map-container v-if="detailVisible" ref="MapContainer"></map-container>
          </el-col>
        </el-row>
        <el-row>
          <div class="add-box-btns">
            <el-button
              type="danger"
              v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
              @click="submitForm(1)"
              >发布</el-button
            >
            <el-button
              type="primary"
              v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
              @click="submitForm(0)"
              >保存</el-button
            >
            <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user"
                            @click="submitForm(0)">保存</el-button> -->
            <el-button
              type="primary"
              v-if="form.status == 1 && hasPaddingBtnPermission()"
              @click="orderLogPass(form.id)"
              >通过</el-button
            >
            <el-button
              type="danger"
              v-if="form.status == 1 && hasRejectionBtnPermission()"
              @click="orderLogReject(form.id)"
              >驳回</el-button
            >
          </div>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button
            type="danger"
            v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
            @click="submitForm(1)"
          >发布</el-button
          >
          <el-button
            type="primary"
            v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
            @click="submitForm(0)"
          >保存</el-button
          >
          <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user"
                          @click="submitForm(0)">保存</el-button> -->
          <el-button
            type="primary"
            v-if="form.status == 1 && hasPaddingBtnPermission()"
            @click="orderLogPass(form.id)"
          >通过</el-button
          >
          <el-button
            type="danger"
            v-if="form.status == 1 && hasRejectionBtnPermission()"
            @click="orderLogReject(form.id)"
          >驳回</el-button
          >
        </div>
        </template>
    </el-dialog>
    <!-- 工单详情 -->
    <el-dialog
      class="ztzf-dialog-mange"
      align-center
      v-model="detailVisibleCopy"
      title="工单详情"
@@ -778,33 +787,33 @@
          </el-col>
        </el-row>
        <el-row>
          <div class="add-box-btns">
            <el-button
              type="danger"
              v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
              @click="submitForm(1)"
              >发布</el-button
            >
            <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user"
                            @click="submitForm(0)">保存</el-button> -->
            <el-button
              type="primary"
              v-if="form.status == 1 && hasPaddingBtnPermission()"
              @click="orderLogPass(form.id)"
              >通过</el-button
            >
            <el-button
              type="danger"
              v-if="form.status == 1 && hasRejectionBtnPermission()"
              @click="orderLogReject(form.id)"
              >驳回</el-button
            >
            <el-button @click="detailVisibleCopy = false">取消</el-button>
          </div>
        </el-row>
      </el-form>
      <template #footer>
      <div class="dialog-footer">
        <el-button
          type="danger"
          v-if="form.status == 0 || (form.status == 2 && userInfo.user_id == form.create_user)"
          @click="submitForm(1)"
        >发布</el-button
        >
        <!-- <el-button type="primary" v-if="form.status == 0 || userInfo.user_id == form.create_user"
                        @click="submitForm(0)">保存</el-button> -->
        <el-button
          type="primary"
          v-if="form.status == 1 && hasPaddingBtnPermission()"
          @click="orderLogPass(form.id)"
        >通过</el-button
        >
        <el-button
          type="danger"
          v-if="form.status == 1 && hasRejectionBtnPermission()"
          @click="orderLogReject(form.id)"
        >驳回</el-button
        >
        <el-button @click="detailVisibleCopy = false">取消</el-button>
      </div>
        </template>
    </el-dialog>
  </basic-container>
</template>
@@ -837,6 +846,7 @@
import 'dayjs/locale/zh-cn'; // 导入中文语言包
import weekday from 'dayjs/plugin/weekday';
import elTooltipCopy from '@/components/ElTooltipCopy.vue';
import { CircleClose } from '@element-plus/icons-vue';
dayjs.extend(weekday);
dayjs.locale('zh-cn');
@@ -1067,6 +1077,9 @@
    }
  },
  computed: {
    CircleClose() {
      return CircleClose
    },
    ...mapGetters(['userInfo', 'permission']),
    filteredTabs() {
      // rejection_and_draft 权限控制“已驳回”和“草稿”tab
src/views/tickets/ticket.vue
@@ -414,13 +414,13 @@
        </div>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
        <div class="dialog-footer-new">
          <el-button type="danger" :loading="submitLoading" @click="submitForm">发布</el-button>
          <el-button type="infoprimary" plain :loading="draftLoading" @click="saveDraft"
            >存草稿</el-button
          >
          <el-button @click="handleCancel">取 消</el-button>
          <el-button @click="handleCancel" :icon="CircleClose">取 消</el-button>
        </div>
      </template>
    </el-dialog>
@@ -724,7 +724,7 @@
        </div>
        <!-- 操作按钮 -->
        <div class="dialog-footer1">
        <div class="dialog-footer1-new">
          <div class="leftBtn" :class="currentIndex === 0 ? 'disableds' : ''" @click="leftClick">
            上一页
          </div>
@@ -745,7 +745,7 @@
                @click="rejectTicket"
                >不通过</el-button
              >
              <el-button @click="detailVisible = false">取消</el-button>
              <el-button @click="detailVisible = false":icon="CircleClose">取消</el-button>
            </template>
            <template v-else-if="currentDetail.status === 0">
              <el-button
@@ -845,6 +845,7 @@
      title="批量审核"
      width="1100"
      append-to-body
      class="ztzf-dialog-mange"
      custom-class="review-dialog"
      @close="cancleBatchReject"
    >
@@ -922,7 +923,7 @@
      title="工单复核"
      width="30%"
      append-to-body
      custom-class="re-check-dialog"
      class="ztzf-dialog-mange"
      @close="reCheckDialog = false"
    >
      <div class="dialog-footer">
@@ -957,6 +958,7 @@
import elTooltipCopy from '@/components/ElTooltipCopy.vue';
import getBaseConfig from '@/buildConfig/config';
import CreateQRcode from '@/components/CreateQRcode/CreateQRcode.vue';
import { CircleClose } from '@element-plus/icons-vue';
const { envName } = getBaseConfig();
function regExp(label, name) {
  var reg = new RegExp(label + '=([^&]*)(&|$)', 'g');
@@ -1177,8 +1179,7 @@
    this.loadAMapScripts();
    this.fetchDropdownData();
    // console.log('permission.tickets_processing_btn', this.permission.tickets_processing_btn);
    // console.log('permission', this.permission.tickets_tab_pending);
  },
  mounted() {
@@ -1191,7 +1192,7 @@
    }
    let curQueryParams = {};
    let isTabProcessed = false;
    if (href.indexOf('?') != -1 && href.split('?').length > 0) {
      curQueryParams = href
        .split('?')[1]
@@ -1204,7 +1205,7 @@
          return pre;
        }, {});
      const { orderNumber = undefined, day = undefined } = curQueryParams;
      const { orderNumber = undefined, day = undefined, tab = undefined } = curQueryParams;
      // 日历传值
      if (day) {
@@ -1233,12 +1234,25 @@
          find && (find.query = {});
        });
      }
        if (tab) {
      const isTabValid = this.filteredTabs.some(t => t.name === tab);
      if (isTabValid) {
        this.activeTab = tab;
        this.handleTabChangeAfterJump();
        isTabProcessed = true;
        const find = this.$store.state.tags.bsTagList.find(i => i.path === '/tickets/ticket');
          find && (find.query = {});
      }
    }
    }
    this.fetchTabCounts(); // 新增:初始化时获取 tab 数据
    this.fetchTableData();
  },
  computed: {
    CircleClose() {
      return CircleClose
    },
    firstRowData() {
      return this.tableData.length > 0 ? this.tableData[0] : null;
    },
@@ -1346,8 +1360,7 @@
          // 修改这里:使用 types 数组查找对应的 label
          value:
            this.types.find(t => t.value === this.currentDetail.type)?.label ||
            this.currentDetail.type ||
            '/',
            this.currentDetail.type
        },
        { label: '关联任务', value: this.currentDetail.job_name || '/' },
        { label: '任务发起人', value: this.currentDetail.creator },
@@ -1357,8 +1370,7 @@
          label: '关联算法',
          value:
            this.algorithms.find(t => t.value === this.currentDetail.aiType)?.label ||
            this.currentDetail.aiType ||
            '/',
            this.currentDetail.aiType
        },
        { label: '发起单位', value: this.currentDetail.department },
        { label: '发起任务时间', value: this.currentDetail.startTime },
@@ -1480,7 +1492,6 @@
    },
    handleSFNodeClick(data) {
      console.log(data.dictKey, '666666666');
      this.filters.type = '';
      this.filters.algorithm = '';
      this.filters.type = data.dictKey;
@@ -2033,7 +2044,6 @@
    handleTabChange(tab) {
      this.activeTab = tab.props?.name || tab.name;
      const isReview = this.findObject(this.option.column, 'isReview');
      // 根据条件切换显隐
      isReview.hide = !['all', 'completed', 'myTickets'].includes(this.activeTab);
@@ -2043,7 +2053,15 @@
      this.fetchTableData();
      this.fetchTabCounts(); // 切换 tab 时重新获取数据
    },
    //新增 跳转后触发的Tab切换
handleTabChangeAfterJump() {
    const isReview = this.findObject(this.option.column, 'isReview');
    isReview.hide = !['all', 'completed', 'myTickets'].includes(this.activeTab);
    this.handleReset();
    this.page.currentPage = 1;
    this.fetchTableData();
    this.fetchTabCounts();
  },
    handleSearch() {
      this.page.currentPage = 1;
      this.fetchTableData();
@@ -3096,6 +3114,10 @@
<style lang="scss">
.custom-dialog {
  max-height: 96vh;
  .el-dialog__body {
    border-top: 0.1rem solid #f0f0f0;
  }
}
.custom-qrcode-popover {
  min-width: 160px !important;
@@ -3324,9 +3346,11 @@
    width: 100%;
  }
}
.dialog-footer {
  text-align: center;
:deep(.el-dialog__body) {
  border-top: 0.1rem solid #f0f0f0;
}
.dialog-footer-new {
  text-align: right;
  padding-top: 16px;
  border-top: 1px solid #ebeef5;
@@ -3342,7 +3366,7 @@
    }
  }
}
.dialog-footer1 {
.dialog-footer1-new {
  position: sticky;
  bottom: 28px;
  left: 0;
@@ -3739,6 +3763,7 @@
  :deep(.el-dialog__body) {
    padding: 0;
    background-color: #f5f7fa;
    border-top: 0.1rem solid #f0f0f0;
  }
}
@@ -3746,6 +3771,7 @@
  :deep(.el-dialog__body) {
    padding: 0;
    background-color: #f5f7fa;
    border-top: 0.1rem solid #f0f0f0;
  }
}
src/views/wel/components/backlog.vue
@@ -30,9 +30,10 @@
            </div>
            <div class="action-area">
              <!-- <img :src="st7" alt="" /> -->
              <!-- <span class="todo-date">{{ item.date?.slice(0, 10).replace(/-/g, '.') }}</span> -->
          <span class="todo-date">{{ item.name }}</span>
          <!-- <span class="todo-date">{{ item.name }}</span> -->
          <el-tooltip effect="dark" :content="item.name" placement="top">
            <span class="todo-date">{{item.name}}</span>
          </el-tooltip>
            </div>
          </div>
        </div>
@@ -397,7 +398,7 @@
      .action-area {
        display: flex;
        align-items: center;
        margin-right: 42px;
        margin-right: 22px;
        img {
          width: 15px;
@@ -406,9 +407,14 @@
        .todo-date {
          font-weight: 400;
        font-size: 14px;
color: #343434;
          margin-left: 2px;
      font-size: 14px;
      color: #343434;
      margin-left: 2px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 200px;
      display: inline-block;
        }
      }
    }
src/views/wel/components/proportionStatic.vue
@@ -13,7 +13,7 @@
          :key="index"
          @click="timeClick(item, index)"
        >
          {{ timeListStr[index] }}
          {{ timeListStr[index] }}
        </div>
      </div>
    </div>
@@ -21,7 +21,7 @@
      <div class="card-group">
        <div class="main-card">
          <div class="status-grid">
            <div class="status-item" v-for="(item, index) in eventTypeList" :key="index">
            <div class="status-item" v-for="(item, index) in eventTypeList" :key="index" @click="jumpEventDetails(item,index)">
              <div class="statusCon">
                <div class="status-label">{{ item.name }}</div>
                <div class="status-value">{{ item.value }}<span>个</span></div>
@@ -51,6 +51,8 @@
import overviewImg3 from '@/assets/images/workbench/tc3.svg';
import overviewImg4 from '@/assets/images/workbench/tc4.svg';
import overviewImg5 from '@/assets/images/workbench/tc5.svg';
import { useRouter } from 'vue-router'
const router = useRouter()
let checked = ref('CURRENT_YEAR');
let timeListStr = ['本周', '本月', '本年'];
let timeListEnum = ['CURRENT_WEEK', 'CURRENT_MONTH', 'CURRENT_YEAR'];
@@ -62,10 +64,10 @@
});
const dateSelect = ref('CURRENT_YEAR');
const eventTypeList = ref([
  { name: '待审核', value: 0, img: overviewImg2, color: '#FF472F', status: '2', rate: 0 },
  { name: '待处理', value: 0, img: overviewImg3, color: '#FF7411', status: '0', rate: 0 },
  { name: '处理中', value: 0, img: overviewImg4, color: '#FFC300', status: '3', rate: 0 },
  { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 },
  { name: '待审核', value: 0, img: overviewImg2, color: '#FF472F', status: '2', rate: 0 ,tagging:'pending' },
  { name: '待处理', value: 0, img: overviewImg3, color: '#FF7411', status: '0', rate: 0 ,tagging:'processing' },
  { name: '处理中', value: 0, img: overviewImg4, color: '#FFC300', status: '3', rate: 0 ,tagging:'inProgress'},
  { name: '已完成', value: 0, img: overviewImg5, color: '#0291A1', status: '4', rate: 0 ,tagging:'completed'},
]);
//  工单统计
const getTypeData = () => {
@@ -95,6 +97,14 @@
  dateSelect.value = item;
  getTypeData();
};
// 跳转事件工单
const jumpEventDetails = (item,index)=>{
// console.log('tiaozhuan',item);
  router.replace({
    path: `/tickets/ticket`,
    query: { tab: item.tagging }
  });
}
// 图表
const echartsRef = ref(null);
let { chart } = useEchartsResize(echartsRef);
@@ -250,7 +260,7 @@
          width: 144px;
          background: #f6f8fe;
          border-radius: 8px 8px 8px 8px;
          cursor: pointer;
          img {
            width: 26px;
            height: 26px;