longyvfengyun
2023-09-28 a350f73edb771cf38bf78188a1f27c42afba5038
驾驶行为页面修改
10个文件已修改
6个文件已添加
660 ■■■■■ 已修改文件
package-lock.json 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/video-content.jpeg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mapJson/map_config.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FlexBox.vue 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/echarts/hdwChart.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/echarts/options/gradientLine.js 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/echarts/options/rosePie.js 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/echarts/options/waterPie.js 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/pageMenu.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/home.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mainLayout/components/pageHeader.vue 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mainLayout/index.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mainLayout/js/headerInfo.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/user/drivingAnalysis.vue 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -10,6 +10,7 @@
      "dependencies": {
        "@element-plus/icons-vue": "^2.1.0",
        "echarts": "^5.4.3",
        "echarts-liquidfill": "^3.1.0",
        "element-plus": "^2.3.14",
        "less": "^4.2.0",
        "less-loader": "^11.1.3",
@@ -1203,6 +1204,14 @@
      "dependencies": {
        "tslib": "2.3.0",
        "zrender": "5.4.4"
      }
    },
    "node_modules/echarts-liquidfill": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-3.1.0.tgz",
      "integrity": "sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==",
      "peerDependencies": {
        "echarts": "^5.0.1"
      }
    },
    "node_modules/echarts/node_modules/tslib": {
@@ -3426,6 +3435,12 @@
        }
      }
    },
    "echarts-liquidfill": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-3.1.0.tgz",
      "integrity": "sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw==",
      "requires": {}
    },
    "electron-to-chromium": {
      "version": "1.4.526",
      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.526.tgz",
package.json
@@ -10,6 +10,7 @@
  "dependencies": {
    "@element-plus/icons-vue": "^2.1.0",
    "echarts": "^5.4.3",
    "echarts-liquidfill": "^3.1.0",
    "element-plus": "^2.3.14",
    "less": "^4.2.0",
    "less-loader": "^11.1.3",
src/assets/images/video-content.jpeg
src/assets/mapJson/map_config.js
@@ -3,7 +3,7 @@
  "elementType": "geometry",
  "stylers": {
    "visibility": "on",
    "color": "#091220ff"
    "color": "#011f39"
  }
}, {
  "featureType": "water",
src/components/FlexBox.vue
New file
@@ -0,0 +1,106 @@
<script setup>
    import {computed} from "vue";
    const props = defineProps({
        type: {
            type: String,
            default: "",
        },
        title: {
            type: String,
            default: "",
        },
        noHeader: {
            type: Boolean,
            default: false,
        },
        noHeaderBg: {
            type: Boolean,
            default: false,
        },
        size: {
            type: String,
            default: "",
        },
    });
    const sizeClass = computed(()=>{
        let size = props.size;
        let result = "";
        switch (size) {
            case "mini":
                result = "flex-box-mini";
                break;
        }
        return result;
    });
</script>
<template>
    <div class="flex-box">
        <div class="flex-box-border border-top-left"></div>
        <div class="flex-box-border border-top-right"></div>
        <div class="flex-box-border border-bottom-left"></div>
        <div class="flex-box-border border-bottom-right"></div>
        <div class="flex-box-header" v-if="!noHeader">
            <slot name="header"></slot>
        </div>
        <div class="flex-box-body">
            <slot></slot>
        </div>
        <div class="flex-box-footer">
            <slot name="footer"></slot>
        </div>
    </div>
</template>
<style lang="less" scoped>
@border-color: #00feff;
@size: 32px;
.flex-box {
    position: relative;
    display: flex;
    flex-direction: column;
    height: 100%;
    background-image: radial-gradient(#151f4140, #3667ec40);
    >.flex-box-border {
        position: absolute;
        z-index: 9;
        width: 20px;
        height: 20px;
        box-sizing: border-box;
        &.border-top-left {
            top: 0;
            left: 0;
            border-top: 2px solid @border-color;
            border-left: 2px solid @border-color;
        }
        &.border-top-right {
            top: 0;
            right: 0;
            border-top: 2px solid @border-color;
            border-right: 2px solid @border-color;
        }
        &.border-bottom-left {
            bottom: 0;
            left: 0;
            border-bottom: 2px solid @border-color;
            border-left: 2px solid @border-color;
        }
        &.border-bottom-right {
            bottom: 0;
            right: 0;
            border-bottom: 2px solid @border-color;
            border-right: 2px solid @border-color;
        }
    }
    >.flex-box-body {
        flex: 1;
    }
}
</style>
src/components/echarts/hdwChart.vue
@@ -3,6 +3,7 @@
import "./transparent";
import usePageMenuStore from "@/stores/pageMenu";
import * as echarts from "echarts";
import "echarts-liquidfill";
const pageMenu = usePageMenuStore()
const hdwChart = ref({});
let chart = "";
src/components/echarts/options/gradientLine.js
New file
@@ -0,0 +1,113 @@
import * as echarts from 'echarts';
const getGradientLineOption = ()=> {
  return {
    tooltip: {},
    grid: {
      top: '10%',
      left: '1%',
      right: '1%',
      bottom: '8%',
      containLabel: true,
    },
    legend: {
      show: false,
    },
    xAxis: [{
      type: 'category',
      boundaryGap: true,
      axisLine: { //坐标轴轴线相关设置。数学上的x轴
        show: true,
        lineStyle: {
          color: '#f9f9f9'
        },
      },
      axisLabel: { //坐标轴刻度标签的相关设置
        textStyle: {
          color: '#d1e6eb',
          margin: 15,
        },
      },
      axisTick: {
        show: false,
      },
      data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', ],
    }],
    yAxis: [{
      type: 'value',
      min: 0,
      // max: 140,
      splitNumber: 7,
      splitLine: {
        show: true,
        lineStyle: {
          color: '#0a3256'
        }
      },
      axisLine: {
        show: true,
      },
      axisLabel: {
        margin: 20,
        textStyle: {
          color: '#d1e6eb',
        },
      },
      axisTick: {
        show: false,
      },
    }],
    series: [
      {
        name: '注册总量',
        type: 'line',
        // smooth: true, //是否平滑曲线显示
        //             symbol:'circle',  // 默认是空心圆(中间是白色的),改成实心圆
        showAllSymbol: true,
        symbol: 'emptyCircle',
        symbolSize: 6,
        lineStyle: {
          normal: {
            color: "#28ffb3", // 线条颜色
          },
          borderColor: '#f0f'
        },
        label: {
          show: false,
          position: 'top',
          textStyle: {
            color: '#fff',
          }
        },
        itemStyle: {
          normal: {
            color: "#28ffb3",
          }
        },
        tooltip: {
          show: false
        },
        areaStyle: { //区域填充样式
          normal: {
            //线性渐变,前4个参数分别是x0,y0,x2,y2(范围0~1);相当于图形包围盒中的百分比。如果最后一个参数是‘true’,则该四个值是绝对像素位置。
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
              offset: 0,
              color: 'rgba(0,154,120,1)'
            },
              {
                offset: 1,
                color: 'rgba(0,0,0, 0)'
              }
            ], false),
            shadowColor: 'rgba(53,142,215, 0.9)', //阴影颜色
            shadowBlur: 20 //shadowBlur设图形阴影的模糊大小。配合shadowColor,shadowOffsetX/Y, 设置图形的阴影效果。
          }
        },
        data: [393, 438, 485, 631, 689, 824, 987]
      },
    ]
  }
}
export default getGradientLineOption;
src/components/echarts/options/rosePie.js
New file
@@ -0,0 +1,92 @@
const getRosePieOption = ()=>{
  return {
    title: {
      text: '',
      left: 'center',
      top: 20,
      textStyle: {
        color: '#ccc'
      }
    },
    tooltip: {
      trigger: 'item',
      formatter: "{b} : {c} ({d}%)"
    },
    visualMap: {
      show: false,
      min: 500,
      max: 600,
      inRange: {
        //colorLightness: [0, 1]
      }
    },
    series: [
      {
        name: '访问来源',
        type: 'pie',
        radius: '50%',
        center: ['50%', '50%'],
        color: ['rgb(131,249,103)', '#FBFE27', '#FE5050', '#1DB7E5'], //'#FBFE27','rgb(11,228,96)','#FE5050'
        data: [{
          value: 285,
          name: '黑名单查询'
        },
          {
            value: 410,
            name: '红名单查询'
          },
          {
            value: 274,
            name: '法人行政处罚'
          },
          {
            value: 235,
            name: '其它查询'
          }
        ].sort(function(a, b) {
          return a.value - b.value
        }),
        roseType: 'radius',
        label: {
          normal: {
            formatter: ['{c|{c}次}', '{b|{b}}'].join('\n'),
            rich: {
              c: {
                color: 'rgb(241,246,104)',
                fontSize: 20,
                fontWeight:'bold',
                lineHeight: 5
              },
              b: {
                color: 'rgb(98,137,169)',
                fontSize: 15,
                height: 40
              },
            },
          }
        },
        labelLine: {
          normal: {
            lineStyle: {
              color: 'rgb(98,137,169)',
            },
            smooth: 0.2,
            length: 10,
            length2: 20,
          }
        },
        itemStyle: {
          normal: {
            shadowColor: 'rgba(0, 0, 0, 0.8)',
            shadowBlur: 50,
          }
        }
      }
    ]
  }
}
export default getRosePieOption;
src/components/echarts/options/waterPie.js
New file
@@ -0,0 +1,66 @@
const getWaterOption = ()=>{
  let value = 0.45;
  return {
    title: [
      {
        text: '',
        textStyle: {
          fontSize: 14,
          fontWeight: '100',
          color: '#5dc3ea',
          lineHeight: 16,
          textAlign: 'center',
        },
      },
    ],
    series: [
      {
        type: 'liquidFill',
        radius: '70%',
        center: ['50%', '50%'],
        color: [
          {
            type: 'linear',
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              {
                offset: 0,
                color: '#446bf5',
              },
              {
                offset: 1,
                color: '#2ca3e2',
              },
            ],
            globalCoord: false,
          },
        ],
        data: [value, value], // data个数代表波浪数
        backgroundStyle: {
          borderWidth: 1,
          color: 'RGBA(51, 66, 127, 0.7)',
        },
        label: {
          normal: {
            textStyle: {
              fontSize: 16,
              color: '#fff',
            },
          },
        },
        outline: {
          // show: false
          borderDistance: 0,
          itemStyle: {
            borderWidth: 2,
            borderColor: '#112165',
          },
        },
      },
    ],
  };
}
export default getWaterOption;
src/router/routes.js
@@ -2,6 +2,7 @@
  {
    path: "/login",
    name: "login",
    meta: {},
    component: () => import('../views/login.vue')
  },
  {
@@ -9,25 +10,36 @@
    name: 'mainLayout',
    component: () => import('../views/mainLayout/index.vue'),
    redirect: '/home',
    meta: {},
    children: [
      {
        path: "home",
        name: "首页",
        meta: {
          isTechPage: true,
          title: "动力电池安全检测大数据分析平台"
        },
        component: () => import("../views/home.vue"),
      },
      {
        path: "user/drivingAnalysis",
        name: "驾驶行为分析图",
        meta: {
          isTechPage: true,
          title: "驾驶行为分析系统"
        },
        component: () => import("../views/user/drivingAnalysis.vue"),
      },
      {
        path: "user/boxList",
        name: "盒子列表",
        meta: {},
        component: () => import("../views/user/boxList.vue"),
      },
      {
        path: "user/videoList",
        name: "摄像头列表",
        meta: {},
        component: () => import("../views/user/videoList.vue"),
      },
    ]
src/stores/pageMenu.js
@@ -3,11 +3,22 @@
const usePageMenuStore = defineStore('pageMenu',()=>{
  const isCollapse = ref(false);
  const sysTitle = ref("");
  const isTechPage = ref(false);
  function changeCollapse(state) {
    isCollapse.value = state;
  }
  return {isCollapse, changeCollapse};
  function changeSysTitle(state) {
    sysTitle.value = state;
  }
  function changeIsTechPage(state) {
    isTechPage.value = state;
  }
  return {isCollapse, changeCollapse, sysTitle, changeSysTitle, isTechPage, changeIsTechPage};
});
export default usePageMenuStore;
src/views/home.vue
@@ -26,6 +26,7 @@
}
onMounted(()=>{
    const boxGaugeOption = getGaugeOption(10, 90, "今日在线盒子数");
    boxGauge.value.setOption(boxGaugeOption);
@@ -64,9 +65,9 @@
                </div>
            </div>
            <div class="baidu-map-content">
                <div class="baidu-map-tools-right" v-if="!isFullScreen">
                    <el-button type="primary" @click="changeScreenState" :icon="FullScreen" />
                </div>
<!--                <div class="baidu-map-tools-right" v-if="!isFullScreen">-->
<!--                    <el-button type="primary" @click="changeScreenState" :icon="FullScreen" />-->
<!--                </div>-->
                <div class="baidu-map-float">
                    <div class="box-container">
                        <div class="box-container-top">
src/views/mainLayout/components/pageHeader.vue
@@ -1,8 +1,10 @@
<script setup>
import {ref} from "vue";
import {ref, computed, watch} from "vue";
import {ArrowDown, ArrowUp, Expand, Fold} from "@element-plus/icons-vue";
import usePageMenuStore from "@/stores/pageMenu";
import slideMenu from "@/views/mainLayout/js/slideMenu";
import headerInfo from "@/views/mainLayout/js/headerInfo";
headerInfo();
const isVisible = ref(false);
const visibleChange = (state)=>{
    isVisible.value = state;
@@ -12,17 +14,28 @@
const changeMenuState = ()=>{
    pageMenuStore.changeCollapse(!isCollapse.value);
}
const isTechPage = computed(()=>{
    return pageMenuStore.isTechPage;
});
const sysTitle = computed(()=>{
    return pageMenuStore.sysTitle;
});
</script>
<template>
    <div class="main-header-wrapper">
    <div class="main-header-wrapper" :class="{'is-tech-page': isTechPage}">
        <span class="menu-state-icon" @click="changeMenuState">
            <el-icon size="20">
                <Fold v-if="!isCollapse" />
                <Expand v-else/>
            </el-icon>
        </span>
        <div class="main-header-wrapper-content"></div>
        <div class="main-header-wrapper-content">
            <span v-if="isTechPage">
                {{ sysTitle }}
            </span>
        </div>
        <div class="page-header-right">
            <div class="hdw-avatar">
                <el-dropdown @visible-change="visibleChange">
@@ -51,12 +64,14 @@
<style lang="less" scoped>
.main-header-wrapper {
    display: flex;
    background-color: #FFFFFF;
    padding: 8px 8px;
    color: #000000;
    .main-header-wrapper-content {
        flex: 1;
        text-align: center;
        font-size: 1.5rem;
        font-weight: bold;
    }
    .menu-state-icon {
        display: inline-block;
        text-align: center;
@@ -64,7 +79,20 @@
        cursor: pointer;
    }
    .menu-state-icon:hover {
        background-color: #f7f7f7;
        background-color: #b0c7f1;
    }
    &.is-tech-page {
        padding: 16px 8px;
        background: #011f39ff url("@/assets/images/header_bg.png") no-repeat;
        background-size: 100% 100%;
        color: #00feff;
        .menu-state-icon:hover {
            background-color: #4ba1fa;
        }
        .hdw-avatar-wrapper {
            color: #00feff;
        }
    }
}
src/views/mainLayout/index.vue
@@ -49,7 +49,7 @@
                        :router="true"
                        text-color="#FFFFFF"
                        active-text-color="#FFFFFF"
                        background-color="#001529"
                        background-color="#01182c"
                        :default-active="menuActive"
                        :unique-opened="true"
                        class="el-menu-vertical"
@@ -108,7 +108,7 @@
        display: flex;
        flex-direction: column;
        height: 100%;
        background-color: #001529;
        background-color: #01182c;
        .slide-header {
            padding: 8px 0;
            color: #FFFFFF;
src/views/mainLayout/js/headerInfo.js
New file
@@ -0,0 +1,23 @@
import {useRoute } from "vue-router";
import {onMounted, watch} from "vue";
import usePageMenuStore from "@/stores/pageMenu";
const headerInfo = ()=>{
  const route = useRoute();
  const pageMenu = usePageMenuStore();
  const changeHeaderInfo = ()=>{
    const meta = route.meta;
    const isTechPage = !!meta.isTechPage;
    const sysTitle = meta.title;
    pageMenu.changeIsTechPage(isTechPage);
    pageMenu.changeSysTitle(sysTitle);
  }
  onMounted(()=>{
    changeHeaderInfo();
  });
  watch(route, ()=>{
    changeHeaderInfo();
  });
}
export default headerInfo;
src/views/user/drivingAnalysis.vue
@@ -1,11 +1,172 @@
<script setup>
import videoContent from "@/assets/images/video-content.jpeg";
import FlexBox from "@/components/FlexBox.vue";
import ChartBox from "@/components/chartBox.vue";
import {onMounted, ref} from "vue";
import HdwChart from "@/components/echarts/hdwChart.vue";
import getWaterOption from "@/components/echarts/options/waterPie";
import getGradientLineOption from "@/components/echarts/options/gradientLine";
import getRosePieOption from "@/components/echarts/options/rosePie";
const carPie = ref(null);
const alarmLine = ref(null);
const rosePie = ref(null);
onMounted(()=>{
    const carPieOption = getWaterOption();
    carPie.value.setOption(carPieOption);
    const alarmLineOption = getGradientLineOption();
    alarmLine.value.setOption(alarmLineOption);
    const rosePieOption = getRosePieOption();
    rosePie.value.setOption(rosePieOption);
});
</script>
<template>
    <div></div>
    <div class="driving-box-wrapper">
        <div class="content-wrapper left">
            <div class="alarm-bar-wrapper">
                <flex-box>
                    <div class="flex-box-content">
                        <chart-box title="实时统计"></chart-box>
                    </div>
                </flex-box>
            </div>
            <div class="car-wrapper">
                <flex-box>
                    <div class="flex-box-content">
                        <chart-box title="车辆评分">
                            <div class="car-content">
                                <div class="car-content-item">
                                    <hdw-chart ref="carPie"></hdw-chart>
                                </div>
                                <div class="car-content-item">
                                    <div class="content-details-wrapper">
                                        <div class="content-details-content">
                                            <div class="car-number">京BHG870</div>
                                            <div class="car-grade">45分</div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </chart-box>
                    </div>
                </flex-box>
            </div>
        </div>
        <div class="content-wrapper middle">
            <div class="video-wrapper">
                <flex-box>
                    <img :src="videoContent" alt="">
                </flex-box>
            </div>
            <div class="alarm-line-wrapper">
                <flex-box>
                    <div class="flex-box-content">
                        <chart-box title="近30天预警趋势">
                            <hdw-chart ref="alarmLine"></hdw-chart>
                        </chart-box>
                    </div>
                </flex-box>
            </div>
        </div>
        <div class="content-wrapper right">
            <div class="alarm-pie-wrapper">
                <flex-box>
                    <div class="flex-box-content">
                        <chart-box title="本月违规行为统计">
                            <hdw-chart ref="rosePie"></hdw-chart>
                        </chart-box>
                    </div>
                </flex-box>
            </div>
            <div class="alarm-bar-wrapper">
                <flex-box>
                    <div class="flex-box-content">
                        <chart-box title="风险行为统计"></chart-box>
                    </div>
                </flex-box>
            </div>
        </div>
    </div>
</template>
<style scoped lang="less">
.driving-box-wrapper {
    display: flex;
    height: 100%;
    background: url("@/assets/images/dw_bg.jpg") no-repeat;
    background-size: 100% 100%;
    .content-wrapper {
        height: 100%;
        &.left {
            width: 25%;
            .alarm-bar-wrapper {
                padding: 8px;
                height: 70%;
            }
            .car-wrapper {
                padding: 8px;
                height: 30%;
            }
        }
        &.middle {
            flex: 1;
            .video-wrapper {
                padding: 8px;
                height: 70%;
                img {
                    width: auto;
                    height: 100%;
                }
            }
            .alarm-line-wrapper {
                padding: 8px;
                height: 30%;
            }
        }
        &.right {
            width: 25%;
            .alarm-pie-wrapper {
                padding: 8px;
                height: 50%;
            }
            .alarm-bar-wrapper {
                padding: 8px;
                height: 50%;
            }
        }
    }
}
.flex-box-content {
    height: 100%;
    padding: 8px;
}
.car-content {
    display: flex;
    height: 100%;
    .car-content-item {
        height: 100%;
        flex: 1;
    }
}
.content-details-wrapper {
    display: flex;
    height: 100%;
    justify-content: center;
    align-items: center;
    .content-details-content {
        text-align: center;
        color: #FFFFFF;
        font-size: 24px;
        font-weight: bold;
        .car-number {
            margin-bottom: 8px;
        }
        .car-grade {
            color: #00FEFF;
        }
    }
}
</style>