riku
2024-06-05 3653db5756ad6ae89eb573409a3b0fa9926175a5
原型制作,新增现场巡查和区县巡查统计
已修改8个文件
已添加14个文件
695 ■■■■■ 文件已修改
src/App.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/fonts/SIMHEI.TTF 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/fonts/SOURCEHANSANSCN-MEDIUM.OTF 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/base.scss 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/index.scss 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/layout.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/text.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components.d.ts 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/core/CoreHeader.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/SubtaskExamineItem.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/SubtaskItem.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/TaskItem.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/inspection/TaskNode.vue 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HomeView.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/InspectionView.vue 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/ProblemTrack.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inspection/TaskTrack.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/MonitorView.vue 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/ManagementView.vue 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/management/TaskStats.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/VisualizationView.vue 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue
@@ -11,4 +11,10 @@
  </el-config-provider>
</template>
<style scoped></style>
<style>
html,
body {
  margin: 0;
  font-family: '思源黑体';
}
</style>
src/assets/fonts/SIMHEI.TTF
Binary files differ
src/assets/fonts/SOURCEHANSANSCN-MEDIUM.OTF
Binary files differ
src/assets/styles/base.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,117 @@
/************************************** font size **************************************/
$fontsize: (
  s: var(--el-font-size-small),
  b: var(--el-font-size-base),
  m: var(--el-font-size-medium),
  l: var(--el-font-size-large)
);
@each $dName, $dValue in $fontsize {
  .f-#{$dName} {
    font-size: #{$dValue};
  }
}
/************************************** color **************************************/
$colors: (
  p: var(--el-color-primary),
  s: var(--el-color-success),
  w: var(--el-color-warning),
  d: var(--el-color-danger),
  e: var(--el-color-error),
  i: var(--el-color-info)
);
@each $dName, $dValue in $colors {
  .color-#{$dName} {
    color: #{$dValue};
  }
  .b-color-#{$dName} {
    background-color: #{$dValue};
  }
}
/************************************** å†…外边距 **************************************/
$direction: (
  l: 'left',
  t: 'top',
  r: 'right',
  b: 'bottom'
);
$size: (2, 4, 8, 10, 16);
@each $dName, $dValue in $direction {
  @each $i in $size {
    .p-#{$dName}-#{$i} {
      padding-#{$dValue}: #{$i}px;
    }
    .m-#{$dName}-#{$i} {
      margin-#{$dValue}: #{$i}px;
    }
  }
}
@each $i in $size {
  .p-v-#{$i} {
    padding: #{$i}px 0;
  }
  .p-h-#{$i} {
    padding: 0 #{$i}px;
  }
  .p-#{$i} {
    padding: #{$i}px;
  }
  .m-v-#{$i} {
    margin: #{$i}px 0;
  }
  .m-h-#{$i} {
    margin: 0 #{$i}px;
  }
  .m-#{$i} {
    margin: #{$i}px;
  }
}
/************************************** å®½é«˜ **************************************/
$csize: (
  small: var(--el-component-size-small),
  default: var(--el-component-size-default),
  large: var(--el-component-size-large)
);
$ws: (20, 40, 50, 60, 80, 100, 120, 150, 200, 250, 300);
@each $name, $value in $csize {
  .w-#{$name} {
    width: #{$value};
  }
  .h-#{$name} {
    height: #{$value};
  }
}
@each $i in $ws {
  .w-#{$i} {
    width: #{$i}px;
  }
  .h-#{$i} {
    height: #{$i}px;
  }
}
/************************************** è¾¹æ¡† **************************************/
$bsize: (
  small: var(--el-border-radius-small),
  base: var(--el-border-radius-base),
  round: var(--el-border-radius-round),
  circle: var(--el-border-radius-circle)
);
@each $name, $value in $bsize {
  .border-r-#{$name} {
    border: var(--el-border);
    border-radius: $value;
  }
}
/************************************** å¯¹é½ **************************************/
.v-center {
  display: flex;
  flex-direction: column;
  align-items: center;
}
src/assets/styles/element/index.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
// @forward 'element-plus/theme-chalk/src/common/var.scss' with (
//   $colors: (
//     'primary': (
//       'base': green
//     )
//   )
// );
src/assets/styles/index.scss
@@ -0,0 +1,16 @@
@use './base.scss';
@use './text.scss';
@use './layout.scss';
@use './element/index.scss' as *;
@font-face {
  font-family: 'SIMHEI';
  src: url(../fonts/SIMHEI.TTF);
}
@font-face {
  font-family: '思源黑体';
  src: url(../fonts/SOURCEHANSANSCN-MEDIUM.OTF);
  font-weight: normal;
  font-style: normal;
}
src/assets/styles/layout.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
:root {
  --fy-header-height: 40px;
  --fy-body-height: calc(100vh - var(--fy-header-height));
}
.fy-header {
  height: var(--fy-header-height);
  // background-color: antiquewhite;
}
.fy-body {
  height: var(--fy-body-height);
  // background-color: azure;
}
src/assets/styles/text.scss
src/components.d.ts
@@ -7,10 +7,21 @@
/* prettier-ignore */
declare module 'vue' {
  export interface GlobalComponents {
    CoreHeader: typeof import('./components/core/CoreHeader.vue')['default']
    ElButton: typeof import('element-plus/es')['ElButton']
    ElCard: typeof import('element-plus/es')['ElCard']
    ElCol: typeof import('element-plus/es')['ElCol']
    ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
    ElProgress: typeof import('element-plus/es')['ElProgress']
    ElRow: typeof import('element-plus/es')['ElRow']
    ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
    ElTag: typeof import('element-plus/es')['ElTag']
    ElText: typeof import('element-plus/es')['ElText']
    RouterLink: typeof import('vue-router')['RouterLink']
    RouterView: typeof import('vue-router')['RouterView']
    SubtaskExamineItem: typeof import('./components/inspection/SubtaskExamineItem.vue')['default']
    SubtaskItem: typeof import('./components/inspection/SubtaskItem.vue')['default']
    TaskItem: typeof import('./components/inspection/TaskItem.vue')['default']
    TaskNode: typeof import('./components/inspection/TaskNode.vue')['default']
  }
}
src/components/core/CoreHeader.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
<template>
  <el-row class="fy-header"> ç³»ç»Ÿæ ‡é¢˜ã€æ—¶é—´ã€å¤©æ°”等信息 </el-row>
</template>
<script>
export default {
  props: {},
  data() {
    return {}
  },
  methods: {}
}
</script>
<style scoped></style>
src/components/inspection/SubtaskExamineItem.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
<template>
  <div :class="itemClass + ' p-v-4 f-s'">
    <div>
      <el-text class="w-200" size="default" truncated>
        {{ name }}
      </el-text>
    </div>
    <el-row justify="space-between">
      <div>{{ type }}</div>
      <!-- <el-text size="small"> {{ type }} </el-text> -->
      <el-progress
        class="w-150"
        :percentage="(checked / total) * 100"
        status="warning"
        striped
        striped-flow
      >
        <span>{{ checked + '/' + total }}</span>
      </el-progress>
    </el-row>
  </div>
</template>
<script>
/**
 * å·¡æŸ¥å­ä»»åŠ¡é—®é¢˜å®¡æ ¸çŠ¶æ€ä¿¡æ¯
 */
export default {
  props: {
    index: Number,
    name: String,
    district: String,
    planTime: String,
    type: String,
    total: Number,
    checked: Number
  },
  data() {
    return {}
  },
  watch: {},
  computed: {
    itemClass() {
      return this.index % 2 == 0 ? 'wrapper-even' : 'wrapper-odd'
    }
  },
  methods: {}
}
</script>
<style scoped>
.wrapper-odd {
  background-color: aliceblue;
}
.wrapper-even {
  /* background-color: aliceblue; */
}
</style>
src/components/inspection/SubtaskItem.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
<template>
  <div :class="itemClass + ' p-v-4 f-s'">
    <div>
      <!-- <el-row justify="center"> -->
      <el-text class="w-200" size="default" truncated>
        {{ name }}
      </el-text>
      <!-- </el-row> -->
    </div>
    <el-row justify="space-between">
      <el-tag type="primary" size="small" effect="plain">
        {{ district }}
      </el-tag>
      <div>{{ planTime }}</div>
      <!-- <div>| {{ startTime }} | {{ endTime }}</div> -->
      <div>{{ userName }}</div>
      <!-- <div>{{ status }}</div> -->
      <!-- <el-button type="primary">queding</el-button> -->
    </el-row>
  </div>
</template>
<script>
/**
 * å·¡æŸ¥å­ä»»åŠ¡æ‰§è¡ŒçŠ¶æ€ä¿¡æ¯
 */
export default {
  props: {
    index: Number,
    name: String,
    district: String,
    planTime: String,
    startTime: String,
    endTime: String,
    userName: String,
    status: String
  },
  data() {
    return {}
  },
  watch: {},
  computed: {
    itemClass() {
      return this.index % 2 == 0 ? 'wrapper-even' : 'wrapper-odd'
    }
  },
  methods: {}
}
</script>
<style scoped>
.wrapper-odd {
  background-color: aliceblue;
}
.wrapper-even {
  /* background-color: aliceblue; */
}
</style>
src/components/inspection/TaskItem.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
<template>
  <div class="demo-progress border-r-small f-b">
    <el-row>
      <el-col span="8">
        <el-progress :width="100" type="dashboard" :percentage="(finish / total) * 100">
          <template #default="{ percentage }">
            <span class="percentage-value">{{ percentage }}%</span>
            <span class="percentage-label">{{ finish + '/' + total }}</span>
          </template>
        </el-progress>
      </el-col>
      <el-col span="16">
        <div>{{ name }}</div>
        <!-- <div>{{ planTime }}</div> -->
        <div>{{ userName }}</div>
        <el-row style="gap: 10px">
          <div class="v-center" v-for="item in count" :key="item.sceneType">
            <el-progress
              :width="50"
              :stroke-width="3"
              type="dashboard"
              :percentage="(item.finish / item.total) * 100"
            >
              <template #default="{ percentage }">
                <span class="percentage-value-small">{{ percentage }}%</span>
              </template>
            </el-progress>
            <div>
              <el-text size="small">{{ item.sceneType }}</el-text>
              <el-text size="small">{{ item.finish + '/' + item.total }}</el-text>
            </div>
            <div></div>
            <!-- <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>
/**
 * å·¡æŸ¥ä»»åŠ¡åŒºåŸŸç»Ÿè®¡ä¿¡æ¯
 */
export default {
  props: {
    name: String,
    district: String,
    planTime: String,
    startTime: String,
    endTime: String,
    userName: String,
    status: String,
    count: Array
  },
  data() {
    return {}
  },
  watch: {},
  computed: {
    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
    }
  },
  methods: {}
}
</script>
<style scoped>
.wrapper {
  border: var(--el-border);
  border-radius: var(--el-border-radius-base);
}
.percentage-value {
  display: block;
  margin-top: 10px;
  font-size: var(--el-font-size-base);
}
.percentage-value-small {
  display: block;
  /* margin-top: 10px; */
  font-size: var(--el-font-size-small);
}
.percentage-label {
  display: block;
  margin-top: 10px;
  font-size: var(--el-font-size-base);
}
.percentage-label-small {
  display: block;
  /* margin-top: 10px; */
  font-size: var(--el-font-size-small);
}
</style>
src/components/inspection/TaskNode.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
<template>
  <div>
    <el-row justify="center">{{ title }}</el-row>
    <div class="border-r-small f-b">
      <div v-for="(item, i) in items" :key="title + i">
        <slot :item="item" :index="i"></slot>
      </div>
    </div>
  </div>
</template>
<script>
/**
 * å·¡æŸ¥å­ä»»åŠ¡èŠ‚ç‚¹
 */
export default {
  props: {
    title: String,
    count: Number,
    items: Array
  },
  data() {
    return {}
  },
  watch: {},
  methods: {}
}
</script>
<style scoped>
.wrapper {
  border: var(--el-border);
  border-radius: var(--el-border-radius-base);
}
</style>
src/views/HomeView.vue
@@ -1,6 +1,8 @@
<template>
  <el-row> ç³»ç»Ÿæ ‡é¢˜ã€æ—¶é—´ã€å¤©æ°”等信息 </el-row>
  <core-header></core-header>
  <div class="fy-body">
  <router-view></router-view>
  </div>
</template>
<script setup></script>
src/views/inspection/InspectionView.vue
@@ -1,11 +1,17 @@
<template>
  <el-row>
    <el-col :span="8">1</el-col>
    <el-col :span="8">2</el-col>
    <el-col :span="8">3</el-col>
  </el-row>
  <div class="wrapper">
    <div>现场巡查</div>
    <TaskTrack></TaskTrack>
  </div>
</template>
<script setup></script>
<script setup>
import TaskTrack from '@/views/inspection/TaskTrack.vue'
</script>
<style scoped></style>
<style scoped>
.wrapper {
  /* height: calc(var(--fy-body-height) / 2);
  background-color: burlywood; */
}
</style>
src/views/inspection/ProblemTrack.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
<template>
  <el-card shadow="hover">
    <div class="f-l">巡查问题跟踪</div>
  </el-card>
</template>
<script>
export default {
  data() {
    return {
      subtaskList: []
    }
  },
  watch: {},
  methods: {},
  mounted() {
    let i = 0
    while (i < 3) {
      this.subtaskList.push({
        guid: 'SMuheEkjswioSn7A',
        name: '中科生态数字港项目巡查',
        district: '金山区',
        planTime: '2024-06-04',
        startTime: '2024-06-04 13:31:26',
        endTime: '2024-06-04 13:33:37',
        userName: '朱正强',
        status: '已结束'
      })
      i++
    }
  }
}
</script>
<style scoped>
.text {
  background-color: aliceblue;
}
</style>
src/views/inspection/TaskTrack.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<template>
  <div>
    <el-row justify="space-evenly">
      <!-- <div class="f-l">现场巡查跟踪(现场人员巡查情况实时掌握)</div> -->
      <!-- <SubtaskItem v-for="item in subtaskList" :key="item.guid" v-bind="item"> </SubtaskItem> -->
      <el-col :span="4">
        <TaskNode title="新任务" :items="subtaskList" v-slot="{ item, index }">
          <SubtaskItem v-bind="item" :index="index"> </SubtaskItem>
        </TaskNode>
      </el-col>
      <el-col :span="4">
        <TaskNode title="正在执行" :items="subtaskList" v-slot="{ item, index }">
          <SubtaskItem v-bind="item" :index="index"> </SubtaskItem>
        </TaskNode>
      </el-col>
      <el-col :span="4">
        <TaskNode title="待审核" :items="subtaskList" v-slot="{ item, index }">
          <SubtaskExamineItem v-bind="item" :index="index" type="问题审核"> </SubtaskExamineItem>
        </TaskNode>
      </el-col>
      <el-col :span="4">
        <TaskNode title="待整改" :items="subtaskList" v-slot="{ item, index }">
          <SubtaskExamineItem v-bind="item" :index="index" type="待整改"> </SubtaskExamineItem>
        </TaskNode>
      </el-col>
      <el-col :span="4">
        <TaskNode title="待确认" :items="subtaskList" v-slot="{ item, index }">
          <SubtaskExamineItem v-bind="item" :index="index" type="整改审核"> </SubtaskExamineItem>
        </TaskNode>
      </el-col>
    </el-row>
  </div>
</template>
<script>
export default {
  data() {
    return {
      subtaskList: []
    }
  },
  watch: {},
  methods: {},
  mounted() {
    let i = 0
    while (i < 5) {
      this.subtaskList.push({
        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
      })
      i++
    }
  }
}
</script>
<style scoped>
.text {
  background-color: aliceblue;
}
</style>
src/views/main/MonitorView.vue
@@ -1,13 +1,17 @@
<template>
  <el-row>
    <el-col :span="8">
      <InspectionView></InspectionView>
    </el-col>
    <el-col :span="8">
      <ManagementView></ManagementView>
    </el-col>
    <el-col :span="8">
    <el-col :span="16">
      <el-scrollbar class="page-left-top">
      <VisualizationView></VisualizationView>
      </el-scrollbar>
      <el-scrollbar class="page-left-bottom">
        <InspectionView></InspectionView>
      </el-scrollbar>
    </el-col>
    <el-col :span="8" class="page-right">
      <el-scrollbar height="var(--fy-body-height)">
        <ManagementView></ManagementView>
      </el-scrollbar>
    </el-col>
  </el-row>
</template>
@@ -18,4 +22,17 @@
import VisualizationView from '@/views/visualization/VisualizationView.vue'
</script>
<style scoped></style>
<style scoped>
.page-left-top {
  height: calc(var(--fy-body-height) / 2);
  background-color: aquamarine;
}
.page-left-bottom {
  height: calc(var(--fy-body-height) / 2);
  background-color: bisque;
}
.page-right {
  /* background-color: aliceblue; */
}
</style>
src/views/management/ManagementView.vue
@@ -1,11 +1,10 @@
<template>
  <el-row>
    <el-col :span="8">1</el-col>
    <el-col :span="8">2</el-col>
    <el-col :span="8">3</el-col>
  </el-row>
  <el-row> ç»Ÿè®¡ç®¡ç† </el-row>
  <TaskStats></TaskStats>
</template>
<script setup></script>
<script setup>
import TaskStats from '@/views/management/TaskStats.vue'
</script>
<style scoped></style>
src/views/management/TaskStats.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
<template>
  <div class="border-r-small">
    <div class="f-l">各监管区县的巡查完成情况</div>
    <el-row>
      <TaskItem v-for="item in tasks" :key="item.guid" v-bind="item"></TaskItem>
    </el-row>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tasks: []
    }
  },
  watch: {},
  methods: {},
  mounted() {
    let i = 0
    while (i < 3) {
      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
          }
        ]
      })
      i++
    }
  }
}
</script>
<style scoped>
.text {
  background-color: aliceblue;
}
</style>
src/views/visualization/VisualizationView.vue
@@ -1,11 +1,11 @@
<template>
  <el-row>
    <el-col :span="8">1</el-col>
    <el-col :span="8">2</el-col>
    <el-col :span="8">3</el-col>
  </el-row>
  <el-row class="wrapper"> å¯è§†åŒ– </el-row>
</template>
<script setup></script>
<style scoped></style>
<style scoped>
.wrapper {
  /* background-color: aquamarine; */
}
</style>