riku
2024-09-11 89ab2ec7f8790c5cc184de98682af032c69c2afc
2024.9.11
已修改18个文件
371 ■■■■■ 文件已修改
src/api/fysp/taskApi.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/TaskItem.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/search/OptionSceneType.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/area.js 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/subtask.js 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/map/marks.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/InspectionView.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/WorkStream.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/problem/component/ProblemChangeChart.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/problem/component/ProblemTable.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/MonitorView.vue 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/ManagementView.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/TaskStats.vue 102 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/TaskSummary.vue 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/SubtaskVisual.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/SupervisionVisual.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/VisualizationView.vue 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fysp/taskApi.js
@@ -8,6 +8,10 @@
    return $fysp.get('task/alltask/0').then((res) => res.data)
  },
  fetchTopTaskProgress(area) {
    return $fysp.post('task/progress', area).then((res) => res.data)
  },
  /**
   * 查询总任务
   * @param {Object} area
src/components.d.ts
@@ -12,6 +12,7 @@
    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']
@@ -31,6 +32,7 @@
    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']
src/components/inspection/TaskItem.vue
@@ -1,5 +1,8 @@
<template>
  <!-- <div class="demo-progress border-r-small"> -->
  <el-row justify="end">
    <el-text type="info">{{ name }}</el-text>
  </el-row>
  <el-row justify="space-evenly">
    <el-col span="12">
      <div class="v-center">
@@ -8,14 +11,14 @@
          :width="100"
          type="circle"
          status="warning"
          :percentage="(finish / total) * 100"
          :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">{{ finish + '/' + total }}</el-text>
        <el-text size="small">{{ completetask + '/' + totaltask }}</el-text>
      </div>
    </el-col>
    <el-col span="12" class="flex-bottom">
@@ -30,7 +33,7 @@
            :stroke-width="3"
            type="circle"
            status="warning"
            :percentage="(item.finish / item.total) * 100"
            :percentage="percentFormat(item.finish, item.total)"
          >
            <template #default="{ percentage }">
              <span class="percentage-value-small">{{ percentage }}%</span>
@@ -53,12 +56,15 @@
export default {
  props: {
    name: String,
    province: String,
    district: String,
    planTime: String,
    startTime: String,
    endTime: String,
    userName: String,
    status: String,
    totaltask: Number,
    completetask: Number,
    count: Array
  },
@@ -67,22 +73,30 @@
  },
  watch: {},
  computed: {
    total() {
      let t = 0
      this.count.forEach((c) => {
        t += c.total
      })
      return t
    // total() {
    //   let t = 0
    //   this.count.forEach((c) => {
    //     t += c.total
    //   })
    //   return t
    // },
    // finish() {
    //   let t = 0
    //   this.count.forEach((c) => {
    //     t += c.finish
    //   })
    //   return t
    // }
    },
    finish() {
      let t = 0
      this.count.forEach((c) => {
        t += c.finish
      })
      return t
  methods: {
    percentFormat(finish, total) {
      if (total == 0) {
        return 0
      } else {
        return Math.round((finish / total) * 100)
    }
  },
  methods: {}
    }
  }
}
</script>
src/components/search/OptionSceneType.vue
@@ -59,7 +59,7 @@
    sceneTypes() {
      if (this.sourceInit) {
        // 当因为type或者allOption参数变化引起选项变更时,清空当前选项
        this.handleChange()
        // this.handleChange()
      }
      return enumScene(this.type, this.allOption)
    }
src/stores/area.js
@@ -6,6 +6,9 @@
export const useAreaStore = defineStore('area', {
  state: () => {
    return {
      locations: {},
      sceneType: {},
      time: '',
      area: {
        provincecode: undefined,
        provincename: undefined,
@@ -28,9 +31,19 @@
      this.area.cityname = location.cName
      this.area.districtcode = location.dCode
      this.area.districtname = location.dName
      this.locations = {
        pCode: location.pCode,
        pName: location.pName,
        cCode: location.cCode,
        cName: location.cName,
        dCode: location.dCode,
        dName: location.dName
      }
    },
    setTimePeriod(time, type) {
      const d = time ? dayjs(time) : dayjs()
      this.time = time ? time : new Date()
      const d = dayjs(this.time)
      this.area.starttime = d.startOf(type).format('YYYY-MM-DD HH:mm:ss')
      this.area.endtime = d.endOf(type).format('YYYY-MM-DD HH:mm:ss')
    },
@@ -44,7 +57,8 @@
    },
    // 设置场景类型
    setSceneType(t) {
      this.area.scensetypeid = t
      this.sceneType = t
      this.area.scensetypeid = t.value
    }
  }
})
src/stores/subtask.js
@@ -1,21 +1,49 @@
import { ref } from 'vue'
import { ref, unref } from 'vue'
import { defineStore } from 'pinia'
import timeUtil from '@/utils/time-util'
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'
const mapStore = useMapStore()
// 巡查任务
export const useSubtaskStore = defineStore('subtask', () => {
  // 总任务信息
  const taskInfo = ref(null)
  // 当期所有巡查统计信息
  const summaryList = ref([])
  // 每日的巡查统计信息
  const summaryMap = ref(new Map())
  const subtaskLoading = ref(false)
  const onFetchInfo = []
  const onFetchList = []
  const onFetchMap = []
  function fetchTopTaskProgress(area) {
    subtaskLoading.value = true
    taskApi.fetchTopTaskProgress(area).then((res) => {
      if (res.data.length == 0) return
      const data = res.data[0]
      // 存储为全局数据
      setSummary(data)
      subtaskLoading.value = false
      // 绘制地图标记
      marks.createLabelMarks(scene_1, unref(data.subTaskSummary), (v) => {
        mapStore.focusMarker = v
      })
      mapUtil.setFitView()
    })
  }
  // 设置新的值
  function setSummary(data) {
    summaryList.value = data
    taskInfo.value = data
    summaryList.value = data.subTaskSummary
    summaryMap.value.clear()
    data.forEach((e) => {
    data.subTaskSummary.forEach((e) => {
      const tag = timeUtil.formatYMD(e.subtask.planstarttime)
      if (!summaryMap.value.has(tag)) {
        summaryMap.value.set(tag, [])
@@ -35,6 +63,19 @@
      onFetchMap.forEach((e) => {
        e(summaryMap.value)
      })
    }
    if (onFetchInfo.length > 0) {
      onFetchInfo.forEach((e) => {
        e(taskInfo.value)
      })
    }
  }
  function getTaskInfo(callback) {
    if (taskInfo.value == null) {
      onFetchInfo.push(callback)
    } else {
      callback(taskInfo.value)
    }
  }
@@ -58,5 +99,15 @@
    }
  }
  return { summaryList, summaryMap, subtaskLoading, setSummary, getSummaryList, getSummaryMap }
  return {
    // taskInfo,
    // summaryList,
    // summaryMap,
    subtaskLoading,
    fetchTopTaskProgress,
    setSummary,
    getTaskInfo,
    getSummaryList,
    getSummaryMap
  }
})
src/utils/map/marks.js
@@ -6,6 +6,7 @@
import util from './util'
var _massMarks = undefined
var _labelMarks = undefined
export default {
  /**
@@ -72,6 +73,10 @@
  },
  createLabelMarks(img, dataList, onClick) {
    if (_labelMarks) {
      map.remove(_labelMarks)
      _labelMarks = undefined
    }
    const layer = new AMap.LabelsLayer({
      zooms: [3, 20],
      zIndex: 1000,
@@ -138,6 +143,7 @@
      layer.add(labelMarker)
    }
    _labelMarks = layer
    return layer
  },
src/views/inspection/InspectionView.vue
@@ -1,7 +1,14 @@
<template>
  <div class="wrapper">
    <div>业务状态中控</div>
    <el-row>
      <el-col :span="12">
        <!-- <TaskSummary></TaskSummary> -->
        <TaskStats></TaskStats>
      </el-col>
      <el-col :span="12">
    <WorkStream></WorkStream>
      </el-col>
    </el-row>
  </div>
</template>
@@ -9,8 +16,10 @@
/**
 * 现场巡查实时跟踪
 */
import TaskSummary from '@/views/management/TaskSummary.vue'
import TaskTrack from '@/views/inspection/TaskTrack.vue'
import WorkStream from '@/views/inspection/WorkStream.vue'
import TaskStats from '@/views/management/TaskStats.vue'
</script>
<style scoped>
src/views/inspection/WorkStream.vue
@@ -1,11 +1,12 @@
<template>
  <!-- <div class="border-r-small m-h-2 p-h-4"> -->
  <BaseCard>
    <div>
    <!-- <div>
      <input type="text" v-model="inputVal" />
      <button @click="handleSend">send</button>
      <button @click="handleLink">link</button>
    </div>
    </div> -->
    <div>业务状态中控</div>
    <el-scrollbar ref="scrollbarRef" :height="height">
      <div ref="scrollContentRef">
        <div v-for="item in streams" :key="item.index">
@@ -109,6 +110,7 @@
}
onMounted(() => {
  handleLink()
  // setInterval(() => {
  //   streams.push({
  //     time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
src/views/inspection/problem/component/ProblemChangeChart.vue
@@ -1,6 +1,6 @@
<template>
  <el-row justify="space-between">
    <el-col :span="18">
    <el-col :span="24">
      <el-text size="small">
        场景数:{{ sceneNum }},问题总数:{{ proNum }},单场景问题均值:{{ proEachSceneNum }},
      </el-text>
@@ -10,11 +10,11 @@
        }},有效整改率:{{ changePassPer }}
      </el-text>
    </el-col>
    <el-col :span="6">
    <!-- <el-col :span="6">
      <el-row justify="end">
        <!-- <OptionTime v-model="time"></OptionTime> -->
        <OptionTime v-model="time"></OptionTime>
      </el-row>
    </el-col>
    </el-col> -->
  </el-row>
  <div ref="echart" class="line-chart"></div>
</template>
src/views/inspection/problem/component/ProblemTable.vue
@@ -105,9 +105,11 @@
  const title = row.scene.name
  const lnglat = [row.scene.longitude, row.scene.latitude]
  const img = scene_1
  mapUtil.clearViews()
  marks.drawMarker(title, lnglat, img)
  mapUtil.setFitView()
  // mapUtil.clearViews()
  // marks.drawMarker(title, lnglat, img)
  // mapUtil.setFitView()
  mapUtil.setCenter(lnglat)
  mapUtil.setZoomSmall()
  mapStore.focusMarker = row
}
src/views/main/MonitorView.vue
@@ -53,20 +53,23 @@
  dCode: '310106',
  dName: '静安区'
})
areaStore.setSceneType('1')
areaStore.setSceneType({ label: '工地', value: '1' })
// 获取本月的所有巡查统计信息
subtaskStore.subtaskLoading = true
taskApi.fetchSubtaskSummaryByArea(areaStore.area).then((res) => {
  // 存储为全局数据
  subtaskStore.setSummary(res.data)
  subtaskStore.subtaskLoading = false
  // 绘制地图标记
  marks.createLabelMarks(scene_1, unref(res.data), (v) => {
    mapStore.focusMarker = v
  })
  mapUtil.setFitView()
})
subtaskStore.fetchTopTaskProgress(areaStore.area)
// subtaskStore.subtaskLoading = true
// taskApi.fetchTopTaskProgress(areaStore.area).then((res) => {
//   if (res.data.length == 0) return
//   const data = res.data[0]
//   // 存储为全局数据
//   subtaskStore.setSummary(data)
//   subtaskStore.subtaskLoading = false
//   // 绘制地图标记
//   marks.createLabelMarks(scene_1, unref(data.subTaskSummary), (v) => {
//     mapStore.focusMarker = v
//   })
//   mapUtil.setFitView()
// })
</script>
<style scoped>
src/views/management/ManagementView.vue
@@ -1,22 +1,16 @@
<template>
  <!-- <el-row> 统计管理 </el-row> -->
  <ProblemTrack ref="statusRef"></ProblemTrack>
  <!-- <TaskStats ref="statusRef"></TaskStats> -->
  <EvaluateSummary :height="height"></EvaluateSummary>
  <!-- <TaskSummary ref="summaryRef"></TaskSummary> -->
  <!-- <ReInspectionView ref="summaryRef"></ReInspectionView> -->
</template>
<script>
import TaskStats from '@/views/management/TaskStats.vue'
import TaskSummary from '@/views/management/TaskSummary.vue'
import EvaluateSummary from '@/views/management/evaluate/EvaluateSummary.vue'
import ReInspectionView from '@/views/inspection/ReInspectionView.vue'
import ProblemTrack from '@/views/inspection/problem/ProblemTrack.vue'
import { vResize } from '@/utils/resize-observer'
export default {
  components: { TaskStats, TaskSummary, EvaluateSummary, ReInspectionView, ProblemTrack },
  components: { EvaluateSummary, ProblemTrack },
  data() {
    return {
      // height: '500px',
src/views/management/TaskStats.vue
@@ -1,10 +1,11 @@
<template>
  <div class="border-r-small">
    <div class="font-large">任务监控</div>
    <el-row justify="space-evenly">
  <BaseCard>
    <div>任务监控</div>
    <el-scrollbar ref="scrollbarRef" :height="height">
      <!-- <el-row justify="space-evenly">
      <el-statistic title="今日完成" :value="10"> </el-statistic>
      <el-statistic title="本周完成" :value="10"> </el-statistic>
    </el-row>
      </el-row> -->
    <!-- <el-row> -->
    <TaskItem v-for="item in tasks" :key="item.guid" v-bind="item"></TaskItem>
    <!-- </el-row> -->
@@ -17,62 +18,67 @@
        <JointEnforcement></JointEnforcement>
      </el-col>
    </el-row> -->
  </div>
    </el-scrollbar>
  </BaseCard>
</template>
<script>
<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 { useSubtaskStore } from '@/stores/subtask.js'
/**
 * 任务完成情况
 */
export default {
  components: { SelfInspection, JointEnforcement },
  props: {
    height: String
  },
  data() {
    return {
      tasks: []
    }
  },
  watch: {},
  methods: {},
  mounted() {
    let i = 0
    while (i < 1) {
      this.tasks.push({
        guid: 'SMuheEkjswioSn7A',
        name: '2024年6月上海市静安区巡查任务',
        district: '静安区',
        planTime: '2024-06',
        startTime: '2024-06-01 00:00:00',
        endTime: '2024-06-30 23:59:59',
        userName: '朱正强#邢子琦',
        status: '正在执行',
        count: [
          {
            sceneType: '工地',
            total: 90,
            finish: 45
          },
          {
            sceneType: '餐饮',
            total: 90,
            finish: 45
          },
          {
            sceneType: '汽修',
            total: 90,
            finish: 45
          }
        ]
const excludeMapHeight = inject('excludeMapHeight')
const height = ref(`calc(${unCalc(excludeMapHeight)} - 36px)`)
const subtaskStore = useSubtaskStore()
const tasks = ref([])
const sceneTaskMap = ref(new Map())
function onGetTaskInfo(tInfo) {
  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
      })
      i++
    }
    const st = sceneTaskMap.value.get(s.scene.type)
    st.finish++
  })
  const task = {
    name: tInfo.name,
    province: tInfo.provinceName,
    district: tInfo.districtName,
    totaltask: tInfo.totaltask,
    completetask: tInfo.completetask,
    count: []
  }
  for (const key of sceneTaskMap.value.keys()) {
    const value = sceneTaskMap.value.get(key)
    task.count.push(value)
}
  resList.push(task)
  tasks.value = resList
}
function cal() {
  subtaskStore.getTaskInfo(onGetTaskInfo)
}
onMounted(() => {
  cal()
})
</script>
<style scoped>
src/views/management/TaskSummary.vue
@@ -1,5 +1,5 @@
<template>
  <div class="border-r-small">
  <BaseCard>
    <el-row> 巡查汇总 </el-row>
    <el-segmented v-model="value" :options="options" />
    <div><el-text tag="i"> 评估 </el-text></div>
@@ -62,26 +62,7 @@
      <el-statistic title="已整改" :value="2" :value-style="styleGreen"> </el-statistic>
      <el-statistic title="待确认" :value="2" :value-style="styleGreen"> </el-statistic>
    </el-row>
    <!-- <el-row>
      <el-col :span="8">
        <TaskSummaryItem title="今日汇总"></TaskSummaryItem>
      </el-col>
      <el-col :span="8">
        <TaskSummaryItem title="周度汇总"></TaskSummaryItem>
      </el-col>
      <el-col :span="8">
        <TaskSummaryItem title="月度汇总"></TaskSummaryItem>
      </el-col>
    </el-row>
    <el-row>
      <el-col :span="12">
        <TaskSummaryItem title="季度汇总"></TaskSummaryItem>
      </el-col>
      <el-col :span="12">
        <TaskSummaryItem title="年度汇总"></TaskSummaryItem>
      </el-col>
    </el-row> -->
  </div>
  </BaseCard>
</template>
<script>
src/views/visualization/SubtaskVisual.vue
@@ -1,7 +1,10 @@
<template>
  <el-scrollbar v-if="mapStore.focusMarker" :height="mapHeight">
    <el-card class="p-events-auto wrapper">
      <el-row justify="space-between">
      <div class="font-small">{{ scene.name }}</div>
        <el-button icon="Close" circle @click="mapStore.focusMarker = undefined"></el-button>
      </el-row>
      <el-divider></el-divider>
      <div class="font-small">状态:{{ subtask.status }}</div>
      <div class="font-small">计划:{{ $fm.formatYMD(subtask.planstarttime) }}</div>
@@ -109,18 +112,18 @@
  computed: {
    ...mapStores(useMapStore),
    subtask() {
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.subtask : {}
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.subtask : undefined
    },
    scene() {
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.scene : {}
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.scene : undefined
    },
    inspection() {
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.inspection : {}
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.inspection : undefined
    }
  },
  watch: {
    subtask(nV, oV) {
      if (nV != oV) {
      if (nV != undefined && nV != oV) {
        this.fetchProblem(nV.stguid)
      }
    }
src/views/visualization/SupervisionVisual.vue
@@ -14,6 +14,7 @@
        v-model="sceneType"
      ></OptionSceneType>
      <OptionTime v-model="time"></OptionTime>
      <el-button size="small" @click="fetchTaskProgress">查询</el-button>
    </div>
  </el-row>
</template>
@@ -21,6 +22,7 @@
<script>
import { inject, unref } from 'vue'
import { useAreaStore } from '@/stores/area.js'
import { useSubtaskStore } from '@/stores/subtask.js'
import { mapStores } from 'pinia'
import taskApi from '@/api/fysp/taskApi.js'
@@ -56,7 +58,8 @@
    }
  },
  computed: {
    ...mapStores(useAreaStore)
    ...mapStores(useAreaStore),
    ...mapStores(useSubtaskStore)
    // area() {
    //   return {
    //     provincecode: this.locations.pCode,
@@ -74,19 +77,10 @@
    // 查询
    fetchTaskProgress() {
      this.areaStore.setLocation(this.locations)
      this.areaStore.setTimeOneDay(this.time)
      this.areaStore.setSceneType(this.sceneType.value)
      this.areaStore.setTimeOneMonth(this.time)
      this.areaStore.setSceneType(this.sceneType)
      return taskApi.fetchTaskProgress(this.areaStore.area).then((res) => {
        let list = []
        res.data.forEach((e) => {
          list = list.concat(e.subTaskSummary)
        })
        this.newLabelMasks(list)
      })
    },
    newLabelMasks(data) {
      marks.createLabelMarks(scene_1, unref(data))
      this.subtaskStore.fetchTopTaskProgress(this.areaStore.area)
    }
  },
  mounted() {
src/views/visualization/VisualizationView.vue
@@ -2,12 +2,14 @@
  <!-- <el-row class="wrapper"> 可视化 </el-row> -->
  <BaseMap></BaseMap>
  <el-row class="overlay-container" :style="height">
    <el-col :span="14">
      <SupervisionVisual></SupervisionVisual>
    </el-col>
    <el-col :span="10">
      <SubtaskVisual></SubtaskVisual>
    </el-col>
    <el-col :span="14">
      <el-row justify="end">
        <SupervisionVisual></SupervisionVisual>
      </el-row>
    </el-col>
  </el-row>
</template>