瀏覽代碼

监测中心

CzRger 4 月之前
父節點
當前提交
689a910a29
共有 32 個文件被更改,包括 8453 次插入12 次删除
  1. 1 0
      src/router/index.ts
  2. 18 3
      src/router/modules/screen.ts
  3. 5 0
      src/router/modules/static.ts
  4. 二進制
      src/style/font/YOUSHEBIAOTIHEI-2.TTF
  5. 4 0
      src/style/font/font.scss
  6. 1 1
      src/utils/util.ts
  7. 二進制
      src/views/screen/components/card-number/card.png
  8. 68 0
      src/views/screen/components/card-number/index.vue
  9. 6063 0
      src/views/screen/components/map/hainan.json
  10. 14 0
      src/views/screen/components/map/tool.ts
  11. 二進制
      src/views/screen/demo/bg.png
  12. 1549 0
      src/views/screen/demo/config.json
  13. 二進制
      src/views/screen/demo/map-bg.png
  14. 213 8
      src/views/screen/demo/map.vue
  15. 151 0
      src/views/screen/demo/res.json
  16. 21 0
      src/views/screen/kouan-run-monitor/bus-index.vue
  17. 125 0
      src/views/screen/kouan-run-monitor/components/head.vue
  18. 95 0
      src/views/screen/kouan-run-monitor/components/normal.scss
  19. 21 0
      src/views/screen/kouan-run-monitor/goods-index.vue
  20. 104 0
      src/views/screen/kouan-run-monitor/guest-index.vue
  21. 二進制
      src/views/screen/kouan-run-monitor/img/block-bg.png
  22. 二進制
      src/views/screen/kouan-run-monitor/img/block-head-2.png
  23. 二進制
      src/views/screen/kouan-run-monitor/img/block-head.png
  24. 二進制
      src/views/screen/kouan-run-monitor/img/bus-bg.png
  25. 二進制
      src/views/screen/kouan-run-monitor/img/goods-bg.png
  26. 二進制
      src/views/screen/kouan-run-monitor/img/guest-bg.png
  27. 二進制
      src/views/screen/kouan-run-monitor/img/header.png
  28. 二進制
      src/views/screen/kouan-run-monitor/img/run-status-error.png
  29. 二進制
      src/views/screen/kouan-run-monitor/img/run-status-normal.png
  30. 二進制
      src/views/screen/kouan-run-monitor/img/run-status-warning.png
  31. 二進制
      src/views/screen/kouan-run-monitor/img/tab-active.png
  32. 二進制
      src/views/screen/kouan-run-monitor/img/tab.png

+ 1 - 0
src/router/index.ts

@@ -1,6 +1,7 @@
 import {createRouter, createWebHistory} from 'vue-router'
 import staticRouter from './modules/static'
 import screenRouter from './modules/screen'
+// @ts-ignore
 import Temp404 from '@/views/global/temp/404.vue'
 import {ElLoading, ElMessage} from "element-plus";
 import {toLogin} from "@/utils/permissions";

+ 18 - 3
src/router/modules/screen.ts

@@ -2,12 +2,27 @@
 export default {
   path: '/screen',
   name: 'eea02f48-479f-48b1-a4a1-0430070e8bee',
-  redirect: '/screen/map',
   children: [
     {
-      path: 'map',
+      path: 'kouan-run-monitor',
       name: '71305311-abcc-4d13-8531-f966b49839c5',
-      component: () => import('@/views/screen/demo/map.vue'),
+      children: [
+        {
+          path: 'guest',
+          name: '9be9b8fc-0d4a-4b7b-bcac-fe6b11ad6005',
+          component: () => import('@/views/screen/kouan-run-monitor/guest-index.vue'),
+        },
+        {
+          path: 'bus',
+          name: '90efb889-1286-4af3-b056-f0aa9b7c98b3',
+          component: () => import('@/views/screen/kouan-run-monitor/bus-index.vue'),
+        },
+        {
+          path: 'goods',
+          name: 'e69e3467-fe72-43da-96f9-46271f7e1972',
+          component: () => import('@/views/screen/kouan-run-monitor/goods-index.vue'),
+        },
+      ]
     },
   ]
 }

+ 5 - 0
src/router/modules/static.ts

@@ -9,5 +9,10 @@ const staticRouter = [
       noToken: true
     }
   },
+  {
+    path: '/map',
+    name: '71305311-abcc-4d13-8531-f966b49839c5',
+    component: () => import('@/views/screen/demo/map.vue'),
+  },
 ]
 export default staticRouter

二進制
src/style/font/YOUSHEBIAOTIHEI-2.TTF


+ 4 - 0
src/style/font/font.scss

@@ -2,3 +2,7 @@
   font-family: "PingFang SC";
   src: url("@/style/font/PingFang Regular.ttf");
 }
+@font-face {
+  font-family: "YouSheBiaoTiHei";
+  src: url("@/style/font/YOUSHEBIAOTIHEI-2.TTF");
+}

+ 1 - 1
src/utils/util.ts

@@ -661,7 +661,7 @@ export const extractRgbFromRgba = (rgbaString) => {
 
 export const _console = (p) => console.log(p)
 export const arrayToTree = ({data, idKey = 'id', parentKey = 'parentId', childrenKey =  'children', root = ''}) => {
-  const result = []
+  const result: any = []
   data.forEach(v => {
     if (v[parentKey] == root) {
       result.push(v)

二進制
src/views/screen/components/card-number/card.png


+ 68 - 0
src/views/screen/components/card-number/index.vue

@@ -0,0 +1,68 @@
+<template>
+  <div class="card-number">
+    <template v-for="item in valueCpt">
+      <div class="card-item">{{item}}</div>
+    </template>
+    <div class="unit" v-if="unit">{{unit}}</div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {computed, getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const props = defineProps({
+  value: {},
+  min: {default: 0},
+  unit: {default: ''},
+})
+const valueCpt = computed(() => {
+  const str = String(props.value).split('')
+  if (props.min > 0) {
+    for (let i = 0; i <= (props.min - str.length); i++) {
+      str.unshift('0')
+    }
+  }
+  return str
+})
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+.card-number {
+  display: flex;
+  align-items: flex-end;
+  gap: 5px;
+  .card-item {
+    width: 26px;
+    height: 33px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-family: Source Han Sans CN;
+    font-weight: bold;
+    font-size: 22px;
+    color: #FFFFFF;
+    background: linear-gradient(0deg, #3FA4F6 0%, #F7FDFF 100%);
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    position: relative;
+    &:before {
+      content: '';
+      background-image: url("./card.png");
+      background-size: 100% 100%;
+      width: 100%;
+      height: 100%;
+      position: absolute;
+      z-index: -1;
+    }
+  }
+  .unit {
+    font-weight: 400;
+    font-size: 14px;
+    color: #FFFFFF;
+    line-height: 27px;
+    opacity: 0.6;
+  }
+}
+</style>

文件差異過大導致無法顯示
+ 6063 - 0
src/views/screen/components/map/hainan.json


+ 14 - 0
src/views/screen/components/map/tool.ts

@@ -0,0 +1,14 @@
+import HainanJson from './hainan.json'
+
+export const getHainanMapJson = (sansha = false) => sansha ? HainanJson : ({
+  "type": "FeatureCollection",
+  "features": HainanJson.features.filter(v => v.properties.name !== '三沙市')
+})
+export const getCenter = (val, key = 'name') => {
+  for (let i = 0; i < HainanJson.features.length; i++) {
+    if (HainanJson.features[i].properties.name == val) {
+      return HainanJson.features[i].properties.center
+    }
+  }
+  return [0, 0]
+}

二進制
src/views/screen/demo/bg.png


文件差異過大導致無法顯示
+ 1549 - 0
src/views/screen/demo/config.json


二進制
src/views/screen/demo/map-bg.png


+ 213 - 8
src/views/screen/demo/map.vue

@@ -1,20 +1,225 @@
 <template>
-  <div class="main">
-    asdasd
+  <div class="chart-main" ref="ref_main">
+    <div class="chart-ref" ref="ref_chart"/>
+    <div class="map-bg">
+      <img src="./map-bg.png"/>
+    </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import {getCurrentInstance, reactive} from "vue";
+import {getCurrentInstance, reactive, ref, onMounted, watch, nextTick} from "vue";
+import * as echarts from 'echarts';
+import mockData from './res.json'
+import {getCenter, getHainanMapJson} from "@/views/screen/components/map/tool";
+
+const props = defineProps({
+  data: {},
+})
 
 const {proxy} = getCurrentInstance()
-const state: any = reactive({})
+const state = reactive({
+  resizeObserver: <any>null,
+  chart: <any>null
+})
+const ref_chart = ref();
+const ref_main = ref();
+const initChart = () => {
+  echarts.dispose(ref_chart.value)
+  const chart = echarts.init(ref_chart.value);
+  echarts.registerMap('海南', getHainanMapJson())
+  const _regions: any = []
+  mockData.data.forEach(v => {
+    const goodPer = Number(v.availability.replace('%', ''))
+    const obj = {
+      name: v.areacode,
+      itemStyle: {
+        borderWidth: 2,
+        borderColor: 'rgba(2, 162, 255, 1)'
+      },
+      emphasis: {
+        label: {
+          show: false
+        },
+        itemStyle: {
+          borderWidth: 2,
+        }
+      }
+    }
+    if (goodPer < 70) {
+      obj.emphasis.itemStyle.borderColor = 'rgba(255, 32, 69, 1)'
+      obj.emphasis.itemStyle.areaColor = 'rgba(255, 32, 69, 0.6)'
+    } else if (goodPer < 90) {
+      obj.emphasis.itemStyle.borderColor = 'rgba(255, 136, 20, 1)'
+      obj.emphasis.itemStyle.areaColor = 'rgba(255, 136, 20, 0.7)'
+    } else {
+      obj.emphasis.itemStyle.borderColor = 'rgba(55, 164, 230, 1)'
+      obj.emphasis.itemStyle.areaColor = 'rgba(55, 164, 230, 0.7)'
+    }
+    _regions.push(obj)
+  })
+  const option = {
+    geo: {
+      map: '海南',
+      aspectScale: 1,
+      itemStyle: {
+        borderWidth: 2,
+        borderColor: 'rgba(2, 162, 255, 1)',
+        areaColor: 'transparent',
+      },
+      regions: _regions,
+    },
+    tooltip: {
+      "backgroundColor": "rgba(50,50,50,0.7)",
+      "borderColor": "#333",
+      "borderWidth": 0,
+      "padding": 0,
+      formatter: (p) => {
+        let h = [`<div style="background-color: rgba(0, 0, 0, 0.7);border: 2px solid ${Number(p.data.availability.replace('%', '')) < 70 ? 'rgba(255, 32, 69, 1)' : (Number(p.data.availability.replace('%', '')) < 90 ? 'rgba(255, 136, 20, 1)' : 'rgba(55, 164, 230, 1)')};">`, '', '</div>']
+        if (Number(p.data.availability.replace('%', '')) < 70) {
+          h[1] += `
+            <div style="background: linear-gradient(90deg, rgba(255, 32, 69, 1) 0%, rgba(255, 32, 69, 0) 100%);font-size: 16px;display: flex; align-items: center;padding: 7px 12px 8px 12px;color: #ffffff;">
+              <img src="./system/attachment/download/file?id=TJ7f383b9fd1e14345acabf03ee89fdb" style="margin-right: 7px;"/>
+              <span>完好率已低于70%!</span>
+            </div>
+          `
+        }
+        h[1] += `
+          <div style="display: grid;grid-template-columns: 1fr 1fr;color: #C4D1E6;padding: 12px 13px 10px 14px;grid-row-gap: 10px;grid-column-gap: 6px;line-height: 1;">
+            <div style="grid-column: 1/3;display: flex; align-items: end;font-size: 16px;">总数:<div style="margin-left: 4px;font-family: Bebas;color: #33dcfc;font-size: 20px;">${p.data['dev_amount']}</div></div>
+            <div style="font-size: 16px;">在线数:${p.data['online_amount']}</div>
+            <div style="font-size: 16px;">异常数:${p.data['abnormal']}</div>
+            <div style="font-size: 16px;">在线率:${p.data['online_rate']}</div>
+            <div style="font-size: 16px;">完好率:${p.data['availability']}</div>
+          </div>
+        `
+        return h.join('')
+      }
+    },
+    series: [
+      {
+        name: '海南地图',
+        type: 'map',
+        geoIndex: 0,
+        label: {
+          show: false
+        },
+        select: {
+          disabled: true
+        },
+        data: mockData.data.map(v => {
+          v.name = v.areacode
+          return v
+        })
+      },
+      {
+        geoIndex: 0,
+        name: "散点层",
+        label: {
+          "formatter": "{b}",
+          "fontSize": 20,
+          "fontWeight": "normal",
+          "color": "#fff",
+          "show": true,
+          "position": "right",
+          "alignTo": "none",
+          "edgeDistance": 20,
+          "overflow": "none",
+          "ellipsis": "...",
+          "distance": 5,
+          "offset": [
+            0,
+            0
+          ]
+        },
+        itemStyle: {
+          "borderWidth": 0,
+          "borderType": "solid",
+          "shadowBlur": 0,
+          "shadowColor": "#000",
+          "borderRadius": [
+            0,
+            0,
+            0,
+            0
+          ],
+          "color": "rgba(244, 62, 17, 1)"
+        },
+        type: "scatter",
+        symbol: "arrow",
+        symbolSize: 40,
+        coordinateSystem: "geo",
+        "data": mockData.data.map(v => {
+          v.name = v.areacode
+          v.value = [...getCenter(v.name), Number(v.abnormal)]
+          const goodPer = Number(v.availability.replace('%', ''))
+          v.symbolSize = 20
+          if (goodPer < 70) {
+            v.itemStyle = {
+              color: 'rgba(255, 32, 69, 1)'
+            }
+          } else if (goodPer < 90) {
+            v.itemStyle = {
+              color: 'rgba(255, 136, 20, 1)'
+            }
+          } else {
+            v.itemStyle = {
+              color: 'rgba(87, 220, 255, 1)'
+            }
+          }
+          return v
+        })
+      }
+    ]
+  }
+  chart.setOption(option);
+  state.resizeObserver = new ResizeObserver((entries) => {
+    for (const entry of entries) {
+      chart && chart.resize()
+    }
+  })
+  state.resizeObserver.observe(ref_main.value);
+  return chart
+}
+watch(() => props.data, () => {
+  state.chart = initChart()
+})
+onMounted(() => {
+  nextTick(() => {
+    state.chart = initChart()
+  })
+  return () => {
+    state.resizeObserver?.unobserve(ref_main?.value)
+    state.resizeObserver?.disconnect()
+  }
+})
 </script>
 
 <style lang="scss" scoped>
-.main {
-  width: 100%;
-  height: 100%;
-  background-color: #2E81FF;
+.chart-main {
+  margin: auto;
+  flex: 1;
+  width: 800px;
+  height: 800px;
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  .chart-ref {
+    width: 100%;
+    height: 100%;
+  }
+  .map-bg {
+    position: absolute;
+    z-index: -1;
+    top: 107px;
+    left: 8px;
+    width: 781px;
+    height: 587px;
+    >img {
+      width: 100%;
+      height: 100%;
+    }
+  }
 }
 </style>

+ 151 - 0
src/views/screen/demo/res.json

@@ -0,0 +1,151 @@
+{
+  "message": "操作成功",
+  "code": 200,
+  "data": [
+    {
+      "dev_amount": "1464",
+      "online_amount": "1399",
+      "availability": "92.62%",
+      "areacode": "陵水黎族自治县",
+      "abnormal": "43",
+      "online_rate": "95.56%"
+    },
+    {
+      "dev_amount": "1353",
+      "online_amount": "1231",
+      "availability": "86.18%",
+      "areacode": "琼中黎族苗族自治县",
+      "abnormal": "65",
+      "online_rate": "90.98%"
+    },
+    {
+      "dev_amount": "332",
+      "online_amount": "301",
+      "availability": "85.84%",
+      "areacode": "五指山市",
+      "abnormal": "16",
+      "online_rate": "90.66%"
+    },
+    {
+      "dev_amount": "723",
+      "online_amount": "636",
+      "availability": "85.34%",
+      "areacode": "乐东黎族自治县",
+      "abnormal": "19",
+      "online_rate": "87.97%"
+    },
+    {
+      "dev_amount": "1962",
+      "online_amount": "1716",
+      "availability": "83.89%",
+      "areacode": "东方市",
+      "abnormal": "70",
+      "online_rate": "87.46%"
+    },
+    {
+      "dev_amount": "1205",
+      "online_amount": "937",
+      "availability": "75.68%",
+      "areacode": "白沙黎族自治县",
+      "abnormal": "25",
+      "online_rate": "77.76%"
+    },
+    {
+      "dev_amount": "844",
+      "online_amount": "707",
+      "availability": "75.0%",
+      "areacode": "屯昌县",
+      "abnormal": "74",
+      "online_rate": "83.77%"
+    },
+    {
+      "dev_amount": "1083",
+      "online_amount": "796",
+      "availability": "70.27%",
+      "areacode": "澄迈县",
+      "abnormal": "35",
+      "online_rate": "73.5%"
+    },
+    {
+      "dev_amount": "10317",
+      "online_amount": "7364",
+      "availability": "70.0%",
+      "areacode": "海口市",
+      "abnormal": "142",
+      "online_rate": "71.38%"
+    },
+    {
+      "dev_amount": "4103",
+      "online_amount": "3124",
+      "availability": "68.54%",
+      "areacode": "三亚市",
+      "abnormal": "312",
+      "online_rate": "76.14%"
+    },
+    {
+      "dev_amount": "673",
+      "online_amount": "464",
+      "availability": "67.61%",
+      "areacode": "昌江黎族自治县",
+      "abnormal": "9",
+      "online_rate": "68.95%"
+    },
+    {
+      "dev_amount": "6356",
+      "online_amount": "4279",
+      "availability": "61.83%",
+      "areacode": "儋州市",
+      "abnormal": "349",
+      "online_rate": "67.32%"
+    },
+    {
+      "dev_amount": "1944",
+      "online_amount": "1282",
+      "availability": "57.66%",
+      "areacode": "琼海市",
+      "abnormal": "161",
+      "online_rate": "65.95%"
+    },
+    {
+      "dev_amount": "1150",
+      "online_amount": "714",
+      "availability": "56.43%",
+      "areacode": "保亭黎族苗族自治县",
+      "abnormal": "65",
+      "online_rate": "62.09%"
+    },
+    {
+      "dev_amount": "955",
+      "online_amount": "521",
+      "availability": "53.19%",
+      "areacode": "文昌市",
+      "abnormal": "13",
+      "online_rate": "54.55%"
+    },
+    {
+      "dev_amount": "1419",
+      "online_amount": "895",
+      "availability": "50.88%",
+      "areacode": "万宁市",
+      "abnormal": "173",
+      "online_rate": "63.07%"
+    },
+    {
+      "dev_amount": "1680",
+      "online_amount": "855",
+      "availability": "48.45%",
+      "areacode": "临高县",
+      "abnormal": "41",
+      "online_rate": "50.89%"
+    },
+    {
+      "dev_amount": "866",
+      "online_amount": "599",
+      "availability": "39.61%",
+      "areacode": "定安县",
+      "abnormal": "256",
+      "online_rate": "69.17%"
+    }
+  ],
+  "status": "success"
+}

+ 21 - 0
src/views/screen/kouan-run-monitor/bus-index.vue

@@ -0,0 +1,21 @@
+<template>
+  <div class="__main">
+    <headCom tab="bus"/>
+    <div></div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+import headCom from './components/head.vue'
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+@use "./components/normal";
+.__main {
+  background-image: url("./img/bus-bg.png");
+}
+</style>

+ 125 - 0
src/views/screen/kouan-run-monitor/components/head.vue

@@ -0,0 +1,125 @@
+<template>
+  <div class="kouan-run-monitor-head">
+    <img src="../img/header.png"/>
+    <div class="head-left">
+      <template v-for="item in tabs">
+        <div class="head-left-tab-item __hover" :class="{active: item.value == tab}" @click="item.value !== tab ? $router.push(item.url) : undefined">{{item.label}}</div>
+      </template>
+    </div>
+    <div class="head-center">
+      口岸运行监测中心
+    </div>
+    <div class="head-right">
+      <div class="head-right-time">{{$util.Hms(new Date())}}</div>
+      <div class="head-right-date">
+        <div class="day">{{dayCpt}}</div>
+        <div class="date">{{$util.YMD(new Date())}}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {computed, getCurrentInstance, reactive} from "vue";
+
+const {proxy} = getCurrentInstance()
+const props = defineProps({
+  tab: {}
+})
+const state: any = reactive({
+})
+const tabs = [
+  {label: '旅客', value: 'guest', url: '/screen/kouan-run-monitor/guest'},
+  {label: '客车', value: 'bus', url: '/screen/kouan-run-monitor/bus'},
+  {label: '货运', value: 'goods', url: '/screen/kouan-run-monitor/goods'},
+]
+const dayCpt = computed(() => {
+  const d = new Date().getDay()
+  let str = ''
+  switch (d) {
+    case 0: str = '星期日'
+      break
+    case 1: str = '星期一'
+      break
+    case 2: str = '星期二'
+      break
+    case 3: str = '星期三'
+      break
+    case 4: str = '星期四'
+      break
+    case 5: str = '星期五'
+      break
+    case 6: str = '星期六'
+      break
+  }
+  return str
+})
+</script>
+
+<style lang="scss" scoped>
+.kouan-run-monitor-head {
+  color: #ffffff;
+  width: 100%;
+  height: 60px;
+  display: flex;
+  justify-content: center;
+  position: relative;
+  >img {
+    z-index: 1;
+    width: 100%;
+    position: absolute;
+  }
+  .head-left {
+    z-index: 2;
+    margin-right: auto;
+    margin-top: 18px;
+    margin-left: 20px;
+    gap: 20px;
+    display: flex;
+    .head-left-tab-item {
+      background-image: url("../img/tab.png");
+      background-size: 100% 100%;
+      width: 108px;
+      height: 39px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      color: rgba(255, 255, 255, 0.5);
+      font-family: YouSheBiaoTiHei;
+      font-size: 24px;
+      letter-spacing: 4px;
+      &.active {
+        background-image: url("../img/tab-active.png");
+        color: #ffffff;
+      }
+    }
+  }
+  .head-center {
+    z-index: 2;
+    position: absolute;
+    font-family: YouSheBiaoTiHei, YouSheBiaoTiHei;
+    font-weight: 400;
+    font-size: 50px;
+    color: #E7F5FF;
+    letter-spacing: 2px;
+    text-shadow: 0px 20px 30px #0091FF, 0px 0px 4px #0D74C2;
+    line-height: 90px;
+  }
+  .head-right {
+    margin-top: 14px;
+    margin-right: 30px;
+    height: fit-content;
+    margin-left: auto;
+    display: flex;
+    align-items: center;
+    gap: 20px;
+    .head-right-time {
+      font-size: 34px;
+      font-weight: bold;
+    }
+    .head-right-date {
+      font-size: 14px;
+    }
+  }
+}
+</style>

+ 95 - 0
src/views/screen/kouan-run-monitor/components/normal.scss

@@ -0,0 +1,95 @@
+.__main {
+  color: #ffffff;
+  width: 100%;
+  height: 100%;
+  background-size: 100% 100%;
+  display: flex;
+  flex-direction: column;
+  >.__content {
+    z-index: 2;
+    flex: 1;
+    padding: 24px;
+    display: flex;
+    gap: 24px;
+    >.__left {
+      width: 404px;
+    }
+    >.__center {
+      flex: 1;
+    }
+    >.__right {
+      width: 404px;
+    }
+  }
+}
+.__block-1 {
+  display: flex;
+  flex-direction: column;
+  >.__title {
+    height: 45px;
+    width: 404px;
+    font-weight: bold;
+    font-size: 22px;
+    padding-left: 44px;
+    position: relative;
+    background: linear-gradient(180deg, rgb(212, 237, 243), rgb(176, 181, 182));
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    &:before {
+      content: '';
+      width: 100%;
+      height: 100%;
+      background-image: url("@/views/screen/kouan-run-monitor/img/block-head.png");
+      background-size: auto 100%;
+      background-position-x: -22px;
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: -1;
+    }
+  }
+  >.__block-content {
+    flex: 1;
+    background-image: url("@/views/screen/kouan-run-monitor/img/block-bg.png");
+    background-size: 100% 100%;
+  }
+}
+.__block-2 {
+  display: flex;
+  flex-direction: column;
+  >.__title {
+    width: fit-content;
+    height: 29px;
+    display: flex;
+    align-items: center;
+    font-weight: 400;
+    font-size: 14px;
+    color: #FFFFFF;
+    position: relative;
+    padding-left: 10px;
+    padding-right: 50px;
+    &:hover {
+      cursor: pointer;
+    }
+    .svg-icon {
+      margin-left: 4px;
+    }
+    &:before {
+      content: '';
+      width: 100%;
+      height: 29px;
+      background-image: url("@/views/screen/kouan-run-monitor/img/block-head-2.png");
+      background-size: 100% 100%;
+      position: absolute;
+      top: 0;
+      left: 0;
+      z-index: -1;
+    }
+  }
+  >.__block-content {
+    flex: 1;
+    background: #122649;
+    border: 1px solid #0D3467;
+    padding: 12px;
+  }
+}

+ 21 - 0
src/views/screen/kouan-run-monitor/goods-index.vue

@@ -0,0 +1,21 @@
+<template>
+  <div class="__main">
+    <headCom tab="goods"/>
+    旅客
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+import headCom from './components/head.vue'
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({})
+</script>
+
+<style lang="scss" scoped>
+@use "./components/normal";
+.__main {
+  background-image: url("./img/goods-bg.png");
+}
+</style>

+ 104 - 0
src/views/screen/kouan-run-monitor/guest-index.vue

@@ -0,0 +1,104 @@
+<template>
+  <div class="__main">
+    <headCom tab="guest"/>
+    <div class="__content">
+      <div class="__left">
+        <div class="__block-1 txts">
+          <div class="__title">通行态势
+            <div class="status">
+              <img src="./img/run-status-error.png"/>
+            </div>
+          </div>
+          <div class="__block-content">
+            <div class="total">
+              <div>
+                计划今日离岛旅客
+                <cardNumber :value="564" :min="5" unit="人"/>
+              </div>
+              <div>
+                实际今日离岛旅客
+                <cardNumber :value="564" :min="5" unit="人"/>
+              </div>
+            </div>
+            <div class="__block-2 video">
+              <div class="__title">视频监控点位 <SvgIcon name="arrow_2" rotate="90" color="#ffffff" size="12"/></div>
+              <div class="__block-content">
+                <div class="play"></div>
+                <div class="page">
+                  <el-pagination
+                    :current-page="state.videoParams.pageNum"
+                    :page-size="state.videoParams.pageSize"
+                    layout="prev, pager, next"
+                    :total="state.videoParams.total"
+                    size="small"
+                    @current-change="onVideoPage"
+                  />
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="__center"></div>
+      <div class="__right"></div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import {getCurrentInstance, reactive} from "vue";
+import headCom from './components/head.vue'
+import cardNumber from '@/views/screen/components/card-number/index.vue'
+
+const {proxy} = getCurrentInstance()
+const state: any = reactive({
+  videoParams: {
+    pageNum: 1,
+    pageSize: 2,
+    total: 0
+  }
+})
+const onVideoPage = (val) => {
+  console.log(val)
+}
+</script>
+
+<style lang="scss" scoped>
+@use "./components/normal";
+.__main {
+  background-image: url("./img/guest-bg.png");
+}
+.txts {
+  width: 100%;
+  height: 100%;
+  .status {
+    position: absolute;
+    top: -6px;
+    left: 140px;
+    width: 30px;
+    height: 19px;
+    >img {
+      height: 100%;
+      width: 100%;
+    }
+  }
+  .__block-content {
+    padding: 18px;
+    .total {
+      display: flex;
+      font-weight: 500;
+      font-size: 16px;
+      color: #FFFFFF;
+      >div {
+        flex: 1;
+        >div {
+          margin-top: 10px;
+        }
+      }
+    }
+    .video {
+      margin-top: 20px;
+    }
+  }
+}
+</style>

二進制
src/views/screen/kouan-run-monitor/img/block-bg.png


二進制
src/views/screen/kouan-run-monitor/img/block-head-2.png


二進制
src/views/screen/kouan-run-monitor/img/block-head.png


二進制
src/views/screen/kouan-run-monitor/img/bus-bg.png


二進制
src/views/screen/kouan-run-monitor/img/goods-bg.png


二進制
src/views/screen/kouan-run-monitor/img/guest-bg.png


二進制
src/views/screen/kouan-run-monitor/img/header.png


二進制
src/views/screen/kouan-run-monitor/img/run-status-error.png


二進制
src/views/screen/kouan-run-monitor/img/run-status-normal.png


二進制
src/views/screen/kouan-run-monitor/img/run-status-warning.png


二進制
src/views/screen/kouan-run-monitor/img/tab-active.png


二進制
src/views/screen/kouan-run-monitor/img/tab.png