吉安感知网项目-前端
shuishen
2026-01-15 d732cf1a77001ff60309a36875af0010b8addc2a
feat:反无系统页面样式调整等等
45 files modified
2652 ■■■■■ changed files
applications/drone-command/env/.env.development 4 ●●●● patch | view | raw | blame | history
applications/drone-command/src/page/index/top/index.vue 13 ●●●● patch | view | raw | blame | history
applications/drone-command/src/page/index/top/top-qna.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/store/modules/user.js 4 ●●●● patch | view | raw | blame | history
applications/drone-command/src/styles/common/cockpit.scss 537 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/aICrudTemplate/index.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/areaStatistics/index.vue 20 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/defenseZone/FormDiaLog.vue 166 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/defenseZone/index.vue 16 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue 265 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/partition/index.vue 10 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue 80 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/precinctInfo/index.vue 18 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue 257 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/areaManage/sceneConfig/index.vue 22 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/deviceScrap/index.vue 24 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/deviceStock/index.vue 4 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/maintainRecord/FormDiaLog.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/basicManage/maintainRecord/index.vue 20 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCenter/components/dataCenterMap.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/DeviceHistoryDialog.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/EquipmentWarning.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/RealWarning.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/dataCockpit/components/RightContainer.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/FormDiaLog.vue 63 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/index.vue 204 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue 327 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue 23 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/FormDiaLog.vue 126 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue 126 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/taskSchedule/FormDiaLog.vue 115 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/detectionCountermeasure/taskSchedule/index.vue 28 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/job/components/JobRelatedEvents.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/job/components/TaskIntermediateContent/AddTask.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/job/components/executeNestDetails.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/layerManagement/components/leftList.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/layerManagement/components/rightEdit.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/recordManage/alarmRecords/index.vue 20 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue 110 ●●●●● patch | view | raw | blame | history
applications/drone-command/src/views/recordManage/historyTracks/index.vue 14 ●●●● patch | view | raw | blame | history
applications/drone-command/src/views/resource/components/spotDetails.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/tickets/ticket.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/src/views/tickets/ticketComponent/DispatchDialog.vue 2 ●●● patch | view | raw | blame | history
applications/drone-command/env/.env.development
@@ -2,7 +2,7 @@
 # @Author       : yuan
 # @Date         : 2026-01-07 14:58:30
 # @LastEditors  : yuan
 # @LastEditTime : 2026-01-13 16:28:33
 # @LastEditTime : 2026-01-15 10:25:10
 # @FilePath     : \applications\drone-command\env\.env.development
 # @Description  : 
 # Copyright 2026 OBKoro1, All Rights Reserved. 
@@ -16,7 +16,7 @@
#开发环境代理地址(推荐本地新建文件 .env.development.local 来进行覆盖)
# VITE_APP_URL = https://wrj.shuixiongit.com/api
VITE_APP_URL= http://192.168.1.168
VITE_APP_URL= http://192.168.1.204
#新大屏地址
VITE_APP_DASHBOARD_URL = 'https://wrj.shuixiongit.com/command-center-dashboard/'
applications/drone-command/src/page/index/top/index.vue
@@ -8,12 +8,13 @@
    <div class="top-bar__right">
      <div class="top-user">
        <div class="icon-box">
         <img class="gateway" @click="jumpMH" src="@/assets/images/mh.png" alt="进入门户" title="进入门户">
          <img class="gateway" @click="jumpMH" src="@/assets/images/mh.png" alt="进入门户" title="进入门户">
        </div>
        <el-dropdown>
          <span class="el-dropdown-link">
            <img class="top-bar__img" :src="userInfo.avatar" alt="" />
            <!-- <img v-if="userInfo.avatar" class="top-bar__img top-bar__user__img" :src="userInfo.avatar" alt="" /> -->
            <img class="top-bar__img" :src="defaultAva" alt="" />
          </span>
          <template #dropdown>
@@ -36,6 +37,8 @@
</template>
<script>
import defaultAva from '@/assets/images/defaultava.png'
import logo from '@/assets/images/topContainer/logo.png'
import { mapGetters } from 'vuex'
@@ -67,6 +70,7 @@
  data () {
    return {
      logoUrl: logo,
      defaultAva: defaultAva
    }
  },
  filters: {},
@@ -190,6 +194,11 @@
  height: 21px;
}
.top-bar__user__img {
  width: 24px;
  height: 24px;
}
.el-dropdown-link {
  cursor: pointer;
  color: #606266;
applications/drone-command/src/page/index/top/top-qna.vue
@@ -25,7 +25,7 @@
const systemupdateFilePath = ref(null);
const rumenPath = ref(null);
const fileData = ref([]);
const loading = ref(false);
const loading = ref(true);
const getlistDataAPI = async () => {
  loading.value = true;
  try {
applications/drone-command/src/store/modules/user.js
@@ -8,7 +8,6 @@
import { setStore, getStore } from '@/utils/store';
import { validatenull } from '@/utils/validate';
import { deepClone } from '@/utils/util';
import defaultAva from '@/assets/images/defaultava.png'
import {
  loginByUsername,
  loginBySocial,
@@ -336,9 +335,6 @@
      if (validatenull(userInfo.user_id) && validatenull(userInfo.account)) {
        state.userInfo = { user_name: 'unauth', role_name: 'unauth' };
      } else {
        if (validatenull(userInfo.avatar)) {
          userInfo.avatar = defaultAva;
        }
        state.userInfo = userInfo;
      }
      setStore({ name: 'userInfo', content: state.userInfo });
applications/drone-command/src/styles/common/cockpit.scss
@@ -53,9 +53,8 @@
.ztzf-data-cockpit-date-picker-popper {
    background: #161B2C !important;
    border: 1px solid !important;
    border: none !important;
    border-radius: 0px 0px 8px 8px;
    border-image: linear-gradient(180deg, rgba(255, 255, 255, 0), rgba(115, 192, 255, 1)) 1 1 !important;
    .el-date-picker__prev-btn,
    .el-date-picker__next-btn {
@@ -73,6 +72,13 @@
            .el-picker-panel__body {
                background: #161B2C !important;
                color: #fff !important;
                .el-date-range-picker__time-header {
                    .el-input__wrapper {
                        box-shadow: none;
                        background: #2E2E48 !important;
                    }
                }
                .el-date-picker__time-header {
                    border: none;
@@ -107,7 +113,7 @@
                            }
                            .el-time-panel__footer {
                                background: #012350 !important;
                                background: #161B2C !important;
                                border-top: 1px solid rgba(71, 157, 255, 0.3) !important;
                                .el-button {
@@ -173,7 +179,7 @@
                        td.start-date span,
                        td.start-date span,
                        td.end-date span {
                            background-color: #012350 !important;
                            background-color: #161B2C !important;
                        }
                        td.in-range div,
@@ -197,7 +203,7 @@
    }
    .el-picker-panel__sidebar {
        background: #012350;
        background: #161B2C;
        color: #fff;
        .el-picker-panel__shortcut {
@@ -207,7 +213,7 @@
    .el-picker-panel__body {
        .el-input.is-disabled .el-input__wrapper {
            background: #012350;
            background: #161B2C;
            box-shadow: 0 0 0 0.1rem#409eff;
            color: #fff;
@@ -218,11 +224,11 @@
        .el-button.is-disabled,
        .el-button.is-disabled:hover {
            background: #012350;
            background: #161B2C;
        }
        .el-input__wrapper {
            background: #012350;
            background: #161B2C;
            box-shadow: 0 0 0 0.1rem#409eff;
            color: #fff;
@@ -233,18 +239,18 @@
    }
    .el-picker-panel__footer {
        background: #012350;
        background: #161B2C;
        color: #fff;
        border-top: none;
        .el-button--small {
            box-shadow: 0 0 0 0.1rem#409eff;
            background-color: #012350;
            background-color: #161B2C;
            color: #fff;
            border: none;
            &:hover {
                background-color: #012350;
                background-color: #161B2C;
                color: #fff;
                border-color: #409eff;
            }
@@ -258,6 +264,7 @@
    }
    .el-select__wrapper {
        padding: 0 8px;
        background: #2E2E48;
        box-shadow: none !important;
        border: none;
@@ -283,11 +290,11 @@
    }
    .el-select .el-input__wrapper {
        background-color: #012350 !important;
        background-color: #161B2C !important;
    }
    .el-input__wrapper {
        --el-input-text-color: #012350 !important;
        --el-input-text-color: #161B2C !important;
    }
}
@@ -698,6 +705,11 @@
    .el-button {
        min-width: 88px;
    }
    .el-button.is-disabled, .el-button.is-disabled:hover {
        background: #1A2652;
        border: none;
    }
}
.ztzf-table-container {
@@ -713,82 +725,82 @@
        flex: 1;
        display: flex;
        flex-direction: column;
        .ztzf-data-cockpit-table {
            height: 0;
            flex: 1;
            background: transparent !important;
            .el-table--border .el-table__inner-wrapper:after,
            .el-table--border:after,
            .el-table--border:before,
            .el-table__inner-wrapper:before {
                height: 0;
            }
            tr {
                background: transparent !important;
            }
            th.el-table__cell {
                height: 40px;
                border-bottom: 1px solid #323241;
                background: transparent !important;
                .cell {
                    padding: 0;
                    padding-left: 16px;
                    font-family: Source Han Sans CN, Source Han Sans CN;
                    font-weight: 500;
                    font-size: 14px;
                    color: #FFFFFF;
                    line-height: 22px;
                    font-style: normal;
                    text-transform: none;
                }
            }
            td.el-table__cell {
                padding: 9px 0;
                height: 56px;
                border-bottom: 1px solid #323241;
                background: transparent !important;
                .cell {
                    padding: 0;
                    padding-left: 16px;
                    font-family: Source Han Sans CN, Source Han Sans CN;
                    font-weight: 400;
                    font-size: 14px;
                    color: #D2D2E7;
                    line-height: 18px;
                    font-style: normal;
                    text-transform: none;
                }
            }
            td.operation-btns .cell {
                display: flex;
                flex-wrap: nowrap;
                gap: 12px;
                /* 按钮间距(推荐) */
                white-space: nowrap;
                /* 双保险 */
                a {
                    min-width: 28px;
                    color: #6A89FF;
                    &:last-child {
                        margin-right: 0;
                    }
                }
            }
        }
    }
    .ztzf-table-content-bg {
        background: #1A1A2A;
    }
}
.ztzf-data-cockpit-table {
    height: 0;
    flex: 1;
    background: transparent !important;
    .el-table--border .el-table__inner-wrapper:after,
    .el-table--border:after,
    .el-table--border:before,
    .el-table__inner-wrapper:before {
        height: 0;
    }
    tr {
        background: transparent !important;
    }
    th.el-table__cell {
        height: 40px;
        border-bottom: 1px solid #323241;
        background: transparent !important;
        .cell {
            padding: 0;
            padding-left: 16px;
            font-family: Source Han Sans CN, Source Han Sans CN;
            font-weight: 500;
            font-size: 14px;
            color: #FFFFFF;
            line-height: 22px;
            font-style: normal;
            text-transform: none;
        }
    }
    td.el-table__cell {
        padding: 9px 0;
        height: 56px;
        border-bottom: 1px solid #323241;
        background: transparent !important;
        .cell {
            padding: 0;
            padding-left: 16px;
            font-family: Source Han Sans CN, Source Han Sans CN;
            font-weight: 400;
            font-size: 14px;
            color: #D2D2E7;
            line-height: 18px;
            font-style: normal;
            text-transform: none;
        }
    }
    td.operation-btns .cell {
        display: flex;
        flex-wrap: nowrap;
        gap: 12px;
        /* 按钮间距(推荐) */
        white-space: nowrap;
        /* 双保险 */
        a {
            min-width: 28px;
            color: #6A89FF;
            &:last-child {
                margin-right: 0;
            }
        }
    }
}
@@ -862,6 +874,7 @@
}
.ztzf-page-view-dialog {
    padding: 30px;
    display: flex;
    flex-direction: column;
    width: 770px;
@@ -947,7 +960,6 @@
        }
        .dialog-form {
            .el-form-item {
                display: flex;
                align-items: center;
@@ -968,7 +980,7 @@
                .el-form-item__content {
                    display: flex;
                    align-items: center;
                    .el-input {
                        width: 0;
                        flex: 1;
@@ -989,6 +1001,44 @@
                        background: #2E2E48 !important;
                        border: none;
                        box-shadow: none;
                    }
                    .ztzf-data-cockpit-date-picker {
                        background: #2E2E48;
                    }
                    .ztzf-data-cockpit-date-picker-popper {
                        background: #2E2E48 !important;
                        .el-picker-panel {
                            .el-picker-panel__body-wrapper {
                                .el-picker-panel__body {
                                    background: #2E2E48 !important;
                                    .el-date-picker__time-header {
                                        .el-date-picker__editor-wrap {
                                            .el-time-panel {
                                                background: #2E2E48 !important;
                                                // 将 time-picker-popper 的样式移到这里
                                                .el-time-panel__header {
                                                    background: #2E2E48 !important;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        .el-popper__arrow {
                            &::before {
                                background: #2E2E48 !important;
                                border: 1px solid #2E2E48 !important;
                                box-sizing: border-box;
                            }
                        }
                    }
                }
@@ -1069,3 +1119,316 @@
    border-color: #2B2B4C !important;
    color: #FFFFFF !important;
}
.ztzf-page-map-view-dialog {
    padding: 30px;
    display: flex;
    flex-direction: column;
    width: 80%;
    height: 812px;
    background: #1A1A2A;
    border-radius: 6px 6px 6px 6px;
    border: 1px solid #2E2E46;
    .el-dialog__header,
    .el-dialog__footer {
        margin: 0;
        padding: 0;
    }
    .el-dialog__footer {
        .el-button {
            margin-top: 30px;
        }
    }
    .el-dialog__body {
        display: flex;
        flex-direction: column;
        height: 0;
        flex: 1;
        .dialog-container {
            display: flex;
            height: 0;
            flex: 1;
            .left-container {
                width: 0;
                flex: 1;
                height: 100%;
                .leftMap {
                    width: 100%;
                    height: 100%;
                }
            }
            .right-container {
                display: flex;
                flex-direction: column;
                width: 344px;
                height: 100%;
                .header {
                    padding: 0 16px;
                    padding-bottom: 16px;
                    font-family: Source Han Sans CN, Source Han Sans CN;
                    font-weight: 400;
                    font-size: 18px;
                    color: #FFFFFF;
                    text-align: left;
                    font-style: normal;
                    text-transform: none;
                }
                .dialog-container {
                    padding: 0 16px;
                    height: 0;
                    flex: 1;
                    display: flex;
                    flex-direction: column;
                    .detail-title {
                        margin-bottom: 30px;
                        font-family: Source Han Sans CN, Source Han Sans CN;
                        font-weight: 500;
                        font-size: 18px;
                        color: #FFFFFF;
                        text-align: left;
                        font-style: normal;
                        text-transform: none;
                    }
                    .el-row {
                        .el-col {
                            margin-bottom: 20px;
                            display: flex;
                            align-items: center;
                            .label {
                                width: 112px;
                                font-family: Source Han Sans CN, Source Han Sans CN;
                                font-weight: 500;
                                font-size: 14px;
                                color: #D4D5D7;
                                line-height: 22px;
                                text-align: right;
                                font-style: normal;
                                text-transform: none;
                            }
                            .val {
                                width: 0;
                                flex: 1;
                                margin-left: 12px;
                                font-family: Source Han Sans CN, Source Han Sans CN;
                                font-weight: 400;
                                font-size: 14px;
                                color: #9E9EBA;
                                text-align: left;
                                font-style: normal;
                                text-transform: none;
                            }
                        }
                    }
                    .ztzf-table-container {
                        height: 360px;
                        .ztzf-table-pagination {
                            justify-content: center;
                        }
                    }
                }
                .dialog-form {
                    padding-left: 16px;
                    height: 0;
                    flex: 1;
                    display: flex;
                    flex-direction: column;
                    .el-form-item {
                        display: flex;
                        align-items: center;
                        .el-form-item__label {
                            display: flex;
                            align-items: center;
                            font-family: Source Han Sans CN, Source Han Sans CN;
                            font-weight: 500;
                            font-size: 14px;
                            color: #D4D5D7;
                            line-height: 22px;
                            text-align: right;
                            font-style: normal;
                            text-transform: none;
                        }
                        .el-form-item__content {
                            display: flex;
                            align-items: center;
                            .el-input,
                            .el-input-number {
                                width: 0;
                                flex: 1;
                            }
                            .el-textarea {
                                .el-textarea__inner {
                                    color: #fff;
                                    background: #2E2E48 !important;
                                    border: none;
                                    box-shadow: none;
                                }
                            }
                            .el-button {
                                color: #fff;
                                background: #2E2E48 !important;
                                border: none;
                                box-shadow: none;
                            }
                            >div.val {
                                color: #fff;
                            }
                            .ztzf-data-cockpit-date-picker {
                                background: #2E2E48;
                            }
                            .ztzf-data-cockpit-date-picker-popper {
                                background: #2E2E48 !important;
                                .el-picker-panel {
                                    .el-picker-panel__body-wrapper {
                                        .el-picker-panel__body {
                                            background: #2E2E48 !important;
                                            .el-date-picker__time-header {
                                                .el-date-picker__editor-wrap {
                                                    .el-time-panel {
                                                        background: #2E2E48 !important;
                                                        // 将 time-picker-popper 的样式移到这里
                                                        .el-time-panel__header {
                                                            background: #2E2E48 !important;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                .el-popper__arrow {
                                    &::before {
                                        background: #2E2E48 !important;
                                        border: 1px solid #2E2E48 !important;
                                        box-sizing: border-box;
                                    }
                                }
                            }
                        }
                        .el-input {
                            .el-input__wrapper {
                                background: #2E2E48 !important;
                                .el-input__inner {
                                    color: #ffffff;
                                }
                            }
                        }
                    }
                    .search-table-container {
                        height: 0;
                        flex: 1;
                        display: flex;
                        flex-direction: column;
                        .search-box {
                            display: flex;
                            margin-bottom: 18px;
                            .label {
                                display: flex;
                                align-items: center;
                                justify-content: flex-end;
                                padding-right: 12px;
                                width: 96px;
                                font-family: Source Han Sans CN, Source Han Sans CN;
                                font-weight: 500;
                                font-size: 14px;
                                color: #D4D5D7;
                                font-style: normal;
                                text-transform: none;
                                box-sizing: border-box;
                            }
                            .el-input {
                                width: 0;
                                flex: 1;
                                .el-input__wrapper {
                                    background: #2E2E48 !important;
                                    .el-input__inner {
                                        color: #ffffff;
                                    }
                                }
                            }
                        }
                        .el-form-item {
                            height: 0;
                            flex: 1;
                            display: flex;
                            flex-direction: column;
                            .el-form-item__content {
                                width: 100%;
                                height: 0;
                                flex: 1;
                                display: flex;
                                flex-direction: column;
                                .el-table {
                                    height: 0;
                                    flex: 1;
                                }
                            }
                        }
                    }
                }
                .footer {
                    width: 100%;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    .el-button {
                        margin-left: 16px;
                        width: 96px;
                        height: 36px;
                        &:first-child {
                            margin-left: 0;
                        }
                    }
                }
            }
        }
    }
}
applications/drone-command/src/views/aICrudTemplate/index.vue
@@ -110,7 +110,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的设备ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/areaManage/areaStatistics/index.vue
@@ -32,23 +32,23 @@
            <div class="ztzf-table-content ztzf-table-content-bg">
                <el-table class="ztzf-data-cockpit-table" :data="list">
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="areaName" show-overflow-tooltip width="150" label="区域名称" />
                    <el-table-column prop="areaType" show-overflow-tooltip width="130" label="区域类型">
                    <el-table-column prop="areaName" show-overflow-tooltip label="区域名称" />
                    <el-table-column prop="areaType" show-overflow-tooltip label="区域类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.areaType, dictObj.areaType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="sceneName" show-overflow-tooltip width="150" label="关联场景" />
                    <el-table-column prop="sceneType" show-overflow-tooltip width="130" label="场景类型">
                    <el-table-column prop="sceneName" show-overflow-tooltip label="关联场景" />
                    <el-table-column prop="sceneType" show-overflow-tooltip label="场景类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.sceneType, dictObj.sceneType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceCount" show-overflow-tooltip width="110" label="设备数量" />
                    <el-table-column prop="alarmCount" show-overflow-tooltip width="110" label="告警次数" />
                    <el-table-column prop="counterCount" show-overflow-tooltip width="120" label="侦测反制次数" />
                    <el-table-column prop="counterSuccessCount" show-overflow-tooltip width="130" label="反制成功次数" />
                    <el-table-column prop="controlEffect" show-overflow-tooltip width="110" label="管控效果" />
                    <el-table-column prop="deviceCount" show-overflow-tooltip label="设备数量" />
                    <el-table-column prop="alarmCount" show-overflow-tooltip label="告警次数" />
                    <el-table-column prop="counterCount" show-overflow-tooltip label="侦测反制次数" />
                    <el-table-column prop="counterSuccessCount" show-overflow-tooltip label="反制成功次数" />
                    <el-table-column prop="controlEffect" show-overflow-tooltip label="管控效果" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm(row)">查看</el-link>
@@ -87,7 +87,7 @@
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const queryParamsRef = ref(null) // 查询表单实例
const dialogRef = ref(null) // 弹框实例
applications/drone-command/src/views/areaManage/defenseZone/FormDiaLog.vue
@@ -1,64 +1,88 @@
<template>
    <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false" width="80%">
        <div class="bodyBox">
            <div class="leftMap ztzf-cesium" id="mapContainer"></div>
            <div class="rightInfo">
                <div v-if="readonly">
                    <div>防区名称: {{ formData.zoneName }}</div>
                    <div>防区面积: {{ formatZoneArea(formData.zoneArea) }}</div>
                    <el-table :data="sceneList" row-key="id">
                        <el-table-column prop="sceneName" label="场景名称" />
                        <el-table-column prop="sceneType" label="场景类型">
                            <template v-slot="{ row }">
                                {{ getDictLabel(row.sceneType, dictObj.sceneType) }}
                            </template>
                        </el-table-column>
                    </el-table>
    <el-dialog class="ztzf-page-map-view-dialog" v-model="visible" :show-close="false" :close-on-click-modal="false">
        <div class="dialog-container">
            <div class="left-container">
                <div class="leftMap ztzf-cesium" id="mapContainer"></div>
            </div>
            <div class="right-container">
                <div class="header">
                    {{ titleEnum[dialogMode] }}
                </div>
                <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px">
                <div class="dialog-container" v-if="readonly">
                    <div class="detail-title">防区详情</div>
                    <el-row>
                        <el-col :span="24">
                            <el-form-item label="防区名称" prop="zoneName">
                                <el-input v-model="formData.zoneName" maxlength="50" placeholder="请输入" clearable />
                            </el-form-item>
                            <div class="label">防区名称</div>
                            <div class="val">{{ formData.zoneName }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="防区面积" prop="zoneArea">{{ formatZoneArea(formData.zoneArea) }}</el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <div>
                                <div>
                                    关联场景
                                    <el-input v-model="searchName" placeholder="请输入" clearable></el-input>
                                </div>
                                <el-form-item label="关联场景" prop="defenseSceneIds" label-width="0">
                                    <el-table
                                        ref="sceneTableRef"
                                        :data="sceneList.filter(item => item.sceneName.includes(searchName))"
                                        row-key="id"
                                        @selection-change="handleSceneSelectionChange"
                                    >
                                        <el-table-column type="selection" width="55" :reserve-selection="true" />
                                        <el-table-column prop="sceneName" label="场景名称" />
                                        <el-table-column prop="sceneType" label="场景类型">
                                            <template v-slot="{ row }">
                                                {{ getDictLabel(row.sceneType, dictObj.sceneType) }}
                                            </template>
                                        </el-table-column>
                                    </el-table>
                                </el-form-item>
                            </div>
                            <div class="label">防区面积</div>
                            <div class="val">{{ formatZoneArea(formData.zoneArea) }}</div>
                        </el-col>
                    </el-row>
                    <div class="detail-title">关联场景</div>
                    <div class="ztzf-table-container">
                        <div class="ztzf-table-content">
                            <el-table class="ztzf-data-cockpit-table" :data="sceneList" row-key="id">
                                <el-table-column prop="sceneName" label="场景名称" />
                                <el-table-column prop="sceneType" label="场景类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.sceneType, dictObj.sceneType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </div>
                    </div>
                </div>
                <el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly"
                    label-width="96px">
                    <el-form-item label="防区名称" prop="zoneName">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.zoneName" maxlength="50"
                            placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="防区面积" prop="zoneArea">
                        <div class="val">{{ formatZoneArea(formData.zoneArea) }}</div>
                    </el-form-item>
                    <div class="search-table-container">
                        <div class="search-box">
                            <div class="label">
                                关联场景
                            </div>
                            <el-input class="ztzf-data-cockpit-search-input" v-model="searchName" placeholder="请输入"
                                clearable></el-input>
                        </div>
                        <el-form-item prop="defenseSceneIds" label-width="0">
                            <el-table class="ztzf-data-cockpit-table" ref="sceneTableRef"
                                :data="sceneList.filter(item => item.sceneName.includes(searchName))" row-key="id"
                                @selection-change="handleSceneSelectionChange">
                                <el-table-column type="selection" width="55" :reserve-selection="true" />
                                <el-table-column prop="sceneName" label="场景名称" />
                                <el-table-column prop="sceneType" label="场景类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.sceneType, dictObj.sceneType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </el-form-item>
                    </div>
                </el-form>
                <div class="footer">
                    <el-button color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
                    <el-button color="#284FE3" v-if="!readonly" type="primary" :loading="submitting"
                        :disabled="submitting" @click="handleSubmit">
                        确定
                    </el-button>
                </div>
            </div>
        </div>
        <template #footer>
            <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit">
                确定
            </el-button>
        </template>
    </el-dialog>
</template>
@@ -106,12 +130,12 @@
}
// 关闭弹框
function handleCancel() {
function handleCancel () {
    visible.value = false
}
// 提交新增/编辑
async function handleSubmit() {
async function handleSubmit () {
    const isValid = await formRef.value?.validate().catch(() => false)
    if (!isValid) return
    if (!pointList.length) {
@@ -134,14 +158,14 @@
}
// 加载详情
async function loadDetail() {
async function loadDetail () {
    if (!formData.value.id) return
    const res = await fwDefenseZoneDetailApi({ id: formData.value.id })
    formData.value = res?.data?.data ?? initForm()
}
// 获取场景列表
async function getSceneList() {
async function getSceneList () {
    const res = await fwDefenseSceneListApi({ filterSelected: 1, zoneId: formData.value.id })
    sceneList.value = res?.data?.data ?? []
    if (readonly.value) {
@@ -151,19 +175,19 @@
}
// 获取场景ID列表
function getSceneIdList() {
function getSceneIdList () {
    if (!formData.value.defenseSceneIds) return []
    return formData.value.defenseSceneIds.split(',')
}
// 关联场景变更
function handleSceneSelectionChange(rows) {
function handleSceneSelectionChange (rows) {
    selectedSceneRows.value = rows
    formData.value.defenseSceneIds = rows.map(item => item.id).join(',')
}
// 同步关联场景
function syncSceneSelection() {
function syncSceneSelection () {
    if (!sceneTableRef.value) return
    sceneTableRef.value.clearSelection()
    const ids = getSceneIdList()
@@ -178,13 +202,13 @@
}
// 格式化防区面积
function formatZoneArea(value) {
function formatZoneArea (value) {
    if (value == null || value === '') return ''
    return `${value}k㎡`
}
// 初始化地图实例
function initMap() {
function initMap () {
    const publicCesiumInstance = new PublicCesium({
        dom: 'mapContainer',
        flatMode: false,
@@ -210,14 +234,14 @@
}
// 新增模式绘制
function addPolygon() {
function addPolygon () {
    drawPolygonExample = new DrawPolygon(viewer)
    drawPolygonExample.initHandler(viewer)
    drawPolygonExample.subscribe('getPolygonPositions', drawFinished)
}
// 编辑面
function editPolygon() {
function editPolygon () {
    if (!formData.value?.geom) return
    pointList = geomAnalysis(formData.value.geom)
    drawPolygonExample?.destroy()
@@ -232,7 +256,7 @@
}
// 查看面
function viewPolygon() {
function viewPolygon () {
    if (!formData.value?.geom) return
    pointList = geomAnalysis(formData.value.geom)
    const result = pointList.map(item => [item.longitude, item.latitude]).flat()
@@ -250,7 +274,7 @@
}
// 打开弹框
async function open({ mode, row } = {}) {
async function open ({ mode, row } = {}) {
    dialogMode.value = mode || 'add'
    formData.value = dialogMode.value === 'add' ? initForm() : row
    selectedSceneRows.value = []
@@ -277,18 +301,4 @@
})
</script>
<style scoped lang="scss">
.bodyBox {
    display: flex;
    height: 600px;
    .leftMap {
        width: 70%;
        height: 100%;
    }
    .rightInfo {
        width: 30%;
        height: 100%;
        overflow: auto;
    }
}
</style>
<style scoped lang="scss"></style>
applications/drone-command/src/views/areaManage/defenseZone/index.vue
@@ -14,7 +14,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="openForm('add')">新增</el-button>
            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Delete" color="#1A2652" type="primary" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -22,11 +22,11 @@
                <el-table class="ztzf-data-cockpit-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="zoneName" show-overflow-tooltip width="150" label="防区名称" />
                    <el-table-column prop="zoneArea" show-overflow-tooltip width="130" label="防区面积(k㎡)" />
                    <el-table-column prop="sceneCount" show-overflow-tooltip width="120" label="场景数量" />
                    <el-table-column prop="areaCount" show-overflow-tooltip width="120" label="区域数量" />
                    <el-table-column prop="deviceCount" show-overflow-tooltip width="120" label="设备数量" />
                    <el-table-column prop="zoneName" show-overflow-tooltip label="防区名称" />
                    <el-table-column prop="zoneArea" show-overflow-tooltip label="防区面积(k㎡)" />
                    <el-table-column prop="sceneCount" show-overflow-tooltip label="场景数量" />
                    <el-table-column prop="areaCount" show-overflow-tooltip label="区域数量" />
                    <el-table-column prop="deviceCount" show-overflow-tooltip label="设备数量" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
@@ -49,7 +49,7 @@
</template>
<script setup>
import { Search, RefreshRight, Plus } from '@element-plus/icons-vue'
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { nextTick, onMounted, provide, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fwDefenseZonePageApi, fwDefenseZoneRemoveApi } from './defenseZoneApi'
@@ -66,7 +66,7 @@
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/areaManage/partition/FormDiaLog.vue
@@ -1,10 +1,17 @@
<template>
    <el-dialog class="ztzf-page-view-dialog" v-model="visible" :title="titleEnum[dialogMode]"
        :close-on-click-modal="false" width="80%">
        <div class="bodyBox">
            <div class="leftMap ztzf-cesium" id="mapContainer"></div>
            <div class="rightInfo">
                <div class="detail-container" v-if="readonly">
    <el-dialog class="ztzf-page-map-view-dialog" v-model="visible" :show-close="false"
        :close-on-click-modal="false">
        <div class="dialog-container">
            <div class="left-container">
                <div class="leftMap ztzf-cesium" id="mapContainer"></div>
            </div>
            <div class="right-container">
                <div class="header">
                    {{ titleEnum[dialogMode] }}
                </div>
                <div class="dialog-container" v-if="readonly">
                    <div class="detail-title">区域详情</div>
                    <el-row>
                        <el-col :span="24">
@@ -60,126 +67,90 @@
                        </div>
                    </div>
                </div>
                <el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly"
                    label-width="100px">
                    <el-row>
                        <el-col :span="24">
                            <el-form-item label="区域名称" prop="areaName">
                                <el-input class="ztzf-data-cockpit-search-input" v-model="formData.areaName"
                                    maxlength="50" placeholder="请输入" clearable />
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="区域位置" prop="longitude">
                                <div>{{ formatLocation(formData) }}</div>
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="区域面积" prop="areaSize">{{ formData.areaSize || '-' }}k㎡</el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="区域类型" prop="areaType">
                                <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                                    v-model="formData.areaType" placeholder="请选择" clearable>
                                    <el-option
                                        v-for="item in dictObj.areaType"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="响应机制" prop="responseMechanism">
                                <el-input class="ztzf-data-cockpit-search-input" v-model="formData.responseMechanism"
                                    maxlength="200" placeholder="请输入" clearable />
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="触发条件" prop="triggerCondition">
                                <el-input class="ztzf-data-cockpit-search-input" v-model="formData.triggerCondition"
                                    maxlength="200" placeholder="请输入" clearable />
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="管控级别" prop="controlLevel">
                                <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                                    v-model="formData.controlLevel" placeholder="请选择" clearable>
                                    <el-option
                                        v-for="item in dictObj.controlLevel"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="可飞行时段" prop="flyDateStart">
                                <el-date-picker
                                    class="ztzf-data-cockpit-date-picker"
                                    popper-class="ztzf-data-cockpit-date-picker-popper"
                                    v-model="flyDateRange"
                                    type="datetimerange"
                                    range-separator="至"
                                    start-placeholder="开始时间"
                                    end-placeholder="结束时间"
                                    value-format="YYYY-MM-DD HH:mm:ss"
                                    clearable
                                />
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="关联派出所" prop="policeStationId">
                                <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                                    v-model="formData.policeStationId" placeholder="请选择" clearable>
                                    <el-option
                                        v-for="item in policeStationOptions"
                                        :key="item.id"
                                        :label="item.stationName"
                                        :value="item.id"
                                    />
                                </el-select>
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <div>
                                <div>
                                    关联设备
                                    <el-input class="ztzf-data-cockpit-search-input" v-model="searchName" placeholder="请输入"
                                        clearable></el-input>
                                </div>
                                <el-form-item prop="deviceIds" label-width="0">
                                    <el-table
                                        class="ztzf-data-cockpit-table"
                                        ref="deviceTableRef"
                                        :data="deviceOptions.filter(item => item.deviceName.includes(searchName))"
                                        row-key="id"
                                        @selection-change="handleDeviceSelectionChange"
                                    >
                                        <el-table-column type="selection" width="55" :reserve-selection="true" />
                                        <el-table-column prop="deviceName" label="设备名称" />
                                        <el-table-column prop="deviceType" label="类型">
                                            <template v-slot="{ row }">
                                                {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                                            </template>
                                        </el-table-column>
                                    </el-table>
                                </el-form-item>
                    label-width="96px">
                    <el-form-item label="区域名称" prop="areaName">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.areaName" maxlength="50"
                            placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="区域位置" prop="longitude">
                        <div class="val">{{ formatLocation(formData) }}</div>
                    </el-form-item>
                    <el-form-item label="区域面积" prop="areaSize">
                        <div class="val">{{ formData.areaSize || '-' }}k㎡</div>
                    </el-form-item>
                    <el-form-item label="区域类型" prop="areaType">
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.areaType" placeholder="请选择" clearable>
                            <el-option v-for="item in dictObj.areaType" :key="item.dictKey" :label="item.dictValue"
                                :value="item.dictKey" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="响应机制" prop="responseMechanism">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.responseMechanism"
                            maxlength="200" placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="触发条件" prop="triggerCondition">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.triggerCondition"
                            maxlength="200" placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="管控级别" prop="controlLevel">
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.controlLevel" placeholder="请选择" clearable>
                            <el-option v-for="item in dictObj.controlLevel" :key="item.dictKey" :label="item.dictValue"
                                :value="item.dictKey" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="可飞行时段" prop="flyDateStart">
                        <el-date-picker class="ztzf-data-cockpit-date-picker"
                            popper-class="ztzf-data-cockpit-date-picker-popper" v-model="flyDateRange"
                            type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"
                            value-format="YYYY-MM-DD HH:mm:ss" clearable />
                    </el-form-item>
                    <el-form-item label="关联派出所" prop="policeStationId">
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.policeStationId" placeholder="请选择" clearable>
                            <el-option v-for="item in policeStationOptions" :key="item.id" :label="item.stationName"
                                :value="item.id" />
                        </el-select>
                    </el-form-item>
                    <div class="search-table-container">
                        <div class="search-box">
                            <div class="label">
                                关联设备
                            </div>
                        </el-col>
                    </el-row>
                            <el-input class="ztzf-data-cockpit-search-input" v-model="searchName" placeholder="请输入"
                                clearable></el-input>
                        </div>
                        <el-form-item prop="deviceIds" label-width="0">
                            <el-table class="ztzf-data-cockpit-table" ref="deviceTableRef"
                                :data="deviceOptions.filter(item => item.deviceName.includes(searchName))" row-key="id"
                                @selection-change="handleDeviceSelectionChange">
                                <el-table-column type="selection" width="55" :reserve-selection="true" />
                                <el-table-column prop="deviceName" label="设备名称" />
                                <el-table-column prop="deviceType" label="类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </el-form-item>
                    </div>
                </el-form>
                <div class="footer">
                    <el-button color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
                    <el-button color="#284FE3" v-if="!readonly" type="primary" :loading="submitting"
                        :disabled="submitting" @click="handleSubmit">
                        确定
                    </el-button>
                </div>
            </div>
        </div>
        <template #footer>
            <el-button color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button color="#284FE3" v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting"
                @click="handleSubmit">
                确定
            </el-button>
        </template>
    </el-dialog>
</template>
@@ -218,7 +189,7 @@
const dialogMode = ref('add') // 弹框模式
const submitting = ref(false) // 提交中
const readonly = computed(() => dialogMode.value === 'view')
const titleEnum = ref({ edit: '编辑', view: '查看', add: '新增' })
const titleEnum = ref({ edit: '编辑场景', view: '查看场景', add: '新增场景' })
const flyDateRange = ref([]) // 飞行时间
const deviceTableRef = ref(null)
const searchName = ref('')
@@ -243,12 +214,12 @@
}
// 关闭弹框
function handleCancel() {
function handleCancel () {
    visible.value = false
}
// 提交新增/编辑
async function handleSubmit() {
async function handleSubmit () {
    const isValid = await formRef.value?.validate().catch(() => false)
    if (!isValid) return
    submitting.value = true
@@ -273,7 +244,7 @@
)
// 加载详情
async function loadDetail() {
async function loadDetail () {
    if (!formData.value.id) return
    const res = await fwAreaDivideDetailApi({ id: formData.value.id })
    formData.value = res?.data?.data ?? initForm()
@@ -281,19 +252,19 @@
}
// 格式化区域位置
function formatLocation(row) {
function formatLocation (row) {
    if (row?.longitude == null || row?.latitude == null) return ''
    return `${_.round(row.longitude, 6)}, ${_.round(row.latitude, 6)}`
}
// 格式化可飞行时间段
function formatFlyDate(row) {
function formatFlyDate (row) {
    if (!row?.flyDateStart && !row?.flyDateEnd) return ''
    return `${row.flyDateStart || '-'} ~ ${row.flyDateEnd || '-'}`
}
// 初始化地图实例
function initMap() {
function initMap () {
    const publicCesiumInstance = new PublicCesium({
        dom: 'mapContainer',
        flatMode: false,
@@ -321,14 +292,14 @@
}
// 新增模式绘制
function addPolygon() {
function addPolygon () {
    drawPolygonExample = new DrawPolygon(viewer)
    drawPolygonExample.initHandler(viewer)
    drawPolygonExample.subscribe('getPolygonPositions', drawFinished)
}
// 编辑面
function editPolygon() {
function editPolygon () {
    if (!formData.value?.geom) return
    pointList = geomAnalysis(formData.value.geom)
    drawPolygonExample?.destroy()
@@ -343,7 +314,7 @@
}
// 查看面
function viewPolygon() {
function viewPolygon () {
    if (!formData.value?.geom) return
    pointList = geomAnalysis(formData.value.geom)
    const result = pointList.map(item => [item.longitude, item.latitude]).flat()
@@ -361,13 +332,13 @@
}
// 获取派出所列表
async function getPoliceStationList() {
async function getPoliceStationList () {
    const res = await fwPoliceStationListApi()
    policeStationOptions.value = res?.data?.data ?? []
}
// 获取设备列表
async function getDeviceList() {
async function getDeviceList () {
    if (deviceOptions.value.length) return
    const res = await fwDeviceListApi({ isAreaSelect: 1, areaId: formData.value.id })
    deviceOptions.value = res?.data?.data ?? []
@@ -377,14 +348,14 @@
}
// 关联设备变更
function handleDeviceSelectionChange(rows) {
function handleDeviceSelectionChange (rows) {
    selectedDeviceRows.value = rows
    const ids = rows.map(item => item.id)
    formData.value.deviceIds = ids.join(',')
}
// 同步选择状态
function syncDeviceSelection() {
function syncDeviceSelection () {
    if (!deviceTableRef.value) return
    deviceTableRef.value.clearSelection()
    const rows = []
@@ -399,7 +370,7 @@
}
// 打开弹框
async function open({ mode, row } = {}) {
async function open ({ mode, row } = {}) {
    dialogMode.value = mode || 'add'
    formData.value = dialogMode.value === 'add' ? initForm() : row
    selectedDeviceRows.value = []
@@ -429,24 +400,4 @@
})
</script>
<style scoped lang="scss">
.bodyBox {
    display: flex;
    height: 600px;
    .leftMap {
        width: 70%;
        height: 100%;
    }
    .rightInfo {
        width: 30%;
        height: 100%;
        overflow: auto;
        .ztzf-table-container,
        .ztzf-table-content {
            height: auto;
            flex: none;
        }
    }
}
</style>
<style scoped lang="scss"></style>
applications/drone-command/src/views/areaManage/partition/index.vue
@@ -22,7 +22,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="openForm('add')">新增</el-button>
            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Delete" color="#1A2652" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -49,8 +49,8 @@
                            {{ getDictLabel(row.controlLevel, dictObj.controlLevel) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="policeStationName" show-overflow-tooltip width="140" label="关联派出所" />
                    <el-table-column show-overflow-tooltip width="160" label="可飞行时间段">
                    <el-table-column prop="policeStationName" show-overflow-tooltip label="关联派出所" />
                    <el-table-column show-overflow-tooltip label="可飞行时间段">
                        <template v-slot="{ row }">
                            {{ formatFlyDate(row) }}
                        </template>
@@ -77,7 +77,7 @@
</template>
<script setup>
import { Search, RefreshRight, Plus } from '@element-plus/icons-vue'
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { nextTick, onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fwAreaDividePageApi, fwAreaDivideRemoveApi } from './partitionApi'
@@ -94,7 +94,7 @@
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/areaManage/precinctInfo/FormDiaLog.vue
@@ -45,7 +45,7 @@
                <el-col :span="24">
                    <el-form-item label="位置" prop="longitude">
                        <el-button @click="selectLocation" style="width: 100%">
                            {{ formData.longitude }}, {{ formData.longitude }}, {{ formData.address }}
                            {{ formData.longitude }}, {{ formData.latitude }}, {{ formData.address }}
                        </el-button>
                    </el-form-item>
                </el-col>
@@ -59,11 +59,17 @@
            </el-button>
        </template>
        <el-dialog v-model="visible1" title="选择位置" destroy-on-close @closed="positionClosed">
            <div class="ztzf-cesium" id="mapContainer"></div>
        <el-dialog class="ztzf-page-map-view-dialog" v-model="visible1" :show-close="false"
            :close-on-click-modal="false" destroy-on-close @closed="positionClosed">
            <div class="dialog-container">
                <div class="left-container">
                    <div class="leftMap ztzf-cesium" id="mapContainer"></div>
                </div>
            </div>
            <template #footer>
                <el-button @click="handleMapCancel">取消</el-button>
                <el-button type="primary" @click="handleMapConfirm">确定</el-button>
                <el-button color="#2B2B4C" @click="handleMapCancel">取消</el-button>
                <el-button color="#284FE3" type="primary" @click="handleMapConfirm">确定</el-button>
            </template>
        </el-dialog>
    </el-dialog>
@@ -106,12 +112,12 @@
}
// 关闭弹框
function handleCancel() {
function handleCancel () {
    visible.value = false
}
// 提交新增/编辑
async function handleSubmit() {
async function handleSubmit () {
    const isValid = await formRef.value?.validate().catch(() => false)
    if (!isValid) return
    submitting.value = true
@@ -126,13 +132,13 @@
}
// 加载详情
async function loadDetail() {
async function loadDetail () {
    if (!formData.value.id) return
    const res = await fwPoliceStationDetailApi({ id: formData.value.id })
    formData.value = res?.data?.data ?? {}
}
function LeftClickEvent(click) {
function LeftClickEvent (click) {
    const pos = click.position // Cartesian2 屏幕坐标
    // 屏幕坐标 -> 椭球面坐标(不考虑地形/模型)
    const cartesian3 = viewer.camera.pickEllipsoid(pos, viewer.scene.globe.ellipsoid)
@@ -174,13 +180,49 @@
    }
}
function positionClosed() {
function positionClosed () {
    redPointEntity = null
}
let viewer
let redPointEntity
async function selectLocation() {
function setMapPoint (longitude, latitude) {
    if (!viewer || longitude == null || latitude == null) return
    if (!redPointEntity) {
        redPointEntity = viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
            point: {
                color: Cesium.Color.RED,
                pixelSize: 10,
            },
            label: {
                text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`,
                font: '14px',
                fillColor: Cesium.Color.WHITE,
                backgroundColor: Cesium.Color.BLACK.withAlpha(0.45),
                backgroundPadding: new Cesium.Cartesian2(5, 5),
                pixelOffset: new Cesium.Cartesian2(0, -20),
                showBackground: true,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                outlineWidth: 1,
                outlineColor: Cesium.Color.WHITE,
                eyeOffset: new Cesium.Cartesian3(0, 0, -20),
            },
        })
    } else {
        redPointEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude)
        redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`
    }
}
function formatCoord (value) {
    if (value == null || value === '') return '-'
    return _.round(Number(value), 6)
}
async function selectLocation () {
    visible1.value = true
    await nextTick()
    const publicCesiumInstance = new PublicCesium({
@@ -192,14 +234,18 @@
    })
    publicCesiumInstance.addLeftClickEvent(null, LeftClickEvent)
    viewer = publicCesiumInstance.getViewer()
    if (formData.value.longitude != null && formData.value.latitude != null) {
        tempLocation.value = { longitude: formData.value.longitude, latitude: formData.value.latitude }
        setMapPoint(formData.value.longitude, formData.value.latitude)
    }
}
function handleMapCancel() {
function handleMapCancel () {
    tempLocation.value = { longitude: null, latitude: null }
    visible1.value = false
}
async function getLocationName() {
async function getLocationName () {
    const tk = import.meta.env.VITE_APP_TDT_TOKEN
    const { latitude, longitude } = tempLocation.value
    const http = axios.create({ withCredentials: false })
@@ -210,7 +256,7 @@
    formData.value.address = res.data.result.formatted_address
}
function handleMapConfirm() {
function handleMapConfirm () {
    if (tempLocation.value.longitude != null && tempLocation.value.latitude != null) {
        formData.value.longitude = _.round(tempLocation.value.longitude, 6)
        formData.value.latitude = _.round(tempLocation.value.latitude, 6)
@@ -219,7 +265,7 @@
    visible1.value = false
}
// 打开弹框
async function open({ mode, row } = {}) {
async function open ({ mode, row } = {}) {
    dialogMode.value = mode || 'add'
    formData.value = dialogMode.value === 'add' ? initForm() : row
    dialogMode.value !== 'add' && (await loadDetail())
@@ -228,8 +274,4 @@
defineExpose({ open })
</script>
<style scoped lang="scss">
#mapContainer {
    width: 100%;
    height: 500px;
}
</style>
applications/drone-command/src/views/areaManage/precinctInfo/index.vue
@@ -14,7 +14,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="openForm('add')">新增</el-button>
            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Delete" color="#1A2652" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -22,12 +22,12 @@
                <el-table class="ztzf-data-cockpit-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="stationName" show-overflow-tooltip width="160" label="派出所名称" />
                    <el-table-column prop="address" show-overflow-tooltip width="200" label="位置" />
                    <el-table-column prop="longitude" show-overflow-tooltip width="120" label="经度" />
                    <el-table-column prop="latitude" show-overflow-tooltip width="120" label="纬度" />
                    <el-table-column prop="contactPerson" show-overflow-tooltip width="120" label="联系人" />
                    <el-table-column prop="contactPhone" show-overflow-tooltip width="140" label="联系方式" />
                    <el-table-column prop="stationName" show-overflow-tooltip label="派出所名称" />
                    <el-table-column prop="address" show-overflow-tooltip label="位置" />
                    <el-table-column prop="longitude" show-overflow-tooltip label="经度" />
                    <el-table-column prop="latitude" show-overflow-tooltip label="纬度" />
                    <el-table-column prop="contactPerson" show-overflow-tooltip label="联系人" />
                    <el-table-column prop="contactPhone" show-overflow-tooltip label="联系方式" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('edit', row)">编辑</el-link>
@@ -49,7 +49,7 @@
</template>
<script setup>
import { Search, RefreshRight, Plus } from '@element-plus/icons-vue'
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { nextTick, onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fwPoliceStationPageApi, fwPoliceStationRemoveApi } from './precinctInfoApi'
@@ -62,7 +62,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/areaManage/sceneConfig/FormDiaLog.vue
@@ -1,116 +1,137 @@
<template>
    <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false" width="80%">
        <div class="bodyBox">
            <div class="leftMap ztzf-cesium" id="mapContainer"></div>
            <div class="rightInfo">
                <div v-if="readonly">
                    <div>场景名称: {{ formData.sceneName }}</div>
                    <div>指挥点位置: {{ formatLocation(formData) }}</div>
                    <div>场景类型: {{ getDictLabel(formData.sceneType, dictObj.sceneType) }}</div>
                    <div>防控负责人: {{ formData.defenseLeader }}</div>
                    <div>防控负责人电话: {{ formData.leaderPhone }}</div>
                    <div>设备模式: {{ getDictLabel(formData.deviceMode, dictObj.deviceMode) }}</div>
                    <div>防控面积: {{ formatDefenseArea(formData.defenseArea) }}</div>
                    <el-table ref="areaTableRef" :data="areaList" row-key="id">
                        <el-table-column prop="areaName" label="区域名称" />
                        <el-table-column prop="areaType" label="区域类型">
                            <template v-slot="{ row }">
                                {{ getDictLabel(row.areaType, dictObj.areaType) }}
                            </template>
                        </el-table-column>
                    </el-table>
    <el-dialog class="ztzf-page-map-view-dialog" v-model="visible" :show-close="false" :close-on-click-modal="false">
        <div class="dialog-container">
            <div class="left-container">
                <div class="leftMap ztzf-cesium" id="mapContainer"></div>
            </div>
            <div class="right-container">
                <div class="header">
                    {{ titleEnum[dialogMode] }}
                </div>
                <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px">
                <div class="dialog-container" v-if="readonly">
                    <div class="detail-title">场景详情</div>
                    <el-row>
                        <el-col :span="24">
                            <el-form-item label="场景名称" prop="sceneName">
                                <el-input v-model="formData.sceneName" maxlength="50" placeholder="请输入" clearable />
                            </el-form-item>
                            <div class="label">场景名称</div>
                            <div class="val">{{ formData.sceneName }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="指挥点位置" prop="longitude">
                                <div>{{ formatLocation(formData) }}</div>
                            </el-form-item>
                            <div class="label">指挥点位置</div>
                            <div class="val">{{ formatLocation(formData) }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="场景类型" prop="sceneType">
                                <el-select v-model="formData.sceneType" placeholder="请选择" clearable>
                                    <el-option
                                        v-for="item in dictObj.sceneType"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                            </el-form-item>
                            <div class="label">场景类型</div>
                            <div class="val">{{ getDictLabel(formData.sceneType, dictObj.sceneType) }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="防控负责人" prop="defenseLeader">
                                <el-input v-model="formData.defenseLeader" maxlength="50" placeholder="请输入" clearable />
                            </el-form-item>
                            <div class="label">负责人</div>
                            <div class="val">{{ formData.defenseLeader }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="防控负责人电话" prop="leaderPhone">
                                <el-input v-model="formData.leaderPhone" maxlength="50" placeholder="请输入" clearable />
                            </el-form-item>
                            <div class="label">负责人电话</div>
                            <div class="val">{{ formData.leaderPhone }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="设备模式" prop="deviceMode">
                                <el-select v-model="formData.deviceMode" placeholder="请选择" clearable>
                                    <el-option
                                        v-for="item in dictObj.deviceMode"
                                        :key="item.dictKey"
                                        :label="item.dictValue"
                                        :value="item.dictKey"
                                    />
                                </el-select>
                            </el-form-item>
                            <div class="label">设备模式</div>
                            <div class="val">{{ getDictLabel(formData.deviceMode, dictObj.deviceMode) }}</div>
                        </el-col>
                        <el-col :span="24">
                            <el-form-item label="防控面积" prop="defenseArea">
                                <div>{{ formatDefenseArea(formData.defenseArea) }}</div>
                            </el-form-item>
                        </el-col>
                        <el-col :span="24">
                            <div>
                                <div>
                                    关联区域
                                    <el-input v-model="searchName" placeholder="请输入" clearable></el-input>
                                </div>
                                <el-form-item prop="areaDivideIds" label-width="0">
                                    <el-table
                                        ref="areaTableRef"
                                        :data="areaList.filter(item => item.areaName.includes(searchName))"
                                        row-key="id"
                                        @selection-change="handleAreaSelectionChange"
                                    >
                                        <el-table-column type="selection" width="55" :reserve-selection="true" />
                                        <el-table-column prop="areaName" label="区域名称" />
                                        <el-table-column prop="areaType" label="区域类型">
                                            <template v-slot="{ row }">
                                                {{ getDictLabel(row.areaType, dictObj.areaType) }}
                                            </template>
                                        </el-table-column>
                                    </el-table>
                                </el-form-item>
                            </div>
                            <div class="label">防控面积</div>
                            <div class="val">{{ formatDefenseArea(formData.defenseArea) }}</div>
                        </el-col>
                    </el-row>
                    <div class="detail-title">关联区域</div>
                    <div class="ztzf-table-container">
                        <div class="ztzf-table-content">
                            <el-table class="ztzf-data-cockpit-table" ref="areaTableRef" :data="areaList" row-key="id">
                                <el-table-column prop="areaName" label="区域名称" />
                                <el-table-column prop="areaType" label="区域类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.areaType, dictObj.areaType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </div>
                    </div>
                </div>
                <el-form class="dialog-form" v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly"
                    label-width="96px">
                    <el-form-item label="场景名称" prop="sceneName">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.sceneName" maxlength="50"
                            placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="指挥点位置" prop="longitude">
                        <div class="val">{{ formatLocation(formData) }}</div>
                    </el-form-item>
                    <el-form-item label="场景类型" prop="sceneType">
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.sceneType" placeholder="请选择" clearable>
                            <el-option v-for="item in dictObj.sceneType" :key="item.dictKey" :label="item.dictValue"
                                :value="item.dictKey" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="负责人" prop="defenseLeader">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.defenseLeader" maxlength="50"
                            placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="负责人电话" prop="leaderPhone">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.leaderPhone" maxlength="50"
                            placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="设备模式" prop="deviceMode">
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.deviceMode" placeholder="请选择" clearable>
                            <el-option v-for="item in dictObj.deviceMode" :key="item.dictKey" :label="item.dictValue"
                                :value="item.dictKey" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="防控面积" prop="defenseArea">
                        <div class="val">{{ formatDefenseArea(formData.defenseArea) }}</div>
                    </el-form-item>
                    <div class="search-table-container">
                        <div class="search-box">
                            <div class="label">
                                关联区域
                            </div>
                            <el-input class="ztzf-data-cockpit-search-input" v-model="searchName" placeholder="请输入"
                                clearable></el-input>
                        </div>
                        <el-form-item prop="areaDivideIds" label-width="0">
                            <el-table class="ztzf-data-cockpit-table" ref="areaTableRef"
                                :data="areaList.filter(item => item.areaName.includes(searchName))" row-key="id"
                                @selection-change="handleAreaSelectionChange">
                                <el-table-column type="selection" width="55" :reserve-selection="true" />
                                <el-table-column prop="areaName" label="区域名称" />
                                <el-table-column prop="areaType" label="区域类型">
                                    <template v-slot="{ row }">
                                        {{ getDictLabel(row.areaType, dictObj.areaType) }}
                                    </template>
                                </el-table-column>
                            </el-table>
                        </el-form-item>
                    </div>
                </el-form>
                <div class="footer">
                    <el-button color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
                    <el-button color="#284FE3" v-if="!readonly" type="primary" :loading="submitting"
                        :disabled="submitting" @click="handleSubmit">
                        确定
                    </el-button>
                </div>
            </div>
        </div>
        <template #footer>
            <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit">
                确定
            </el-button>
        </template>
    </el-dialog>
</template>
<script setup>
import { computed, inject, nextTick, onMounted, ref } from 'vue'
import { computed, inject, nextTick, onMounted, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { fwDefenseSceneDetailApi, fwDefenseSceneSubmitApi } from './sceneConfigApi'
import { fieldRules, geomAnalysis, getDictLabel } from '@ztzf/utils'
@@ -122,8 +143,8 @@
const initForm = () => ({
    sceneName: '', // 场景名称
    sceneType: '', // 场景类型
    defenseLeader: '', // 防控负责人
    leaderPhone: '', // 防控负责人电话
    defenseLeader: '', // 负责人
    leaderPhone: '', // 负责人电话
    deviceMode: '', // 设备模式
    areaDivideIds: '', // 关联区域ID
    areaCount: 0, // 区域数量
@@ -159,12 +180,12 @@
}
// 关闭弹框
function handleCancel() {
function handleCancel () {
    visible.value = false
}
// 提交新增/编辑
async function handleSubmit() {
async function handleSubmit () {
    const isValid = await formRef.value?.validate().catch(() => false)
    if (!isValid) return
    submitting.value = true
@@ -183,21 +204,21 @@
}
// 加载详情
async function loadDetail() {
async function loadDetail () {
    if (!formData.value.id) return
    const res = await fwDefenseSceneDetailApi({ id: formData.value.id })
    formData.value = res?.data?.data ?? initForm()
}
// 获取区域列表
async function getAreaList() {
async function getAreaList () {
    if (areaList.value.length) return
    const res = await fwAreaDivideListApi({ filterSelected: 1, sceneId: formData.value.id })
    areaList.value = res?.data?.data ?? []
}
// 关联区域变更
function handleAreaSelectionChange(rows) {
function handleAreaSelectionChange (rows) {
    selectedAreaRows.value = rows
    formData.value.areaDivideIds = rows.map(item => item.id)
    formData.value.areaCount = rows.length
@@ -205,7 +226,7 @@
}
// 渲染面
function renderingSurface() {
function renderingSurface () {
    geometricSource && geometricSource.entities.removeAll()
    selectedAreaRows.value.forEach(item => {
        if (item.geom) {
@@ -227,13 +248,13 @@
watch(() => selectedAreaRows.value, renderingSurface)
function calcDefenseArea(rows) {
function calcDefenseArea (rows) {
    const total = rows.reduce((sum, item) => sum + (Number(item.areaSize) || 0), 0)
    return _.round(total, 2)
}
// 同步关联区域
function syncAreaSelection() {
function syncAreaSelection () {
    if (!areaTableRef.value) return
    areaTableRef.value.clearSelection()
    const rows = []
@@ -250,20 +271,20 @@
    formData.value.defenseArea = calcDefenseArea(rows)
}
function formatDefenseArea(value) {
function formatDefenseArea (value) {
    if (value == null || value === '') return ''
    return `${value}k㎡`
}
// 格式化指挥点位置
function formatLocation(row) {
function formatLocation (row) {
    if (row?.longitude == null || row?.latitude == null) return ''
    return `${_.round(row.longitude, 6)}, ${_.round(row.latitude, 6)}`
}
let geometricSource
// 初始化地图实例
function initMap() {
function initMap () {
    const publicCesiumInstance = new PublicCesium({
        dom: 'mapContainer',
        flatMode: false,
@@ -279,7 +300,7 @@
    viewer.dataSources.add(geometricSource)
}
function LeftClickEvent(click) {
function LeftClickEvent (click) {
    const pos = click.position
    const cartesian3 = viewer.camera.pickEllipsoid(pos, viewer.scene.globe.ellipsoid)
    if (!cartesian3) return
@@ -291,7 +312,7 @@
    setMapPoint(formData.value.longitude, formData.value.latitude)
}
function setMapPoint(longitude, latitude) {
function setMapPoint (longitude, latitude) {
    if (!viewer || longitude == null || latitude == null) return
    if (!redPointEntity) {
        redPointEntity = viewer.entities.add({
@@ -303,17 +324,17 @@
            label: {
                text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`,
                font: '14px',
                fillColor: Cesium.Color.WHITE, // 文字颜色:白色
                backgroundColor: Cesium.Color.BLACK.withAlpha(0.45), //背景颜色
                backgroundPadding: new Cesium.Cartesian2(5, 5), // 水平/垂直内边距(像素)
                pixelOffset: new Cesium.Cartesian2(0, -20), // 可选:微调位置
                showBackground: true, // 确保背景显示(某些版本需要)
                fillColor: Cesium.Color.WHITE,
                backgroundColor: Cesium.Color.BLACK.withAlpha(0.45),
                backgroundPadding: new Cesium.Cartesian2(5, 5),
                pixelOffset: new Cesium.Cartesian2(0, -20),
                showBackground: true,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                outlineWidth: 1,
                outlineColor: Cesium.Color.WHITE,
                eyeOffset: new Cesium.Cartesian3(0, 0, -20), // 负值更靠近相机(显示在前)
                eyeOffset: new Cesium.Cartesian3(0, 0, -20),
            },
        })
    } else {
@@ -323,7 +344,7 @@
}
// 打开弹框
async function open({ mode, row } = {}) {
async function open ({ mode, row } = {}) {
    dialogMode.value = mode || 'add'
    formData.value = dialogMode.value === 'add' ? initForm() : row
    selectedAreaRows.value = []
@@ -348,18 +369,4 @@
})
</script>
<style scoped lang="scss">
.bodyBox {
    display: flex;
    height: 600px;
    .leftMap {
        width: 70%;
        height: 100%;
    }
    .rightInfo {
        width: 30%;
        height: 100%;
        overflow: auto;
    }
}
</style>
<style scoped lang="scss"></style>
applications/drone-command/src/views/areaManage/sceneConfig/index.vue
@@ -55,7 +55,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="openForm('add')">新增</el-button>
            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Delete" color="#1A2652" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -64,22 +64,22 @@
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="sceneName" show-overflow-tooltip width="130" label="场景名称" />
                    <el-table-column prop="sceneType" show-overflow-tooltip width="120" label="场景类型">
                    <el-table-column prop="sceneName" show-overflow-tooltip label="场景名称" />
                    <el-table-column prop="sceneType" show-overflow-tooltip label="场景类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.sceneType, dictObj.sceneType) }}
                        </template>
                    </el-table-column>
                    <el-table-column show-overflow-tooltip width="150" label="指挥点位置">
                    <el-table-column show-overflow-tooltip label="指挥点位置">
                        <template v-slot="{ row }">
                            {{ formatLocation(row) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="defenseLeader" show-overflow-tooltip width="120" label="防控负责人" />
                    <el-table-column prop="leaderPhone" show-overflow-tooltip width="140" label="防控负责人电话" />
                    <el-table-column prop="areaCount" show-overflow-tooltip width="110" label="区域数量" />
                    <el-table-column prop="counterDeviceCount" show-overflow-tooltip width="120" label="反制设备数量" />
                    <el-table-column prop="detectDeviceCount" show-overflow-tooltip width="120" label="探测设备数量" />
                    <el-table-column prop="defenseLeader" show-overflow-tooltip label="防控负责人" />
                    <el-table-column prop="leaderPhone" show-overflow-tooltip label="防控负责人电话" />
                    <el-table-column prop="areaCount" show-overflow-tooltip label="区域数量" />
                    <el-table-column prop="counterDeviceCount" show-overflow-tooltip label="反制设备数量" />
                    <el-table-column prop="detectDeviceCount" show-overflow-tooltip label="探测设备数量" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)">查看</el-link>
@@ -107,7 +107,7 @@
</template>
<script setup>
import { Search, RefreshRight, Plus } from '@element-plus/icons-vue'
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { nextTick, onMounted, provide, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fwDefenseScenePageApi, fwDefenseSceneRemoveApi } from './sceneConfigApi'
@@ -125,7 +125,7 @@
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/basicManage/deviceScrap/index.vue
@@ -31,21 +31,21 @@
                <el-table class="ztzf-data-cockpit-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="deviceName" show-overflow-tooltip width="130" label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip width="130" label="设备类型">
                    <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceModel" show-overflow-tooltip width="98" label="型号" />
                    <el-table-column prop="manufacturer" show-overflow-tooltip width="130" label="生产厂商" />
                    <el-table-column prop="createTime" show-overflow-tooltip width="96" label="入库时间" />
                    <el-table-column prop="source" show-overflow-tooltip width="112" label="来源" />
                    <el-table-column prop="charger" show-overflow-tooltip width="100" label="负责人" />
                    <el-table-column prop="scrapTime" show-overflow-tooltip width="96" label="报废时间" />
                    <el-table-column prop="scrapReason" show-overflow-tooltip width="136" label="报废原因" />
                    <el-table-column prop="disposeWay" show-overflow-tooltip width="116" label="处置方式" />
                    <el-table-column prop="maintainReminder" show-overflow-tooltip width="116" label="维护提醒" />
                    <el-table-column prop="deviceModel" show-overflow-tooltip label="型号" />
                    <el-table-column prop="manufacturer" show-overflow-tooltip label="生产厂商" />
                    <el-table-column prop="createTime" show-overflow-tooltip label="入库时间" />
                    <el-table-column prop="source" show-overflow-tooltip label="来源" />
                    <el-table-column prop="charger" show-overflow-tooltip label="负责人" />
                    <el-table-column prop="scrapTime" show-overflow-tooltip label="报废时间" />
                    <el-table-column prop="scrapReason" show-overflow-tooltip label="报废原因" />
                    <el-table-column prop="disposeWay" show-overflow-tooltip label="处置方式" />
                    <el-table-column prop="maintainReminder" show-overflow-tooltip label="维护提醒" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="handleView(row)">查看</el-link>
@@ -84,7 +84,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/basicManage/deviceStock/FormDiaLog.vue
@@ -272,7 +272,7 @@
    formData.value = initForm()
}
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
async function getList () {
    loading.value = true
applications/drone-command/src/views/basicManage/deviceStock/index.vue
@@ -65,7 +65,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="handleAdd">新增</el-button>
            <el-button :icon="Download" type="primary" @click="exportFile" :loading="exportLoading">导出</el-button>
            <el-button :icon="Download" color="#1A2652" type="primary" @click="exportFile" :loading="exportLoading">导出</el-button>
            <!--            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>-->
        </div>
@@ -147,7 +147,7 @@
    size: 10, // 每页大小
})
const searchParams = ref(initSearchParams()) // 查询参数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const total = ref(0) // 总数
const selectedIds = ref([]) // 勾选的设备ID列表
applications/drone-command/src/views/basicManage/maintainRecord/FormDiaLog.vue
@@ -198,7 +198,7 @@
})
const searchParams = ref(initSearchParams())
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
async function getList() {
    loading.value = true
applications/drone-command/src/views/basicManage/maintainRecord/index.vue
@@ -28,7 +28,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="handleAdd">维护计划</el-button>
            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Delete" color="#1A2652" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -36,17 +36,17 @@
                <el-table class="ztzf-data-cockpit-table" :data="list" @selection-change="handleSelectionChange">
                    <el-table-column type="selection" width="46" />
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="deviceName" show-overflow-tooltip width="130" label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip width="130" label="设备类型">
                    <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceModel" show-overflow-tooltip width="98" label="型号" />
                    <el-table-column prop="manufacturer" show-overflow-tooltip width="130" label="生产厂商" />
                    <el-table-column prop="charger" show-overflow-tooltip width="100" label="负责人" />
                    <el-table-column prop="maintainReminder" show-overflow-tooltip width="116" label="维护提醒" />
                    <el-table-column prop="planCycleType" show-overflow-tooltip width="160" label="维护计划">
                    <el-table-column prop="deviceModel" show-overflow-tooltip label="型号" />
                    <el-table-column prop="manufacturer" show-overflow-tooltip label="生产厂商" />
                    <el-table-column prop="charger" show-overflow-tooltip label="负责人" />
                    <el-table-column prop="maintainReminder" show-overflow-tooltip label="维护提醒" />
                    <el-table-column prop="planCycleType" show-overflow-tooltip label="维护计划">
                        <template v-slot="{ row }">
                            {{ getPlanCycleLabel(row) }}
                        </template>
@@ -73,7 +73,7 @@
    </basic-container>
</template>
<script setup>
import { Search, RefreshRight, Plus } from '@element-plus/icons-vue'
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getDictionaryByCode } from '@/api/system/dictbiz'
@@ -95,7 +95,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/dataCenter/components/dataCenterMap.vue
@@ -233,7 +233,7 @@
};
// 地图接口
const loading = ref(false);
const loading = ref(true);
const getMapInfoAPIFun = async ids => {
  try {
    const res = await getMapInfoAPI(ids);
applications/drone-command/src/views/dataCockpit/components/DeviceHistoryDialog.vue
@@ -108,7 +108,7 @@
})
const searchParams = ref(initSearchParams())
const queryParamsRef = ref(null)
const loading = ref(false)
const loading = ref(true)
const list = ref([])
const total = ref(0)
const areaTree = ref([
applications/drone-command/src/views/dataCockpit/components/EquipmentWarning.vue
@@ -33,7 +33,7 @@
import EmptyState from './EmptyState.vue'
const equipmentWarningData = ref([])
const loading = ref(false)
const loading = ref(true)
const minLoadingMs = 400
const statusMap = {
applications/drone-command/src/views/dataCockpit/components/HistoryWarning.vue
@@ -44,7 +44,7 @@
import EmptyState from './EmptyState.vue'
const historyWarningData = ref([])
const loading = ref(false)
const loading = ref(true)
const minLoadingMs = 400
// 查询条件:keyword + dateRange(YYYY-MM-DD数组)
applications/drone-command/src/views/dataCockpit/components/RealWarning.vue
@@ -36,7 +36,7 @@
import { ElMessage } from 'element-plus'
const realWarningData = ref([])
const loading = ref(false)
const loading = ref(true)
const minLoadingMs = 400
const actionTextMap = {
applications/drone-command/src/views/dataCockpit/components/RightContainer.vue
@@ -94,7 +94,7 @@
const historyVisible = ref(false)
const historyDevice = ref(null)
const loading = ref(false)
const loading = ref(true)
const minLoadingMs = 400
const onHistory = (item) => {
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/FormDiaLog.vue
@@ -1,53 +1,73 @@
<template>
    <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false">
        <div v-if="readonly">
<template>
    <el-dialog
        class="ztzf-page-view-dialog"
        v-model="visible"
        :title="titleEnum[dialogMode]"
        :close-on-click-modal="false"
        width="520px"
    >
        <div class="detail-container">
            <el-row>
                <el-col :span="12">
                    <div>无人机名称: {{ formData.droneName }}</div>
                    <div class="label">无人机名称</div>
                    <div class="val">{{ formData.droneName || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>无人机类型: {{ formData.droneType }}</div>
                    <div class="label">无人机类型</div>
                    <div class="val">{{ formData.droneType || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>无人机设备编码: {{ formData.droneDeviceCode }}</div>
                    <div class="label">无人机设备编码</div>
                    <div class="val">{{ formData.droneDeviceCode || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>发现时间: {{ formData.findTime }}</div>
                    <div class="label">发现时间</div>
                    <div class="val">{{ formData.findTime || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>反制效果: {{ getDictLabel(formData.counterEffect, dictObj.counterEffect) }}</div>
                    <div class="label">反制效果</div>
                    <div class="val">{{ getDictLabel(formData.counterEffect, dictObj.counterEffect) || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>反制方式: {{ getCounterWayLabel(formData.counterWay) }}</div>
                    <div class="label">反制方式</div>
                    <div class="val">{{ getCounterWayLabel(formData.counterWay) || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>反制设备名称: {{ formData.deviceName }}</div>
                    <div class="label">反制设备名称</div>
                    <div class="val">{{ formData.deviceName || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>反制设备型号: {{ formData.deviceModel }}</div>
                    <div class="label">反制设备型号</div>
                    <div class="val">{{ formData.deviceModel || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>反制设备类型: {{ getDeviceTypeLabel(formData.deviceType) }}</div>
                    <div class="label">反制设备类型</div>
                    <div class="val">{{ getDeviceTypeLabel(formData.deviceType) || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>反制设备编码: {{ formData.deviceSn }}</div>
                    <div class="label">反制设备编码</div>
                    <div class="val">{{ formData.deviceSn || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>区域编码: {{ formData.areaCode }}</div>
                    <div class="label">区域编码</div>
                    <div class="val">{{ formData.areaCode || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>部署位置: {{ getDeployPosition() }}</div>
                    <div class="label">部署位置</div>
                    <div class="val">{{ getDeployPosition() || '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>覆盖范围: {{ formData.coverRadiusM ? `${formData.coverRadiusM}米` : '' }}</div>
                    <div class="label">覆盖范围</div>
                    <div class="val">{{ formData.coverRadiusM ? `${formData.coverRadiusM}米` : '-' }}</div>
                </el-col>
                <el-col :span="12">
                    <div>工作模式: {{ getWorkModeLabel(formData.workMode) }}</div>
                    <div class="label">工作模式</div>
                    <div class="val">{{ getWorkModeLabel(formData.workMode) || '-' }}</div>
                </el-col>
            </el-row>
        </div>
        <template #footer>
            <el-button @click="handleCancel">关闭</el-button>
            <el-button color="#2B2B4C" @click="handleCancel">关闭</el-button>
        </template>
    </el-dialog>
</template>
@@ -78,7 +98,6 @@
// 注入字典数据
const dictObj = inject('dictObj')
// 注入反制效果选项
const formData = ref(initForm()) // 表单数据
const visible = defineModel() // 弹框显隐
@@ -94,7 +113,7 @@
// 获取反制方式标签
function getCounterWayLabel(value) {
    const map = { '1': '信号干扰', '2': '诱导驱离' }
    return map[value] || value || '无'
    return map[value] || value || '暂无'
}
// 获取设备类型标签
@@ -128,7 +147,9 @@
async function open({ mode, row } = {}) {
    dialogMode.value = mode || 'view'
    formData.value = row ? { ...row } : initForm()
    dialogMode.value === 'view' && (await loadDetail())
    if (readonly.value) {
        await loadDetail()
    }
}
defineExpose({ open })
applications/drone-command/src/views/detectionCountermeasure/countermeasureEvaluation/index.vue
@@ -1,93 +1,114 @@
<template>
<template>
    <basic-container>
        <el-form ref="queryParamsRef" :model="searchParams">
            <el-row :gutter="16">
                <el-col :span="4">
                    <el-form-item label="设备名称" prop="deviceName">
                        <el-input v-model="searchParams.deviceName" placeholder="请输入" clearable @clear="handleSearch" />
                    </el-form-item>
                </el-col>
                <el-col :span="4">
                    <el-form-item label="设备类型" prop="deviceType">
                        <el-select v-model="searchParams.deviceType" placeholder="请选择" clearable @change="handleSearch">
                            <el-option
                                v-for="item in dictObj.deviceType"
                                :key="item.dictKey"
                                :label="item.dictValue"
                                :value="item.dictKey"
                            />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="4">
                    <el-form-item label="反制效果" prop="counterEffect">
                        <el-select v-model="searchParams.counterEffect" placeholder="请选择" clearable @change="handleSearch">
                            <el-option
                                v-for="item in dictObj.counterEffect"
                                :key="item.dictKey"
                                :label="item.dictValue"
                                :value="item.dictKey"
                            />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="4">
                    <el-form-item>
                        <el-button @click="resetForm">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-col>
            </el-row>
        <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search">
            <el-form-item label="设备名称" prop="deviceName">
                <el-input
                    class="ztzf-data-cockpit-search-input"
                    v-model="searchParams.deviceName"
                    placeholder="请输入"
                    clearable
                    @clear="handleSearch"
                />
            </el-form-item>
            <el-form-item label="设备类型" prop="deviceType">
                <el-select
                    class="ztzf-data-cockpit-select"
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model="searchParams.deviceType"
                    placeholder="请选择"
                    clearable
                    @change="handleSearch"
                >
                    <el-option
                        v-for="item in dictObj.deviceType"
                        :key="item.dictKey"
                        :label="item.dictValue"
                        :value="item.dictKey"
                    />
                </el-select>
            </el-form-item>
            <el-form-item label="反制效果" prop="counterEffect">
                <el-select
                    class="ztzf-data-cockpit-select"
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model="searchParams.counterEffect"
                    placeholder="请选择"
                    clearable
                    @change="handleSearch"
                >
                    <el-option
                        v-for="item in dictObj.counterEffect"
                        :key="item.dictKey"
                        :label="item.dictValue"
                        :value="item.dictKey"
                    />
                </el-select>
            </el-form-item>
            <el-form-item class="history-search-actions">
                <el-button :icon="RefreshRight" @click="resetForm"></el-button>
                <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button>
            </el-form-item>
        </el-form>
        <el-table v-loading="loading" :data="list">
            <el-table-column type="index" width="60" label="序号" />
            <el-table-column prop="droneName" label="无人机名称" />
            <el-table-column prop="droneType" label="无人机类型" />
            <el-table-column prop="droneDeviceCode" label="无人机设备编码" />
            <el-table-column prop="findTime" label="发现时间" />
            <el-table-column prop="counterEffect" label="反制效果">
                <template v-slot="{ row }">
                    {{ getDictLabel(row.counterEffect, dictObj.counterEffect) }}
                </template>
            </el-table-column>
            <el-table-column prop="deviceName" label="反制设备名称" />
            <el-table-column prop="deviceModel" label="反制设备型号" />
            <el-table-column prop="deviceType" label="反制设备类型">
                <template v-slot="{ row }">
                    {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                </template>
            </el-table-column>
            <el-table-column prop="deviceSn" label="反制设备编码" />
            <el-table-column prop="areaCode" label="场景" />
            <el-table-column prop="areaCode" label="区域" />
            <el-table-column label="部署位置">
                <template v-slot="{ row }">
                    {{ row.deployLongitude && row.deployLatitude ? `${row.deployLongitude}, ${row.deployLatitude}` : '' }}
                </template>
            </el-table-column>
            <el-table-column prop="coverRadiusM" label="覆盖范围">
                <template v-slot="{ row }">
                    {{ row.coverRadiusM ? `${row.coverRadiusM}米` : '' }}
                </template>
            </el-table-column>
            <el-table-column prop="workMode" label="工作模式">
                <template v-slot="{ row }">
                    {{ getWorkModeLabel(row.workMode) }}
                </template>
            </el-table-column>
            <el-table-column label="操作" width="100">
                <template v-slot="{ row }">
                    <el-link @click="openForm('view', row)" type="primary">查看</el-link>
                </template>
            </el-table-column>
        </el-table>
        <div>
            <el-pagination
                v-model:current-page="searchParams.current"
                v-model:page-size="searchParams.size"
                :total="total"
                @change="getList"
            />
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
            <div class="ztzf-table-content ztzf-table-content-bg">
                <el-table class="ztzf-data-cockpit-table" :data="list">
                    <el-table-column type="index" width="64" show-overflow-tooltip label="序号" />
                    <el-table-column prop="droneName" show-overflow-tooltip width="130" label="无人机名称" />
                    <el-table-column prop="droneType" show-overflow-tooltip width="130" label="无人机类型" />
                    <el-table-column prop="droneDeviceCode" show-overflow-tooltip width="140" label="无人机设备编码" />
                    <el-table-column prop="findTime" show-overflow-tooltip width="140" label="发现时间" />
                    <el-table-column prop="counterEffect" show-overflow-tooltip width="120" label="反制效果">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.counterEffect, dictObj.counterEffect) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceName" show-overflow-tooltip width="130" label="反制设备名称" />
                    <el-table-column prop="deviceModel" show-overflow-tooltip width="120" label="反制设备型号" />
                    <el-table-column prop="deviceType" show-overflow-tooltip width="120" label="反制设备类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceSn" show-overflow-tooltip width="140" label="反制设备编码" />
                    <el-table-column prop="areaCode" show-overflow-tooltip width="120" label="场景" />
                    <el-table-column prop="areaCode" show-overflow-tooltip width="120" label="区域" />
                    <el-table-column show-overflow-tooltip width="160" label="部署位置">
                        <template v-slot="{ row }">
                            {{ row.deployLongitude && row.deployLatitude ? `${row.deployLongitude}, ${row.deployLatitude}` : '' }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="coverRadiusM" show-overflow-tooltip width="120" label="覆盖范围">
                        <template v-slot="{ row }">
                            {{ row.coverRadiusM ? `${row.coverRadiusM}米` : '' }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="workMode" show-overflow-tooltip width="120" label="工作模式">
                        <template v-slot="{ row }">
                            {{ getWorkModeLabel(row.workMode) }}
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" class-name="operation-btns" width="100">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('view', row)" type="primary">查看</el-link>
                        </template>
                    </el-table-column>
                </el-table>
            </div>
            <div class="ztzf-table-pagination">
                <el-pagination
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model:current-page="searchParams.current"
                    v-model:page-size="searchParams.size"
                    layout="total, prev, pager, next, sizes"
                    :total="total"
                    @change="getList"
                />
            </div>
        </div>
        <FormDiaLog v-if="dialogVisible" v-model="dialogVisible" ref="dialogRef" />
@@ -95,6 +116,7 @@
</template>
<script setup>
import { RefreshRight, Search } from '@element-plus/icons-vue'
import { onMounted, ref, nextTick, provide } from 'vue'
import { fwEffectEvalPageApi } from './countermeasureEvaluationApi'
import FormDiaLog from './FormDiaLog.vue'
@@ -112,17 +134,17 @@
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const queryParamsRef = ref(null) // 查询表单实例
const dialogRef = ref(null) // 弹框实例
const dialogVisible = ref(null) // 弹框显隐
const dialogVisible = ref(false) // 弹框显隐
const dictObj = ref({
    deviceType: [], // 设备类型
    counterEffect: [], // 反制效果
})
// 注入字典和反制效果选项供FormDiaLog使用
// 注入字典和反制效果选项供 FormDiaLog 使用
provide('dictObj', dictObj)
// 获取列表
applications/drone-command/src/views/detectionCountermeasure/detectionRange/DetectionRangeDialog.vue
@@ -1,86 +1,101 @@
<template>
    <el-dialog
        v-model="visible"
        :title="dialogTitle"
        class="detection-range-dialog"
        destroy-on-close
        @closed="handleClosed"
    >
        <div class="dialog-body">
            <div class="dialog-map">
                <DeviceMapContainer
                    :online-devices="mapDevices"
                    :show-layer-control="false"
                    container-id="detection-range-map"
                />
                <div class="map-toolbar">
                    <button class="map-btn" type="button" aria-label="编辑范围"></button>
                    <button class="map-btn" type="button" aria-label="定位设备"></button>
                </div>
                <div class="map-mini-controls">
                    <button class="map-mini-btn" type="button" aria-label="放大">+</button>
                    <button class="map-mini-btn" type="button" aria-label="缩小">-</button>
                </div>
    <el-dialog v-model="visible" class="ztzf-page-map-view-dialog" :show-close="false" :close-on-click-modal="false"
        destroy-on-close @closed="handleClosed">
        <div class="dialog-container">
            <div class="left-container">
                <div class="leftMap ztzf-cesium" id="detectionRangeMap"></div>
            </div>
            <div class="dialog-form">
                <div class="form-title">{{ formTitle }}</div>
                <el-form ref="formRef" :model="formData" :rules="rules" label-width="84px" :disabled="dialogReadonly">
            <div class="right-container">
                <div class="header">{{ formTitle }}</div>
                <div class="dialog-container" v-if="dialogReadonly">
                    <el-row>
                        <el-col :span="24">
                            <div class="label">侦测设备</div>
                            <div class="val">{{ formData.deviceName || '-' }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">设备类型</div>
                            <div class="val">{{ getDeviceTypeLabel(formData.deviceType) }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">设备位置</div>
                            <div class="val">{{ formData.deployLocation || '-' }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">设备编号</div>
                            <div class="val">{{ formData.deviceSn || '-' }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">设备型号</div>
                            <div class="val">{{ formData.deviceModel || '-' }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">覆盖范围</div>
                            <div class="val">{{ formatRange(formData.effectiveRangeKm) }}</div>
                        </el-col>
                    </el-row>
                </div>
                <el-form v-else ref="formRef" class="dialog-form" :model="formData" :rules="rules" label-width="96px">
                    <el-form-item label="侦测设备" prop="deviceId">
                        <el-select v-model="formData.deviceId" placeholder="请选择" clearable @change="handleDeviceChange">
                            <el-option v-for="item in deviceOptions" :key="item.value" :label="item.label" :value="item.value" />
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.deviceId" placeholder="请选择" clearable @change="handleDeviceChange">
                            <el-option v-for="item in deviceOptions" :key="item.value" :label="item.label"
                                :value="item.value" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="设备类型" prop="deviceType">
                        <el-select v-model="formData.deviceType" placeholder="请选择" clearable>
                            <el-option
                                v-for="item in dictObj.deviceType"
                                :key="item.dictKey"
                                :label="item.dictValue"
                                :value="item.dictKey"
                            />
                        <el-select class="ztzf-data-cockpit-select" popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.deviceType" placeholder="请选择" clearable>
                            <el-option v-for="item in dictObj.deviceType" :key="item.dictKey" :label="item.dictValue"
                                :value="item.dictKey" />
                        </el-select>
                    </el-form-item>
                    <el-form-item label="设备位置" prop="deployLocation">
                        <el-input v-model="formData.deployLocation" placeholder="请选择位置">
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.deployLocation"
                            placeholder="请选择位置">
                            <template #suffix>
                                <span class="suffix-action">地图选点</span>
                            </template>
                        </el-input>
                    </el-form-item>
                    <el-form-item label="设备编号" prop="deviceSn">
                        <el-input v-model="formData.deviceSn" placeholder="请输入" clearable />
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.deviceSn" placeholder="请输入"
                            clearable />
                    </el-form-item>
                    <el-form-item label="设备型号" prop="deviceModel">
                        <el-input v-model="formData.deviceModel" placeholder="请输入" clearable />
                        <el-input class="ztzf-data-cockpit-search-input" v-model="formData.deviceModel"
                            placeholder="请输入" clearable />
                    </el-form-item>
                    <el-form-item label="覆盖范围" prop="effectiveRangeKm">
                        <el-input-number
                            v-model="formData.effectiveRangeKm"
                            :min="0"
                            :precision="2"
                            :controls="false"
                            placeholder="请输入"
                        />
                        <el-input-number class="ztzf-data-cockpit-search-input" v-model="formData.effectiveRangeKm" :min="0" :precision="2" :controls="false"
                            placeholder="请输入" />
                    </el-form-item>
                </el-form>
                <div class="footer">
                    <el-button color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
                    <el-button color="#284FE3" v-if="!dialogReadonly" type="primary" :loading="submitting"
                        :disabled="submitting" @click="handleSubmit">
                        保存
                    </el-button>
                </div>
            </div>
        </div>
        <template v-if="!dialogReadonly" #footer>
            <el-button @click="handleCancel">取消</el-button>
            <el-button type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit">保存</el-button>
        </template>
    </el-dialog>
</template>
<script setup>
import { computed, inject, ref } from 'vue'
import { computed, inject, nextTick, ref } from 'vue'
import { ElMessage } from 'element-plus'
import DeviceMapContainer from '@/components/map-container/device-map-container.vue'
import {
    detectionRangeDetailApi,
    detectionRangePageApi,
    detectionRangeSubmitApi,
} from '@/api/detectionCountermeasure/detectionRange'
import { PublicCesium } from '@/utils/cesium/publicCesium'
import * as Cesium from 'cesium'
const initForm = () => ({
    deviceId: '', // 侦测设备ID
@@ -99,17 +114,10 @@
const visible = ref(false) // 弹框显隐
const dialogMode = ref('add') // 弹框模式
const submitting = ref(false) // 提交中
const mapDevices = ref([])
const deviceOptions = ref([])
const dialogReadonly = computed(() => dialogMode.value === 'view')
const dialogTitle = computed(() => {
    if (dialogMode.value === 'edit') {
        return '编辑'
    } else if (dialogMode.value === 'view') {
        return '查看'
    }
    return '新增'
})
let viewer
let redPointEntity
const formTitle = computed(() => {
    if (dialogMode.value === 'edit') {
        return '编辑侦测范围'
@@ -123,10 +131,11 @@
const rules = {
    deviceId: [{ required: true, message: '请选择侦测设备', trigger: ['blur', 'change'] }],
    deviceType: [{ required: true, message: '请选择设备类型', trigger: ['blur', 'change'] }],
    deployLocation: [{ required: true, message: '请选择设备位置', trigger: ['blur', 'change'] }],
    effectiveRangeKm: [{ required: true, message: '请输入覆盖范围', trigger: ['blur', 'change'] }],
}
function handleDeviceChange(value) {
function handleDeviceChange (value) {
    const target = deviceOptions.value.find(item => item.value === value)
    const raw = target?.raw
    if (!raw) return
@@ -139,13 +148,24 @@
        raw.deployLocation ?? raw.address ?? raw.location ?? raw.deployAddress ?? formData.value.deployLocation
}
function getDeviceTypeLabel (value) {
    const list = dictObj?.deviceType ?? []
    const target = list.find(item => item.dictKey === value)
    return target?.dictValue ?? value ?? '-'
}
function formatRange (value) {
    if (value == null || value === '') return '-'
    return `${value}km`
}
// 关闭弹框
function handleCancel() {
function handleCancel () {
    visible.value = false
}
// 提交新增/编辑
async function handleSubmit() {
async function handleSubmit () {
    const isValid = await formRef.value?.validate().catch(() => false)
    if (!isValid) return
    submitting.value = true
@@ -166,13 +186,13 @@
}
// 加载详情
async function loadDetail(id) {
async function loadDetail (id) {
    if (!id) return null
    const res = await detectionRangeDetailApi({ id })
    return res?.data?.data ?? null
}
async function loadDeviceOptions() {
async function loadDeviceOptions () {
    const res = await detectionRangePageApi({
        current: 1,
        size: 200,
@@ -187,14 +207,75 @@
}
// 关闭后重置
function handleClosed() {
function handleClosed () {
    formData.value = initForm()
    viewer = null
    redPointEntity = null
}
function setMapPoint (longitude, latitude) {
    if (!viewer || longitude == null || latitude == null) return
    if (!redPointEntity) {
        redPointEntity = viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(longitude, latitude),
            point: {
                color: Cesium.Color.RED,
                pixelSize: 10,
            },
            label: {
                text: `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`,
                font: '14px',
                fillColor: Cesium.Color.WHITE,
                backgroundColor: Cesium.Color.BLACK.withAlpha(0.45),
                backgroundPadding: new Cesium.Cartesian2(5, 5),
                pixelOffset: new Cesium.Cartesian2(0, -20),
                showBackground: true,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                verticalOrigin: Cesium.VerticalOrigin.CENTER,
                outlineWidth: 1,
                outlineColor: Cesium.Color.WHITE,
                eyeOffset: new Cesium.Cartesian3(0, 0, -20),
            },
        })
    } else {
        redPointEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude)
        redPointEntity.label.text = `${longitude.toFixed(6)}, ${latitude.toFixed(6)}`
    }
}
function initMap () {
    if (viewer) return
    const publicCesiumInstance = new PublicCesium({
        dom: 'detectionRangeMap',
        flatMode: false,
        terrain: true,
        layerMode: 4,
        boundary: false,
    })
    if (!dialogReadonly.value) {
        publicCesiumInstance.addLeftClickEvent(null, handleMapClick)
    }
    viewer = publicCesiumInstance.getViewer()
}
function handleMapClick (click) {
    const pos = click.position
    const cartesian3 = viewer.camera.pickEllipsoid(pos, viewer.scene.globe.ellipsoid)
    if (!cartesian3) return
    const carto = Cesium.Cartographic.fromCartesian(cartesian3)
    const longitude = Number(Cesium.Math.toDegrees(carto.longitude).toFixed(6))
    const latitude = Number(Cesium.Math.toDegrees(carto.latitude).toFixed(6))
    formData.value.deployLocation = `${longitude}, ${latitude}`
    setMapPoint(longitude, latitude)
}
// 打开弹框
async function open({ mode, row } = {}) {
async function open ({ mode, row } = {}) {
    dialogMode.value = mode || 'add'
    visible.value = true
    await nextTick()
    initMap()
    if (dialogMode.value === 'add') {
        await loadDeviceOptions()
        formData.value = initForm()
@@ -212,114 +293,16 @@
    if (currentId && !deviceOptions.value.some(item => item.value === currentId)) {
        deviceOptions.value.unshift({ label: currentName || '-', value: currentId })
    }
    const location = formData.value.deployLocation
    if (location) {
        const [longitude, latitude] = location.split(',').map(item => Number(item.trim()))
        if (!Number.isNaN(longitude) && !Number.isNaN(latitude)) {
            setMapPoint(longitude, latitude)
        }
    }
}
defineExpose({ open })
</script>
<style scoped lang="scss">
.detection-range-dialog {
    :deep(.el-dialog) {
        width: 1100px;
        background: #071833;
        border-radius: 8px;
    }
    :deep(.el-dialog__header) {
        border-bottom: 1px solid rgba(70, 110, 180, 0.35);
    }
}
.dialog-body {
    display: flex;
    gap: 16px;
    min-height: 560px;
}
.dialog-map {
    position: relative;
    flex: 1;
    min-height: 520px;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid rgba(70, 110, 180, 0.35);
    background: #031024;
}
.map-toolbar {
    position: absolute;
    top: 16px;
    right: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 2;
}
.map-btn {
    width: 34px;
    height: 34px;
    border-radius: 6px;
    border: 1px solid rgba(80, 120, 180, 0.6);
    background: rgba(7, 18, 44, 0.9);
    cursor: pointer;
}
.map-mini-controls {
    position: absolute;
    left: 16px;
    bottom: 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    z-index: 2;
}
.map-mini-btn {
    width: 28px;
    height: 28px;
    border-radius: 4px;
    border: 1px solid rgba(80, 120, 180, 0.6);
    background: rgba(7, 18, 44, 0.9);
    color: #cfe3ff;
    cursor: pointer;
}
.dialog-form {
    width: 300px;
    padding: 12px 12px 0;
    border-radius: 8px;
    background: linear-gradient(180deg, rgba(10, 28, 58, 0.95), rgba(6, 16, 34, 0.95));
    border: 1px solid rgba(70, 110, 180, 0.35);
    color: #d7e7ff;
}
.form-title {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 12px;
    letter-spacing: 1px;
}
:deep(.el-form-item__label) {
    color: rgba(210, 230, 255, 0.85);
}
:deep(.el-input__wrapper),
:deep(.el-select__wrapper),
:deep(.el-input-number .el-input__wrapper) {
    background: rgba(7, 20, 44, 0.85);
    border: 1px solid rgba(80, 120, 190, 0.45);
    box-shadow: none;
}
:deep(.el-input__inner) {
    color: #d5e6ff;
}
.suffix-action {
    font-size: 12px;
    color: #7fb6ff;
    cursor: pointer;
}
</style>
<style scoped lang="scss"></style>
applications/drone-command/src/views/detectionCountermeasure/detectionRange/index.vue
@@ -1,4 +1,4 @@
<template>
<template>
    <basic-container>
        <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search">
            <el-form-item label="名称" prop="deviceName">
@@ -43,24 +43,24 @@
            <div class="ztzf-table-content ztzf-table-content-bg">
                <el-table class="ztzf-data-cockpit-table" :data="list">
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="deviceName" show-overflow-tooltip width="140" label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip width="120" label="设备类型">
                    <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                    <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                        </template>
                    </el-table-column>
                    <el-table-column show-overflow-tooltip width="160" label="部署位置">
                    <el-table-column show-overflow-tooltip label="部署位置">
                        <template v-slot="{ row }">
                            {{ formatDeployLocation(row) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceModel" show-overflow-tooltip width="110" label="型号" />
                    <el-table-column show-overflow-tooltip width="120" label="覆盖范围">
                    <el-table-column prop="deviceModel" show-overflow-tooltip label="型号" />
                    <el-table-column show-overflow-tooltip label="覆盖范围">
                        <template v-slot="{ row }">
                            {{ formatRange(row) }}
                        </template>
                    </el-table-column>
                    <el-table-column show-overflow-tooltip width="150" label="设备编码">
                    <el-table-column show-overflow-tooltip label="设备编码">
                        <template v-slot="{ row }">
                            {{ formatDeviceCode(row) }}
                        </template>
@@ -107,7 +107,7 @@
    size: 10, // 每页大小
})
const searchParams = ref(initSearchParams()) // 查询参数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const total = ref(0) // 总数
const queryParamsRef = ref(null) // 查询表单实例
@@ -160,7 +160,12 @@
// 删除
async function handleDelete(row) {
    await ElMessageBox.confirm('确认删除该条数据吗?', '提示', { type: 'warning' })
    await ElMessageBox.confirm('确认删除该条数据吗?', '提示', {
        type: 'warning',
        customClass: 'ztzf-page-view-message-box',
        confirmButtonClass: 'ztzf-message-box-confirm',
        cancelButtonClass: 'ztzf-message-box-cancel',
    })
    await detectionRangeSubmitApi({ id: row.id, effectiveRangeKm: 0 })
    ElMessage.success('删除成功')
    getList()
applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/FormDiaLog.vue
@@ -1,67 +1,120 @@
<template>
    <el-dialog v-model="visible" :title="titleEnum[dialogMode]" :close-on-click-modal="false">
        <div v-if="readonly">
<template>
    <el-dialog
        class="ztzf-page-view-dialog"
        v-model="visible"
        :title="titleEnum[dialogMode]"
        :close-on-click-modal="false"
        @closed="handleClosed"
        destroy-on-close
    >
        <div v-if="readonly" class="detail-container">
            <div class="detail-title">配置详情</div>
            <el-row>
                <el-col :span="12">
                    <div>起始扇区: {{ formData.startSector }}</div>
                    <div class="label">起始扇区</div>
                    <div class="val">{{ formData.startSector }}</div>
                </el-col>
                <el-col :span="12">
                    <div>终止扇区: {{ formData.endSector }}</div>
                    <div class="label">终止扇区</div>
                    <div class="val">{{ formData.endSector }}</div>
                </el-col>
                <el-col :span="12">
                    <div>搜索模式: {{ formData.searchMode }}</div>
                    <div class="label">搜索模式</div>
                    <div class="val">{{ formData.searchMode }}</div>
                </el-col>
                <el-col :span="12">
                    <div>雷达频点: {{ formData.radarFreq }}</div>
                    <div class="label">雷达频点</div>
                    <div class="val">{{ formData.radarFreq }}</div>
                </el-col>
                <el-col :span="12">
                    <div>伺服模式: {{ formData.servoMode }}</div>
                    <div class="label">伺服模式</div>
                    <div class="val">{{ formData.servoMode }}</div>
                </el-col>
                <el-col :span="12">
                    <div>伺服数据模式: {{ formData.servoDataMode }}</div>
                    <div class="label">伺服数据模式</div>
                    <div class="val">{{ formData.servoDataMode }}</div>
                </el-col>
                <el-col :span="12">
                    <div>轴选择: {{ formData.axisSelect }}</div>
                    <div class="label">轴选择</div>
                    <div class="val">{{ formData.axisSelect }}</div>
                </el-col>
                <el-col :span="12">
                    <div>伺服转速度: {{ formData.servoTurnSpeed }}</div>
                    <div class="label">伺服转速度</div>
                    <div class="val">{{ formData.servoTurnSpeed }}</div>
                </el-col>
            </el-row>
        </div>
        <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="120px">
        <el-form v-else ref="formRef" :model="formData" :rules="rules" label-width="120px" class="dialog-form">
            <el-row>
                <el-col :span="12">
                    <el-form-item label="起始扇区" prop="startSector">
                        <el-input v-model="formData.startSector" maxlength="50" placeholder="请输入" clearable />
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.startSector"
                            maxlength="50"
                            placeholder="请输入"
                            clearable
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="终止扇区" prop="endSector">
                        <el-input v-model="formData.endSector" maxlength="50" placeholder="请输入" clearable />
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.endSector"
                            maxlength="50"
                            placeholder="请输入"
                            clearable
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="搜索模式" prop="searchMode">
                        <el-select v-model="formData.searchMode" placeholder="请选择" clearable>
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.searchMode"
                            placeholder="请选择"
                            clearable
                        >
                            <el-option v-for="item in searchModeOptions" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="雷达频点" prop="radarFreq">
                        <el-input v-model="formData.radarFreq" maxlength="50" placeholder="请输入" clearable />
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.radarFreq"
                            maxlength="50"
                            placeholder="请输入"
                            clearable
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="伺服模式" prop="servoMode">
                        <el-select v-model="formData.servoMode" placeholder="请选择" clearable>
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.servoMode"
                            placeholder="请选择"
                            clearable
                        >
                            <el-option v-for="item in servoModeOptions" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="伺服数据模式" prop="servoDataMode">
                        <el-select v-model="formData.servoDataMode" placeholder="请选择" clearable>
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.servoDataMode"
                            placeholder="请选择"
                            clearable
                        >
                            <el-option
                                v-for="item in servoDataModeOptions"
                                :key="item.value"
@@ -73,22 +126,41 @@
                </el-col>
                <el-col :span="12">
                    <el-form-item label="轴选择" prop="axisSelect">
                        <el-select v-model="formData.axisSelect" placeholder="请选择" clearable>
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.axisSelect"
                            placeholder="请选择"
                            clearable
                        >
                            <el-option v-for="item in axisSelectOptions" :key="item.value" :label="item.label" :value="item.value" />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="伺服转速度" prop="servoTurnSpeed">
                        <el-input v-model="formData.servoTurnSpeed" maxlength="50" placeholder="请输入" clearable />
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.servoTurnSpeed"
                            maxlength="50"
                            placeholder="请输入"
                            clearable
                        />
                    </el-form-item>
                </el-col>
            </el-row>
        </el-form>
        <template #footer>
            <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit">
                确定
            <el-button color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button
                color="#284FE3"
                v-if="!readonly"
                type="primary"
                :loading="submitting"
                :disabled="submitting"
                @click="handleSubmit"
            >
                保存
            </el-button>
        </template>
    </el-dialog>
@@ -97,7 +169,7 @@
<script setup>
import { computed, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { fwDeviceConfigDetailApi, fwDeviceConfigSubmitApi } from './deviceAppConfigApi'
import { fwDeviceConfigSubmitApi } from './deviceAppConfigApi'
import { fieldRules } from '@ztzf/utils'
const configKeys = [
@@ -144,7 +216,7 @@
    { label: '扇区', value: '扇区' },
    { label: '定位', value: '定位' },
]
const servoDataModeOptions = [{ label: '编码器', value: '编码器' }]
const servoDataModeOptions = [{ label: '编码模式', value: '编码模式' }]
const axisSelectOptions = [{ label: '方位', value: '方位' }]
const rules = {
@@ -171,6 +243,10 @@
    visible.value = false
}
function handleClosed() {
    formData.value = initForm()
}
// 提交更新
async function handleSubmit() {
    const isValid = await formRef.value?.validate().catch(() => false)
applications/drone-command/src/views/detectionCountermeasure/deviceAppConfig/index.vue
@@ -1,59 +1,74 @@
<template>
<template>
    <basic-container>
        <el-form ref="queryParamsRef" :model="searchParams">
            <el-row :gutter="16">
                <el-col :span="4">
                    <el-form-item label="设备名称" prop="deviceName">
                        <el-input v-model="searchParams.deviceName" placeholder="请输入" clearable @clear="handleSearch" />
                    </el-form-item>
                </el-col>
                <el-col :span="4">
                    <el-form-item label="设备类型" prop="deviceType">
                        <el-select v-model="searchParams.deviceType" placeholder="请选择" clearable @change="handleSearch">
                            <el-option
                                v-for="item in dictObj.deviceType"
                                :key="item.dictKey"
                                :label="item.dictValue"
                                :value="item.dictKey"
                            />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="4">
                    <el-form-item>
                        <el-button @click="resetForm">重置</el-button>
                        <el-button type="primary" @click="handleSearch">查询</el-button>
                    </el-form-item>
                </el-col>
            </el-row>
        <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search">
            <el-form-item label="设备名称" prop="deviceName">
                <el-input
                    class="ztzf-data-cockpit-search-input"
                    v-model="searchParams.deviceName"
                    placeholder="请输入"
                    clearable
                    @clear="handleSearch"
                />
            </el-form-item>
            <el-form-item label="设备类型" prop="deviceType">
                <el-select
                    class="ztzf-data-cockpit-select"
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model="searchParams.deviceType"
                    placeholder="请选择"
                    clearable
                    @change="handleSearch"
                >
                    <el-option
                        v-for="item in dictObj.deviceType"
                        :key="item.dictKey"
                        :label="item.dictValue"
                        :value="item.dictKey"
                    />
                </el-select>
            </el-form-item>
            <el-form-item class="history-search-actions">
                <el-button :icon="RefreshRight" @click="resetForm"></el-button>
                <el-button class="search-btn" :icon="Search" @click="handleSearch"></el-button>
            </el-form-item>
        </el-form>
        <el-table v-loading="loading" :data="list">
            <el-table-column type="index" width="60" label="序号" />
            <el-table-column prop="deviceType" label="设备类型">
                <template v-slot="{ row }">
                    {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                </template>
            </el-table-column>
            <el-table-column prop="deviceModel" label="设备型号" />
            <el-table-column prop="deviceName" label="设备名称" />
            <el-table-column prop="deviceSn" label="设备编码" />
            <el-table-column prop="deployLocation" label="部署位置" />
            <el-table-column prop="manufacturer" label="厂商" />
            <el-table-column prop="contactPhone" label="联系方式" />
            <el-table-column prop="sceneName" label="所属场景" />
            <el-table-column label="操作">
                <template v-slot="{ row }">
                    <el-link @click="openForm('edit', row)" type="warning">配置接口</el-link>
                </template>
            </el-table-column>
        </el-table>
        <div>
            <el-pagination
                v-model:current-page="searchParams.current"
                v-model:page-size="searchParams.size"
                :total="total"
                @change="getList"
            />
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
            <div class="ztzf-table-content ztzf-table-content-bg">
                <el-table class="ztzf-data-cockpit-table" :data="list">
                    <el-table-column type="index" width="64" show-overflow-tooltip label="序号" />
                    <el-table-column prop="deviceType" show-overflow-tooltip label="设备类型">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceType, dictObj.deviceType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceModel" show-overflow-tooltip label="设备型号" />
                    <el-table-column prop="deviceName" show-overflow-tooltip label="设备名称" />
                    <el-table-column prop="deviceSn" show-overflow-tooltip label="设备编码" />
                    <el-table-column prop="deployLocation" show-overflow-tooltip label="部署位置" />
                    <el-table-column prop="manufacturer" show-overflow-tooltip label="厂商" />
                    <el-table-column prop="contactPhone" show-overflow-tooltip label="联系方式" />
                    <el-table-column prop="sceneName" show-overflow-tooltip label="所属场景" />
                    <el-table-column label="操作" class-name="operation-btns">
                        <template v-slot="{ row }">
                            <el-link @click="openForm('edit', row)" type="warning">配置接口</el-link>
                        </template>
                    </el-table-column>
                </el-table>
            </div>
            <div class="ztzf-table-pagination">
                <el-pagination
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model:current-page="searchParams.current"
                    v-model:page-size="searchParams.size"
                    layout="total, prev, pager, next, sizes"
                    :total="total"
                    @change="getList"
                />
            </div>
        </div>
        <FormDiaLog v-if="dialogVisible" v-model="dialogVisible" ref="dialogRef" @success="getList" />
@@ -61,6 +76,7 @@
</template>
<script setup>
import { RefreshRight, Search } from '@element-plus/icons-vue'
import { nextTick, onMounted, provide, ref } from 'vue'
import FormDiaLog from './FormDiaLog.vue'
import { getDictionaryByCode } from '@/api/system/dictbiz'
@@ -77,7 +93,7 @@
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const queryParamsRef = ref(null) // 查询表单实例
const dialogRef = ref(null) // 弹框实例
applications/drone-command/src/views/detectionCountermeasure/taskSchedule/FormDiaLog.vue
@@ -1,56 +1,101 @@
<template>
    <el-dialog v-model="visible" :title="titleEnum[dialogMode]">
        <div v-if="readonly">
<template>
    <el-dialog
        class="ztzf-page-view-dialog"
        v-model="visible"
        :title="titleEnum[dialogMode]"
        destroy-on-close
        :close-on-click-modal="false"
        @closed="handleClosed"
    >
        <div v-if="readonly" class="detail-container">
            <div class="detail-title">调度详情</div>
            <el-row>
                <el-col :span="12">
                    <div>设备名称: {{ formData.deviceName }}</div>
                    <div class="label">设备名称</div>
                    <div class="val">{{ formData.deviceName }}</div>
                </el-col>
                <el-col :span="12">
                    <div>设备编码: {{ formData.deviceSn }}</div>
                    <div class="label">设备编码</div>
                    <div class="val">{{ formData.deviceSn }}</div>
                </el-col>
                <el-col :span="12">
                    <div>场景: {{ formData.defenseSceneName }}</div>
                    <div class="label">场景</div>
                    <div class="val">{{ formData.defenseSceneName }}</div>
                </el-col>
                <el-col :span="12">
                    <div>区域: {{ formData.areaDivideName }}</div>
                    <div class="label">区域</div>
                    <div class="val">{{ formData.areaDivideName }}</div>
                </el-col>
                <el-col :span="12">
                    <div>调度人员: {{ formData.dispatchUser }}</div>
                    <div class="label">调度人员</div>
                    <div class="val">{{ formData.dispatchUser }}</div>
                </el-col>
                <el-col :span="12">
                    <div>调度位置: {{ formData.longitude }}, {{ formData.latitude }}</div>
                    <div class="label">调度位置</div>
                    <div class="val">{{ formData.longitude }}, {{ formData.latitude }}</div>
                </el-col>
                <el-col :span="12">
                    <div>调度日期: {{ formData.dispatchStartTime }} ~ {{ formData.dispatchEndTime }}</div>
                    <div class="label">调度日期</div>
                    <div class="val">{{ formData.dispatchStartTime }} ~ {{ formData.dispatchEndTime }}</div>
                </el-col>
                <el-col :span="24">
                    <div>调度内容: {{ formData.dispatchContent }}</div>
                    <div class="label">调度内容</div>
                    <div class="val">{{ formData.dispatchContent }}</div>
                </el-col>
                <el-col :span="24">
                    <div>调度结果: {{ formData.dispatchResult }}</div>
                    <div class="label">调度结果</div>
                    <div class="val">{{ formData.dispatchResult }}</div>
                </el-col>
                <el-col :span="24">
                    <div>处理措施: {{ formData.disposeMeasure }}</div>
                    <div class="label">处理措施</div>
                    <div class="val">{{ formData.disposeMeasure }}</div>
                </el-col>
            </el-row>
        </div>
        <el-form v-else ref="formRef" :model="formData" :rules="rules" :disabled="readonly" label-width="100px">
        <el-form
            v-else
            ref="formRef"
            :model="formData"
            :rules="rules"
            :disabled="readonly"
            label-width="100px"
            class="dialog-form"
        >
            <el-row>
                <el-col :span="12">
                    <el-form-item label="设备" prop="deviceId">
                        <el-select v-model="formData.deviceId" placeholder="请选择" clearable @change="handleDeviceChange">
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.deviceId"
                            placeholder="请选择"
                            clearable
                            @change="handleDeviceChange"
                        >
                            <el-option v-for="item in deviceList" :key="item.id" :label="item.deviceName" :value="item.id" />
                        </el-select>
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="设备编码" prop="deviceSn">
                        <el-input v-model="formData.deviceSn" disabled placeholder="选择设备后自动带出" />
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.deviceSn"
                            disabled
                            placeholder="选择设备后自动带出"
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="场景" prop="defenseSceneId">
                        <el-select v-model="formData.defenseSceneId" placeholder="请选择" clearable @change="handleSceneChange">
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.defenseSceneId"
                            placeholder="请选择"
                            clearable
                            @change="handleSceneChange"
                        >
                            <el-option v-for="item in sceneList" :key="item.id" :label="item.sceneName" :value="item.id" />
                        </el-select>
                    </el-form-item>
@@ -58,6 +103,8 @@
                <el-col :span="12">
                    <el-form-item label="区域" prop="areaDivideId">
                        <el-select
                            class="ztzf-data-cockpit-select"
                            popper-class="ztzf-data-cockpit-select-popper"
                            v-model="formData.areaDivideId"
                            placeholder="请先选择场景"
                            clearable
@@ -70,12 +117,20 @@
                </el-col>
                <el-col :span="12">
                    <el-form-item label="调度人员" prop="dispatchUser">
                        <el-input v-model="formData.dispatchUser" maxlength="50" placeholder="请输入" clearable />
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.dispatchUser"
                            maxlength="50"
                            placeholder="请输入"
                            clearable
                        />
                    </el-form-item>
                </el-col>
                <el-col :span="12">
                    <el-form-item label="调度日期" prop="dispatchDateRange">
                        <el-date-picker
                            class="ztzf-data-cockpit-date-picker"
                            popper-class="ztzf-data-cockpit-date-picker-popper"
                            v-model="formData.dispatchDateRange"
                            type="datetimerange"
                            range-separator="至"
@@ -87,7 +142,7 @@
                </el-col>
                <el-col :span="24">
                    <el-form-item label="调度位置" prop="longitude">
<!--                        <el-button @click="selectLocation" style="width: 100%">-->
                        <!--                        <el-button @click="selectLocation" style="width: 100%">-->
                        <el-button style="width: 100%">
                            {{
                                formData.longitude && formData.latitude ? `${formData.longitude}, ${formData.latitude}` : '选择区域后自动带出'
@@ -98,6 +153,7 @@
                <el-col :span="24">
                    <el-form-item label="调度内容" prop="dispatchContent">
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.dispatchContent"
                            type="textarea"
                            :rows="3"
@@ -110,6 +166,7 @@
                <el-col :span="24">
                    <el-form-item label="调度结果" prop="dispatchResult">
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.dispatchResult"
                            type="textarea"
                            :rows="3"
@@ -122,6 +179,7 @@
                <el-col :span="24">
                    <el-form-item label="处理措施" prop="disposeMeasure">
                        <el-input
                            class="ztzf-data-cockpit-search-input"
                            v-model="formData.disposeMeasure"
                            type="textarea"
                            :rows="3"
@@ -135,9 +193,16 @@
        </el-form>
        <template #footer>
            <el-button @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button v-if="!readonly" type="primary" :loading="submitting" :disabled="submitting" @click="handleSubmit">
                确定
            <el-button color="#2B2B4C" @click="handleCancel">{{ readonly ? '关闭' : '取消' }}</el-button>
            <el-button
                color="#284FE3"
                v-if="!readonly"
                type="primary"
                :loading="submitting"
                :disabled="submitting"
                @click="handleSubmit"
            >
                保存
            </el-button>
        </template>
@@ -152,7 +217,7 @@
</template>
<script setup>
import { computed, nextTick, ref, inject } from 'vue'
import { computed, nextTick, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { fwTaskScheduleDetailApi, fwTaskScheduleSubmitApi } from './taskScheduleApi'
import { fwAreaDivideListApi } from '@/views/areaManage/partition/partitionApi'
@@ -249,6 +314,10 @@
    visible.value = false
}
function handleClosed() {
    formData.value = initForm()
}
// 提交新增/编辑
async function handleSubmit() {
    const isValid = await formRef.value?.validate().catch(() => false)
applications/drone-command/src/views/detectionCountermeasure/taskSchedule/index.vue
@@ -1,9 +1,10 @@
<template>
<template>
    <basic-container>
        <el-form ref="queryParamsRef" :model="searchParams" class="ztzf-page-history-search">
            <el-form-item label="设备名称" prop="deviceId">
                <el-select
                    class="ztzf-data-cockpit-search-input"
                    class="ztzf-data-cockpit-select"
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model="searchParams.deviceId"
                    placeholder="请选择"
                    clearable
@@ -13,9 +14,11 @@
                    <el-option v-for="item in deviceList" :key="item.id" :label="item.deviceName" :value="item.id" />
                </el-select>
            </el-form-item>
            <el-form-item label="设备类型" prop="deviceType">
                <el-select
                    class="ztzf-data-cockpit-search-input"
                    class="ztzf-data-cockpit-select"
                    popper-class="ztzf-data-cockpit-select-popper"
                    v-model="searchParams.deviceType"
                    placeholder="请选择"
                    clearable
@@ -30,6 +33,7 @@
                    />
                </el-select>
            </el-form-item>
            <el-form-item label="设备编号" prop="deviceSn">
                <el-input
                    class="ztzf-data-cockpit-search-input"
@@ -48,7 +52,7 @@
        <div class="ztzf-table-toolbar">
            <el-button :icon="Plus" color="#284FE3" type="primary" @click="openForm('add')">新增</el-button>
            <el-button type="danger" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
            <el-button :icon="Delete" color="#1A2652" :disabled="!selectedIds.length" @click="handleDelete()">删除</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -59,17 +63,17 @@
                    <el-table-column prop="deviceName" show-overflow-tooltip width="140" label="设备名称" />
                    <el-table-column prop="deviceSn" show-overflow-tooltip width="140" label="设备编码" />
                    <!--                    <el-table-column prop="deviceStatus" show-overflow-tooltip width="100" label="设备状态">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceStatus, dictObj.deviceStatus) }}
                        </template>
                    </el-table-column>-->
                            <template v-slot="{ row }">
                                {{ getDictLabel(row.deviceStatus, dictObj.deviceStatus) }}
                            </template>
                        </el-table-column>-->
                    <el-table-column prop="areaName" show-overflow-tooltip width="120" label="区域" />
                    <el-table-column prop="defenseZoneName" show-overflow-tooltip width="120" label="场景" />
                    <el-table-column show-overflow-tooltip width="200" label="调度位置">
                    <el-table-column show-overflow-tooltip label="调度位置">
                        <template v-slot="{ row }">{{ row.longitude }}, {{ row.latitude }}</template>
                    </el-table-column>
                    <el-table-column prop="dispatchUser" show-overflow-tooltip width="100" label="调度人员" />
                    <el-table-column show-overflow-tooltip width="180" label="调度日期">
                    <el-table-column show-overflow-tooltip label="调度日期">
                        <template v-slot="{ row }">
                            {{ formatDispatchDate(row) }}
                        </template>
@@ -110,7 +114,7 @@
</template>
<script setup>
import { Search, RefreshRight, Plus } from '@element-plus/icons-vue'
import { Search, RefreshRight, Plus, Delete } from '@element-plus/icons-vue'
import { nextTick, onMounted, ref, provide } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { fwTaskSchedulePageApi, fwTaskScheduleRemoveApi } from './taskScheduleApi'
@@ -130,7 +134,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const selectedIds = ref([]) // 勾选的ID列表
const queryParamsRef = ref(null) // 查询表单实例
applications/drone-command/src/views/job/components/JobRelatedEvents.vue
@@ -144,7 +144,7 @@
    params.value.ai_types = val
  handleSearch()
}
const loading = ref(false)
const loading = ref(true)
const list = ref()
const params = ref({
    way_line_job_info_id: null,
applications/drone-command/src/views/job/components/TaskIntermediateContent/AddTask.vue
@@ -151,7 +151,7 @@
})
const isShowAddTask = defineModel('show')
const loading = ref(false)
const loading = ref(true)
// 禁用当天之前的日期
const disabledDate = time => {
applications/drone-command/src/views/job/components/executeNestDetails.vue
@@ -79,7 +79,7 @@
const deviseName = ref(null)
const devisejobInfoId = ref('')
const devisebatchNo = ref(null)
const loading = ref(false)
const loading = ref(true)
const isShowContinuingToFly = code => {
    return ContinuingToFly.find(i => i.code === code)
}
applications/drone-command/src/views/layerManagement/components/leftList.vue
@@ -123,7 +123,7 @@
  dkbh: '',
  patchesName: '',
});
const loading = ref(false);
const loading = ref(true);
const treeData = ref([]);
const treeAllData = ref([]);
// 存储过滤后显示的节点ID(返回true的节点)
applications/drone-command/src/views/layerManagement/components/rightEdit.vue
@@ -156,7 +156,7 @@
  geo_data: '',
});
const loading = ref(false);
const loading = ref(true);
const detailData = ref(null);
const fenceArea = ref(0);
detailData.value = layerParams.value.editDetailData;
applications/drone-command/src/views/recordManage/alarmRecords/index.vue
@@ -56,7 +56,7 @@
        </el-form>
        <div class="ztzf-table-toolbar">
            <el-button :icon="Download" type="primary" @click="exportFile" :loading="exportLoading">导出</el-button>
            <el-button :icon="Download" color="#1A2652" type="primary" @click="exportFile" :loading="exportLoading">导出</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -64,18 +64,18 @@
                <el-table class="ztzf-data-cockpit-table" :data="list">
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="droneName" show-overflow-tooltip width="140" label="无人机名称" />
                    <el-table-column prop="droneSerialNo" show-overflow-tooltip width="160" label="无人机序列号" />
                    <el-table-column prop="alarmTime" show-overflow-tooltip width="160" label="告警时间" />
                    <el-table-column prop="areaName" show-overflow-tooltip width="120" label="区域" />
                    <el-table-column prop="triggerReason" show-overflow-tooltip width="160" label="触发原因" />
                    <el-table-column prop="deviceName" show-overflow-tooltip width="160" label="侦测反制设备" />
                    <el-table-column prop="droneType" show-overflow-tooltip width="120" label="设备类型">
                    <el-table-column prop="droneSerialNo" show-overflow-tooltip label="无人机序列号" />
                    <el-table-column prop="alarmTime" show-overflow-tooltip label="告警时间" />
                    <el-table-column prop="areaName" show-overflow-tooltip label="区域" />
                    <el-table-column prop="triggerReason" show-overflow-tooltip label="触发原因" />
                    <el-table-column prop="deviceName" show-overflow-tooltip label="侦测反制设备" />
                    <el-table-column prop="droneType" show-overflow-tooltip label="设备类型">
                        <template v-slot="{ row }">
                            {{ getDeviceTypeName(row.droneType) }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="deviceSn" show-overflow-tooltip width="140" label="设备编码" />
                    <el-table-column show-overflow-tooltip width="120" label="设备状态">
                    <el-table-column prop="deviceSn" show-overflow-tooltip label="设备编码" />
                    <el-table-column show-overflow-tooltip label="设备状态">
                        <template v-slot="{ row }">
                            {{ getDictLabel(row.deviceStatus, dictObj.deviceStatus) }}
                        </template>
@@ -116,7 +116,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const queryParamsRef = ref(null) // 查询表单实例
const dialogRef = ref(null) // 弹框实例
applications/drone-command/src/views/recordManage/historyTracks/TrajectoryDiaLog.vue
@@ -1,32 +1,59 @@
<template>
    <el-dialog v-model="visible" :title="dialogTitle" @closed="handleClosed" destroy-on-close>
        <div class="bodyBox">
            <div class="leftMap ztzf-cesium" id="leftMapContainer"></div>
            <div class="rightInfo">
                <div>
                    <div>无人机名称:{{ formData.droneName }}</div>
                    <div>序列号: {{ formData.serialNo }}</div>
                    <div>告警时间: {{ formData.alarmTime }}</div>
                    <div>触发原因: {{ formData.triggerType }}</div>
                    <div>停留时长: {{ formData.stayDuration }}</div>
<template>
    <el-dialog class="ztzf-page-map-view-dialog" v-model="visible" :show-close="false"
        :close-on-click-modal="false" @closed="handleClosed" destroy-on-close>
        <div class="dialog-container">
            <div class="left-container">
                <div class="leftMap ztzf-cesium" id="leftMapContainer"></div>
            </div>
            <div class="right-container">
                <div class="header">{{ dialogTitle }}</div>
                <div class="dialog-container">
                    <div class="detail-title">轨迹信息</div>
                    <el-row>
                        <el-col :span="24">
                            <div class="label">无人机名称</div>
                            <div class="val">{{ formData.droneName }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">序列号</div>
                            <div class="val">{{ formData.serialNo }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">告警时间</div>
                            <div class="val">{{ formData.alarmTime }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">触发原因</div>
                            <div class="val">{{ formData.triggerType }}</div>
                        </el-col>
                        <el-col :span="24">
                            <div class="label">停留时长</div>
                            <div class="val">{{ formData.stayDuration }}</div>
                        </el-col>
                    </el-row>
                    <div class="detail-title">轨迹点</div>
                    <div class="ztzf-table-container">
                        <div class="ztzf-table-content">
                            <el-table class="ztzf-data-cockpit-table" :data="list">
                                <el-table-column type="index" width="60" label="序号" />
                                <el-table-column label="经纬度">
                                    <template #default="{ row }">{{ row.longitude }},{{ row.latitude }}</template>
                                </el-table-column>
                                <el-table-column prop="createTime" label="时间" />
                            </el-table>
                        </div>
                    </div>
                </div>
                <el-table :data="list">
                    <el-table-column type="index" width="60" label="序号" />
                    <el-table-column label="经纬度">
                        <template #default="{ row }">{{ row.longitude }},{{ row.latitude }}</template>
                    </el-table-column>
                    <el-table-column prop="createTime" label="时间" />
                </el-table>
                <div class="footer">
                    <el-button color="#2B2B4C" @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
                </div>
            </div>
        </div>
        <template #footer>
            <el-button @click="handleCancel">{{ dialogReadonly ? '关闭' : '取消' }}</el-button>
        </template>
    </el-dialog>
</template>
<script setup>
import { computed, ref } from 'vue'
import { computed, nextTick, ref } from 'vue'
import { fwDroneFlightRecordDetailApi } from '@/views/recordManage/historyTracks/fwDroneFlightRecord'
import { fwDroneFlightRecordDetailPageApi } from '@/views/recordManage/historyTracks/flyTrajectory'
import { PublicCesium } from '@/utils/cesium/publicCesium'
@@ -57,12 +84,12 @@
})
// 关闭弹框
function handleCancel() {
function handleCancel () {
    visible.value = false
}
// 加载详情
async function loadDetail() {
async function loadDetail () {
    if (!formData.value.id) return
    const res = await fwDroneFlightRecordDetailApi({ id: formData.value.id })
    const res1 = await fwDroneFlightRecordDetailPageApi({ flightRecordId: formData.value.id })
@@ -72,11 +99,11 @@
}
// 角度转c3
function degreesToC3({ longitude, latitude, height = 0 }) {
function degreesToC3 ({ longitude, latitude, height = 0 }) {
    return Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
}
// 渲染航线
function drawFlightPath() {
function drawFlightPath () {
    const positions = list.value.map(p => degreesToC3(p))
    droneLineEntity && geometricSource.entities.remove(droneLineEntity)
    const color = Cesium.Color.fromCssColorString('#00D690')
@@ -92,12 +119,17 @@
}
// 关闭后重置
function handleClosed() {
function handleClosed () {
    formData.value = initForm()
    list.value = []
    viewer = null
    geometricSource = null
    droneLineEntity = null
}
let viewer, geometricSource, droneLineEntity
function initMap() {
function initMap () {
    if (viewer) return
    const publicCesiumInstance = new PublicCesium({
        dom: 'leftMapContainer',
        flatMode: false,
@@ -111,12 +143,11 @@
}
// 打开弹框
async function open({ mode, row } = {}) {
async function open ({ mode, row } = {}) {
    dialogMode.value = mode || 'add'
    visible.value = true
    await nextTick(() => {
        initMap()
    })
    await nextTick()
    initMap()
    if (dialogMode.value === 'add') {
        formData.value = initForm()
    } else {
@@ -127,16 +158,5 @@
defineExpose({ open })
</script>
<style scoped lang="scss">
.bodyBox {
    display: flex;
    .rightInfo {
        width: 50%;
        height: 500px;
    }
    .leftMap {
        width: 50%;
        height: 500px;
    }
}
</style>
<style scoped lang="scss"></style>
applications/drone-command/src/views/recordManage/historyTracks/index.vue
@@ -39,7 +39,7 @@
        </el-form>
        <div class="ztzf-table-toolbar">
            <el-button :icon="Download" type="primary" @click="exportFile" :loading="exportLoading">导出</el-button>
            <el-button :icon="Download" color="#1A2652" type="primary" @click="exportFile" :loading="exportLoading">导出</el-button>
        </div>
        <div class="ztzf-table-container" v-loading="loading" element-loading-background="rgba(5, 5, 15, 0.6)">
@@ -47,11 +47,11 @@
                <el-table class="ztzf-data-cockpit-table" :data="list">
                    <el-table-column type="index" show-overflow-tooltip width="64" label="序号" />
                    <el-table-column prop="droneName" show-overflow-tooltip width="140" label="无人机名称" />
                    <el-table-column prop="serialNo" show-overflow-tooltip width="160" label="序列号" />
                    <el-table-column prop="alarmTime" show-overflow-tooltip width="160" label="告警时间" />
                    <el-table-column prop="areaName" show-overflow-tooltip width="120" label="区域" />
                    <el-table-column prop="triggerType" show-overflow-tooltip width="160" label="触发原因" />
                    <el-table-column show-overflow-tooltip width="140" label="停留时长">
                    <el-table-column prop="serialNo" show-overflow-tooltip label="序列号" />
                    <el-table-column prop="alarmTime" show-overflow-tooltip label="告警时间" />
                    <el-table-column prop="areaName" show-overflow-tooltip label="区域" />
                    <el-table-column prop="triggerType" show-overflow-tooltip label="触发原因" />
                    <el-table-column show-overflow-tooltip label="停留时长">
                        <template v-slot="{ row }">
                            {{ formatStayDuration(row.stayDuration) }}
                        </template>
@@ -95,7 +95,7 @@
})
const searchParams = ref(initSearchParams()) // 查询参数
const total = ref(0) // 总条数
const loading = ref(false) // 列表加载中
const loading = ref(true) // 列表加载中
const list = ref([]) // 列表数据
const queryParamsRef = ref(null) // 查询表单实例
const dateRange = ref([])
applications/drone-command/src/views/resource/components/spotDetails.vue
@@ -168,7 +168,7 @@
const viewInstance = shallowRef(null);
const homeViewer = shallowRef(null);
let tbJwdList = [];
const loading = ref(false);
const loading = ref(true);
const tableLoading = ref(true);
const tableData = ref([]);
const AlltableData = ref([]);
applications/drone-command/src/views/tickets/ticket.vue
@@ -509,7 +509,7 @@
const detailVisible = ref(false)
const currentDetail = ref({})
const departmentUsers = ref({})
const loading = ref(false)
const loading = ref(true)
const globalCounts = ref({})
const mapLoaded = ref(false)
const isFetching = ref(false)
applications/drone-command/src/views/tickets/ticketComponent/DispatchDialog.vue
@@ -88,7 +88,7 @@
});
const emit = defineEmits(['update:modelValue', 'dispatch-success', 'dispatch-error']);
const formRef = ref(null); // 表单引用
const loading = ref(false);
const loading = ref(true);
const form = ref({
  department: '',
  handler: ''