Riku
2024-07-08 04e9d32ac49bf5a38adf3cd7dab6bff6e346eefd
问题整改跟踪和工作流模块
已修改6个文件
已添加3个文件
319 ■■■■■ 文件已修改
package-lock.json 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/InspectionView.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/WorkStream.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/problem/ProblemTrack.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/problem/component/ProblemChangeChart.vue 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/problem/component/ProblemType.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -13,6 +13,7 @@
        "@vueuse/core": "^10.10.0",
        "axios": "^1.7.2",
        "dayjs": "^1.11.11",
        "echarts": "^5.5.1",
        "element-plus": "^2.7.4",
        "pinia": "^2.1.7",
        "unplugin-vue-components": "^0.27.0",
@@ -1746,6 +1747,20 @@
      "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
      "dev": true
    },
    "node_modules/echarts": {
      "version": "5.5.1",
      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.5.1.tgz",
      "integrity": "sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==",
      "dependencies": {
        "tslib": "2.3.0",
        "zrender": "5.6.0"
      }
    },
    "node_modules/echarts/node_modules/tslib": {
      "version": "2.3.0",
      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
    },
    "node_modules/editorconfig": {
      "version": "1.0.4",
@@ -4677,6 +4692,19 @@
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/zrender": {
      "version": "5.6.0",
      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.0.tgz",
      "integrity": "sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==",
      "dependencies": {
        "tslib": "2.3.0"
      }
    },
    "node_modules/zrender/node_modules/tslib": {
      "version": "2.3.0",
      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
    }
  },
  "dependencies": {
@@ -5820,6 +5848,22 @@
      "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
      "dev": true
    },
    "echarts": {
      "version": "5.5.1",
      "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.5.1.tgz",
      "integrity": "sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==",
      "requires": {
        "tslib": "2.3.0",
        "zrender": "5.6.0"
      },
      "dependencies": {
        "tslib": {
          "version": "2.3.0",
          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
          "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
        }
      }
    },
    "editorconfig": {
      "version": "1.0.4",
@@ -7810,6 +7854,21 @@
      "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
      "dev": true
    },
    "zrender": {
      "version": "5.6.0",
      "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.0.tgz",
      "integrity": "sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==",
      "requires": {
        "tslib": "2.3.0"
      },
      "dependencies": {
        "tslib": {
          "version": "2.3.0",
          "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
          "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
        }
      }
    }
  }
}
package.json
@@ -17,6 +17,7 @@
    "@vueuse/core": "^10.10.0",
    "axios": "^1.7.2",
    "dayjs": "^1.11.11",
    "echarts": "^5.5.1",
    "element-plus": "^2.7.4",
    "pinia": "^2.1.7",
    "unplugin-vue-components": "^0.27.0",
src/api/index.js
@@ -11,7 +11,8 @@
let ip2_file = 'https://fyami.com.cn/'
if (debug) {
  ip1 = 'http://192.168.0.138:8082/'
  // ip1 = 'http://192.168.0.138:8082/'
  ip1 = 'http://localhost:8080/'
  // ip1_file = 'http://47.100.191.150:9005/';
  // ip2 = 'http://192.168.0.138:8080/';
  // ip2_file = 'https://fyami.com.cn/';
src/components.d.ts
@@ -8,22 +8,18 @@
declare module 'vue' {
  export interface GlobalComponents {
    BaseMap: typeof import('./components/map/BaseMap.vue')['default']
    copy: typeof import('./components/search/OptionLocation copy.vue')['default']
    CoreHeader: typeof import('./components/core/CoreHeader.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']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
    ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
    ElFormItem: typeof import('element-plus/es')['ElFormItem']
    ElIcon: typeof import('element-plus/es')['ElIcon']
    ElLink: typeof import('element-plus/es')['ElLink']
    ElOption: typeof import('element-plus/es')['ElOption']
    ElProgress: typeof import('element-plus/es')['ElProgress']
    ElRow: typeof import('element-plus/es')['ElRow']
    ElScorllbar: typeof import('element-plus/es')['ElScorllbar']
    ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
    ElSegmented: typeof import('element-plus/es')['ElSegmented']
    ElSelect: typeof import('element-plus/es')['ElSelect']
@@ -34,7 +30,6 @@
    ElText: typeof import('element-plus/es')['ElText']
    ElTimeline: typeof import('element-plus/es')['ElTimeline']
    ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
    FYOptionTime: typeof import('./components/search/FYOptionTime.vue')['default']
    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/views/inspection/InspectionView.vue
@@ -1,7 +1,7 @@
<template>
  <div class="wrapper">
    <div>现场巡查</div>
    <TaskTrack></TaskTrack>
    <WorkStream></WorkStream>
  </div>
</template>
@@ -10,6 +10,8 @@
 * çŽ°åœºå·¡æŸ¥å®žæ—¶è·Ÿè¸ª
 */
import TaskTrack from '@/views/inspection/TaskTrack.vue'
import WorkStream from '@/views/inspection/WorkStream.vue'
</script>
<style scoped>
src/views/inspection/WorkStream.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<template>
  <div class="border-r-small m-h-2 p-h-4">
    <el-scrollbar ref="scrollbarRef" height="calc(var(--fy-body-height) / 3 * 1 - 30px)">
      <div ref="scrollContentRef">
        <div v-for="item in streams" :key="item.index">
          <el-text type="primary">[{{ item.time }}]: </el-text>
          <el-text>用户</el-text>
          <el-text type="warning">{{ item.user }}</el-text>
          <el-text>在</el-text>
          <el-text type="success">{{ item.obj }}</el-text>
          <el-text>{{ item.event }}</el-text>
        </div>
      </div>
    </el-scrollbar>
  </div>
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import dayjs from 'dayjs'
const streams = reactive([])
const scrollContentRef = ref()
const scrollbarRef = ref()
const users = ['pcheck', 'zzq', 'xzq']
const events = [
  '新增一个问题',
  '新增一项现场整改',
  '审核了一个问题',
  '审核了一个整改',
  '开始巡查',
  '结束巡查'
]
const objs = [
  '大宁国际学校(小学部)新建工程',
  '新建472街坊公共绿地和地下空间开发项目',
  '黄浦江延伸段WS3单元xH130E街坊030406070911地块',
  '徐汇区龙华街道188N-F-04地块(桩基工程)',
  '网易上海西岸研发中心项目',
  '徐汇区黄浦江南延伸段WS3单元xh130D街坊03、04、06、08、09、11和12地块项目桩基工程',
  '太保家园·上海静安国际康养社区项目装修工程',
  '彭浦西系统雨调蓄池工程',
  '徐汇区长桥街道395街坊xh311B-07B地块新建幼儿园',
  '彭一住宅小区旧住房拆除重建工程',
  '阿里巴巴上海徐汇项目二期'
]
function scrollToBottom() {
  const h1 = scrollContentRef.value.clientHeight + 100
  setTimeout(() => {
    scrollbarRef.value.setScrollTop(h1)
  }, 100)
}
onMounted(() => {
  //   var index = 0
  setInterval(() => {
    streams.push({
      //   index: index,
      time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
      user: users[parseInt(Math.random() * users.length)],
      obj: objs[parseInt(Math.random() * objs.length)],
      event: events[parseInt(Math.random() * events.length)]
    })
    scrollToBottom()
    // index++
  }, 10000)
})
</script>
src/views/inspection/problem/ProblemTrack.vue
@@ -5,6 +5,12 @@
      <ProblemSummary :data="subtaskList"></ProblemSummary>
      <ProblemTable :data="subtaskList"></ProblemTable>
    </div>
    <div>
      <ProblemChangeChart></ProblemChangeChart>
    </div>
    <div>
      <ProblemType></ProblemType>
    </div>
  </div>
</template>
@@ -14,10 +20,13 @@
import ProblemTable from './component/ProblemTable.vue'
import ProblemSummary from './component/ProblemSummary.vue'
import ProblemChangeChart from './component/ProblemChangeChart.vue'
import ProblemType from './component/ProblemType.vue'
import taskApi from '@/api/fysp/taskApi.js'
export default {
  components: { ProblemSummary, ProblemTable },
  components: { ProblemSummary, ProblemTable, ProblemChangeChart, ProblemType },
  data() {
    return {
      subtaskList: []
src/views/inspection/problem/component/ProblemChangeChart.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,81 @@
<template>
  <el-row justify="space-between">
    <div>分期趋势</div>
    <OptionTime v-model="time"></OptionTime>
  </el-row>
  <div ref="echart" class="line-chart"></div>
</template>
<script>
import * as echarts from 'echarts'
export default {
  methods: {
    refresh() {
      const fontSize = 12
      const option = {
        legend: {
          data: ['问题', '整改'],
          textStyle: {
            fontSize: fontSize,
            color: 'white'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: ['1号', '2号', '3号', '4号', '5号', '6号'],
          axisLabel: {
            textStyle: {
              fontSize: fontSize
            },
            color: '#ffffff',
            textBorderColor: '#fff'
          }
        },
        yAxis: {
          type: 'value',
          axisLabel: {
            textStyle: {
              fontSize: fontSize,
              color: 'white'
            }
          }
        },
        series: [
          {
            name: '问题',
            type: 'bar',
            data: [67, 45, 90, 67, 45, 90]
          },
          {
            name: '整改',
            type: 'bar',
            data: [67, 45, 90, 67, 40, 81]
          }
          //   {
          //     name: '整改率',
          //     type: 'bar',
          //     data: [820, 832, 901, 934, 1290, 1330, 1320]
          //   }
        ]
      }
      this.echart.setOption(option)
    }
  },
  mounted() {
    this.echart = echarts.init(this.$refs.echart)
    this.refresh()
  }
}
</script>
<style scoped>
.line-chart {
  /* width: 200px; */
  height: 200px;
}
</style>
src/views/inspection/problem/component/ProblemType.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
<template>
  <el-row justify="space-between">
    <div>问题分布</div>
    <OptionTime v-model="time"></OptionTime>
  </el-row>
  <div ref="echart" class="line-chart"></div>
</template>
<script>
import * as echarts from 'echarts'
export default {
  methods: {
    refresh() {
      const fontSize = 12
      const option = {
        legend: {
          data: ['问题', '整改'],
          textStyle: {
            fontSize: fontSize,
            color: 'white'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        tooltip: {
          trigger: 'item'
        },
        series: [
          {
            name: '问题分布',
            type: 'pie',
            radius: '55%',
            center: ['50%', '50%'],
            data: [
              { value: 24, name: '出入口(道路)扬尘' },
              { value: 20, name: '工程车辆' },
              { value: 18, name: '道路扬尘' },
              { value: 26, name: '路面硬化' },
              { value: 30, name: '渣土' }
            ].sort(function (a, b) {
              return a.value - b.value
            }),
            roseType: 'radius',
            label: {
              color: 'rgba(255, 255, 255, 0.3)'
            },
            labelLine: {
              lineStyle: {
                color: 'rgba(255, 255, 255, 0.3)'
              },
              smooth: 0.2,
              length: 10,
              length2: 20
            },
            itemStyle: {
              color: '#c23531',
              shadowBlur: 200,
              shadowColor: 'rgba(0, 0, 0, 0.5)'
            },
            animationType: 'scale',
            animationEasing: 'elasticOut',
            animationDelay: function (idx) {
              return Math.random() * 200
            }
          }
        ]
      }
      this.echart.setOption(option)
    }
  },
  mounted() {
    this.echart = echarts.init(this.$refs.echart)
    this.refresh()
  }
}
</script>
<style scoped>
.line-chart {
  /* width: 200px; */
  height: 200px;
}
</style>