发布时间:2023-04-21 文章分类:WEB开发, 电脑百科 投稿人:赵颖 字号: 默认 | | 超大 打印

目录

  • 需求
  • 实现效果
  • 主要代码
    • 前端首页
    • 面板组组件:
    • 折线图组件:
  • 详细解释
        • 面板组
        • 折线图
      • 关于他们底下的数据
  • 后端传来的json参考
  • 租户配置的页面
    • 后端,这里做个参考就好,每个项目都不一样,就是把数据返回前端,样子就是json上那个样子

关键词:Vue;若依管理系统;实现管理员配置 首页计数框/折线图 数据

需求

自定义若依首页展示的数据内容,并且每个租户能够自行配置
没实现之前的页面:
Vue若依管理系统-实现管理员配置首页计数框/折线图

实现效果

管理员配置展示信息(计数框选择入库、提交、核销、采集。折线图选发票数/转出数。):
Vue若依管理系统-实现管理员配置首页计数框/折线图
效果(页面展示与用户设置的选择相同):
Vue若依管理系统-实现管理员配置首页计数框/折线图

主要代码

首页+首页中的组件 代码:https://cloud.189.cn/web/share?code=MZfaQnqi6Nbm(访问码:0w36)

前端首页

  1. 主页
<template>
  <div className="dashboard-editor-container">
    <panel-group @handleSetLineChartData="handleSetLineChartData"
                 :count01="countList.count01"
                 :count-t0="countList.countT0"
                 :count-s0="countList.countS0"
                 :count05="countList.count05"
                 :count10="countList.count10"
                 :count15="countList.count15"
                 :count20="countList.count20"
                 :count25="countList.count25"
    />
    <!--折线图-->
    <el-row style="background:#fff; padding:16px 16px 0; margin-bottom:32px;">
      <line-chart :chart-data="lineChartData" />
    </el-row>
    <!--用不到的几个,因为我只用到了计数框和折线图,其他就不让显示了-->
<!--    <el-row :gutter="32">-->
<!--      &lt;!&ndash;雷达图&ndash;&gt;-->
<!--      <el-col :xs="24" :sm="24" :lg="8">-->
<!--        <div class="chart-wrapper">-->
<!--          <raddar-chart />-->
<!--        </div>-->
<!--      </el-col>-->
<!--      &lt;!&ndash;饼状图&ndash;&gt;-->
<!--      <el-col :xs="24" :sm="24" :lg="8">-->
<!--        <div class="chart-wrapper">-->
<!--          <pie-chart />-->
<!--        </div>-->
<!--      </el-col>-->
<!--      &lt;!&ndash;条形图&ndash;&gt;-->
<!--      <el-col :xs="24" :sm="24" :lg="8">-->
<!--        <div class="chart-wrapper">-->
<!--          <bar-chart />-->
<!--        </div>-->
<!--      </el-col>-->
<!--    </el-row>-->
  </div>
</template>
<script>
import {
  getConfigInfo,
  getIndexLinechartData,
  getIndexLinechartDataByMonth,
  getIndexSelectBoxCount01,
  getIndexSelectBoxCount05,
  getIndexSelectBoxCount10,
  getIndexSelectBoxCount15,
  getIndexSelectBoxCount20,
  getIndexSelectBoxCount25,
  getIndexSelectBoxCountS0,
  getIndexSelectBoxCountT0
} from "@/api/index";
// 面板组
import PanelGroup from './dashboard/PanelGroup'
// 折线图
import LineChart from './dashboard/LineChart'
// 雷达图
import RaddarChart from './dashboard/RaddarChart'
// 饼状图
import PieChart from './dashboard/PieChart'
// 条形图
import BarChart from './dashboard/BarChart'
export default {
  name: 'Index',
  components: {
    PanelGroup,
    LineChart,
    RaddarChart,
    PieChart,
    BarChart
  },
  data() {
    return {
      /** 当前配置信息,这里是存放获取的租户管理员配置的展示信息 */
      config: {},
      /** 面板组,该用户配置的计数列表,这里你显示什么需要先定义 */
      countList: {
        count01: null,
        countT0: null,
        countS0: null,
        count05: null,
        count10: null,
        count15: null,
        count20: null,
        count25: null,
      },
      // 该用户选择的面板组(数组)
      selected: null,
      /** 折线图 */
      lineChartData: {
        expectedData: [200, 192, 120, 144, 160, 130, 140],
        actualData: [180, 160, 151, 106, 145, 150, 130],
        dateData: ["1", "2", "3", "4", "5", "6", "7"]
      },
    }
  },
  created() {
    /** 2022-5-31,初始化租户参数 */
    this.configInfo();
  },
  methods: {
    /** 2022-5-27,获取接口参数信息,这里是配置的,我做了管理员选项,让每个租户管理自己选要展示的框 */
    configInfo(){
      getConfigInfo().then(response => {
        this.config = response.data;
        this.selected = this.config.selectBoxCount.split(",");
        /** 2022-5-31,获取面板组框:获取该租户设置了展示哪几个计数框 */
        this.check(this.selected);
        /** 2022-5-31,获取折线图数据 */
        this.getLinechardData();
      });
    },
    /** 判断当前选中了那些,注:这是面板组的,getIndexSelectBoxCount01-xx,这些方法是每个框各自获取自己的框的数据,因为是配置的,就分别获取的 */
    check(selected) {
      for (const s of selected) {
        switch (s) {
          case "01":
            getIndexSelectBoxCount01().then(response => {
              this.countList.count01 = parseInt(response.data);
            });
            break;
          case "S0":
            getIndexSelectBoxCountS0().then(response => {
              this.countList.countT0 = parseInt(response.data);
            });
            break;
          case "T0":
            getIndexSelectBoxCountT0().then(response => {
              this.countList.countS0 = parseInt(response.data);
            });
            break;
          case "05":
            getIndexSelectBoxCount05().then(response => {
              this.countList.count05 = parseInt(response.data);
            });
            break;
          case "10":
            getIndexSelectBoxCount10().then(response => {
              this.countList.count10 = parseInt(response.data)
            });
            break;
          case "15":
            getIndexSelectBoxCount15().then(response => {
              this.countList.count15 = parseInt(response.data);
            });
            break;
          case "20":
            getIndexSelectBoxCount20().then(response => {
              this.countList.count20 = parseInt(response.data);
            });
            break;
          case "25":
            getIndexSelectBoxCount25().then(response => {
              this.countList.count25 = parseInt(response.data);
            });
            break;
        }
      }
    },
    /** 获取折现图的数据,这里也是管理员可配置,所以用到了判断 */
    getLinechardData() {
      getIndexLinechartDataByMonth(this.config.selectLine).then(response => {
        this.lineChartData = response.data;
        // 当前租户设置中选择展示的折线图(1:第一种,2:第二种)
        if (this.config.selectLine === '1') {
          this.lineChartData.selectName = ['发票数','核销数']
        } else {
          this.lineChartData.selectName = ['发票数','转出数']
        }
      })
    },
    // 调用变化线型图,给4个数据卡片调用的,卡片调用的时候就加载卡片传过来的数据
    handleSetLineChartData(type) {
      // 根据子集的调用切换对应的数据
      // this.lineChartData = lineChartData[type]
    },
  }
}
</script>
<style lang="scss" scoped>
.dashboard-editor-container {
  padding: 32px;
  background-color: rgb(240, 242, 245);
  position: relative;
  .chart-wrapper {
    background: #fff;
    padding: 16px 16px 0;
    margin-bottom: 32px;
  }
}
@media (max-width: 1024px) {
  .chart-wrapper {
    padding: 8px;
  }
}
</style>
  1. 在webStorm找到src/views/dashboard,里面就是首页这几个组件

面板组组件:

<template>
  <el-row :gutter="40" class="panel-group">
    <el-col v-show="count01 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-people">
          <svg-icon icon-class="nested" class-name="card-panel-icon"/>
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            入库
          </div>
          <count-to :start-val="0" :end-val="count01" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="countT0 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-message">
          <svg-icon icon-class="nested" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            提交
          </div>
          <count-to :start-val="0" :end-val="countT0" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="countS0 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-money">
          <svg-icon icon-class="post" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            核销
          </div>
          <count-to :start-val="0" :end-val="countS0" :duration="3200" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="count05 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-shopping">
          <svg-icon icon-class="xy-choice2" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            采集
          </div>
          <count-to :start-val="0" :end-val="count05" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="count10 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-shopping">
          <svg-icon icon-class="nested" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            认证提交
          </div>
          <count-to :start-val="0" :end-val="count10" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="count15 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-shopping">
          <svg-icon icon-class="nested" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            验收
          </div>
          <count-to :start-val="0" :end-val="count15" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="count20 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-shopping">
          <svg-icon icon-class="nested" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            认证
          </div>
          <count-to :start-val="0" :end-val="count20" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
    <el-col v-show="count25 != null" :xs="12" :sm="12" :lg="6" class="card-panel-col">
      <div class="card-panel">
        <div class="card-panel-icon-wrapper icon-shopping">
          <svg-icon icon-class="nested" class-name="card-panel-icon" />
        </div>
        <div class="card-panel-description">
          <div class="card-panel-text">
            转出
          </div>
          <count-to :start-val="0" :end-val="count25" :duration="2600" class="card-panel-num" />
        </div>
      </div>
    </el-col>
  </el-row>
</template>
<script>
import CountTo from 'vue-count-to'
export default {
  props:{
    count01: {type: Number, default: 0},
    countT0: {type: Number, default: 0},
    countS0: {type: Number, default: 0},
    count05: {type: Number, default: 0},
    count10: {type: Number, default: 0},
    count15: {type: Number, default: 0},
    count20: {type: Number, default: 0},
    count25: {type: Number, default: 0},
  },
  components: {
    CountTo
  }
}
</script>
<style lang="scss" scoped>
.panel-group {
  margin-top: 18px;
  .card-panel-col {
    margin-bottom: 32px;
  }
  .card-panel {
    height: 108px;
    font-size: 12px;
    position: relative;
    overflow: hidden;
    color: #666;
    background: #fff;
    box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
    border-color: rgba(0, 0, 0, .05);
    &:hover {
      .card-panel-icon-wrapper {
        color: #fff;
      }
      .icon-people {
        background: #40c9c6;
      }
      .icon-message {
        background: #36a3f7;
      }
      .icon-money {
        background: #f4516c;
      }
      .icon-shopping {
        background: #34bfa3
      }
    }
    .icon-people {
      color: #40c9c6;
    }
    .icon-message {
      color: #36a3f7;
    }
    .icon-money {
      color: #f4516c;
    }
    .icon-shopping {
      color: #34bfa3
    }
    .card-panel-icon-wrapper {
      float: left;
      margin: 14px 0 0 14px;
      padding: 16px;
      transition: all 0.38s ease-out;
      border-radius: 6px;
    }
    .card-panel-icon {
      float: left;
      font-size: 48px;
    }
    .card-panel-description {
      float: right;
      font-weight: bold;
      margin: 26px;
      margin-left: 0px;
      .card-panel-text {
        line-height: 18px;
        color: rgba(0, 0, 0, 0.45);
        font-size: 16px;
        margin-bottom: 12px;
      }
      .card-panel-num {
        font-size: 20px;
      }
    }
  }
}
@media (max-width:550px) {
  .card-panel-description {
    display: none;
  }
  .card-panel-icon-wrapper {
    float: none !important;
    width: 100%;
    height: 100%;
    margin: 0 !important;
    .svg-icon {
      display: block;
      margin: 14px auto !important;
      float: none !important;
    }
  }
}
</style>

折线图组件:

<template>
  <div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
export default {
  mixins: [resize],
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '350px'
    },
    autoResize: {
      type: Boolean,
      default: true
    },
    chartData: {
      type: Object,
      required: true,
    }
  },
  data() {
    return {
      chart: null,
    }
  },
  watch: {
    chartData: {
      deep: true,
      handler(val) {
        // console.log('触发了Line组件调用x轴初始化')
        this.setOptions(val)
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart()
    })
  },
  created() {
    this.$nextTick(() => {
      this.initChart()
    })
  },
  beforeDestroy() {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.chart = null
  },
  methods: {
    initChart() {
      this.chart = echarts.init(this.$el, 'macarons')
      this.setOptions(this.chartData)
    },
    setOptions({ dateData, firstData, secondData, selectName } = {}) {
      this.chart.setOption({
        xAxis: {
          data: dateData,
          boundaryGap: false,
          axisTick: {
            show: false
          }
        },
        grid: {
          left: 10,
          right: 10,
          bottom: 20,
          top: 30,
          containLabel: true
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross'
          },
          padding: [5, 10]
        },
        yAxis: {
          axisTick: {
            show: false
          }
        },
        legend: {
          // data: ['发票数', '核销数']
          data: selectName
        },
        // 图表描述
        series: [{
          name: selectName?.[0], itemStyle: {
            normal: {
              color: '#FF005A',
              lineStyle: {
                color: '#FF005A',
                width: 2
              }
            }
          },
          // 柔性过过渡
          smooth: true,
          type: 'line',
          data: firstData,
          animationDuration: 2800,
          animationEasing: 'cubicInOut'
        },
        {
          name: selectName?.[1],
          smooth: true,
          type: 'line',
          itemStyle: {
            normal: {
              color: '#3888fa',
              lineStyle: {
                color: '#3888fa',
                width: 2
              },
              areaStyle: {
                color: '#f3f8ff'
              }
            }
          },
          data: secondData,
          animationDuration: 2800,
          animationEasing: 'quadraticOut'
        }]
      })
    }
  }
}
</script>

详细解释

面板组

大概说一下,实现面板组的话,需要先在组件里面写好,你都要有哪些框,先在页面写好,通过v-show控制其是否渲染

可以看到这里面都用了v-show,之后如果管理员没有选中的话,返回到前端肯定是null,那样就不会显示了,从而实现根据配置展示

折线图

Vue若依管理系统-实现管理员配置首页计数框/折线图
这个方法,就是对应首页的折线图的标题。data: [‘发票数’, ‘核销数’]这样标题就是固定的,为了实现需求,我们需要通过后端传过来,这个selectName就是折线图的标题数组
Vue若依管理系统-实现管理员配置首页计数框/折线图
首页把这个selectName传递给组件
Vue若依管理系统-实现管理员配置首页计数框/折线图
这是用到了父传子,可以看到:chart-data=“lineChartData”,将父组件的数据传给了折线图组件
Vue若依管理系统-实现管理员配置首页计数框/折线图

关于他们底下的数据

比如折线图,原来的数据如下,这些是写死的,所以通过后端传入的数据改一下就行。折线图不是有两个标题吗,firstData:就是第一个标题的数值;secondData:就是第二个标题的;dateData:就是底下的数(天数)

lineChartData: {
        firstData: [200, 192, 120, 144, 160, 130, 140],
        secondData: [180, 160, 151, 106, 145, 150, 130],
        dateData: ["1", "2", "3", "4", "5", "6", "7"]
      },

把上面固定的数据通过后端传过来,就能实现租户自定义了
Vue若依管理系统-实现管理员配置首页计数框/折线图
这块就是后端返回的数据,赋值给了这些数据:
Vue若依管理系统-实现管理员配置首页计数框/折线图

后端传来的json参考

面板组
{"msg":"操作成功","code":200,"data":"0"}
折线图
{
    "msg": "获取数据成功!",
    "code": 200,
    "data": {
        "dateData": [
            "2021-07",
            "2021-08",
            "2021-09",
            "2021-10",
            "2021-11",
            "2021-12",
            "2022-01",
            "2022-02",
            "2022-03",
            "2022-04",
            "2022-05",
            "2022-06",
            "本月"
        ],
        "firstData": [
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0"
        ],
        "secondData": [
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0",
            "0"
        ]
    }
}
管理员配置的
{
        "selectBoxCount": "05,01,S0,T0",
        "selectLine": "2",
}
  1. js
/**
 * 2022-5-27,获取接口参数
 */
export function getConfigInfo(){
  return request({
    url: 'invoice/invoice/getConfigInfo',
    method: 'get',
  })
}
/**
 * 2022-5-27,首页展示面板图
 */
export function getIndexSelectBoxCount01(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCount01',
    method: 'get',
  })
}
export function getIndexSelectBoxCountS0(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCountS0',
    method: 'get',
  })
}
export function getIndexSelectBoxCountT0(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCountT0',
    method: 'get',
  })
}
export function getIndexSelectBoxCount05(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCount05',
    method: 'get',
  })
}
export function getIndexSelectBoxCount10(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCount10',
    method: 'get',
  })
}
export function getIndexSelectBoxCount15(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCount15',
    method: 'get',
  })
}
export function getIndexSelectBoxCount20(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCount20',
    method: 'get',
  })
}
export function getIndexSelectBoxCount25(){
  return request({
    url: 'invoice/invoice/getIndexSelectBoxCount25',
    method: 'get',
  })
}
//查询首页折线图 当前周数据
export function getIndexLinechartData(){
  return request({
    url: '/invoice/invoice/getindexlinechart',
    method: 'get'
  })
}
//查询首页折线图 当年数据
export function getIndexLinechartDataByMonth(query){
  return request({
    url: '/invoice/invoice/getIndexLineChartByMonth',
    method: 'get',
    params: {type: query}
  })
}

租户配置的页面

  1. template
        <!--首页参数-->
        <el-col :span="24">
          <el-divider content-position="center">首页参数</el-divider>
        </el-col>
        <el-col :span="24">
          <label style="display: flex;margin-bottom: 20px">首页中展示的计数框</label>
            <el-checkbox-group v-model="checkboxGroup" :min="1" :max="4" size="small" @change="handleUpdateCheck">
              <el-col :span="24">
                <el-checkbox label="入库" border></el-checkbox>
                <el-checkbox label="提交" border></el-checkbox>
                <el-checkbox label="核销" border></el-checkbox>
              </el-col>
              <el-col :span="24" style="display: flex; margin-top: 5px">
                <el-checkbox label="采集" border></el-checkbox>
                <el-checkbox label="认证提交" border></el-checkbox>
                <el-checkbox label="验收" border></el-checkbox>
                <el-checkbox label="认证" border></el-checkbox>
                <el-checkbox label="转出" border></el-checkbox>
              </el-col>
            </el-checkbox-group>
        </el-col>
        <el-col :span="24">
          <label style="display: flex;margin-bottom: 20px; margin-top: 20px">首页中展示的折线图</label>
          <el-col :span="24">
            <el-radio-group v-model="form.selectLine" size="small" @change="handleUpdateLineCheck">
              <el-radio label="1" border>发票数/核销数</el-radio>
              <el-radio label="2" border>发票数/转出数</el-radio>
            </el-radio-group>
          </el-col>
        </el-col>
  1. data
data{
      checkboxGroup: [],
}
  1. methods
methods: {
    /** 2022-5-27,kxb,获得并计算当前选中的首页计数框的值 */
    setSelectCountBox(v){
      this.checkboxGroup = [];
      for (let node of v) {
        if (node === "01") this.checkboxGroup.push("入库");
        if (node === "S0") this.checkboxGroup.push("提交");
        if (node === "T0") this.checkboxGroup.push("核销");
        if (node === "05") this.checkboxGroup.push("采集");
        if (node === "10") this.checkboxGroup.push("认证提交");
        if (node === "15") this.checkboxGroup.push("验收");
        if (node === "20") this.checkboxGroup.push("认证");
        if (node === "25") this.checkboxGroup.push("转出");
      }
    },
    // 多选框改变调用
    handleUpdateCheck(checkeds){
      let str = "";
      for (let check of checkeds) {
        switch (check) {
          case "入库":
            str === "" ? str = "01" : str += ",01"
            break;
          case "提交":
            str === "" ? str = "S0" : str += ",S0"
            break;
          case "核销":
            str === "" ? str = "T0" : str += ",T0"
            break;
          case "采集":
            str === "" ? str = "05" : str += ",05"
            break;
          case "认证提交":
            str === "" ? str = "10" :  str += ",10"
            break;
          case "验收":
            str === "" ? str = "15" : str += ",15"
            break;
          case "认证":
            str === "" ? str = "20" : str += ",20"
            break;
          case "转出":
            str === "" ? str = "25" : str += ",25"
            break;
        }
      }
      this.form.selectBoxCount = str;
    },
    handleUpdateLineCheck(checked){
      this.form.selectLine = checked.toString();
    },
}

存到sql的数据长这个样子
Vue若依管理系统-实现管理员配置首页计数框/折线图

后端,这里做个参考就好,每个项目都不一样,就是把数据返回前端,样子就是json上那个样子

  1. controller
/**
     * 2022-5-27,获取当前用户展示的显示框的信息。区别:根据后缀01、S0、T0来区分
     */
    // 获取接口参数
    @GetMapping("getConfigInfo")
    public AjaxResult getConfigInfo(){
        YsIvInterfacelinemsg ysIvInterfacelinemsg = ysIvInterfacelinemsgService.selectCurIvInterfaceLinemsg();
        RemoteYsIvInterfacelinemsg remoteYsIvInterfacelinemsg = new RemoteYsIvInterfacelinemsg();
        BeanUtils.copyBeanProp(remoteYsIvInterfacelinemsg, ysIvInterfacelinemsg);
        return AjaxResult.success(ysIvInterfacelinemsg);
    }
    // 入库
    @GetMapping("getIndexSelectBoxCount01")
    public AjaxResult getIndexSelectBoxCount01(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_NOTYET));
    }
    // 提交
    @GetMapping("getIndexSelectBoxCountS0")
    public AjaxResult getIndexSelectBoxCountS0(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_SUBMIT));
    }
    // 核销
    @GetMapping("getIndexSelectBoxCountT0")
    public AjaxResult getIndexSelectBoxCountT0(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_DESTROY));
    }
    // 采集
    @GetMapping("getIndexSelectBoxCount05")
    public AjaxResult getIndexSelectBoxCount05(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_CONFIRMED));
    }
    // 认证提交
    @GetMapping("getIndexSelectBoxCount10")
    public AjaxResult getIndexSelectBoxCount10(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_AUTH_SUBMIT));
    }
    // 验收
    @GetMapping("getIndexSelectBoxCount15")
    public AjaxResult getIndexSelectBoxCount15(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_AUTH_CHECK));
    }
    // 认证
    @GetMapping("getIndexSelectBoxCount20")
    public AjaxResult getIndexSelectBoxCount20(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_AUTH));
    }
    // 转出
    @GetMapping("getIndexSelectBoxCount25")
    public AjaxResult getIndexSelectBoxCount25(){
        return AjaxResult.success(ysInvoiceService.getIndexSelectBoxCount(InvoiceConstants.OPERATE_STATUS_TRANSFER));
    }
    /** 获取折线图数据 */
    @GetMapping("/getIndexLineChartByMonth")
    public AjaxResult getIndexLineChart(@RequestParam String type){
        Map<String,Object> map = ysInvoiceService.getOrSetLineCountByRedis(type);
        return AjaxResult.success("获取数据成功!", map);
    }
  1. service
    /**
     * 2022-5-27,获取最上方的采集、提交等等的数量
     * @return
     */
    public Long getIndexSelectBoxCount(String status){
        ArrayList<String> condition = new ArrayList<>();
        switch (status){
            case InvoiceConstants.OPERATE_STATUS_NOTYET:
                // 入库过
                condition.add(InvoiceConstants.OPERATE_STATUS_NOTYET);
                condition.add(InvoiceConstants.OPERATE_STATUS_SUBMIT);
                condition.add(InvoiceConstants.OPERATE_STATUS_DESTROY);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_NOTYET, condition);
            case InvoiceConstants.OPERATE_STATUS_SUBMIT:
                // 提交过
                condition.add(InvoiceConstants.OPERATE_STATUS_NOTYET);
                condition.add(InvoiceConstants.OPERATE_STATUS_SUBMIT);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_SUBMIT, condition);
            case InvoiceConstants.OPERATE_STATUS_DESTROY:
                // 核销过
                condition.add(InvoiceConstants.OPERATE_STATUS_DESTROY);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_DESTROY,condition);
            case InvoiceConstants.OPERATE_STATUS_CONFIRMED:
                // 采集过
                condition.add(InvoiceConstants.OPERATE_STATUS_CONFIRMED);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_SUBMIT);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_CHECK);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH);
                condition.add(InvoiceConstants.OPERATE_STATUS_TRANSFER);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_CONFIRMED, condition);
            case InvoiceConstants.OPERATE_STATUS_AUTH_SUBMIT:
                // 认证提交过
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_SUBMIT);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_CHECK);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH);
                condition.add(InvoiceConstants.OPERATE_STATUS_TRANSFER);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_AUTH_SUBMIT, condition);
            case InvoiceConstants.OPERATE_STATUS_AUTH_CHECK:
                // 验收过
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_CHECK);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH);
                condition.add(InvoiceConstants.OPERATE_STATUS_TRANSFER);
            case InvoiceConstants.OPERATE_STATUS_AUTH:
                // 认证过
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH);
                condition.add(InvoiceConstants.OPERATE_STATUS_TRANSFER);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_AUTH, condition);
            case InvoiceConstants.OPERATE_STATUS_TRANSFER:
                // 转出过
                condition.add(InvoiceConstants.OPERATE_STATUS_TRANSFER);
                return getOrSetBoxCountByRedis(InvoiceConstants.OPERATE_STATUS_TRANSFER, condition);
        }
        return 0L;
    }
    /**
     * 通过redis获取,或存到redis
     * @param status
     * @return
     */
    private Long getOrSetBoxCountByRedis(String status, ArrayList<String> condition){
        String key = "index_SelectBox:" + SecurityUtils.getEnterpriseId();
        // 1.如果缓存存在,则从缓存取
        if (RedisHashUtils.hExist(key,status)) {
            return (Long) RedisHashUtils.hGet(key, status);
        }
        // 2.如果缓存不存在,则从数据库取
        YsInvoice invoice = new YsInvoice();
        invoice.getParams().put("operateStatus",condition);
        Long value = ysInvoiceMapper.selectBoxCount(invoice);
        RedisHashUtils.hSetExpireOneDay(key, status, value);
        return value;
    }
    /**
     * 获取首页折线图数据 最近7天发票数据
     * invoiceData:[],
     * destroyedData:[],
     * dateData:[]
     *
     * @return
     */
    @Override
    public Map<String, Object> getIndexLineChartByMonth(String type) {
        Map<String, Object> dataMap = new LinkedHashMap<>();
        List<String> dateData = new ArrayList<>();
        List<Long> fisstDataList = new ArrayList<>();
        List<Long> secondDataList = new ArrayList<>();
        Long enterpriseId = SecurityUtils.getEnterpriseId();
        for (int i = 12; i >= 0; i--) {
            String month = DateUtils.getNowBeforeMonthStr2(i);
            if (i == 0) {
                dateData.add("本月");
            } else {
                dateData.add(month);
            }
            // 1.查询当前发票数
            YsInvoice invoice = new YsInvoice();
            ArrayList<String> condition = new ArrayList<>();
            // 2.查询当前核销数/转出数
            Long first = 0L;
            Long second = 0L;
            if ("1".equals(type)) {
                condition.add(InvoiceConstants.OPERATE_STATUS_NOTYET);
                condition.add(InvoiceConstants.OPERATE_STATUS_SUBMIT);
                condition.add(InvoiceConstants.OPERATE_STATUS_DESTROY);
                invoice.getParams().put("operateStatus", condition);
                invoice.getParams().put("startDate", month + "-01");
                invoice.getParams().put("endDate",month + "-31");
                first = ysInvoiceMapper.selectLineCount(invoice);
                second = ysInvoiceLogMapper.selectByTypeBetween(InvoiceConstants.OPERATE_STATUS_DESTROY,month + "-01",month + "-31", enterpriseId);
            } else if ("2".equals(type)) {
                condition.add(InvoiceConstants.OPERATE_STATUS_NOTYET);
                condition.add(InvoiceConstants.OPERATE_STATUS_CONFIRMED);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_SUBMIT);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH_CHECK);
                condition.add(InvoiceConstants.OPERATE_STATUS_AUTH);
                condition.add(InvoiceConstants.OPERATE_STATUS_TRANSFER);
                invoice.getParams().put("operateStatus", condition);
                invoice.getParams().put("startDate", month + "-01");
                invoice.getParams().put("endDate",month + "-31");
                first = ysInvoiceMapper.selectLineCount(invoice);
                second = ysInvoiceLogMapper.selectByTypeBetween(InvoiceConstants.OPERATE_STATUS_TRANSFER,month + "-01",month + "-31", enterpriseId);
            }
            fisstDataList.add(first);
            secondDataList.add(second);
        }
        dataMap.put("dateData", dateData);
        dataMap.put("firstData", fisstDataList);
        dataMap.put("secondData", secondDataList);
        return dataMap;
    }
    /**
     * 获取当前折线图的数据或从redis获取
     * @param type 当前用户选择的类型
     * @return
     */
    @Override
    public Map<String, Object> getOrSetLineCountByRedis(String type){
        String key = "index_SelectLine:" + SecurityUtils.getEnterpriseId();
        // 1.如果缓存存在,则从缓存取
        if (RedisHashUtils.hExist(key,type)) {
            return (Map<String, Object>) RedisHashUtils.hGet(key, type);
        }
        // 2.如果缓存不存在,则从数据库取
        Map<String, Object> map = getIndexLineChartByMonth(type);
        // 当前日期到当月最后一天的秒数
        LocalDateTime midnight = LocalDateTime.now().plusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
        long between = ChronoUnit.SECONDS.between(LocalDateTime.now(), midnight);
        RedisHashUtils.hSetExpireOneMonth(key, type, map, between);
        return map;
    }
  1. 工具类
public class RedisHashUtils {
    private final static RedisService redisService = SpringUtils.getBean(RedisService.class);
    /**
     * 直接以map集合的方式添加key对应的值
     * @param key map中key已经存在,覆盖替换
     * @param map map中key不存在,新增
     * @return
     */
    public static Boolean hmSet(final String key, Map map) {
        boolean result = false;
        try {
            redisService.redisTemplate.opsForHash().putAll(key, map);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 以map集合的方式添加key对应的值,并缓存一天时间
     */
    public static Boolean hmSetExpireOneDay(final String key, Map map) {
        boolean result = false;
        try {
            redisService.redisTemplate.opsForHash().putAll(key, map);
            redisService.redisTemplate.expire(key, 1, TimeUnit.DAYS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 新增hashMap值
     * @param key   为Redis的key
     * @param mapKey    为key对应的map值的key
     * @param value 为key对应的map值的值
     * @return
     */
    public static Boolean hSet(String key, String mapKey, Object value){
        boolean result = false;
        try {
            redisService.redisTemplate.opsForHash().put(key, mapKey, value);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 新增hashMap值,并缓存一天时间
     */
    public static Boolean hSetExpireOneDay(String key, String mapKey, Object value){
        boolean result = false;
        try {
            redisService.redisTemplate.opsForHash().put(key, mapKey, value);
            redisService.redisTemplate.expire(key, 86400, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    public static Boolean hSetExpireOneMonth(String key, String mapKey, Object value, Long time){
        boolean result = false;
        try {
            redisService.redisTemplate.opsForHash().put(key, mapKey, value);
            redisService.redisTemplate.expire(key, time, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 以hashMap集合的方式添加key对应的值,并缓存到指定的时间
     */
    public static Boolean hSetExpireCustomize(final String key, String mapKey, Object value, Date date) {
        boolean result = false;
        try {
            redisService.redisTemplate.opsForHash().put(key, mapKey, value);
            redisService.redisTemplate.expireAt(key, date);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * 获取hash缓存
     * @param key   redis的key
     * @param filed hash的map的key
     * @return
     */
    public static Object hGet(String key, Object filed) {
        return redisService.redisTemplate.opsForHash().get(key, filed);
    }
    /**
     * 当前key是否存在value
     */
    public static Boolean hExist(String key, String mapName){
        return redisService.redisTemplate.opsForHash().hasKey(key, mapName);
    }
    /**
     * 以集合的方式获取这些键对应的map
     * @param key   redis的key
     * @param list  将hash中的key存到list当中查找
     * @return
     */
    public static List HmultiGet(String key, List list) {
        return redisService.redisTemplate.opsForHash().multiGet(key, list);
    }
    /**
     * 删除整个对应key的redis数据
     */
    public static Boolean DelAll(String key) {
        return redisService.redisTemplate.delete(key);
    }
    /**
     * 删除hash中某个对应key的数据
     * @param key  redis的key
     * @param filed key
     * @return
     */
    public static Long HDelete(String key, Object filed){
        return redisService.redisTemplate.opsForHash().delete(key, filed);
    }
    /**
     * redis的hash自助工具:先判空,有数据就删除,重新写入;否则,直接写入
     * @param key redis的key
     * @param filed 数据的key
     * @param obj 数据的value
     */
    public static void HelpMeSet(String key, Object filed, Object obj){
        if (RedisHashUtils.hExist(key, String.valueOf(filed))) {
            RedisHashUtils.HDelete(key, String.valueOf(filed));
        }
        RedisHashUtils.hSet(key, String.valueOf(filed), obj);
    }
}