cyy пре 1 година
родитељ
комит
0a11500536

+ 203 - 0
src/views/business/trainManagement/components/jobPlanChart.vue

@@ -0,0 +1,203 @@
+<template>
+  <div class="statisticsPage" :style="{width:width,height:height}">
+    <div style="height:8%;font-size:28px;font-weight: 600;"> {{ title }} </div>
+    <div style="height:92%;display:flex">
+      <div style="width:30%;display: flex;margin-top: 5%;">
+        <div style="width: 100%;display:flex;border: 1px solid #fff;padding: 5%;height: 50%;display: flex;align-items: center;flex-flow: column;">
+          <div style="width: 100%;height:20%;font-size: 20px;">自动创建培训计划</div>
+          <div style="display:flex;height: 90%;display: flex;align-items: center;width:100%">
+            <div style="width: 46%;display:flex;flex-flow: column;height: 100%;font-size: 20px;">
+              <div style="line-height: 250%;">{{data.num}}</div>
+              <div>占比{{data.proportion}}%</div>
+            </div>
+            <div :id="'jobPie'+id" :style="{height:'100%',width:'64%'}"/>
+          </div>
+        </div>
+      </div>
+      <div :id="'job'+id" :style="{height:'100%',width:'70%'}"/>
+    </div>
+  </div>
+</template>
+
+<script>
+  import * as echarts from 'echarts'
+  import { getFormatDate } from '../utils/config.js'
+
+  export default {
+    props: {
+      value: {
+        type: Array,
+      },
+      width:{
+        type:String,
+        default:"100%"
+      },
+      height:{
+        type:String,
+        default: "100%"
+      },
+      id:{
+        type:Number,
+        default:0
+      },
+      click:{
+        type:String,
+        default:'true'
+      },
+      colorw:{
+        type:String,
+        default:'#fff'
+      },
+      title:{
+        type: String
+      },
+      data: {
+        type: Object,
+      }
+    },
+    data () {
+      return {
+      }
+    },
+    watch: {
+        value: {
+            handler () {
+                this.drawLine()
+            },
+            deep: true
+        },
+        data: {
+            handler () {
+                this.drawLinePie()
+            },
+            deep: true
+        }
+    },
+    mounted(){
+      setTimeout(() => {
+        this.drawLine()
+        this.drawLinePie()
+      }, 100);
+      
+    },
+    methods: {
+      drawLine(){
+        let xData = []
+        let yData = []
+        this.value.forEach(e => {
+          xData.push(getFormatDate('string', 5, 10, e.date)+'\n'+e.week)
+          yData.push(e.value)
+        })
+        const that = this
+        let job = echarts.init(document.getElementById('job'+this.id))
+        let option;
+        option = {
+          title: {
+            text: '近一周计划发布',
+            left: 'left',
+            textStyle:{ fontSize:20,color: this.colorw }
+          },
+          grid: {
+            left: '5%',
+            right: '3%',
+            bottom: '15%',
+            top: '15%'
+          },
+          tooltip: {
+            trigger: 'axis',
+            formatter: function (params) {
+              return `${that.value[params[0].dataIndex].date} <br /> ${params[0].marker} ${params[0].data}`
+            }
+          },
+          xAxis: {
+            type: 'category',
+            boundaryGap: false,
+            data: xData,
+            axisLabel: {
+                color: '#fff'
+            }
+          },
+          yAxis: {
+            type: 'value',
+            axisLabel: {
+                color: '#fff'
+            },
+            splitLine:{
+              show:true,
+              lineStyle:{
+                  type: [15,8],
+                  color: ['#fff'],
+              }
+            }
+          },
+          series: [
+            {
+              data: yData,
+              type: 'line',
+              smooth: true,
+              itemStyle: {
+                color: 'rgba(24,146,234,1)'
+              },
+              areaStyle: {
+                opacity: 0.8,
+                color: 'rgba(24,146,234,0.5)'
+              }
+            }
+          ]
+       };
+       option && job.setOption(option);
+      },
+      drawLinePie(){
+        const that = this
+        let jobPie = echarts.init(document.getElementById('jobPie'+this.id))
+        let option
+        option = {
+          tooltip: {
+            show: false,
+            trigger: 'item'
+          },
+          series: [
+            {
+              name: 'Access From',
+              type: 'pie',
+              radius: ['60%', '90%'],
+              avoidLabelOverlap: false,
+              label: {
+                show: false,
+                position: 'center'
+              },
+              itemStyle:{
+                color: function(params) {
+                  let colorList = ['#1892ea','#e9e9e9'];
+                  return colorList[params.dataIndex];
+                }
+              },
+              emphasis: {
+                scale: false
+              },
+              labelLine: {
+                show: false
+              },
+              data: [
+                { value: this.data.proportion, name: 'Search Engine' },
+                { value: 100-this.data.proportion, name: 'Direct' }
+              ]
+            }
+          ]
+       }
+       option && jobPie.setOption(option)
+      }
+    }
+  }
+</script>
+<style scoped>
+  /* #zlmbPie:hover{
+    transition: all 0.5s;
+    transform:scale(1.03);
+  } */
+  .statisticsPage{
+      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+      padding: 1%;
+      background-color: rgba(6, 30, 93, 0.5);
+  }
+</style>

+ 169 - 0
src/views/business/trainManagement/components/pieChart.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="statisticsPage" :style="{width:width,height:height}">
+    <div :id="'pie'+id" :style="{height:'100%'}"/>
+  </div>
+</template>
+
+<script>
+  import * as echarts from 'echarts'
+  import {GetTotality} from '../utils/config'
+  export default {
+    props: {
+      value: {
+        type: Array,
+      },
+      width:{
+        type:String,
+        default:"100%"
+      },
+      height:{
+        type:String,
+        default: "100%"
+      },
+      id:{
+        type:Number,
+        default:0
+      },
+      click:{
+        type:String,
+        default:'true'
+      },
+      colorw:{
+        type:String,
+        default:'#fff'
+      },
+      title:{
+        type: String
+      }
+    },
+    data () {
+      return {
+      }
+    },
+    watch: {
+        value: {
+            handler () {
+                this.drawLine()
+            },
+            deep: true
+        }
+    },
+    mounted(){
+      setTimeout(() => {
+        this.drawLine()
+      }, 100);
+      
+    },
+    methods: {
+      drawLine(){
+        const totality = GetTotality(this.value)
+        const that = this
+        let pie = echarts.init(document.getElementById('pie'+this.id))
+        let option;
+        option = {
+          title: {
+            text: this.title,
+            left: 'left',
+            textStyle:{ fontSize:28,color: this.colorw }
+          },
+          tooltip: {
+            trigger: 'item'
+          },
+          legend:{
+            type: 'scroll',
+            selectedMode: false,
+            orient: 'vertical',
+            itemWidth: 18, // 图例标记的图形宽度,默认为24
+            itemHeight: 18, // 图例标记的图形高度,默认为18
+            icon: 'circle',
+            right: '0',
+            top: '45',
+            formatter: function (name) {
+                let mid = that.value.find(i => i.name === name)
+                let rate = ((mid.value/totality)*100).toFixed(2)
+                let str = `{a|${name}} | {b|${rate}%}{c|${mid.value}}`
+                return str
+            },
+            textStyle: {
+              
+              color: '#fff',
+              // align: 'right',
+              rich: {
+                a: {
+                  width:120,
+                  align: 'left',
+                  fontSize: 16
+                },
+                b: {
+                  width:60,
+                  align: 'right',
+                  fontSize: 16,
+                  fontWeight: 300
+                },
+                c: {
+                  width:50,
+                  align: 'right',
+                  fontSize: 16
+                }
+              }
+            }
+          },
+          series: [
+            {
+              type: 'pie',
+              radius: ['45%', '70%'],
+              center: ['20%', '55%'],
+              label: {
+                show: true,
+                formatter: (data, type) => {
+                  let str = `{a|总培训数}\n\n {b|${totality}}` //这里对不同的内容进行标识 a,b,或者可以随便自己起个别的名字
+                  return str;
+                },
+                rich: { //在rich中对两个标识进行样式修改
+                  a: {
+                    fontSize: 16,
+                    fontWeight: 300
+                  },
+                  b: {
+                    fontSize: 28
+                  }
+                },
+                color: this.colorw,
+                position: 'center'
+              },
+              data: this.value,
+              labelLine: {
+                normal: {
+                    show: false,
+                },
+              },
+              // emphasis: {
+              //   label: {
+              //     show: true,
+              //     fontSize: '12px'
+              //   },
+              //   itemStyle: {
+              //     shadowBlur: 10,
+              //     shadowOffsetX: 0,
+              //     shadowColor: 'rgba(0, 0, 0, 0.5)'
+              //   }
+              // }
+            }
+          ]
+       }
+       option && pie.setOption(option);
+      }
+    }
+  }
+</script>
+<style scoped>
+  /* #zlmbPie:hover{
+    transition: all 0.5s;
+    transform:scale(1.03);
+  } */
+  .statisticsPage{
+      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+      padding: 1%;
+      background-color: rgba(6, 30, 93, 0.5);
+  }
+</style>

+ 143 - 0
src/views/business/trainManagement/components/preWorkChart.vue

@@ -0,0 +1,143 @@
+<template>
+  <div class="statisticsPage" :style="{width:width,height:height}">
+    <div :id="'pre'+id" :style="{height:'100%',width:'100%'}"/>
+  </div>
+</template>
+
+<script>
+  import * as echarts from 'echarts'
+  import { getFormatDate } from '../utils/config.js'
+  export default {
+    props: {
+      value: {
+        type: Array,
+      },
+      width:{
+        type:String,
+        default:"100%"
+      },
+      height:{
+        type:String,
+        default: "100%"
+      },
+      id:{
+        type:Number,
+        default:0
+      },
+      click:{
+        type:String,
+        default:'true'
+      },
+      colorw:{
+        type:String,
+        default:'#fff'
+      },
+      title:{
+        type: String
+      },
+      data: {
+        type: Array,
+      }
+    },
+    data () {
+      return {
+      }
+    },
+    watch: {
+        value: {
+            handler () {
+                this.drawLine()
+            },
+            deep: true
+        }
+    },
+    mounted(){
+      setTimeout(() => {
+        this.drawLine()
+      }, 100);
+    },
+    methods: {
+      drawLine(){
+        let xData = []
+        let yData = []
+        // let yData1 = []
+        // let yData2 = []
+        this.value.forEach(e => {
+          xData.push(e.date)
+          yData.push(e.num)
+          // yData1.push(e.numUn)
+          // yData2.push(e.numAll)
+        })
+        const that = this
+        let pre = echarts.init(document.getElementById('pre'+this.id))
+        let option
+        option = {
+          title: {
+            text: this.title,
+            left: 'left',
+            textStyle:{ fontSize:28,color: this.colorw }
+          },
+          grid: {
+            left: '3%',
+            right: '1%',
+            bottom: '10%'
+          },
+          tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+              type: 'cross',
+              crossStyle: {
+                color: '#999'
+              }
+            },
+          },
+          xAxis: {
+            type: 'category',
+            boundaryGap: true,
+            data: xData,
+            axisLabel: {
+                color: '#fff'
+            },
+            axisTick: {
+              alignWithLabel: true
+            }
+          },
+          yAxis: {
+            type: 'value',
+            axisLabel: {
+                color: '#fff'
+            },
+            splitLine:{
+              show:true,
+              lineStyle:{
+                  type: [15,8],
+                  color: ['#fff'],
+              }
+            }
+          },
+          series: [
+            {
+              // name: 'num',
+              type: 'bar',
+              barWidth: 20,
+              color: 'rgb(16,142,233)',
+              data: yData
+            }
+          ]
+       };
+       option && pre.setOption(option);
+      },
+    }
+  }
+</script>
+<style scoped>
+  /* #zlmbPie:hover{
+    transition: all 0.5s;
+    transform:scale(1.03);
+  } */
+  .statisticsPage{
+      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+      padding: 1%;
+      background-color: rgba(6, 30, 93, 0.5);
+  }
+</style>

+ 121 - 0
src/views/business/trainManagement/components/staffList.vue

@@ -0,0 +1,121 @@
+<template>
+    <div style="height:100%">
+        <div class="mb10 fontS">个人培训次数排名</div>
+        <div class="box mt10"  style="height:100%">
+            <div style="height:100%">
+                <dv-scroll-board
+                    :config="provinceConfirmedCountBoardConfig"
+                    style="width: 100%; height: 100%"
+                />
+            </div>
+        </div>
+    </div>
+  
+</template>
+
+<script>
+const initProvinceConfirmedCountBoardConfig = (resultList = []) => {
+  return {
+    columnWidth: [100, 240, 160],
+    data: resultList,
+    align: ["center"],
+    rowNum: 5,
+    headerBGC: "",
+    oddRowBGC: "",
+    evenRowBGC: "",
+    carousel: "single",
+  };
+};
+export default {
+    props: {
+        value: {
+            type: Array,
+        },
+    },
+    data () {
+        return {
+        provinceConfirmedCountBoardConfig:
+            initProvinceConfirmedCountBoardConfig(),
+        }
+    },
+
+  created () {
+    this.getBizBoardFn()
+  },
+
+  methods: {
+    // 当前最新作业
+    getBizBoardFn () {
+      this.queryProvinceDataList(this.value)
+    },
+    queryProvinceDataList (arr) {
+      this.setProvinceComfirmedCountBoardData(arr)
+    },
+    setProvinceComfirmedCountBoardData (areaList) {
+      if (areaList && areaList.length > 0) {
+        let resultList = areaList.map((item,i) => {
+            let mid = i > 2 ? `<span class="circleOption" >${i+1}</span>` : `<span class="circleOption indexStyle">${i+1}</span>`
+            return [
+                mid,
+                item.name,
+                `<div style="width:100%;text-align: right;">${item.num}</div>`,
+            ]
+        })
+        this.provinceConfirmedCountBoardConfig =
+          initProvinceConfirmedCountBoardConfig(resultList);
+      } else {
+        this.provinceConfirmedCountBoardConfig =
+          initProvinceConfirmedCountBoardConfig([])
+      }
+    },
+  }
+}
+</script>
+
+<style scoped  lang="scss">
+.box {
+  padding: 20px;
+  box-sizing: border-box;
+//   background-color: rgba(255, 255, 255, 0.1);
+  border-radius: 10px;
+}
+.fontS{
+    font-size: 20px;
+    font-weight: 600;
+}
+//修改的是下拉框选项内容上方的尖角
+::v-deep .el-popper .popper__arrow,
+.el-popper .popper__arrow::after {
+  display: none;
+}
+::v-deep .dv-scroll-board .header {
+  background: transparent !important;
+//   border-bottom: 2px solid #9ca3b3 !important;
+  border-radius: 0;
+}
+::v-deep .rows .ceil{
+    display: flex;
+    align-items: center;
+}
+::v-deep .indexStyle {
+    background-color: #fff;
+    color: #A3A3A3 !important;
+}
+::v-deep .circleOption{ 
+    align-items: center;
+    border-radius: 100%;
+    border: 1px solid;
+    cursor: pointer;
+    display: flex;
+    font-size: 14px;
+    font-weight: 400;
+    height: 20px;
+    justify-content: center;
+    line-height: 25px;
+    // margin: 0 20px 30px;
+    position: relative;
+    width: 20px;
+    border-color: #FAFAFA;
+    color: #fff;
+}
+</style>

+ 192 - 0
src/views/business/trainManagement/components/trainingStaffChart.vue

@@ -0,0 +1,192 @@
+<template>
+  <div class="statisticsPage" :style="{width:width,height:height}">
+    <div style="height:8%;font-size:28px;font-weight: 600;"> {{title}} </div>
+    <div style="height:90%;display:flex;justify-content: space-between;">
+      <div :id="'staff'+id" :style="{height:'100%',width:'76%'}"/>
+      <staff-list v-model="data" :style="{height:'80%',width:'22%'}"></staff-list>
+    </div>
+  </div>
+</template>
+
+<script>
+  import * as echarts from 'echarts'
+  import { getFormatDate } from '../utils/config.js'
+  export default {
+    components: {
+        StaffList: () => import('./staffList.vue')
+    },
+    props: {
+      value: {
+        type: Array,
+      },
+      width:{
+        type:String,
+        default:"100%"
+      },
+      height:{
+        type:String,
+        default: "100%"
+      },
+      id:{
+        type:Number,
+        default:0
+      },
+      click:{
+        type:String,
+        default:'true'
+      },
+      colorw:{
+        type:String,
+        default:'#fff'
+      },
+      title:{
+        type: String
+      },
+      data: {
+        type: Array,
+      }
+    },
+    data () {
+      return {
+      }
+    },
+    watch: {
+        value: {
+            handler () {
+                this.drawLine()
+            },
+            deep: true
+        }
+    },
+    mounted(){
+      setTimeout(() => {
+        this.drawLine()
+      }, 100);
+    },
+    methods: {
+      drawLine(){
+        let xData = []
+        let yData = []
+        let yData1 = []
+        let yData2 = []
+        this.value.forEach(e => {
+          xData.push(e.date)
+          yData.push(e.numReal)
+          yData1.push(e.numUn)
+          yData2.push(e.numAll)
+        })
+        const that = this
+        let staff = echarts.init(document.getElementById('staff'+this.id))
+        let option
+        option = {
+          grid: {
+            left: '3%',
+            right: '1%',
+            bottom: '20%',
+            top: '10%'
+          },
+          tooltip: {
+            trigger: 'axis',
+            axisPointer: {
+              type: 'cross',
+              crossStyle: {
+                color: '#999'
+              }
+            },
+            formatter: function (params) {
+              let str = `${that.value[params[0].dataIndex].date}`
+              params.forEach(item =>{
+                let nameNum = ''
+                if(item.seriesName === 'numUn'){
+                  nameNum = '未参加人数'
+                }else if(item.seriesName === 'numReal'){
+                  nameNum = '实际参训人数'
+                }else if(item.seriesName === 'numAll'){
+                  nameNum = '培训总人数'
+                }
+                str += `<br /> ${item.marker} ${nameNum}  ${item.data}`
+              })
+              return str
+            }
+          },
+          legend: {
+            data: ['numReal', 'numUn', 'numAll'],
+            textStyle: {
+              color: '#fff'
+            },
+            icon: 'circle',
+            bottom: 0,
+            formatter: function (name) {
+              if(name === 'numUn'){
+                return '未参加人数';
+              }else if(name === 'numReal'){
+                return '实际参训人数';
+              }else if(name === 'numAll'){
+                return '培训总人数';
+              }
+            }
+          },
+          xAxis: {
+            type: 'category',
+            boundaryGap: true,
+            data: xData,
+            axisLabel: {
+                color: '#fff'
+            },
+            axisTick: {
+              alignWithLabel: true
+            }
+          },
+          yAxis: {
+            type: 'value',
+            axisLabel: {
+                color: '#fff'
+            },
+            // boundaryGap:true,
+            splitLine:{
+              show:true,
+              lineStyle:{
+                  type: [15,8],
+                  color: ['#fff'],
+              }
+            }
+          },
+          series: [
+            {
+              name: 'numReal',
+              type: 'bar',
+              barWidth: 10,
+              color: 'rgb(78,203,115)',
+              data: yData
+            },
+            {
+              name: 'numUn',
+              type: 'bar',
+              barWidth: 10,
+              color: 'rgb(251,211,55)',
+              data: yData1
+            },
+            {
+              name: 'numAll',
+              type: 'line',
+              color: 'rgb(16,142,233)',
+              data: yData2
+            }
+          ]
+       };
+       option && staff.setOption(option);
+      },
+    }
+  }
+</script>
+<style scoped>
+  /* #zlmbPie:hover{
+    transition: all 0.5s;
+    transform:scale(1.03);
+  } */
+  .statisticsPage{
+      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+      padding: 1%;
+      background-color: rgba(6, 30, 93, 0.5);
+  }
+</style>

+ 349 - 0
src/views/business/trainManagement/constants/option.js

@@ -0,0 +1,349 @@
+import * as echarts from 'echarts'
+
+const rowLimit = (params, max) => {
+    let result = ''
+    // 一行显示几个字
+    const rowMax = max
+    const rowNumber = Math.ceil(params.length / rowMax)
+    // 超过 3 个字换行
+    if (params.length > 3) {
+        for (let p = 0; p < rowNumber; p++) {
+            let tempStr = ''
+            const start = p * rowMax
+            const end = start + rowMax
+            if (p === rowNumber - 1) {
+                tempStr = params.substring(start, params.length)
+            } else {
+                tempStr = params.substring(start, end) + '\n'
+            }
+            result += tempStr
+        }
+    } else {
+        result = params
+    }
+    return result
+}
+
+const basicChart = {
+    title: {
+        show: true,
+        text: '',
+        subtext: '',
+        textStyle: {
+            color: '#fff',
+            fontSize: 24,
+            fontWeight: '600'
+        },
+        subtextStyle: {
+            color: '#fff',
+            fontSize: 14,
+            fontWeight: '400',
+            align: 'center'
+        },
+        textAlign: 'center',
+        left: '50%',
+        top: '5px'
+    },
+    grid: {
+        top: '80px',
+        bottom: '30px'
+    },
+    xAxis: {
+        type: 'category',
+        data: [],
+        axisTick: {
+            alignWithLabel: true
+        },
+        axisLabel: {
+            style: {
+                fill: '#fff'
+            },
+            formatter (params) {
+                return rowLimit(params, 4)
+            }
+        },
+        axisLine: {
+            lineStyle: {
+                color: '#fff'
+            }
+        }
+    },
+    yAxis: {
+        type: 'value',
+        name: '',
+        nameTextStyle: {
+            color: '#fff',
+            fontSize: 14
+        },
+        splitLine: {
+            show: false
+        },
+        axisLine: {
+            lineStyle: {
+                color: '#fff'
+            }
+        }
+    },
+    series: [{
+        type: 'line',
+        name: '合格率',
+        data: [],
+        markLine: {
+            data: [
+                {
+                    yAxis: '',
+                    tooltip: {
+                        formatter: ''
+                    },
+                    label: {
+                        show: true, position: 'inside',
+                        color: '#83bff6',
+                        formatter: ''
+                    },
+                    lineStyle: {
+                        color: '#ff4757',
+                        type: 'dashed'
+                    }
+                }
+            ]
+        },
+        itemStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#83bff6' },
+                { offset: 0.5, color: '#188df0' },
+                { offset: 1, color: '#188df0' }
+            ])
+        },
+        emphasis: {
+            itemStyle: {
+                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#2378f7' },
+                    { offset: 0.7, color: '#2378f7' },
+                    { offset: 1, color: '#83bff6' }
+                ])
+            }
+        },
+        label: {
+            show: true,
+            position: 'top',
+            textStyle: {
+                color: '#fff',
+                fontSize: 14
+            },
+            formatter (params) {
+                return params.value ? params.value : ''
+            }
+        }
+    }],
+    tooltip: {
+        show: true,
+        trigger: 'axis',
+        formatter: '指标详情<br/>{b}月:{c}'
+    }
+}
+
+export const colors = [
+    '#d20962',
+    '#f47721',
+    '#7ac143',
+    '#00a78e',
+    '#00bce4',
+    '#7d3f98',
+    '#037ef3',
+    '#f85a40',
+    '#00c16e',
+    '#12CBC4',
+    '#b4a996',
+    '#7552cc',
+    '#67809f',
+    '#f19066'
+]
+
+export function* getRandomColor (shuffledColors) {
+    let index = 0
+    while (index < shuffledColors.length) {
+        yield shuffledColors[index]
+        index++
+    }
+}
+
+export const monthChartOption = basicChart
+
+export const quarterChartOption = {
+    ...basicChart,
+    series: [{
+        type: 'bar',
+        name: '',
+        data: [],
+        markLine: {
+            data: [
+                {
+                    yAxis: '',
+                    tooltip: {
+                        formatter: ''
+                    },
+                    label: {
+                        show: true, position: 'inside',
+                        color: '#83bff6',
+                        formatter: ''
+                    },
+                    lineStyle: {
+                        color: '#ff4757',
+                        type: 'dashed'
+                    }
+                }
+            ]
+        },
+        itemStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#83bff6' },
+                { offset: 0.5, color: '#188df0' },
+                { offset: 1, color: '#188df0' }
+            ])
+        },
+        emphasis: {
+            itemStyle: {
+                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#2378f7' },
+                    { offset: 0.7, color: '#2378f7' },
+                    { offset: 1, color: '#83bff6' }
+                ])
+            }
+        },
+        label: {
+            show: true,
+            position: 'top',
+            textStyle: {
+                color: '#fff',
+                fontSize: 14
+            },
+            formatter (params) {
+                return params.value ? params.value : ''
+            }
+        }
+    }],
+    tooltip: {
+        show: true,
+        trigger: 'axis',
+        formatter: '指标详情<br/>{b}:{c}'
+    }
+}
+
+export const yearChartOption = {
+    ...basicChart,
+    series: [{
+        type: 'bar',
+        name: '',
+        data: [],
+        markLine: {
+            data: [
+                {
+                    yAxis: '',
+                    tooltip: {
+                        formatter: ''
+                    },
+                    label: {
+                        show: true, position: 'inside',
+                        color: '#83bff6',
+                        formatter: ''
+                    },
+                    lineStyle: {
+                        color: '#ff4757',
+                        type: 'dashed'
+                    }
+                }
+            ]
+        },
+        itemStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                { offset: 0, color: '#83bff6' },
+                { offset: 0.5, color: '#188df0' },
+                { offset: 1, color: '#188df0' }
+            ])
+        },
+        emphasis: {
+            itemStyle: {
+                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#2378f7' },
+                    { offset: 0.7, color: '#2378f7' },
+                    { offset: 1, color: '#83bff6' }
+                ])
+            }
+        },
+        label: {
+            show: true,
+            position: 'top',
+            textStyle: {
+                color: '#fff',
+                fontSize: 14
+            },
+            formatter (params) {
+                return params.value ? params.value : ''
+            }
+        }
+    }],
+    tooltip: {
+        show: true,
+        trigger: 'axis',
+        formatter: '指标详情<br/>{b}年度:{c}'
+    }
+}
+
+export const lineChartOption = {
+    ...basicChart,
+    grid: {
+        top: '80px',
+        bottom: '30px',
+        left: '30px',
+        right: '30px'
+    }
+}
+
+export const barChartOption = {
+    ...basicChart,
+    grid: {
+        top: '80px',
+        bottom: '30px',
+        left: '30px',
+        right: '30px'
+    },
+    series: [
+        {
+            type: 'bar',
+            name: '中位数',
+            data: [],
+            barMaxWidth: '35px',
+            barStyle: {
+                fill: 'rgba(0, 186, 255, 0.4)'
+            },
+            itemStyle: {
+                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: "#83bff6" },
+                    { offset: 0.5, color: "#188df0" },
+                    { offset: 1, color: "#188df0" },
+                ])
+            },
+            emphasis: {
+                itemStyle: {
+                    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                        { offset: 0, color: "#2378f7" },
+                        { offset: 0.7, color: "#2378f7" },
+                        { offset: 1, color: "#83bff6" },
+                    ])
+                }
+            },
+            label: {
+                show: true,
+                position: 'top',
+                textStyle: {
+                    color: '#fff',
+                    fontSize: 14
+                },
+                formatter (params) {
+                    return params.value ? params.value : ''
+                }
+            }
+        },
+        ...basicChart.series
+    ]
+}

+ 275 - 0
src/views/business/trainManagement/constants/simulated.js

@@ -0,0 +1,275 @@
+export const hospitalSection = ['综合/质量管理组', '临检组', '生化组', '免疫组', '微生物组']
+
+export const dataObj = [
+    {
+        name: '技术',
+        value: 10
+    },
+    {
+        name: '质量管理',
+        value: 10
+    },
+    {
+        name: '体系文件修订',
+        value: 10
+    }
+]
+
+export const jobPlanObj = [
+    {
+        date: '2024-07-22',
+        value: 15
+    },
+    {
+        date: '2024-07-23',
+        value: 13
+    },
+    {
+        date: '2024-07-24',
+        value: 3
+    },
+    {
+        date: '2024-07-25',
+        value: 8
+    },
+    {
+        date: '2024-07-26',
+        value: 8
+    },
+    {
+        date: '2024-07-27',
+        value: 0
+    },
+    {
+        date: '2024-07-28',
+        value: 10
+    }
+]
+export const jobPlanObjPie = {
+    num: 10,
+    proportion: 60
+}
+export const personList = [
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    },
+    {
+        name: '蛇口',
+        num: 60
+    }
+]
+export const staffWeek = [
+    {
+        date: '周一',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '周二',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '周三',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '周四',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '周五',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '周六',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '周日',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    }
+]
+export const staffYear = [
+    {
+        date: '1月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '2月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '3月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '4月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '5月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '6月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '7月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '8月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '9月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '10月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '11月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    },
+    {
+        date: '12月',
+        numAll: 60,
+        numReal: 40,
+        numUn: 20
+    }
+]
+export const preData = [
+    {
+        date: '1月',
+        num: 60
+    },
+    {
+        date: '2月',
+        num: 60
+    },
+    {
+        date: '3月',
+        num: 60
+    },
+    {
+        date: '4月',
+        num: 60
+    },
+    {
+        date: '5月',
+        num: 60
+    },
+    {
+        date: '6月',
+        num: 60
+    },
+    {
+        date: '7月',
+        num: 60
+    },
+    {
+        date: '8月',
+        num: 60
+    },
+    {
+        date: '9月',
+        num: 60
+    },
+    {
+        date: '10月',
+        num: 60
+    },
+    {
+        date: '11月',
+        num: 60
+    },
+    {
+        date: '12月',
+        num: 60
+    }
+]
+export default {
+    dataObj,
+    hospitalSection,
+    jobPlanObj,
+    jobPlanObjPie,
+    personList,
+    staffWeek,
+    staffYear,
+    preData
+}

+ 554 - 0
src/views/business/trainManagement/index.vue

@@ -0,0 +1,554 @@
+<template>
+    <div :class="$style.content">
+        <dv-full-screen-container>
+            <!-- 头部内容 -->
+            <div :class="$style.header">
+                <dv-decoration-8 :class="$style.left" />
+                <dv-decoration-5 :class="$style.center" :dur="5" />
+                <dv-decoration-8 :class="$style.right" :reverse="true" />
+                <div :class="$style.title">{{ title }}</div>
+                <div :class="$style.daterange" style="width:10%">
+                    <el-row style="display:flex">
+                        <el-button type="text" size="mini">部门</el-button>
+                    </el-row>
+                    <dv-border-box-8>
+                        <el-select v-model="deptVal" clearable placeholder="请选择部门">
+                            <el-option
+                            v-for="item in chooseDept"
+                            :key="item.positionId"
+                            :label="item.positionName"
+                            :value="item.positionId"
+                            @change="updatePart">
+                            </el-option>
+                        </el-select>
+                    </dv-border-box-8>
+                </div>
+                <div :class="$style.daterange" style="width:20%;right:60%">
+                    <el-row style="display:flex">
+                        <el-button :class="hoverClassAdd === 'w'? 'hoverClass' : ''" type="text" @click="changeDate('week')" size="mini">本周</el-button>
+                        <el-button :class="hoverClassAdd === 'm'? 'hoverClass' : ''" type="text" @click="changeDate('month')" size="mini">本月</el-button>
+                        <el-button :class="hoverClassAdd === 'y'? 'hoverClass' : ''" type="text" @click="changeDate('year')" size="mini">全年</el-button>
+                    </el-row>
+                    <dv-border-box-8>
+                        <el-date-picker
+                            v-model="daterange"
+                            type="daterange"
+                            format="yyyy-MM-dd"
+                            value-format="yyyy-MM-dd"
+                            range-separator="~"
+                            start-placeholder="开始日期"
+                            end-placeholder="结束日期"
+                            @change="changeDate"
+                        />
+                    </dv-border-box-8>  
+                </div>
+                
+                <!-- <dv-decoration-7 :class="$style.cycle">
+                    <el-dropdown @command="changeCycle">
+                        <span class="el-dropdown-link" :style="`font-size: ${fontSize}px;`">{{ selectedCycle }}</span>
+                        <el-dropdown-menu slot="dropdown" class="dept-dropdown">
+                            <el-dropdown-item
+                                v-for="(item, index) in cycleList"
+                                :key="index"
+                                :command="index"
+                            >{{ item }}</el-dropdown-item>
+                        </el-dropdown-menu>
+                    </el-dropdown>
+                </dv-decoration-7> -->
+                <div :class="$style.back" @click.prevent="goBack()">
+                    <dv-border-box-8>返回</dv-border-box-8>
+                </div>
+                <!-- <div :class="$style.parse" @click="toggleAutoPlay">
+                    <img v-if="autoPlay" src="~@/assets/images/icons/parse.png">
+                    <img v-else src="~@/assets/images/icons/play.png">
+                </div> -->
+            </div>
+            <!-- 图表区域 -->
+            <dv-border-box-1>
+                <!-- <div class="vessel" v-if="show">
+                    <job-plan-chart class="merge" :title="mergeData[1].title" v-model="nowWeekData" :data="mergeData[1].numData" :width="'58%'" :height="'44%'" :id="1" />
+                    <dv-decoration-2 :key="`line1`" :reverse="true" :dur="5" style="width:1%;height:44%;" />
+                    <pie-chart class="tabular" :title="mergeData[0].title" v-model="mergeData[0].numData" :width="'37%'" :height="'44%'" :id="1"/>
+                    <dv-decoration-10 style="width:100%;height:0.5%" />
+                    <training-staff-chart class="merge"  :title="mergeData[2].title" v-model="mergeData[2].numData" :data="mergeData[2].perList" :width="'58%'" :height="'44%'" :id="1" />
+                    <dv-decoration-2 :key="`line2`" :reverse="true" :dur="5" style="width:1%;height:44%;" />
+                    <pie-chart class="tabular" :title="mergeData[3].title" v-model="mergeData[3].numData" :width="'37%'" :height="'44%'" :id="2"/>
+                </div>
+                <div class="vessel" style="align-content: normal;" v-else>
+                    <pre-work-chart class="merge" :title="mergeData[5].title" v-model="mergeData[5].numData" :width="'58%'" :height="'44%'" :id="1" />
+                    <dv-decoration-2 :key="`line3`" :reverse="true" :dur="5" style="width:1%;height:44%;" />
+                    <pie-chart class="tabular" :title="mergeData[4].title" v-model="mergeData[4].numData" :width="'37%'" :height="'44%'" :id="3"/>
+                </div> -->
+                <div class="vessel">
+                    <job-plan-chart class="merge" :title="mergeData[1].title" v-model="nowWeekData" :data="mergeData[1].numData" :width="'63%'" :height="'29%'" :id="1" />
+                    <dv-decoration-2 :key="`line1`" :reverse="true" :dur="6" style="width:1%;height:33%;" />
+                    <pie-chart class="tabular" :title="mergeData[0].title" v-model="mergeData[0].numData" :width="'32%'" :height="'29%'" :id="1"/>
+                    <dv-decoration-10 style="width:100%;height:1%" />
+                    <training-staff-chart class="merge"  :title="mergeData[2].title" v-model="mergeData[2].numData" :data="mergeData[2].perList" :width="'63%'" :height="'29%'" :id="1" />
+                    <dv-decoration-2 :key="`line2`" :reverse="true" :dur="6" style="width:1%;height:33%;" />
+                    <pie-chart class="tabular" :title="mergeData[3].title" v-model="mergeData[3].numData" :width="'32%'" :height="'29%'" :id="2"/>
+                    <dv-decoration-10 style="width:100%;height:1%" />
+                    <pre-work-chart class="merge" :title="mergeData[5].title" v-model="mergeData[5].numData" :width="'63%'" :height="'29%'" :id="1" />
+                    <dv-decoration-2 :key="`line3`" :reverse="true" :dur="6" style="width:1%;height:33%;" />
+                    <pie-chart class="tabular" :title="mergeData[4].title" v-model="mergeData[4].numData" :width="'32%'" :height="'29%'" :id="3"/>
+                </div>
+            </dv-border-box-1>
+        </dv-full-screen-container>
+    </div>
+</template>
+<script>
+import screenfull from 'screenfull'
+import data from './constants/simulated.js'
+import { getFormatDate } from './utils/config.js'
+import PreWorkChart from './components/preWorkChart.vue'
+
+// import { labsDashBoard } from '@/api/platform/spectaculars/lab'
+export default {
+    components: {
+        JobPlanChart: () => import('./components/jobPlanChart.vue'),
+        TrainingStaffChart: () => import('./components/trainingStaffChart.vue'),
+        PieChart: () => import('./components/pieChart.vue'),
+        PreWorkChart: () => import('./components/preWorkChart.vue')
+    },
+    data () {
+        const d = new Date()
+        const { deptList = [] } = this.$store.getters || {}
+        let chooseDept = deptList.filter(e => e.depth == 4)
+        chooseDept.unshift({positionId: " ",positionName: "全科室"})
+        return {
+            deptList,
+            chooseDept,
+            deptVal: ' ',
+            level: '',
+            title: '培训',
+            year: d.toJSON().slice(0, 4),
+            cycleList: [],
+            initData: {},
+            fontSize: 18,
+            itemIndex: 0,
+            chartIndex: 0,
+            autoPlay: true,
+            tabularArr1:[],
+            tabularArr2:[],
+            daterange: [],
+            nowWeekData: [],
+            show: true,
+            hoverClassAdd:'w',
+            mergeData:[
+                {
+                    title: '培训类别占比',
+                    numData: data.dataObj
+                },
+                {
+                    title: '在岗培训计划',
+                    numData: data.jobPlanObjPie
+                },
+                {
+                    title: '培训人员统计情况',
+                    numData: data.staffWeek,
+                    perList: data.personList
+                },
+                {
+                    title: '培训对象占比',
+                    numData: data.dataObj
+                },
+                {
+                    title: '本年度培训类别占比',
+                    numData: data.dataObj
+                },
+                {
+                    title: '本年度岗前培训',
+                    numData: data.preData
+                }
+            ]
+        }
+    },
+    computed: {
+        selectedCycle () {
+            return this.cycleList[this.itemIndex] || '每月'
+        },
+        size () {
+            return this.sizeMap[this.selectedCycle]
+        }
+    },
+    watch: {
+    },
+    created () {
+        // 默认全屏展示
+        if (screenfull.isEnabled && !screenfull.isFullscreen) {
+            screenfull.request()
+        }
+
+        this.updateAll()
+    },
+    beforeDestroy () {
+        if (screenfull.isFullscreen) {
+            screenfull.toggle()
+        }
+        this.clenUp()
+    },
+    methods: {
+        initializeData () {
+            const w = window.innerWidth
+            const { first = '', second = '' } = this.$store.getters.level || {}
+            this.nowWeekData = this.getNowWeek()
+            this.daterange = this.getCurrentWeek()
+            this.initData = {}
+            this.itemIndex = 0
+            this.chartIndex = 0
+            this.level = second || first
+            this.fontSize = w >= 1600 ? 20 : w > 1366 && w < 1600 ? 18 : 16
+            this.tabularArr1=[]
+            this.tabularArr2=[]
+        },
+        updateAll () {
+            this.initializeData()
+            // this.startAutoPlay()
+            data.jobPlanObj.forEach(e => {
+                let mid = this.nowWeekData.find(i => i.date === e.date)
+                mid['value'] = e.value
+            })
+        },
+        updatePart () {
+
+        },
+        async fetchData () {
+        },
+        goBack () {
+            this.$router.back(-1)
+        },
+        changeDate (val) {
+            switch (val) {
+                case 'week':
+                    this.hoverClassAdd = 'w'
+                    let w = this.getCurrentWeek()
+                    this.daterange = w
+                    this.updatePart()
+                    break
+                case 'month':
+                    this.hoverClassAdd = 'm'
+                    let m = this.getCurrentMonth()
+                    this.daterange = m
+                    this.updatePart()
+                    break
+                case 'year':
+                    this.hoverClassAdd = 'y'
+                    let y = this.getCurrentYear()
+                    this.daterange = y
+                    this.updatePart()
+                    break
+                default:
+                    this.hoverClassAdd = 'A'
+                    this.updatePart()
+                    break
+            }
+        },
+        getNowWeek () {
+            return this.getAllDatesBetween(this.getCurrentWeek())
+        },
+        getCurrentWeek () {
+            const now = new Date()
+            const dayOfWeek = now.getDay() // 0-6, 0是周日
+            const dayOfWeekMonday = dayOfWeek || 7 // 如果是周日,使用7
+            const startDate = new Date(now)
+            startDate.setDate(now.getDate() - (dayOfWeekMonday - 1))
+            const endDate = new Date(now)
+            endDate.setDate(now.getDate() + (7 - dayOfWeekMonday))
+            return [getFormatDate('string', 0, 10, startDate), getFormatDate('string', 0, 10, endDate)]
+        },
+        getCurrentMonth () {
+            const now = new Date()
+            const startDate = new Date(now.getFullYear(), now.getMonth(), 1)
+            const endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0)
+            return [getFormatDate('string', 0, 10, startDate), getFormatDate('string', 0, 10, endDate)]
+        },
+        getCurrentYear () {
+            const currentYear = new Date().getFullYear()
+            const startDate = new Date(currentYear, 0, 1)
+            const endDate = new Date(currentYear, 11, 31)
+            return [getFormatDate('string', 0, 10, startDate), getFormatDate('string', 0, 10, endDate)]
+        },
+        getAllDatesBetween(d) {
+            let startDate = new Date(d[0])
+            let endDate = new Date(d[1])
+            let dates = []
+            let currentDate = new Date(startDate)
+            while (currentDate <= endDate) {
+                let obj = {week: this.getWeekOfDay(currentDate), date: getFormatDate('string', 0, 10, new Date(currentDate))}
+                dates.push(obj)
+                currentDate.setDate(currentDate.getDate() + 1)
+            }
+            return dates;
+        },
+        getWeekOfDay(d){
+            const date = new Date(d)
+            const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
+            const dayOfWeek = weekDays[date.getDay()]
+            return dayOfWeek
+        },
+        toggleAutoPlay () {
+            this.autoPlay ? this.stopAutoPlay() : this.startAutoPlay()
+        },
+        startAutoPlay () {
+            this.autoPlay = true
+            if (this.autoPlayTimer) {
+                clearInterval(this.autoPlayTimer)
+            }
+            this.autoPlayTimer = setInterval(() => {
+                this.show = !this.show
+            }, 5000)
+        },
+        stopAutoPlay () {
+            this.autoPlay = false
+            clearInterval(this.autoPlayTimer)
+        },
+        clenUp () {
+            // clearInterval(this.dataFetchTimer)
+            clearInterval(this.autoPlayTimer)
+        }
+    }
+}
+</script>
+<style lang="scss" scoped>
+// ::v-deep .el-button--text.is-active,
+//     .el-button--text:active {
+//         background: #1892ea;
+//         border-color: #1892ea;
+//         color: #FFFFFF;
+//     }
+    
+//     ::v-deep .el-button--text:focus,
+//     .el-button--text:hover {
+//         background: #1892ea;
+//         border-color: #1892ea;
+//         color: #FFFFFF;
+//     }
+    
+    ::v-deep .el-button--text {
+        color: #FFFFFF;
+        padding: 5px 5px;
+        border-radius: 4px;
+    }
+    .hoverClass{
+        background: #1892ea;
+        border-color: #1892ea;
+        color: #FFFFFF;
+    }
+</style>
+<style lang="scss" module>
+    .content {
+        width: 100%;
+        height: 100%;
+        background-color: #030409;
+        position: absolute;
+        color: #fff;
+        z-index: 999;
+        :global {
+            #dv-full-screen-container {
+                background-image: url('~@/assets/images/screen/bg.png');
+                background-size: 100% 100%;
+                box-shadow: 0 0 3px blue;
+                display: flex;
+                flex-direction: column;
+            }
+            .dv-border-box-1 .border-box-content{
+                height: calc(100vh - 90px);
+                .vessel{
+                    width: 98%;
+                    height: 96%;
+                    padding: 1%;
+                    display: flex;
+                    flex-flow: wrap;
+                    justify-content: space-evenly;
+                    align-content: space-evenly;
+                    .tabular{
+                        width: 40%;
+                    }
+                    .merge{
+                        width: 80%;
+                    }
+                }
+            }
+            .main-content {
+                flex: 1;
+                display: flex;
+                flex-direction: column;
+            }
+
+            .block-left-right-content {
+                flex: 1;
+                display: flex;
+                margin-top: 0.8%;
+            }
+
+            .block-top-bottom-content {
+                flex: 1;
+                display: flex;
+                flex-direction: column;
+                box-sizing: border-box;
+                padding-left: 0.8%;
+            }
+
+            .block-top-content {
+                height: 55%;
+                display: flex;
+                flex-grow: 0;
+                box-sizing: border-box;
+                padding-bottom: 0.8%;
+            }
+        }
+        .header {
+            position: relative;
+            width: 100%;
+            height: 90px;
+            display: flex;
+            justify-content: space-between;
+            flex-shrink: 0;
+            .left, .right {
+                width: 25%;
+                height: 60px;
+            }
+            .center {
+                width: 40%;
+                height: 60px;
+                margin-top: 30px;
+            }
+            .title {
+                position: absolute;
+                font-size: 30px;
+                font-weight: bold;
+                left: 50%;
+                top: 15px;
+                transform: translateX(-50%);
+            }
+            .daterange, .cycle, .back, .parse {
+                width: 8%;
+                // max-width: 180px;
+                cursor: pointer;
+                height: 2.825rem;
+                line-height: 2.825rem;
+                text-align: center;
+                margin-top: 2%;
+                flex: 1;
+                position: absolute;
+                color: #ffffff;
+            }
+            .daterange {
+                width: 8%;
+                right: 83%;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                :global {
+                    .el-input--small .el-input__inner {
+                        width: 100% !important;
+                        background: rgba(255, 255, 255, 0);
+                        border: none;
+                        color: #fff;
+                        font-size: 16px;
+                        cursor: pointer;
+                        // padding-left: 0;
+                        padding-right: 0;
+                    }
+                    .el-select--small .el-input .el-input__inner {
+                        width: 100% !important;
+                        background: rgba(255, 255, 255, 0);
+                        border: none;
+                        color: #fff;
+                        font-size: 12px;
+                        cursor: pointer;
+                        // padding-left: 0;
+                        padding-right: 0;
+                    }
+                    .el-input__inner {
+                        width: 100% !important;
+                        background: rgba(255, 255, 255, 0);
+                        border: none;
+                        font-size: 16px;
+                        cursor: pointer;
+                        // padding-left: 0;
+                        padding-right: 0;
+                        .el-range-input {
+                            background: rgba(255, 255, 255, 0);
+                            color: #fff;
+                        }
+                        .el-input__icon {
+                            color: #fff;
+                        }
+                        .el-range-separator{
+                            color: #fff;
+                        }
+                    }
+                }
+            }
+            .cycle {
+                display: flex;
+                min-width: 150px;
+                justify-content: flex-end;
+                // width: 125px;
+                right: 75%;
+                padding-left: 10px;
+                color: #fff;
+                font-size: 22px;
+                font-weight: 400;
+                :global {
+                    .el-dropdown {
+                        width: calc(100% - 52px);
+                        text-overflow: ellipsis;
+                        overflow: hidden;
+                        white-space: nowrap;
+                        .el-dropdown-link {
+                            text-align: center;
+                        }
+                    }
+                }
+            }
+            .back {
+                width: 5%;
+                left: calc(75% + 80px);
+            }
+            .parse {
+                width: 2%;
+                left: 75%;
+                align-items: center;
+                padding: 5px;
+                > img {
+                    height: calc(100% - 10px);
+                }
+            }
+            @media only screen and (max-width: 1680px) {
+                .daterange, .cycle, .back, .parse {
+                    height: 2.5rem;
+                    line-height: 2.5rem;
+                    margin-top: 2.5%;
+                }
+                .daterange {
+                    right: 82%;
+                }
+                .cycle {
+                    width: 5%;
+                    min-width: 120px;
+                    font-size: 18px;
+                    font-weight: normal;
+                }
+                .back {
+                    left: calc(75% + 60px);
+                }
+            }
+            @media only screen and (max-width: 1366px) {
+                .daterange {
+                    right: 80%;
+                }
+                .cycle {
+                    right: 70%;
+                    min-width: 140px;
+                    font-size: 16px;
+                    font-weight: normal;
+                }
+                .back {
+                    left: calc(75% + 50px);
+                }
+            }
+        }
+    }
+</style>

+ 72 - 0
src/views/business/trainManagement/utils/config.js

@@ -0,0 +1,72 @@
+export const GetPercent = (num, total)=> {
+    /// <summary>
+    /// 求百分比
+    /// </summary>
+    /// <param name="num">当前数</param>
+    /// <param name="total">总数</param>
+    num = parseFloat(num);
+    total = parseFloat(total);
+    if (isNaN(num) || isNaN(total)) {
+        return "-";
+    }
+    return total <= 0 ? "0%" : (Math.round(num / total * 10000) / 100.00)+"%";
+}
+export const GetMax = (arr)=> {
+    let max = 1;
+    if(arr ==undefined)
+        return 1;
+
+    arr.forEach(v => {
+        if (max<v) {
+          max = v;
+        }
+      })
+   return max;
+}
+
+export const GetTotality = (arr)=> {
+    let mid = 0;
+    if(arr == undefined)
+        return mid;
+
+    arr.forEach(v => {
+        mid += v.value
+    })
+   return mid;
+}
+
+// 时间格式化
+export const getFormatDate = (type, start, length, date = new Date()) => {
+    const now = new Date(new Date(date).getTime())
+    // eslint-disable-next-line
+    if (now == 'Invalid Date') {
+        console.log('非法日期,无法格式化')
+        return date
+    }
+    const year = now.getFullYear()
+    const month = now.getMonth() + 1
+    const day = now.getDate()
+    const hours = now.getHours()
+    const minutes = now.getMinutes()
+    const seconds = now.getSeconds()
+    // 补零
+    const padZero = (num) => {
+        return num.toString().padStart(2, '0')
+    }
+    // 默认返回String类型
+    let result = `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`
+    switch (type) {
+        case 'string':
+            result = `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`
+            break
+        case 'cn':
+            result = `${year}年${padZero(month)}月${padZero(day)}日 ${padZero(hours)}时${padZero(minutes)}分${padZero(seconds)}秒`
+            break
+        case 'number':
+            result = `${year}${padZero(month)}${padZero(day)}${padZero(hours)}${padZero(minutes)}${padZero(seconds)}`
+            break
+        default:
+            break
+    }
+    return result.slice(start, length || result.length)
+}