riku
2025-07-08 91513e171078ed6b0887f87b9fced33895d6d3fb
2025.7.8
已修改7个文件
已添加4个文件
678 ■■■■ 文件已修改
src/components.d.ts 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/SceneDevice.vue 392 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/TaskItem.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/enum/device/device.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/enum/device/monitorDevice.js 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/enum/device/productionDevice.js 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/enum/device/treatmentDevice.js 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/MonitorView.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/TaskStats.vue 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/SubtaskVisual.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/SupervisionVisual.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts
@@ -11,15 +11,22 @@
    BaseMap: typeof import('./components/map/BaseMap.vue')['default']
    BaseTable: typeof import('./components/BaseTable.vue')['default']
    CoreHeader: typeof import('./components/core/CoreHeader.vue')['default']
    ElBadge: typeof import('element-plus/es')['ElBadge']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElCalendar: typeof import('element-plus/es')['ElCalendar']
    ElCard: typeof import('element-plus/es')['ElCard']
    ElCascader: typeof import('element-plus/es')['ElCascader']
    ElCol: typeof import('element-plus/es')['ElCol']
    ElCollapse: typeof import('element-plus/es')['ElCollapse']
    ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
    ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
    ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
    ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
    ElDivider: typeof import('element-plus/es')['ElDivider']
    ElEmpty: typeof import('element-plus/es')['ElEmpty']
    ElForm: typeof import('element-plus/es')['ElForm']
    ElFormItem: typeof import('element-plus/es')['ElFormItem']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElImage: typeof import('element-plus/es')['ElImage']
    ElLink: typeof import('element-plus/es')['ElLink']
src/components/inspection/SceneDevice.vue
@@ -4,158 +4,190 @@
  <!-- é€‰é¡¹ -->
  <!-- è®¾å¤‡ç±»åž‹  -->
  <el-row>
    <el-col>
      <el-tabs class="child_select" placeholder="设备类型" v-model="currSelect.topDeviceTypeId">
        <el-tab-pane v-for="item in deviceTopTypes" :key="item.id" :name="item.id">
          <template #label>
            <el-badge :value="item.count" :type="item.count == 0 ? 'danger' : 'primary'">
              <span class="custom-tabs-label">
                <span>{{ item.label }}</span>
              </span>
            </el-badge>
          </template>
        </el-tab-pane>
      </el-tabs>
    </el-col>
    <el-tabs style="width: 100%" placeholder="设备类型" v-model="currSelect.topDeviceTypeId">
      <el-tab-pane v-for="item in deviceTopTypes" :key="item.id" :name="item.id">
        <template #label>
          <el-badge :value="item.count" :type="item.count == 0 ? 'danger' : 'primary'">
            <span class="custom-tabs-label">
              <span>{{ item.label }}</span>
            </span>
          </el-badge>
        </template>
      </el-tab-pane>
    </el-tabs>
  </el-row>
  <el-collapse v-model="activeNames" style="border: 4px">
    <el-collapse-item
      v-for="item in formInfo"
      :key="item.id"
      :name="item.id"
      class="collapse-item-class"
    >
      <template #title>
        <div style="display: flex; width: 100%; justify-content: space-between">
          <div style="">
            <el-descriptions style="" :column="3" size="small" border>
              <el-descriptions-item
                width="64px"
                :label="currSelect.topDeviceTypeId == 0 ? '站点名称' : '设备名称'"
                :span="3"
                >{{ item.name || '无' }}</el-descriptions-item
              >
              <el-descriptions-item label="供应商">{{
                item.supplier || '无'
              }}</el-descriptions-item>
              <el-descriptions-item label="运维商">{{
                item.maintainer || '无'
              }}</el-descriptions-item>
              <el-descriptions-item label="运维频次">
                <el-select
                  v-model="item.maintainFrequency"
                  :disabled="isDisabled"
                  style="width: 150px"
                >
                  <el-option
                    v-for="frequency of maintainFrequencysArray"
                    :key="frequency.key"
                    :label="frequency.value"
                    :value="frequency.key"
                  ></el-option>
                </el-select>
              </el-descriptions-item>
              <el-descriptions-item label="运维人员">{{
                item.maintainStaff || '无'
              }}</el-descriptions-item>
              <el-descriptions-item label="运维联系方式">{{
                item.maintainTel || '无'
              }}</el-descriptions-item>
              <el-descriptions-item label="品牌型号">{{
                item.brandModel || '无'
              }}</el-descriptions-item>
              <el-descriptions-item label="运行状态">
                <el-select v-model="item.runningStatus" :disabled="isDisabled" style="width: 150px">
                  <el-option
                    v-for="status of runStatusArray"
                    :key="status.key"
                    :label="status.value"
                    :value="status.key"
                  ></el-option>
                </el-select>
              </el-descriptions-item>
              <el-descriptions-item label="类型">
                {{ item._typename || '无' }}
              </el-descriptions-item>
            </el-descriptions>
          </div>
          <div style="display: flex">
            <!-- <div class="sub-title">{{ item.name }}</div> -->
            <!-- å›¾ç‰‡ -->
            <div class="image-container">
              <div
                class="block-div"
                @click="onClickPic($event)"
                v-for="(status, index) in item._statusList"
                :key="index"
              >
                <el-image
                  v-if="index == 0"
                  fit="cover"
                  class="pic-style"
                  :src="status._picUrl"
                  :preview-src-list="Array.of(status._picUrl)"
                />
                <span class="abstract_pic_text" v-if="index == 0">{{
                  `最新状态图片 ${status.dlCreateTime.slice(0, 10)}`
                }}</span>
  <el-scrollbar :height="height" v-loading="loading">
    <!-- <el-collapse v-model="activeNames" style="border: 4px"> -->
    <!-- <el-collapse-item
        v-for="item in formInfo"
        :key="item.id"
        :name="item.id"
        class="collapse-item-class"
      > -->
    <!-- <template #title> -->
    <div v-for="item in formInfo" :key="item.id" :name="item.id" class="collapse-item-class">
      <el-card class="m-b-10">
        <div style="text-align: start">
          <el-row>
            <el-col :span="12">
              <div>
                <el-text>{{
                  (currSelect.topDeviceTypeId == 0 ? '站点名称:' : '设备名称:') +
                  (item.name || '无')
                }}</el-text>
              </div>
            </div>
          </div>
              <template v-if="item._showMore">
                <div>
                  <el-text>{{ '供应商:' + (item.supplier || '无') }}</el-text>
                </div>
                <div>
                  <el-text>{{ '运维商:' + (item.maintainer || '无') }}</el-text>
                </div>
                <el-space>
                  <el-text>{{ '运维频次:' }}</el-text>
                  <el-select
                    v-model="item.maintainFrequency"
                    :disabled="isDisabled"
                    style="width: 100px"
                  >
                    <el-option
                      v-for="frequency of maintainFrequencysArray"
                      :key="frequency.key"
                      :label="frequency.value"
                      :value="frequency.key"
                    ></el-option>
                  </el-select>
                </el-space>
              </template>
            </el-col>
            <el-col :span="12">
              <div>
                <el-text>{{ '类型:' + (item._typename || '无') }}</el-text>
              </div>
              <template v-if="item._showMore">
                <div>
                  <el-text>{{ '运维人员:' + (item.maintainStaff || '无') }}</el-text>
                </div>
                <div>
                  <el-text>{{ '联系方式:' + (item.maintainTel || '无') }}</el-text>
                </div>
                <div>
                  <el-text>{{ '品牌型号:' + (item.brandModel || '无') }}</el-text>
                </div>
                <el-space>
                  <el-text>{{ '运行状态:' }}</el-text>
                  <el-select
                    v-model="item.runningStatus"
                    :disabled="isDisabled"
                    style="width: 100px"
                  >
                    <el-option
                      v-for="status of runStatusArray"
                      :key="status.key"
                      :label="status.value"
                      :value="status.key"
                    ></el-option>
                  </el-select>
                </el-space>
              </template>
            </el-col>
          </el-row>
          <el-row justify="end">
            <el-link type="success" @click="item._showMore = !item._showMore">
              <el-icon>
                <Bottom v-if="!item._showMore" />
                <Top v-else />
              </el-icon>
              {{ item._showMore ? '收起更多' : '更多信息' }}
            </el-link>
          </el-row>
          <!-- <div style="display: flex">
              <div class="image-container">
                <div
                  class="block-div"
                  @click="onClickPic($event)"
                  v-for="(status, index) in item._statusList"
                  :key="index"
                >
                  <el-image
                    v-if="index == 0"
                    fit="cover"
                    class="pic-style"
                    :src="status._picUrl"
                    :preview-src-list="Array.of(status._picUrl)"
                  />
                  <span class="abstract_pic_text" v-if="index == 0">{{
                    `最新状态图片 ${status.dlCreateTime.slice(0, 10)}`
                  }}</span>
                </div>
              </div>
            </div> -->
        </div>
      </template>
      <!-- è¯¦ç»†å†…容开始 -->
      <el-form :model="item" class="form_class">
        <el-form-item label="状态">
        <!-- </template> -->
        <!-- è¯¦ç»†å†…容开始 -->
        <el-space>
          <div>
            <div>设</div>
            <div>备</div>
            <div>状</div>
            <div>态</div>
          </div>
          <el-tabs tab-position="top">
            <el-tab-pane
              v-for="(status, i) in item._statusList"
              :label="status.dlCreateTime.slice(0, 10)"
              :key="i"
            >
              <el-form :model="status" class="form-class">
                <el-form-item label="位置" style="margin-bottom: 10px">
                  {{ status.dlLocation }}
                </el-form-item>
                <el-form-item label="图片">
                  <!-- å›¾ç‰‡ -->
                  <el-space>
                    <div v-if="status._paths && status._paths.length > 0">
                      <el-image
                        v-for="(path, i) in status._paths"
                        fit="cover"
                        class="pic-style"
                        :src="path"
                        :preview-src-list="Array.of(path)"
                        :key="i"
                      />
                    </div>
                    <el-empty v-else></el-empty>
                  </el-space>
                </el-form-item>
              </el-form>
              <!-- <el-form :model="status" class="form-class"> -->
              <!-- <el-form-item label=""> -->
              <!-- å›¾ç‰‡ -->
              <el-space>
                <div v-if="status._paths && status._paths.length > 0">
                  <el-image
                    v-for="(path, i) in status._paths"
                    fit="cover"
                    class="pic-style"
                    :src="path"
                    :preview-src-list="Array.of(path)"
                    :key="i"
                  />
                </div>
                <el-empty v-else></el-empty>
              </el-space>
              <!-- </el-form-item> -->
              <el-form-item v-if="status.dlLocation" label="位置" style="margin-bottom: 10px">
                {{ status.dlLocation }}
              </el-form-item>
              <!-- </el-form> -->
            </el-tab-pane>
          </el-tabs>
        </el-form-item>
      </el-form>
      <!-- è¯¦ç»†å†…容结束 -->
    </el-collapse-item>
  </el-collapse>
  <!-- ç©ºçŠ¶æ€ -->
  <el-empty v-if="isEmpty" />
        </el-space>
      </el-card>
    </div>
    <!-- è¯¦ç»†å†…容结束 -->
    <!-- </el-collapse-item> -->
    <!-- </el-collapse> -->
    <!-- ç©ºçŠ¶æ€ -->
    <el-empty v-if="isEmpty" />
  </el-scrollbar>
  <!-- </template>
  </CompGenericWrapper> -->
</template>
<script>
import { reactive } from 'vue'
import deviceApi from '@/api/fysp/deviceApi'
import { $fysp } from '@/api/index'
import { toLabel } from '@/enum/device/device'
export default {
  components: {},
  props: {
    scene: Object
    scene: Object,
    height: {
      type: String,
      default: '70vh'
    }
  },
  watch: {
    // é€‰æ‹©æ”¹å˜ç›‘听
@@ -164,10 +196,16 @@
        this.getList()
      },
      deep: true
    },
    scene(nV, oV) {
      if (nV != oV) {
        this.init()
      }
    }
  },
  data() {
    return {
      loading: false,
      activeNames: [],
      // æŽ§åˆ¶æ˜¯å¦å±•示空状态
      isEmpty: false,
@@ -180,7 +218,7 @@
      },
      // æŽ§åˆ¶è¡¨å•是否可以编辑
      isDisabled: true,
      formInfo: {},
      formInfo: [],
      rules: [],
      // è®¾å¤‡ç±»åž‹
      deviceTopTypes: [
@@ -206,8 +244,7 @@
      ownershipArray: [
        { key: 0, value: 'è´­ä¹°' },
        { key: 1, value: '租赁' }
      ],
      scene: {}
      ]
    }
  },
@@ -234,10 +271,7 @@
    showDetail(item) {
      item._isDetail = !item._isDetail
    },
    init(scene) {
      // çˆ¶ç»„件主动调用初始化子组件的方法
      this.scene = scene
    init() {
      this.getList()
      this.getTabsCount()
    },
@@ -262,51 +296,55 @@
        newKey = newKey.charAt(0).toLowerCase() + newKey.slice(1)
        newObj[newKey] = obj[key]
      }
      return newObj
      return reactive(newObj)
    },
    // æ–°å¢žå­—段
    initFormData(data) {
      data._isDetail = false
    },
    getList() {
      deviceApi.fetchDevices(this.scene.guid, this.currSelect.topDeviceTypeId).then((result) => {
        this.initList()
        if (result.data == null || result.data.length <= 0) {
          this.isEmpty = true
          return
        }
        // æ ‡å‡†åŒ–属性名
        for (let index = 0; index < result.data.length; index++) {
          var element = this.convertKeys(result.data[index])
          this.initFormData(element)
          // èŽ·å–è®¾å¤‡çŠ¶æ€ä¿¡æ¯
          let data = {
            deviceId: element.id,
            sceneId: element.sceneGuid,
            deviceTypeId: this.currSelect.topDeviceTypeId
      this.loading = true
      deviceApi
        .fetchDevices(this.scene.guid, this.currSelect.topDeviceTypeId)
        .then((result) => {
          this.initList()
          if (result.data == null || result.data.length <= 0) {
            this.isEmpty = true
            return
          }
          deviceApi.fetchDeviceStatus(data).then((status) => {
            var statusData = status.data
            var imgPaths = []
            if (statusData) {
              if (statusData.length == 0) {
                this.formInfo.push(element)
                return
              }
              element = this.convertKeys(result.data[index])
              element = this.setDeviceType(element)
              element._picUrls = imgPaths
              for (let index = 0; index < statusData.length; index++) {
                const statusItem = statusData[index]
                // è®¾å¤‡å¯¹è±¡æ·»åŠ ä¸€ä¸ªå±žæ€§åˆ—è¡¨å±žæ€§ç”¨æ¥ä¿å­˜è®¾å¤‡çŠ¶æ€
                this.saveStatus(element, statusItem)
                element.dlLocation = statusItem.dlLocation
                this.formInfo.push(element)
              }
          // æ ‡å‡†åŒ–属性名
          for (let index = 0; index < result.data.length; index++) {
            var element = this.convertKeys(result.data[index])
            this.initFormData(element)
            // èŽ·å–è®¾å¤‡çŠ¶æ€ä¿¡æ¯
            let data = {
              deviceId: element.id,
              sceneId: element.sceneGuid,
              deviceTypeId: this.currSelect.topDeviceTypeId
            }
          })
        }
      })
            deviceApi.fetchDeviceStatus(data).then((status) => {
              var statusData = status.data
              var imgPaths = []
              if (statusData) {
                if (statusData.length == 0) {
                  this.formInfo.push(element)
                  return
                }
                element = this.convertKeys(result.data[index])
                element = this.setDeviceType(element)
                element._picUrls = imgPaths
                for (let index = statusData.length - 1; index >= 0; index--) {
                  const statusItem = statusData[index]
                  // è®¾å¤‡å¯¹è±¡æ·»åŠ ä¸€ä¸ªå±žæ€§åˆ—è¡¨å±žæ€§ç”¨æ¥ä¿å­˜è®¾å¤‡çŠ¶æ€
                  this.saveStatus(element, statusItem)
                  element.dlLocation = statusItem.dlLocation
                }
                this.formInfo.push(element)
              }
            })
          }
        })
        .finally(() => (this.loading = false))
    },
    setDeviceType(element) {
      var type = []
@@ -330,7 +368,7 @@
      }
      // æŽ’序
      device._statusList.sort(function (x, y) {
        return new Date(x.dlCreateTime) - new Date(y.dlCreateTime) //    é™åºï¼Œå‡åºåˆ™åä¹‹
        return new Date(y.dlCreateTime) - new Date(x.dlCreateTime) //    é™åºï¼Œå‡åºåˆ™åä¹‹
      })
    },
    submit() {},
@@ -390,8 +428,8 @@
  /* overflow: hidden; ç¡®ä¿å›¾ç‰‡ä¸ä¼šè¶…出容器 */
}
.pic-style {
  width: 150px;
  height: 150px;
  width: 100px;
  height: 100px;
  border-radius: 4px;
}
.card-style {
src/components/inspection/TaskItem.vue
@@ -85,7 +85,7 @@
    <div>
      <div class="text_title">日程进度</div>
      <el-space>
        <el-text style="color: transparent;">日程</el-text>
        <el-text style="color: transparent">日程</el-text>
        <el-progress
          style="width: 350px"
          type="line"
@@ -130,7 +130,7 @@
    return planEndTime.daysInMonth()
  }
})
const dateStr = computed(()=>{
const dateStr = computed(() => {
  const today = dayjs()
  const planEndTime = dayjs(areaStore.area.endtime)
  if (today.isBefore(planEndTime)) {
@@ -160,6 +160,7 @@
  box-shadow: var(--el-box-shadow-lighter);
  background-color: rgba(161, 161, 161, 0.068);
  padding: 8px 8px;
  margin-bottom: 4px;
}
.text_title {
src/enum/device/device.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
import monitor from './monitorDevice';
import treatment from './treatmentDevice';
import production from './productionDevice';
function enumDevice() {
  return [
    { value: 0, label: '监控设备' },
    { value: 1, label: '治理设备' },
    { value: 2, label: '生产设备' }
  ];
}
function toLabel(sceneType, deviceType, valueArr) {
  switch (deviceType + '') {
    case '0':
      return monitor.toLabel(sceneType, valueArr);
    case '1':
      return treatment.toLabel(sceneType, valueArr);
    case '2':
      return production.toLabel(sceneType, valueArr);
  }
}
export { enumDevice, toLabel };
src/enum/device/monitorDevice.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
const dustDeviceType = [
  {
    label: '扬尘',
    value: '1',
    children: [
      {
        label: '监测设备',
        value: '1',
      },
    ],
  },
];
const fumeDeviceType = [
  {
    label: '油烟',
    value: '1',
    children: [
      {
        label: '监测设备',
        value: '1',
      },
    ],
  },
];
const vocDeviceType = [
  {
    label: 'VOC',
    value: '1',
    children: [
      {
        label: '监测设备',
        value: '1',
      },
    ],
  },
];
// ç›‘测设备类型
function monitorDevices(sceneType) {
  switch (parseInt(sceneType)) {
    // å·¥åœ°,码头,搅拌站,堆场
    case 1:
    case 2:
    case 3:
    case 14:
      return dustDeviceType;
    // é¤é¥®
    case 5:
      return fumeDeviceType;
    // å·¥ä¸šä¼ä¸š,汽修
    case 4:
    case 6:
      return vocDeviceType;
    default:
      return dustDeviceType;
  }
}
function toLabel(sceneType, valueArr) {
  const labelArr = [];
  let options = monitorDevices(sceneType);
  valueArr.forEach(v => {
    if (options) {
      const op = options.find(o => {
        return (o.value + '') == (v + '');
      });
      labelArr.push(op.label);
      options = op.children;
    }
  });
  return labelArr;
}
export default { monitorDevices, toLabel };
src/enum/device/productionDevice.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
const dustDeviceType = [
  {
    label: '非道',
    value: '1',
    children: [
      { label: '挖掘机', value: '1' },
      { label: '叉车', value: '2' },
      { label: '履带吊', value: '3' },
      { label: '铲车', value: '4' },
      { label: '发动机', value: '5' },
    ],
  },
];
const fumeDeviceType = [
  {
    label: '厨具',
    value: '1',
    children: [{ label: '厨具', value: '1' }],
  },
];
const vocDeviceType = [
  {
    label: 'VOC',
    value: '1',
    children: [{ label: 'VOC', value: '1' }],
  },
];
// ç”Ÿäº§è®¾å¤‡ç±»åž‹
function productionDevices(sceneType) {
  switch (parseInt(sceneType)) {
    // å·¥åœ°,码头,搅拌站,堆场
    case 1:
    case 2:
    case 3:
    case 14:
      return dustDeviceType;
    // é¤é¥®
    case 5:
      return fumeDeviceType;
    // å·¥ä¸šä¼ä¸š,汽修
    case 4:
    case 6:
      return vocDeviceType;
    default:
      return dustDeviceType;
  }
}
function toLabel(sceneType, valueArr) {
  const labelArr = [];
  let options = productionDevices(sceneType);
  valueArr.forEach(v => {
    if (options) {
      const op = options.find(o => {
        return (o.value + '') == (v + '');
      });
      labelArr.push(op.label);
      options = op.children;
    }
  });
  return labelArr;
}
export default { productionDevices, toLabel };
src/enum/device/treatmentDevice.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,75 @@
const dustDeviceType = [
  {
    label: '技防',
    value: '1',
    children: [
      { label: '环保洒水车(大型非电动)', value: '1' },
      { label: '电动雾炮车', value: '2' },
      { label: '电动洒水车(小型)', value: '3' },
      { label: '雾炮车(固定或轮式)', value: '4' },
      { label: '自动冲洗装置(封闭式)', value: '5' },
      { label: '高效洗轮机', value: '6' },
      { label: '高压水枪', value: '7' },
      { label: '普通水管或消防栓', value: '8' },
      { label: '塔吊喷淋', value: '9' },
      { label: '围墙喷淋', value: '10' },
      { label: '扬尘监测与喷淋联动', value: '11' },
      { label: '堆场喷淋', value: '12' },
      { label: '生产区喷淋', value: '13' },
    ],
  },
];
const fumeDeviceType = [
  {
    label: '净化',
    value: '1',
    children: [{ label: '油烟净化', value: '1' }],
  },
];
const vocDeviceType = [
  {
    label: '净化',
    value: '1',
    children: [{ label: '固废净化', value: '1' }],
  },
];
// æ²»ç†è®¾å¤‡ç±»åž‹
function treatmentDevices(sceneType) {
  switch (parseInt(sceneType)) {
    // å·¥åœ°,码头,搅拌站,堆场
    case 1:
    case 2:
    case 3:
    case 14:
      return dustDeviceType;
    // é¤é¥®
    case 5:
      return fumeDeviceType;
    // å·¥ä¸šä¼ä¸š,汽修
    case 4:
    case 6:
      return vocDeviceType;
    default:
      return dustDeviceType;
  }
}
function toLabel(sceneType, valueArr) {
  const labelArr = [];
  let options = treatmentDevices(sceneType);
  valueArr.forEach(v => {
    if (options) {
      const op = options.find(o => {
        return (o.value + '') == (v + '');
      });
      labelArr.push(op.label);
      options = op.children;
    }
  });
  return labelArr;
}
export default { treatmentDevices, toLabel };
src/views/main/MonitorView.vue
@@ -20,11 +20,12 @@
    </el-col>
    <el-col :span="7" class="page-right">
      <el-scrollbar height="var(--fy-body-height)" class="p-events-auto">
        <SupervisionVisual></SupervisionVisual>
        <ManagementView></ManagementView>
      </el-scrollbar>
    </el-col>
  </el-row>
  <SupervisionVisual class="supervision-view"></SupervisionVisual>
  <!-- <SupervisionVisual class="supervision-view"></SupervisionVisual> -->
  <WorkStream class="work-stream"></WorkStream>
  <!-- <ProblemTrack class="problem-track"></ProblemTrack> -->
src/views/management/TaskStats.vue
@@ -39,6 +39,8 @@
import { useSubtaskStore } from '@/stores/subtask.js'
import taskApi from '@/api/fysp/taskApi.js'
/**
 * ä»»åŠ¡å®Œæˆæƒ…å†µ
 */
@@ -48,6 +50,7 @@
const subtaskStore = useSubtaskStore()
const tasks = ref([])
const sceneTaskMap = ref(new Map())
const subtaskLoading = ref(false)
function onGetTaskInfo(tInfoList) {
  const resList = []
@@ -95,8 +98,27 @@
  tasks.value = resList
}
const area = {
  provincecode: null,
  provincename: '上海市',
  citycode: undefined,
  cityname: undefined,
  districtcode: undefined,
  districtname: undefined,
  starttime: '2025-06-01 00:00:00',
  endtime: '2025-06-30 23:59:59',
  scensetypeid: undefined
}
function cal() {
  subtaskStore.onAllTaskRefreshed(onGetTaskInfo)
  subtaskLoading.value = true
  taskApi
    .fetchTopTaskProgress(area)
    .then((res) => {
      if (res.data.length == 0) return
      onGetTaskInfo(res.data)
    })
    .finally(() => (subtaskLoading.value = false))
  // subtaskStore.onAllTaskRefreshed(onGetTaskInfo)
}
onMounted(() => {
src/views/visualization/SubtaskVisual.vue
@@ -57,7 +57,7 @@
        ></FYImageSelectDialog>
      </div>
      <div v-show="value == '设备设施'">
        <SceneDevice :scene="scene" height="500px"></SceneDevice>
      </div>
    </el-card>
  </el-scrollbar>
src/views/visualization/SupervisionVisual.vue
@@ -9,7 +9,7 @@
      ></OptionLocation>
      <OptionSceneType
        :type="2"
        :width="120"
        :width="100"
        :initValue="false"
        v-model="sceneType"
      ></OptionSceneType>