riku
2025-07-08 91513e171078ed6b0887f87b9fced33895d6d3fb
src/views/visualization/SubtaskVisual.vue
@@ -1,146 +1,196 @@
<template>
  <el-scrollbar v-if="mapStore.focusMarker" :height="mapHeight">
    <el-card class="p-events-auto wrapper">
      <div class="font-small">{{ scene.name }}</div>
  <el-scrollbar v-if="mapStore.focusMarker" class="wrapper">
    <el-card class="p-events-auto">
      <el-row justify="space-between">
        <!-- <div class="font-small">{{ scene.name }}</div> -->
        <el-text size="large">{{ scene.name }}</el-text>
        <el-button icon="Close" circle @click="mapStore.focusMarker = undefined"></el-button>
      </el-row>
      <el-row justify="space-between">
        <el-text size="small">{{ '地址:' + scene.location }}</el-text>
      </el-row>
      <el-space class="m-t-8">
        <el-tag type="info" effect="plain">
          {{ scene.districtname + scene.townname }}
        </el-tag>
        <el-tag type="info" effect="plain">
          {{ scene.type }}
        </el-tag>
      </el-space>
      <el-divider></el-divider>
      <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> - </span>
        <span>{{ $fm.formatH(subtask.executionendtime) }}</span>
      <el-row justify="space-between">
        <el-col :span="8" style="text-align: center">
          <el-text>状态:{{ subtask.status }}</el-text>
        </el-col>
        <el-col :span="8" style="text-align: center">
          <el-text>计划:{{ $fm.formatYMD(subtask.planstarttime) }}</el-text>
        </el-col>
        <el-col v-if="subtask.status != '未执行'" :span="8" style="text-align: center">
          <el-text>
            <span>执行:{{ $fm.formatH(subtask.executionstarttime) }}</span>
            <!-- <span> - </span>
          <span>{{ $fm.formatYMDH(subtask.executionendtime) }}</span> -->
          </el-text>
        </el-col>
      </el-row>
      <el-segmented v-model="value" :options="options" block />
      <div v-show="value == '现场问题'">
        <problem-item
          v-for="(item, i) in problemList"
          :key="item.guid"
          :index="i + 1"
          :problem="item"
        ></problem-item>
        <el-empty v-if="problemList.length == 0" description="无现场问题">
          <template #image> </template>
        </el-empty>
      </div>
      <div class="font-small">问题:</div>
      <problem-item
        v-for="(item, i) in problemList"
        :key="item.guid"
        :index="i + 1"
        :problem="item"
      ></problem-item>
      <!-- <div v-for="item in problemList" :key="item.guid">
        {{ item.problemname }}
      </div> -->
      <!-- <el-timeline style="max-width: 600px">
        <el-timeline-item
          v-for="(activity, index) in activities"
          :key="index"
          :timestamp="activity.timestamp"
          :hide-timestamp="activity.running"
          :type="activity.running ? 'danger' : 'success'"
          :size="activity.running ? 'large' : 'normal'"
          :hollow="false"
        >
          {{ activity.content }}
        </el-timeline-item>
      </el-timeline> -->
      <div v-show="value == '场景图片'">
        <FYImageSelectDialog
          readonly
          height="500px"
          :imageWidth="134"
          v-loading="scenePicLoading"
          :typeList="scenePicTypeList"
          :typeImgMap="scenePicTypeMap"
        ></FYImageSelectDialog>
      </div>
      <div v-show="value == '设备设施'">
        <SceneDevice :scene="scene" height="500px"></SceneDevice>
      </div>
    </el-card>
  </el-scrollbar>
</template>
<script>
import { inject } from 'vue'
<script setup>
import { inject, ref, computed, watch } from 'vue'
import { useMapStore } from '@/stores/map.js'
import { mapStores } from 'pinia'
import { $fysp } from '@/api/index.js'
import problemApi from '@/api/fysp/problemApi.js'
import mediafileApi from '@/api/fysp/mediafileApi.js'
import deviceApi from '@/api/fysp/deviceApi'
/**
 * 具体巡查任务可视化
 * 包括地图定位信息展示、巡查任务全流程平铺展示
 */
export default {
  setup() {
    const mapHeight = inject('mapHeight')
const mapHeight = inject('mapHeight')
const height = 'height:' + mapHeight
    const height = 'height:' + mapHeight
    return { height, mapHeight }
  },
  props: {
    // subtask: {
    //   type: Object,
    //   default: () => {
    //     return {
    //       guid: 'SMuheEkjswioSn7A',
    //       name: '中科生态数字港项目巡查中科生态数字港项目巡查',
    //       district: '金山区',
    //       planTime: '2024-06-04',
    //       startTime: '2024-06-04 13:31:26',
    //       endTime: '2024-06-04 13:33:37',
    //       userName: '朱正强',
    //       status: '已结束',
    //       total: 4,
    //       checked: 2
    //     }
    //   }
    // }
  },
  data() {
    return {
      // activities: [
      //   {
      //     content: '任务创建',
      //     timestamp: '2024-06-04 08:00',
      //     running: false
      //   },
      //   {
      //     content: '开始巡查',
      //     timestamp: '2024-06-04 09:00',
      //     running: false
      //   },
      //   {
      //     content: '结束巡查',
      //     timestamp: '2024-06-04 09:15',
      //     running: false
      //   },
      //   {
      //     content: '完成问题审核',
      //     timestamp: '2024-06-04 10:15',
      //     running: false
      //   },
      //   {
      //     content: '问题整改中...',
      //     timestamp: '2024-06-04 10:15',
      //     running: true
      //   }
      // ]
      problemList: []
    }
  },
  computed: {
    ...mapStores(useMapStore),
    subtask() {
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.subtask : {}
    },
    scene() {
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.scene : {}
    },
    inspection() {
      return this.mapStore.focusMarker ? this.mapStore.focusMarker.inspection : {}
    }
  },
  watch: {
    subtask(nV, oV) {
      if (nV != oV) {
        this.fetchProblem(nV.stguid)
const mapStore = useMapStore()
const subtask = computed(() => (mapStore.focusMarker ? mapStore.focusMarker.subtask : undefined))
const scene = computed(() => (mapStore.focusMarker ? mapStore.focusMarker.scene : undefined))
const inspection = computed(() =>
  mapStore.focusMarker ? mapStore.focusMarker.inspection : undefined
)
const value = ref('现场问题')
const options = ['现场问题', '场景图片', '设备设施']
const problemList = ref([])
const problemListLoading = ref(false)
const scenePicTypeList = ref([])
const scenePicTypeMap = ref(new Map())
const scenePicLoading = ref(false)
watch(subtask, (nV, oV) => {
  if (nV != undefined && nV != oV) {
    fetchProblem(nV.stguid)
    getRoutineByStGuid(nV.stguid)
  }
})
function fetchProblem(stguid) {
  problemListLoading.value = true
  problemApi
    .fetchProblems(stguid)
    .then((res) => {
      problemList.value = res
    })
    .finally(() => (problemListLoading.value = false))
}
// 图片分类
function getRoutineByStGuid(stguid) {
  scenePicLoading.value = true
  mediafileApi
    .getRoutineByStGuid(stguid)
    .then((res) => {
      let typeList = []
      let typeMap = new Map()
      const data = res.data
      for (const e of data) {
        let img = {
          url: $fysp.imgUrl + e.extension1 + e.guid + '.jpg',
          data: e
        }
        const businesstype = e.businesstype
        const businesstypeid = e.businesstypeid
        if (typeList.find((item) => item.typeId == businesstypeid) != undefined) {
          typeMap.get(businesstypeid).push(img)
        } else {
          typeList.push({
            typeId: businesstypeid,
            typeName: businesstype
          })
          typeMap.set(businesstypeid, [img])
        }
      }
      scenePicTypeList.value = typeList
      scenePicTypeMap.value = typeMap
    })
    .finally(() => (scenePicLoading.value = false))
}
function fetchDevices() {
  deviceApi.fetchDevices(scene.value.guid, this.currSelect.topDeviceTypeId).then((result) => {
    this.initList()
    if (result.data == null || result.data.length <= 0) {
      this.isEmpty = true
      return
    }
  },
  methods: {
    fetchProblem(stguid) {
      problemApi.fetchProblems(stguid).then((res) => {
        this.problemList = res
    // 标准化属性名
    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 = 0; index < statusData.length; index++) {
            const statusItem = statusData[index]
            // 设备对象添加一个属性列表属性用来保存设备状态
            this.saveStatus(element, statusItem)
            element.dlLocation = statusItem.dlLocation
            this.formInfo.push(element)
          }
        }
      })
    }
  }
  })
}
</script>
<style scoped>
.wrapper {
  /* position: absolute; */
  top: 0;
  right: 0;
  /* background-color: wheat; */
  width: 450px;
  max-height: 800px;
}
.el-card {