riku
2025-06-09 38ff09bd2a638bc43a365efe0390cc3510d62e68
2025.6.9 功能编写中
已修改18个文件
已添加1个文件
448 ■■■■ 文件已修改
src/api/index.js 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element/index.scss 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element/transition.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/BaseCard.vue 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/TaskItem.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/subtask.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/index.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/marks.js 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/LoginView.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/InspectionView.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/WorkStream.vue 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/problem/component/ProblemSummary.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/MonitorView.vue 59 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/ManagementView.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/TaskStats.vue 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/SubtaskVisual.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/SupervisionVisual.vue 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/VisualizationView.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js
@@ -1,13 +1,13 @@
import axios from 'axios'
import { ElMessage } from 'element-plus'
const debug = false
const debug = true
var IP = '47.100.191.150'
var PORT = '9005'
if (debug) {
  IP = '192.168.0.138'
  PORT = '8080'
  IP = '192.168.0.103'
  PORT = '9001'
}
let ws = `${IP}:${PORT}`
src/assets/styles/element/index.scss
@@ -6,8 +6,11 @@
    'overlay': #102f63c9
  ),
  $colors: (
    'primary': (
      'base': #e6a23c
    'info': (
      'base': #ffb74c
    )
  ),
  $text-color: (
    'regular': #fff
  )
);
src/assets/styles/element/transition.scss
src/components.d.ts
@@ -11,17 +11,16 @@
    BaseMap: typeof import('./components/map/BaseMap.vue')['default']
    BaseTable: typeof import('./components/BaseTable.vue')['default']
    CoreHeader: typeof import('./components/core/CoreHeader.vue')['default']
    DataTable: typeof import('./components/DataTable.vue')['default']
    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']
    ElCollapseTransition: typeof import('element-plus/es')['ElCollapseTransition']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
    ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
    ElDivider: typeof import('element-plus/es')['ElDivider']
    ElEmpty: typeof import('element-plus/es')['ElEmpty']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElImage: typeof import('element-plus/es')['ElImage']
    ElLink: typeof import('element-plus/es')['ElLink']
@@ -32,14 +31,11 @@
    ElSegmented: typeof import('element-plus/es')['ElSegmented']
    ElSelect: typeof import('element-plus/es')['ElSelect']
    ElSpace: typeof import('element-plus/es')['ElSpace']
    ElSpan: typeof import('element-plus/es')['ElSpan']
    ElStatistic: typeof import('element-plus/es')['ElStatistic']
    ElTable: typeof import('element-plus/es')['ElTable']
    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
    ElTag: typeof import('element-plus/es')['ElTag']
    ElText: typeof import('element-plus/es')['ElText']
    ElTimeline: typeof import('element-plus/es')['ElTimeline']
    ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
    OptionLocation: typeof import('./components/search/OptionLocation.vue')['default']
    OptionSceneType: typeof import('./components/search/OptionSceneType.vue')['default']
    OptionTime: typeof import('./components/search/OptionTime.vue')['default']
src/components/BaseCard.vue
@@ -1,9 +1,50 @@
<template>
  <div class="wrap-2">
  <div class="wrap-2 p-events-auto">
    <el-space>
      <span class="close-icon" @click="showToggle">
        <el-icon :size="16">
          <!-- <Transition name="rotate">
            <Close v-if="show" />
          </Transition>
          <Transition name="rotate-reverse">
            <Plus v-if="!show" />
          </Transition> -->
          <Close :class="closeRotate" />
        </el-icon>
      </span>
      <el-row justify="space-between" align="middle">
        <span>{{ title }}</span>
        <div class="m-l-16">
          <slot name="expand"></slot>
        </div>
      </el-row>
    </el-space>
    <!-- <Transition name="el-zoom-in-left"> -->
    <div class="m-t-8" v-if="show">
    <slot></slot>
  </div>
    <!-- </Transition> -->
  </div>
</template>
<script></script>
<script setup>
import { ref } from 'vue'
const props = defineProps({
  title: String
})
const show = ref(true)
const closeRotate = ref('')
function showToggle() {
  show.value = !show.value
  if (show.value) {
    closeRotate.value = 'rotate-enter-active close-rotate'
  } else {
    closeRotate.value = 'rotate-enter-active close-rotate-reverse'
  }
}
</script>
<style scoped>
.wrap {
  background-image: url('@/assets/icon/bg-border-1.png');
@@ -18,9 +59,48 @@
}
.wrap-2 {
  border: 2px solid rgba(255, 255, 255, 0.829);
  border: 2px solid rgb(255, 255, 255);
  border-radius: 8px;
  padding: 4px;
  background: linear-gradient(#14428be8, #14428b8f);
  /* background: linear-gradient(#14428be8, #14428b8f); */
  background: #0034888f;
}
.close-icon {
  border: 1px solid white;
  border-radius: 4px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.close-icon:hover {
  border-color: #87f8f2;
  color: #87f8f2;
}
.close-rotate {
  transform: rotate(90deg);
}
.close-rotate-reverse {
  transform: rotate(-135deg);
}
.rotate-enter-active {
  transition: transform 0.5s ease;
}
</style>
<!-- <style>
.rotate-enter-from {
  transform: rotate(135deg);
}
.rotate-reverse-enter-active {
  transition: transform 0.5s ease;
  /* transition: opacity 0.5s ease; */
}
.rotate-reverse-enter-from {
  transform: rotate(-135deg);
}
</style> -->
src/components/inspection/TaskItem.vue
@@ -1,52 +1,56 @@
<template>
  <!-- <div class="demo-progress border-r-small"> -->
  <el-row justify="end">
    <el-text type="info">{{ name }}</el-text>
  <el-row justify="start">
    <el-text>{{ name }}</el-text>
  </el-row>
  <el-row justify="space-evenly">
    <el-col span="12">
      <div class="v-center">
  <div>
        <el-text>总量</el-text>
    <el-text size="small">{{ completetask + '/' + totaltask }}</el-text>
        <el-progress
          :width="100"
          type="circle"
      style="width: 300px"
      type="line"
          status="warning"
      :text-inside="true"
      :stroke-width="18"
      :striped="percentFormat(completetask, totaltask) < 100"
      striped-flow
          :percentage="percentFormat(completetask, totaltask)"
        >
          <template #default="{ percentage }">
            <span class="percentage-value">{{ percentage }}%</span>
            <!-- <span class="percentage-label">{{ finish + '/' + total }}</span> -->
          </template>
        </el-progress>
        <el-text size="small">{{ completetask + '/' + totaltask }}</el-text>
      </div>
    </el-col>
    <el-col span="12" class="flex-bottom">
  <!-- </el-col> -->
  <!-- <el-col span="12" class="flex-bottom"> -->
      <!-- <div>{{ name }}</div> -->
      <!-- <div>{{ planTime }}</div> -->
      <!-- <div>{{ userName }}</div> -->
      <el-row style="gap: 40px" justify="space-between">
        <div class="v-center" v-for="item in count" :key="item.sceneType">
          <el-text size="small">{{ item.sceneType }}</el-text>
  <el-row class="m-t-8">
    <div
      align="center"
      :style="'width: ' + 300 / count.length + 'px'"
      v-for="item in count"
      :key="item.sceneType"
    >
          <el-progress
            :width="50"
            :stroke-width="3"
            type="circle"
            status="warning"
        :stroke-width="18"
        status="exception"
        :text-inside="true"
        :striped="percentFormat(item.finish, item.total) < 100"
        striped-flow
            :percentage="percentFormat(item.finish, item.total)"
          >
            <template #default="{ percentage }">
              <span class="percentage-value-small">{{ percentage }}%</span>
            </template>
          </el-progress>
          <el-text size="small">{{ item.finish + '/' + item.total }}</el-text>
      <el-text size="small" truncated>{{ item.sceneType }}</el-text>
      <!-- <el-text size="small">{{ item.finish + '/' + item.total }}</el-text> -->
      <!-- <span class="percentage-value-small">{{ percentFormat(item.finish, item.total) }}%</span> -->
          <!-- <div class="percentage-label-small">{{ item.sceneType }}</div> -->
          <!-- <span class="percentage-label-small">{{ item.finish + '/' + item.total }} </span> -->
        </div>
      </el-row>
    </el-col>
  </el-row>
  <!-- </div> -->
</template>
<script>
@@ -93,8 +97,12 @@
      if (total == 0) {
        return 0
      } else {
        return Math.round((finish / total) * 100)
        const per = finish / total > 1 ? 1 : finish / total
        return Math.round(per * 100)
      }
    },
    format(percentage) {
      percentage === 100 ? 'Full' : `${percentage}%`
    }
  }
}
@@ -114,8 +122,7 @@
.percentage-value {
  display: block;
  margin-top: 10px;
  font-size: var(--el-font-size-base);
  font-size: var(--el-font-size-small);
}
.percentage-value-small {
  display: block;
src/stores/subtask.js
@@ -11,6 +11,8 @@
// 巡查任务
export const useSubtaskStore = defineStore('subtask', () => {
  const allTask = ref(null)
  const onFetchAllTask = []
  // 总任务信息
  const taskInfo = ref(null)
  // 当期所有巡查统计信息
@@ -24,18 +26,35 @@
  function fetchTopTaskProgress(area) {
    subtaskLoading.value = true
    taskApi.fetchTopTaskProgress(area).then((res) => {
    taskApi
      .fetchTopTaskProgress(area)
      .then((res) => {
      if (res.data.length == 0) return
        allTask.value = res.data
        if (onFetchAllTask.length > 0) {
          onFetchAllTask.forEach((e) => {
            e(allTask.value)
          })
        }
      const data = res.data[0]
      // 存储为全局数据
      setSummary(data)
      subtaskLoading.value = false
      // 绘制地图标记
      marks.createLabelMarks(scene_1, unref(data.subTaskSummary), (v) => {
        mapStore.focusMarker = v
      })
      mapUtil.setFitView()
    })
      .finally(() => (subtaskLoading.value = false))
  }
  function onAllTaskRefreshed(callback) {
    if (allTask.value != null) {
      callback(taskInfo.value)
    }
    onFetchAllTask.push(callback)
  }
  // 设置新的值
@@ -105,6 +124,7 @@
    // summaryMap,
    subtaskLoading,
    fetchTopTaskProgress,
    onAllTaskRefreshed,
    setSummary,
    getTaskInfo,
    getSummaryList,
src/utils/map/index.js
@@ -62,7 +62,8 @@
    alwaysRender: false,
    showLabel: true,
    showBuildingBlock: true,
    mapStyle: 'amap://styles/e1e78509de64ddcd2efb4cb34c6fae2a',
    // mapStyle: 'amap://styles/e1e78509de64ddcd2efb4cb34c6fae2a',
    mapStyle: 'amap://styles/macaron',
    features: ['bg', 'road'],
    pitch: 0, // 地图俯仰角度,有效范围 0 度- 83 度
    viewMode: '3D', // 地图模式
src/utils/map/marks.js
@@ -108,16 +108,16 @@
          retina: true
        },
        text: {
          content: data.sceneName,
          // content: data.sceneName,
          direction: 'top',
          offset: [0, -5],
          style: {
            fontSize: 12,
            fontWeight: 'normal',
            // fontWeight: 'normal',
            fillColor: '#fff',
            strokeColor: '#333',
            strokeWidth: 0,
            backgroundColor: '#122b54a9'
            // strokeColor: '#333',
            // strokeWidth: 0,
            backgroundColor: '#14428b'
          }
        }
      }
src/views/LoginView.vue
@@ -0,0 +1,2 @@
<template></template>
<script></script>
src/views/inspection/InspectionView.vue
@@ -1,11 +1,11 @@
<template>
  <div class="wrapper">
    <el-row>
      <el-col :span="12">
      <el-col span="12">
        <!-- <TaskSummary></TaskSummary> -->
        <TaskStats></TaskStats>
      </el-col>
      <el-col :span="12">
      <el-col span="12">
        <WorkStream></WorkStream>
      </el-col>
    </el-row>
src/views/inspection/WorkStream.vue
@@ -1,20 +1,14 @@
<template>
  <!-- <div class="border-r-small m-h-2 p-h-4"> -->
  <BaseCard>
    <!-- <div>
      <input type="text" v-model="inputVal" />
      <button @click="handleSend">send</button>
      <button @click="handleLink">link</button>
    </div> -->
    <div>业务状态中控</div>
    <el-scrollbar ref="scrollbarRef" :height="height">
  <BaseCard title="业务状态中控">
    <el-scrollbar ref="scrollbarRef" class="scrollbar">
      <div ref="scrollContentRef">
        <el-row justify="center" class="m-t-16">
          <el-text v-if="streams.length == 0">暂无新消息</el-text>
        </el-row>
        <div v-for="item in streams" :key="item.index">
          <el-text type="primary">[{{ item.time }}]: </el-text>
          <el-text type="warning">[{{ item.time }}]: </el-text>
          <el-text>用户</el-text>
          <el-text type="warning">{{ item.userName }}</el-text>
          <!-- <el-text>在</el-text>
          <el-text type="success">{{ item.obj }}</el-text> -->
          <el-text>{{ item.event }}</el-text>
        </div>
      </div>
@@ -66,13 +60,12 @@
  }, 100)
}
const inputVal = ref('')
const handleSend = () => {
  if (socket) {
    socket.send(inputVal.value)
  }
}
// const inputVal = ref('')
// const handleSend = () => {
//   if (socket) {
//     socket.send(inputVal.value)
//   }
// }
let socket
const handleLink = () => {
@@ -112,18 +105,56 @@
}
onMounted(() => {
  // handleLink()
  setInterval(() => {
    streams.push({
      time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
      userName: users[parseInt(Math.random() * users.length)],
      obj: objs[parseInt(Math.random() * objs.length)],
      event: events[parseInt(Math.random() * events.length)]
    })
    scrollToBottom()
  }, 5000)
  handleLink()
  if (import.meta.env.DEV) {
    // setInterval(() => {
    // streams.push({
    //   time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    //   userName: users[parseInt(Math.random() * users.length)],
    //   obj: objs[parseInt(Math.random() * objs.length)],
    //   event: events[parseInt(Math.random() * events.length)]
    // })
    // streams.push({
    //   time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    //   userName: users[parseInt(Math.random() * users.length)],
    //   obj: objs[parseInt(Math.random() * objs.length)],
    //   event: events[parseInt(Math.random() * events.length)]
    // })
    // streams.push({
    //   time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    //   userName: users[parseInt(Math.random() * users.length)],
    //   obj: objs[parseInt(Math.random() * objs.length)],
    //   event: events[parseInt(Math.random() * events.length)]
    // })
    // streams.push({
    //   time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    //   userName: users[parseInt(Math.random() * users.length)],
    //   obj: objs[parseInt(Math.random() * objs.length)],
    //   event: events[parseInt(Math.random() * events.length)]
    // })
    // streams.push({
    //   time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    //   userName: users[parseInt(Math.random() * users.length)],
    //   obj: objs[parseInt(Math.random() * objs.length)],
    //   event: events[parseInt(Math.random() * events.length)]
    // })
    // streams.push({
    //   time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
    //   userName: users[parseInt(Math.random() * users.length)],
    //   obj: objs[parseInt(Math.random() * objs.length)],
    //   event: events[parseInt(Math.random() * events.length)]
    // })
    // scrollToBottom()
    // }, 60000)
  }
})
onUnmounted(() => {
  socket.close()
})
</script>
<style scoped>
.scrollbar {
  height: 80px;
  width: 600px;
}
</style>
src/views/inspection/problem/component/ProblemSummary.vue
@@ -133,7 +133,7 @@
  const option = pieChartOption('问题分布', chartData, 1)
  const series = option.series[0]
  // series.radius = '50%'
  series.center = ['10%', '50%']
  series.center = ['15%', '50%']
  series.label.formatter = '{b}\n{c}个({d}%)'
  echart.setOption(option)
  setTimeout(() => {
src/views/main/MonitorView.vue
@@ -1,7 +1,8 @@
<template>
  <el-row>
  <BaseMap></BaseMap>
  <el-row class="overlay-container" v-if="false">
    <el-col :span="7" class="page-right">
      <el-scrollbar height="var(--fy-body-height)">
      <el-scrollbar height="var(--fy-body-height)" class="p-events-auto">
        <ManagementView></ManagementView>
      </el-scrollbar>
    </el-col>
@@ -9,8 +10,8 @@
      <el-scrollbar class="page-left-top">
        <VisualizationView></VisualizationView>
      </el-scrollbar>
      <el-scrollbar class="page-left-bottom">
        <InspectionView></InspectionView>
      <el-scrollbar class="page-left-bottom p-events-auto">
        <!-- <InspectionView></InspectionView> -->
      </el-scrollbar>
    </el-col>
    <!-- <el-col :span="7" class="page-right">
@@ -19,23 +20,33 @@
      </el-scrollbar>
    </el-col> -->
  </el-row>
  <SupervisionVisual class="supervision-view"></SupervisionVisual>
  <TaskStats class="task-stats"></TaskStats>
  <WorkStream class="work-stream"></WorkStream>
</template>
<script setup>
import { provide, ref, unref } from 'vue'
import InspectionView from '@/views/inspection/InspectionView.vue'
import ManagementView from '@/views/management/ManagementView.vue'
import StatisticView from '@/views/management/StatisticView.vue'
import VisualizationView from '@/views/visualization/VisualizationView.vue'
import { useAreaStore } from '@/stores/area.js'
import { useSubtaskStore } from '@/stores/subtask.js'
import { useMapStore } from '@/stores/map.js'
import taskApi from '@/api/fysp/taskApi.js'
import marks from '@/utils/map/marks.js'
import mapUtil from '@/utils/map/util.js'
import scene_1 from '@/assets/icon/scene_1.png'
provide('mapHeight', 'calc(var(--fy-body-height) / 4 * 3)')
import InspectionView from '@/views/inspection/InspectionView.vue'
import ManagementView from '@/views/management/ManagementView.vue'
import StatisticView from '@/views/management/StatisticView.vue'
import VisualizationView from '@/views/visualization/VisualizationView.vue'
import SupervisionVisual from '@/views/visualization/SupervisionVisual.vue'
import WorkStream from '@/views/inspection/WorkStream.vue'
import TaskStats from '@/views/management/TaskStats.vue'
// provide('mapHeight', 'calc(var(--fy-body-height) / 4 * 3)')
provide('mapHeight', 'calc(var(--fy-body-height))')
provide('excludeMapHeight', 'calc(var(--fy-body-height) / 4 * 1)')
const windowHeight = ref(window.innerHeight)
@@ -85,4 +96,34 @@
.page-right {
  /* background-color: aliceblue; */
}
.overlay-container {
  /* background: aliceblue; */
  position: absolute;
  width: 100%;
  /* height: 100vh; */
  top: 0;
  left: 0;
  /* padding: 4px; */
  pointer-events: none;
}
.work-stream {
  position: absolute;
  bottom: 0;
  right: 0;
}
.task-stats {
  position: absolute;
  top: 0;
  left: 0;
}
.supervision-view {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}
</style>
src/views/management/ManagementView.vue
@@ -1,7 +1,7 @@
<template>
  <!-- <el-row> 统计管理 </el-row> -->
  <ProblemTrack ref="statusRef"></ProblemTrack>
  <EvaluateSummary :height="height"></EvaluateSummary>
  <!-- <EvaluateSummary :height="height"></EvaluateSummary> -->
</template>
<script>
src/views/management/TaskStats.vue
@@ -1,7 +1,9 @@
<template>
  <BaseCard>
    <div>任务监控</div>
    <el-scrollbar ref="scrollbarRef" :height="height">
  <BaseCard title="任务监控">
    <!-- <template #expand> -->
    <!-- <SupervisionVisual></SupervisionVisual> -->
    <!-- </template> -->
    <el-scrollbar ref="scrollbarRef">
      <!-- <el-row justify="space-evenly">
        <el-statistic title="今日完成" :value="10"> </el-statistic>
        <el-statistic title="本周完成" :value="10"> </el-statistic>
@@ -25,8 +27,11 @@
<script setup>
import { inject, ref, onMounted, computed } from 'vue'
import { unCalc } from '@/utils/css-util'
import SelfInspection from '@/views/inspection/SelfInspection.vue'
import JointEnforcement from '@/views/inspection/JointEnforcement.vue'
import SupervisionVisual from '@/views/visualization/SupervisionVisual.vue'
import { useSubtaskStore } from '@/stores/subtask.js'
/**
@@ -39,21 +44,31 @@
const tasks = ref([])
const sceneTaskMap = ref(new Map())
function onGetTaskInfo(tInfo) {
function onGetTaskInfo(tInfoList) {
  const resList = []
  sceneTaskMap.value.clear()
  const total = tInfo.totaltask
  tInfo.subTaskSummary.forEach((s) => {
    if (!sceneTaskMap.value.has(s.scene.type)) {
      sceneTaskMap.value.set(s.scene.type, {
        sceneType: s.scene.type,
        total: total,
        finish: 0
  tInfoList.forEach((tInfo) => {
    const _sceneTaskMap = new Map()
    for (const key in tInfo.totaltaskByScene) {
      const e = tInfo.totaltaskByScene[key]
      _sceneTaskMap.set(key, {
        sceneType: key,
        total: e,
        finish: tInfo.completetaskByScene[key] ? tInfo.completetaskByScene[key] : 0
      })
    }
    const st = sceneTaskMap.value.get(s.scene.type)
    st.finish++
  })
    // const total = tInfo.totaltask
    // tInfo.subTaskSummary.forEach((s) => {
    //   if (!_sceneTaskMap.has(s.scene.type)) {
    //     _sceneTaskMap.set(s.scene.type, {
    //       sceneType: s.scene.type,
    //       total: total,
    //       finish: 0
    //     })
    //   }
    //   const st = _sceneTaskMap.get(s.scene.type)
    //   st.finish++
    // })
  const task = {
    name: tInfo.name,
@@ -64,16 +79,18 @@
    count: []
  }
  for (const key of sceneTaskMap.value.keys()) {
    const value = sceneTaskMap.value.get(key)
    for (const key of _sceneTaskMap.keys()) {
      const value = _sceneTaskMap.get(key)
    task.count.push(value)
  }
  resList.push(task)
  })
  tasks.value = resList
}
function cal() {
  subtaskStore.getTaskInfo(onGetTaskInfo)
  subtaskStore.onAllTaskRefreshed(onGetTaskInfo)
}
onMounted(() => {
src/views/visualization/SubtaskVisual.vue
@@ -9,9 +9,9 @@
      <div class="font-small">状态:{{ subtask.status }}</div>
      <div class="font-small">计划:{{ $fm.formatYMD(subtask.planstarttime) }}</div>
      <div v-if="subtask.status != '未执行'" class="font-small">
        <span>执行:{{ $fm.formatH(subtask.executionstarttime) }}</span>
        <span>执行:{{ $fm.formatYMDH(subtask.executionstarttime) }}</span>
        <span> - </span>
        <span>{{ $fm.formatH(subtask.executionendtime) }}</span>
        <span>{{ $fm.formatYMDH(subtask.executionendtime) }}</span>
      </div>
      <div class="font-small">问题:</div>
      <problem-item
src/views/visualization/SupervisionVisual.vue
@@ -1,6 +1,6 @@
<template>
  <el-row>
    <div class="p-events-auto">
  <el-row justify="center" class="wrapper">
    <div class="p-events-auto sv-content">
      <OptionLocation
        :level="3"
        :width="170"
@@ -14,7 +14,9 @@
        v-model="sceneType"
      ></OptionSceneType>
      <OptionTime v-model="time"></OptionTime>
      <el-button size="small" @click="fetchTaskProgress">查询</el-button>
      <el-button :loading="subtaskStore.subtaskLoading" size="small" @click="fetchTaskProgress"
        >查询</el-button
      >
    </div>
  </el-row>
</template>
@@ -89,4 +91,15 @@
}
</script>
<style scoped></style>
<style scoped>
.wrapper {
  pointer-events: none;
}
.sv-content {
  background-color: #14428be8;
  border: 2px solid rgb(255, 255, 255);
  border-radius: 8px;
  padding: 4px;
}
</style>
src/views/visualization/VisualizationView.vue
@@ -1,7 +1,6 @@
<template>
  <!-- <el-row class="wrapper"> 可视化 </el-row> -->
  <BaseMap></BaseMap>
  <el-row class="overlay-container" :style="height">
  <el-row class="wrapper">
    <el-col :span="10">
      <SubtaskVisual></SubtaskVisual>
    </el-col>
@@ -34,4 +33,8 @@
  /* padding: 4px; */
  pointer-events: none;
}
.wrapper {
  background-color: aliceblue;
}
</style>