图形报表、POI报表 权限控制菜单动态展示

1. 套餐预约占比饼形图

1.1 需求分析

会员可以通过移动端自助进行体检预约,在预约时需要选择预约的体检套餐。本章节我们需要通过饼形
图直观的展示出会员预约的各个套餐占比情况。展示效果如下图:
在这里插入图片描述

1.2 完善页面

  • 导入ECharts库
  • 发送请求查询,返回值赋值给两个数据模型
  • 没有匹配的对象,用map封装,setmealCount查询出来的套餐有name,可以赋值给前面setmealNames数据模型
  • 重点是sql语句,按名字分组,然后用cout来
<!DOCTYPE html>
<html>
    <head>
        <!-- 页面meta -->
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>传智健康</title>
        <meta name="description" content="传智健康">
        <meta name="keywords" content="传智健康">
        <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
        <!-- 引入样式 -->
        <link rel="stylesheet" href="../css/style.css">
        <script src="../plugins/echarts/echarts.js"></script>
    </head>
    <body class="hold-transition">
        <div id="app">
            <div class="content-header">
                <h1>统计分析<small>套餐占比</small></h1>
                <el-breadcrumb separator-class="el-icon-arrow-right" class="breadcrumb">
                    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                    <el-breadcrumb-item>统计分析</el-breadcrumb-item>
                    <el-breadcrumb-item>套餐占比</el-breadcrumb-item>
                </el-breadcrumb>
            </div>
            <div class="app-container">
                <div class="box">
                    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
                    <div id="chart1" style="height:600px;"></div>
                </div>
            </div>
        </div>
    </body>
    <!-- 引入组件库 -->
    <script src="../js/vue.js"></script>
    <script src="../js/axios-0.18.0.js"></script>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart1 = echarts.init(document.getElementById('chart1'));

        // 使用刚指定的配置项和数据显示图表。
        //myChart.setOption(option);

        axios.get("/report/getSetmealReport.do").then((res)=>{
            myChart1.setOption({
                                    title : {
                                        text: '套餐预约占比',
                                        subtext: '',
                                        x:'center'
                                    },
                                    tooltip : {//提示框组件
                                        trigger: 'item',//触发类型,在饼形图中为item
                                        formatter: "{a} <br/>{b} : {c} ({d}%)"//提示内容格式
                                    },
                                    legend: {
                                        orient: 'vertical',
                                        left: 'left',
                                        data: res.data.data.setmealNames
                                    },
                                    series : [
                                        {
                                            name: '套餐预约占比',
                                            type: 'pie',
                                            radius : '55%',
                                            center: ['50%', '60%'],
                                            data:res.data.data.setmealCount,
                                            itemStyle: {
                                                emphasis: {
                                                    shadowBlur: 10,
                                                    shadowOffsetX: 0,
                                                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                                                }
                                            }
                                        }
                                    ]
                                });
        });
    </script>
</html>

根据饼形图对数据格式的要求,我们发送ajax请求,服务端需要返回如下格式的数据

{ 
"data":{"
         setmealNames":["套餐1","套餐2","套餐3"], 
        "setmealCount":[{"name":"套餐1","value":10}, 
                        {"name":"套餐2","value":30}, 
                        {"name":"套餐3","value":25} ] }, 
 "flag":true, 
 "message":"获取套餐统计数据成功" }

1.3后端代码

@RestController
@RequestMapping("/report")
public class ReportController {

    @Reference
    private SetmealService setmealService;

 //套餐预约占比,饼图
    @RequestMapping("/getSetmealReport")
    public Result getSetmealReport() {
        try {
            Map<String, Object> data = new HashMap<>();
            //setmealNames   setmealCount
            List<String> setmealNames = new ArrayList<>();

            List<Map<String, Object>> setmealCount = setmealService.findSetmealCount();
            for (Map<String, Object> map : setmealCount) {
                String name = (String) map.get("name");
                setmealNames.add(name);
            }
            data.put("setmealNames", setmealNames);
            data.put("setmealCount", setmealCount);
            return new Result(true, MessageConstant.GET_SETMEAL_LIST_SUCCESS, data);

        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.GET_SETMEAL_LIST_FAIL);
        }
    }

service

public interface ReportService {

    Map<String,Object> getBusinessReportData();

}

serviceImpl

 //查询套餐预约占比数据
    @Override
    public List<Map<String, Object>> findSetmealCount() {
        return setmealDao.findSetmealCount();
    }

dao

public List<Map<String,Object>> findSetmealCount();

dao.xml

 <select id="findHotSetmeal" resultType="java.util.Map">
        select s.name,count(o.id) setmeal_count, count(o.id)/(select count(id) from t_order)*100 proportion
        from t_order o,t_setmeal s where
        o.setmeal_id=s.id
        group by o.setmeal_id
        order by setmeal_count desc
        limit 3
    </select>

2. 运营数据统计

2.1 需求分析

在这里插入图片描述

2.2完善页面

<!DOCTYPE html>
<html>
    <head>
        <!-- 页面meta -->
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>传智健康</title>
        <meta name="description" content="传智健康">
        <meta name="keywords" content="传智健康">
        <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
        <!-- 引入样式 -->
        <link rel="stylesheet" href="../plugins/elementui/index.css">
        <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min(1).css">
        <link rel="stylesheet" href="../css/style.css">
        <style>
            .grid-content {
                border-radius: 4px;
                min-height: 40px;
            }
        </style>
    </head>
    <body class="hold-transition">
        <div id="app">
            <div class="content-header">
                <h1>统计分析<small>运营数据</small></h1>
                <el-breadcrumb separator-class="el-icon-arrow-right" class="breadcrumb">
                    <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                    <el-breadcrumb-item>统计分析</el-breadcrumb-item>
                    <el-breadcrumb-item>运营数据</el-breadcrumb-item>
                </el-breadcrumb>
            </div>
            <div class="app-container">
                <div class="box" style="height: 900px">
                    <div class="excelTitle" >
                        <el-button @click="exportExcel">导出Excel</el-button>运营数据统计
                    </div>
                    <div class="excelTime">日期:{{reportData.reportDate}}</div>
                    <table class="exceTable" cellspacing="0" cellpadding="0">
                        <tr>
                            <td colspan="4" class="headBody">会员数据统计</td>
                        </tr>
                        <tr>
                            <td width='20%' class="tabletrBg">新增会员数</td>
                            <td width='30%'>{{reportData.todayNewMember}}</td>
                            <td width='20%' class="tabletrBg">总会员数</td>
                            <td width='30%'>{{reportData.totalMember}}</td>
                        </tr>
                        <tr>
                            <td class="tabletrBg">本周新增会员数</td>
                            <td>{{reportData.thisWeekNewMember}}</td>
                            <td class="tabletrBg">本月新增会员数</td>
                            <td>{{reportData.thisMonthNewMember}}</td>
                        </tr>
                        <tr>
                            <td colspan="4" class="headBody">预约到诊数据统计</td>
                        </tr>
                        <tr>
                            <td class="tabletrBg">今日预约数</td>
                            <td>{{reportData.todayOrderNumber}}</td>
                            <td class="tabletrBg">今日到诊数</td>
                            <td>{{reportData.todayVisitsNumber}}</td>
                        </tr>
                        <tr>
                            <td class="tabletrBg">本周预约数</td>
                            <td>{{reportData.thisWeekOrderNumber}}</td>
                            <td class="tabletrBg">本周到诊数</td>
                            <td>{{reportData.thisWeekVisitsNumber}}</td>
                        </tr>
                        <tr>
                            <td class="tabletrBg">本月预约数</td>
                            <td>{{reportData.thisMonthOrderNumber}}</td>
                            <td class="tabletrBg">本月到诊数</td>
                            <td>{{reportData.thisMonthVisitsNumber}}</td>
                        </tr>
                        <tr>
                            <td colspan="4" class="headBody">热门套餐</td>
                        </tr>
                        <tr class="tabletrBg textCenter">
                            <td>套餐名称</td>
                            <td>预约数量</td>
                            <td>占比</td>
                            <td>备注</td>
                        </tr>
                        <tr v-for="s in reportData.hotSetmeal">
                            <td>{{s.name}}</td>
                            <td>{{s.setmeal_count}}</td>
                            <td>{{s.proportion}}</td>
                            <td></td>
                        </tr>
                    </table>
                </div>
        </div>
    </body>
    <!-- 引入组件库 -->
    <script src="../js/vue.js"></script>
    <script src="../plugins/elementui/index.js"></script>
    <script type="text/javascript" src="../js/jquery.min.js"></script>
    <script src="../js/axios-0.18.0.js"></script>
    <script>
        var vue = new Vue({
            el: '#app',
            data:{
                reportData:{
                    reportDate:null,
                    todayNewMember :0,
                    totalMember :0,
                    thisWeekNewMember :0,
                    thisMonthNewMember :0,
                    todayOrderNumber :0,
                    todayVisitsNumber :0,
                    thisWeekOrderNumber :0,
                    thisWeekVisitsNumber :0,
                    thisMonthOrderNumber :0,
                    thisMonthVisitsNumber :0,
                    hotSetmeal :[
                        {name:'阳光爸妈升级肿瘤12项筛查(男女单人)体检套餐',setmeal_count:200,proportion:0.222},
                        {name:'阳光爸妈升级肿瘤12项筛查体检套餐',setmeal_count:200,proportion:0.222}
                    ]
                }
            },
            created() {
                axios.get("/report/getBusinessReportData.do").then((res)=>{
                    if (res.data.flag){
                        this.reportData = res.data.data;
                    }else {
                        this.$message.error(res.data.message);
                    }
                });
            },
            methods:{
                exportExcel(){
                    window.location.href = '/report/exportBusinessReport.do';
                }
            }
        })
    </script>
</html>

这里重点是数据模型,要把这一块理清楚,然后一个一个赋值,一个一个sql查询,取名字要见名之意

  reportData:{
                    reportDate:null,
                    todayNewMember :0,
                    totalMember :0,
                    thisWeekNewMember :0,
                    thisMonthNewMember :0,
                    todayOrderNumber :0,
                    todayVisitsNumber :0,
                    thisWeekOrderNumber :0,
                    thisWeekVisitsNumber :0,
                    thisMonthOrderNumber :0,
                    thisMonthVisitsNumber :0,
                    hotSetmeal :[
                        {name:'阳光爸妈升级肿瘤12项筛查(男女单人)体检套餐',setmeal_count:200,proportion:0.222},
                        {name:'阳光爸妈升级肿瘤12项筛查体检套餐',setmeal_count:200,proportion:0.222}
                    ]
                }

2.3 Controller

 @Reference
    private ReportService reportService;

    @RequestMapping("/getBusinessReportData")
    public Result getBusinessReportData() {
        try {
            Map<String, Object> data = reportService.getBusinessReportData();
            return new Result(true,MessageConstant.GET_BUSINESS_REPORT_SUCCESS,data);
        }catch (Exception e){
            return new Result(false,MessageConstant.GET_BUSINESS_REPORT_FAIL);
        }
    }

service

public interface ReportService {

    Map<String,Object> getBusinessReportData();

}

serviceImpl

package com.ybb.service.Impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.ybb.dao.MemberDao;
import com.ybb.dao.OrderDao;
import com.ybb.service.ReportService;
import com.ybb.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Description :
 * Version :1.0
 */
@Service(interfaceClass = ReportService.class)
@Transactional  //查询,可加可不加
public class ReportServiceImpl implements ReportService {

    @Autowired
    private MemberDao memberDao;

    @Autowired
    private OrderDao orderDao;

    @Override
    public Map<String, Object> getBusinessReportData() {
         /*      reportDate:null,
                    todayNewMember :0,
                    totalMember :0,
                    thisWeekNewMember :0,
                    thisMonthNewMember :0,
                    todayOrderNumber :0,
                    todayVisitsNumber :0,
                    thisWeekOrderNumber :0,
                    thisWeekVisitsNumber :0,
                    thisMonthOrderNumber :0,
                    thisMonthVisitsNumber :0,
                    hotSetmeal :[
                        {name:'阳光爸妈升级肿瘤12项筛查(男女单人)体检套餐',setmeal_count:200,proportion:0.222},
                        {name:'阳光爸妈升级肿瘤12项筛查体检套餐',setmeal_count:200,proportion:0.222}
                    ] */
        try {
            Map<String, Object> map = new HashMap<>();
            //获得当前日期
            String today = DateUtils.parseDate2String(new Date());
            map.put("reportDate",today);
            //获得本周一的日期
            String thisweekMonday = DateUtils.parseDate2String(DateUtils.getThisWeekMonday());
            //获得本月第一天的日期
            String firstDat4ThisMonth = DateUtils.parseDate2String(DateUtils.getFirstDay4ThisMonth());
            //今日新增的会员
            Integer todayNewMember = memberDao.findMemberCountByDate(today);
            map.put("todayNewMember",todayNewMember);
            //总会员数
            Integer totalMember = memberDao.findMemberTotalCount();
            map.put("totalMember",totalMember);
            //本周新增的会员
            Integer thisWeekNewMember = memberDao.findMemberCountAfterDate(thisweekMonday);
            map.put("thisWeekNewMember",thisWeekNewMember);
            //本月新增的会员
            Integer thisMonthNewMember = memberDao.findMemberCountAfterDate(firstDat4ThisMonth);
            map.put("thisMonthNewMember",thisMonthNewMember);
            //今日预约数
            Integer todayOrderNumber=orderDao.findOrderCountByDate(today);
            map.put("todayOrderNumber",todayOrderNumber);
            //今日到诊数
            Integer todayVisitsNumber=orderDao.findVisitsCountByDate(today);
            map.put("todayVisitfindMemberCountBeforeDatesNumber",todayVisitsNumber);
           //本周预约数
           Integer thisweekOrderNumber= orderDao.findOrderCountAfterDate(thisweekMonday);
            map.put("thisWeekOrderNumber",thisweekOrderNumber);
            //本周到诊数
           Integer thisweekVisitsNumber= orderDao.findVisitsCountAfterDate(thisweekMonday);
           map.put("thisWeekVisitsNumber",thisweekVisitsNumber);
           //本月预约数
            Integer thisMonthOrderNumber = orderDao.findOrderCountAfterDate(firstDat4ThisMonth);
            map.put("thisMonthOrderNumber",thisMonthOrderNumber);
            //本月预约到诊数
            Integer thisMonthVisitsNumber = orderDao.findVisitsCountAfterDate(firstDat4ThisMonth);
            map.put("thisMonthVisitsNumber",thisMonthVisitsNumber);

            //热门套餐
            List<Map> hotSetmeal = orderDao.findHotSetmeal();

            map.put("hotSetmeal",hotSetmeal);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }
}

工具类

package com.ybb.utils;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期操作工具类
 */
public class DateUtils {
    /**
     * 日期转换-  String -> Date
     *
     * @param dateString 字符串时间
     * @return Date类型信息
     * @throws Exception 抛出异常
     */
    public static Date parseString2Date(String dateString) throws Exception {
        if (dateString == null) {
            return null;
        }
        return parseString2Date(dateString, "yyyy-MM-dd");
    }

    /**
     * 日期转换-  String -> Date
     *
     * @param dateString 字符串时间
     * @param pattern    格式模板
     * @return Date类型信息
     * @throws Exception 抛出异常
     */
    public static Date parseString2Date(String dateString, String pattern) throws Exception {
        if (dateString == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date date = sdf.parse(dateString);
        return date;
    }

    /**
     * 日期转换 Date -> String
     *
     * @param date Date类型信息
     * @return 字符串时间
     * @throws Exception 抛出异常
     */
    public static String parseDate2String(Date date) throws Exception {
        if (date == null) {
            return null;
        }
        return parseDate2String(date, "yyyy-MM-dd");
    }

    /**
     * 日期转换 Date -> String
     *
     * @param date    Date类型信息
     * @param pattern 格式模板
     * @return 字符串时间
     * @throws Exception 抛出异常
     */
    public static String parseDate2String(Date date, String pattern) throws Exception {
        if (date == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String strDate = sdf.format(date);
        return strDate;
    }

    /**
     * 获取当前日期的本周一是几号
     *
     * @return 本周一的日期
     */
    public static Date getThisWeekMonday() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.getTime();
    }

    /**
     * 获取当前日期周的最后一天
     *
     * @return 当前日期周的最后一天
     */
    public static Date getSundayOfThisWeek() {
        Calendar c = Calendar.getInstance();
        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek == 0) {
            dayOfWeek = 7;
        }
        c.add(Calendar.DATE, -dayOfWeek + 7);
        return c.getTime();
    }

    /**
     * 根据日期区间获取月份列表
     *
     * @param minDate 开始时间
     * @param maxDate 结束时间
     * @return 月份列表
     * @throws Exception
     */
    public static List<String> getMonthBetween(String minDate, String maxDate, String format) throws Exception {
        ArrayList<String> result = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");

        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();

        min.setTime(sdf.parse(minDate));
        min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

        max.setTime(sdf.parse(maxDate));
        max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
        SimpleDateFormat sdf2 = new SimpleDateFormat(format);

        Calendar curr = min;
        while (curr.before(max)) {
            result.add(sdf2.format(curr.getTime()));
            curr.add(Calendar.MONTH, 1);
        }

        return result;
    }

    /**
     * 根据日期获取年度中的周索引
     *
     * @param date 日期
     * @return 周索引
     * @throws Exception
     */
    public static Integer getWeekOfYear(String date) throws Exception {
        Date useDate = parseString2Date(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(useDate);
        return cal.get(Calendar.WEEK_OF_YEAR);
    }

    /**
     * 根据年份获取年中周列表
     *
     * @param year 年分
     * @return 周列表
     * @throws Exception
     */
    public static Map<Integer, String> getWeeksOfYear(String year) throws Exception {
        Date useDate = parseString2Date(year, "yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(useDate);
        //获取年中周数量
        int weeksCount = cal.getWeeksInWeekYear();
        Map<Integer, String> mapWeeks = new HashMap<>(55);
        for (int i = 0; i < weeksCount; i++) {
            cal.get(Calendar.DAY_OF_YEAR);
            mapWeeks.put(i + 1, parseDate2String(getFirstDayOfWeek(cal.get(Calendar.YEAR), i)));
        }
        return mapWeeks;
    }

    /**
     * 获取某年的第几周的开始日期
     *
     * @param year 年分
     * @param week 周索引
     * @return 开始日期
     * @throws Exception
     */
    public static Date getFirstDayOfWeek(int year, int week) throws Exception {
        Calendar c = new GregorianCalendar();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, Calendar.JANUARY);
        c.set(Calendar.DATE, 1);

        Calendar cal = (GregorianCalendar) c.clone();
        cal.add(Calendar.DATE, week * 7);

        return getFirstDayOfWeek(cal.getTime());
    }

    /**
     * 获取某年的第几周的结束日期
     *
     * @param year 年份
     * @param week 周索引
     * @return 结束日期
     * @throws Exception
     */
    public static Date getLastDayOfWeek(int year, int week) throws Exception {
        Calendar c = new GregorianCalendar();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, Calendar.JANUARY);
        c.set(Calendar.DATE, 1);

        Calendar cal = (GregorianCalendar) c.clone();
        cal.add(Calendar.DATE, week * 7);

        return getLastDayOfWeek(cal.getTime());
    }

    /**
     * 获取当前时间所在周的开始日期
     *
     * @param date 当前时间
     * @return 开始时间
     */
    public static Date getFirstDayOfWeek(Date date) {
        Calendar c = new GregorianCalendar();
        c.setFirstDayOfWeek(Calendar.SUNDAY);
        c.setTime(date);
        c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek());
        return c.getTime();
    }

    /**
     * 获取当前时间所在周的结束日期
     *
     * @param date 当前时间
     * @return 结束日期
     */
    public static Date getLastDayOfWeek(Date date) {
        Calendar c = new GregorianCalendar();
        c.setFirstDayOfWeek(Calendar.SUNDAY);
        c.setTime(date);
        c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6);
        return c.getTime();
    }
    //获得上周一的日期
    public static Date geLastWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, -7);
        return cal.getTime();
    }

    //获得本周一的日期
    public static Date getThisWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        // 获得当前日期是一个星期的第几天
        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
        if (1 == dayWeek) {
            cal.add(Calendar.DAY_OF_MONTH, -1);
        }
        // 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        // 获得当前日期是一个星期的第几天
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);
        return cal.getTime();
    }

    //获得下周一的日期
    public static Date getNextWeekMonday(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getThisWeekMonday(date));
        cal.add(Calendar.DATE, 7);
        return cal.getTime();
    }

    //获得今天日期
    public static Date getToday(){
        return new Date();
    }

    //获得本月一日的日期
    public static Date getFirstDay4ThisMonth(){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_MONTH,1);
        return calendar.getTime();
    }

    public static void main(String[] args) {
        try {
            System.out.println("本周一" + parseDate2String(getThisWeekMonday()));
            System.out.println("本月一日" + parseDate2String(getFirstDay4ThisMonth()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

menberdao

public interface MemberDao {
    public List<Member> findAll();
    public Page<Member> selectByCondition(String queryString);
    public void add(Member member);
    public void deleteById(Integer id);
    public Member findById(Integer id);
    public Member findByTelephone(@Param("phoneNumber") String telephone);
    public void edit(Member member);
    public Integer findMemberCountBeforeDate(String date);
    public Integer findMemberCountByDate(String date);
    public Integer findMemberCountAfterDate(String date);
    public Integer findMemberTotalCount();
}

memberdao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ybb.dao.MemberDao" >
    <select id="findAll" resultType="com.ybb.pojo.Member">
        select * from t_member
    </select>

    <!--根据条件查询-->
    <select id="selectByCondition" parameterType="string" resultType="com.ybb.pojo.Member">
        select * from t_member
        <if test="value != null and value.length > 0">
            where fileNumber = #{value} or phoneNumber = #{value} or name = #{value}
        </if>
    </select>

    <!--新增会员-->
    <insert id="add" parameterType="com.ybb.pojo.Member">
        <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into t_member(fileNumber,name,sex,idCard,phoneNumber,regTime,password,email,birthday,remark)
        values (#{fileNumber},#{name},#{sex},#{idCard},#{phoneNumber},#{regTime},#{password},#{email},#{birthday},#{remark})
    </insert>

    <!--删除会员-->
    <delete id="deleteById" parameterType="int">
        delete from t_member where id = #{id}
    </delete>

    <!--根据id查询会员-->
    <select id="findById" parameterType="int" resultType="com.ybb.pojo.Member">
        select * from t_member where id = #{id}
    </select>

    <!--根据id查询会员-->
    <select id="findByTelephone" parameterType="string" resultType="com.ybb.pojo.Member">
        select * from t_member where phoneNumber = #{phoneNumber}
    </select>

    <!--编辑会员-->
    <update id="edit" parameterType="com.ybb.pojo.Member">
        update t_member
        <set>
            <if test="fileNumber != null">
                fileNumber = #{fileNumber},
            </if>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="sex != null">
                sex = #{sex},
            </if>
            <if test="idCard != null">
                idCard = #{idCard},
            </if>
            <if test="phoneNumber != null">
                phoneNumber = #{phoneNumber},
            </if>
            <if test="regTime != null">
                regTime = #{regTime},
            </if>
            <if test="password != null">
                password = #{password},
            </if>
            <if test="email != null">
                email = #{email},
            </if>
            <if test="birthday != null">
                birthday = #{birthday},
            </if>
            <if test="remark != null">
                remark = #{remark},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--根据日期统计会员数,统计指定日期之前的会员数-->
    <select id="findMemberCountBeforeDate" parameterType="string" resultType="int">
        select count(id) from t_member where regTime &lt;= #{value}
    </select>
    <!--根据日期统计会员数-->
    <select id="findMemberCountByDate" parameterType="string" resultType="int">
        select count(id) from t_member where regTime = #{value}
    </select>

    <!--根据日期统计会员数,统计指定日期之后的会员数-->
    <select id="findMemberCountAfterDate" parameterType="string" resultType="int">
        select count(id) from t_member where regTime >= #{value}
    </select>

    <!--总会员数-->
    <select id="findMemberTotalCount" resultType="int">
        select count(id) from t_member
    </select>
</mapper>

orderdao

package com.ybb.dao;

import com.github.pagehelper.Page;
import com.ybb.pojo.*;
import org.apache.ibatis.annotations.Param;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator
 * Date :2020/8/24
 * Description :
 * Version :1.0
 */
public interface OrderDao {


    Map findById4Detail(Integer id);

    Member findByCondition(@Param("id") Integer id, @Param("orderDate") Date order_date, @Param("setmeal_id") String setmealId);

    void add(Map map);

   List<Map> findHotSetmeal();

    Integer findOrderCountByDate(String today);

    Integer findVisitsCountByDate(String today);

    Integer findOrderCountAfterDate(String thisweekMonday);

    Integer findVisitsCountAfterDate(String thisweekMonday);
}

orderdao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ybb.dao.OrderDao">



    <insert id="add" parameterType="map">
          insert into t_order (member_id,orderDate,orderType,orderStatus,setmeal_id)
        values
        (#{member_id},#{orderDate},#{orderType},#{orderStatus},#{setmeal_id})
    </insert>

    <select id="findById4Detail" parameterType="int" resultType="map">
       select m.name member ,s.name setmeal,o.orderDate orderDate,o.orderType orderType from
        t_order o, t_member m, t_setmeal s
       where o.member_id=m.id and o.setmeal_id=s.id and o.member_id=#{id}
   </select>

    <select id="findByCondition" resultType="com.ybb.pojo.Member">
        select * from t_order where id=#{id} and orderDate =#{orderDate} and setmeal_id =#{setmeal_id}
    </select>

    <select id="findHotSetmeal" resultType="java.util.Map">
        select s.name,count(o.id) setmeal_count, count(o.id)/(select count(id) from t_order)*100 proportion
        from t_order o,t_setmeal s where
        o.setmeal_id=s.id
        group by o.setmeal_id
        order by setmeal_count desc
        limit 3
    </select>

    <!--今日预约-->
    <select id="findOrderCountByDate" resultType="java.lang.Integer" parameterType="string">
        select count(id) from t_order where orderDate=#{today}
    </select>
<!--今日预约到诊-->
    <select id="findVisitsCountByDate" resultType="java.lang.Integer" parameterType="string">
         select count(id) from t_order where orderDate=#{today} and  orderStatus='已到诊'
    </select>
<!--本周预约数-->
    <select id="findOrderCountAfterDate" resultType="java.lang.Integer" parameterType="string">
        select count(id) from t_order where orderDate >=#{thisweekMonday}
    </select>

    <select id="findVisitsCountAfterDate" resultType="java.lang.Integer" parameterType="string">
           select count(id) from t_order where orderDate >=#{today} and  orderStatus='已到诊'
    </select>
</mapper>

重点在套餐查询,需要分组,排序和分页,然后查出来后还需要除总的,起别名。

3. 运营数据统计报表导出

3.1 需求分析

运营数据统计报表导出就是将统计数据写入到Excel并提供给客户端浏览器进行下载,以便体检机构管
理人员对运营数据的查看和存档。

3.2 提供模板文件

在这里插入图片描述

通过上面的Excel效果可以看到,表格比较复杂,涉及到合并单元格、字体、字号、字体加粗、对齐方
式等的设置。如果我们通过POI编程的方式来设置这些效果代码会非常繁琐。
在企业实际开发中,对于这种比较复杂的表格导出一般我们会提前设计一个Excel模板文件,在这个模
板文件中提前将表格的结构和样式设置好,我们的程序只需要读取这个文件并在文件中的相应位置写入
具体的值就可以了。
在本章节资料中已经提供了一个名为report_template.xlsx的模板文件,需要将这个文件复制到
health_backend工程的template目录中

3.3 完善页面

 <div class="excelTitle" >
                        <el-button @click="exportExcel">导出Excel</el-button>运营数据统计
                    </div>
 methods:{
                exportExcel(){
                    window.location.href = '/report/exportBusinessReport.do';
                }
            }

3.4 后台代码

在ReportController中提供exportBusinessReport方法,基于POI将数据写入到Excel中并通过输出流下
载到客户端

 @RequestMapping("/exportBusinessReport")
    public Result exportBusinessReport(HttpServletRequest request, HttpServletResponse response){
        try {
            Map<String, Object> data = reportService.getBusinessReportData();
            String reportData = (String) data.get("reportDate");
            Integer todayNewMember = (Integer)data.get("todayNewMember");
            Integer totalMember = (Integer) data.get("totalMember");
            Integer thisWeekNewMember = (Integer) data.get("thisWeekNewMember");
            Integer thisMonthNewMember = (Integer) data.get("thisMonthNewMember");
            Integer todayOrderNumber = (Integer) data.get("todayOrderNumber");
            Integer todayVisitfindMemberCountBeforeDatesNumber = (Integer) data.get("todayVisitfindMemberCountBeforeDatesNumber");
            Integer thisWeekOrderNumber = (Integer) data.get("thisWeekOrderNumber");
            Integer thisWeekVisitsNumber = (Integer) data.get("thisWeekVisitsNumber");
            Integer thisMonthOrderNumber = (Integer) data.get("thisMonthOrderNumber");
            Integer thisMonthVisitsNumber = (Integer) data.get("thisMonthVisitsNumber");
            List<Map> hotSetmeal = (List<Map>) data.get("hotSetmeal");
            //动态的获得该文件所在的磁盘路径,     file.separator自动适应操作系统分隔符
            String filePath = request.getSession().getServletContext().getRealPath("template") + File.separator + "report_template.xlsx";
            XSSFWorkbook excel=new XSSFWorkbook(new File(filePath));
            //读取第一个工作表
            XSSFSheet sheet = excel.getSheetAt(0);
            //日期
            XSSFRow row = sheet.getRow(2);
            row.getCell(5).setCellValue(reportData);
            //新增会员
            row = sheet.getRow(4);
            row.getCell(5).setCellValue(todayNewMember);
            row.getCell(7).setCellValue(totalMember);

            row=sheet.getRow(5);
            row.getCell(5).setCellValue(thisWeekNewMember);
            row.getCell(7).setCellValue(thisMonthNewMember);

            row=sheet.getRow(7);
            row.getCell(5).setCellValue(todayOrderNumber);
            row.getCell(7).setCellValue(todayVisitfindMemberCountBeforeDatesNumber);

            row=sheet.getRow(8);
            row.getCell(5).setCellValue(thisWeekOrderNumber);
            row.getCell(7).setCellValue(thisWeekVisitsNumber);

            row=sheet.getRow(9);
            row.getCell(5).setCellValue(thisMonthOrderNumber);
            row.getCell(7).setCellValue(thisMonthVisitsNumber);

            int rowNum=12;

            for (Map map : hotSetmeal) {
                row=sheet.getRow(rowNum++);

                BigDecimal proportion = (BigDecimal)map.get("proportion");

                row.getCell(4).setCellValue((String) map.get("name"));
                row.getCell(5).setCellValue((long) map.get("setmeal_count"));
                row.getCell(6).setCellValue(proportion.doubleValue());
            }

            ServletOutputStream out = response.getOutputStream();
            response.setContentType("application/vnd.ms-execl");//execl文件类型
            response.setHeader("content-Disposition","attachment;filename=report.xlsx");//指定以附件下载
            excel.write(out);
            out.flush();
            out.close();
            excel.close();

            return null;
        }catch (Exception e){
            return new Result(false,MessageConstant.GET_MENU_FAIL);
        }
    }

同步请求喔。
这个主要是繁琐,一个一个表的位置插入之前查询的数据,execl表0,0开始的,写入的时候注意位置,写完后注意设置响应格式,然后关流。

权限控制菜单动态展示

分析

在这里插入图片描述

  1. 根据传入的user id查中间表和角色表,拿到角色表的id,然后根据role id查中间表和menu表。

  2. menu表示关键。因为有子菜单,这里用java代码简化查询,第一次查询的时候根据role的id拿到父菜单,条件记得加and
    level=1.出来的是集合,遍历集合,根据父菜单的id和parentMenuld查询子菜单,这里有一个点,每次遍历记得new一个,不然引用对象会有问题。

  3. 数据模型是数组对象,然后对象里套了个数组,这里用map封装
    [ {x:y,xx:yy,xxx:{ } },{x:y,xx:yy,xxx:{ } }]

在这里插入图片描述
根据

<!DOCTYPE html>
<html>
<head>
    <!-- 页面meta -->
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>传智健康</title>
    <meta name="description" content="传智健康">
    <meta name="keywords" content="传智健康">
    <meta content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" name="viewport">
    <!-- 引入样式 -->
    <link rel="stylesheet" href="../plugins/elementui/index.css">
    <link rel="stylesheet" href="../plugins/font-awesome/css/font-awesome.min(1).css">
    <link rel="stylesheet" href="../css/style.css">
    <style type="text/css">
        .el-main {
            position: absolute;
            top: 70px;
            bottom: 0px;
            left: 200px;
            right: 10px;
            padding: 0;
        }
    </style>



    <script type="text/javascript" charset="utf-8" src="../L2Dwidget/L2Dwidget.0.min.js"></script>
    <script type="text/javascript" charset="utf-8" src="../L2Dwidget/L2Dwidget.min.js"></script>
    <script type="text/javascript">
        L2Dwidget.init({
            "display": {
                "superSample": 3,
                "width": 200,
                "height": 400,
                "position": "right",
                "hOffset": 0,
                "vOffset": 0
            }
        });
    </script>


    <style>
        #live2dcanvas {
            border: 0 !important;
        }
    </style>

</head>

<body class="hold-transition skin-purple sidebar-mini">
<div id="app">
    <el-container>
        <el-header class="main-header" style="height:70px;">
            <nav class="navbar navbar-static-top" :class=''>
                <!-- Logo -->
                <a href="#" class="logo" style="text-align:center">
                    <span class="logo-lg"><img src="../img/logo.png"></span>
                </a>
<!--autoplay 搞完吧auto加入-->
                <audio id="audio" src="../1551961057/acb.mp3" controls  loop controlsList="nodownload"
                       oncontextmenu="return false">
                </audio>
                <div class="right-menu">
                    <span class="help"><i class="fa fa-exclamation-circle" aria-hidden="true"></i>帮助</span>
                    <el-dropdown class="avatar-container right-menu-item" trigger="click">
                        <div class="avatar-wrapper">
                            <img src="../img/user2-160x160.jpg" class="user-avatar">
                            {{username}}
                        </div>
                        <el-dropdown-menu slot="dropdown">
                            <el-dropdown-item divided>
                                <span style="display:block;">修改密码</span>
                            </el-dropdown-item>
                            <el-dropdown-item divided>
                                <span style="display:block;">
                                    <a href="/logout.do">退出</a>
                                </span>
                            </el-dropdown-item>
                        </el-dropdown-menu>
                    </el-dropdown>
                </div>
            </nav>
        </el-header>
        <el-container>
            <el-aside width="200px">
                <el-menu>
                    <el-submenu v-for="menu in menuList" :index="menu.path">

                        <template slot="title">
                            <i class="fa" :class="menu.icon"></i>
                            {{menu.title}}
                        </template>
                        <template v-for="child in menu.children">
                            <el-menu-item :index="child.path">
                                <a :href="child.linkUrl" target="right">{{child.title}}</a>
                            </el-menu-item>
                        </template>
                    </el-submenu>
                </el-menu>
            </el-aside>
            <el-container>
                <iframe name="right" class="el-main" src="../1551961057/bb.html" width="100%" height="750px"
                        frameborder="0"></iframe>
            </el-container>
        </el-container>
    </el-container>
</div>
</body>
<!-- 引入组件库 -->
<script type="text/javascript" src="../js/jquery.min.js"></script>
<script src="../js/vue.js"></script>
<script src="../plugins/elementui/index.js"></script>
<script src="../js/axios-0.18.0.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            username: null,
            menuList: [
                {
                    "path": "1",
                    "title": "工作台",
                    "icon": "fa-dashboard",
                    "children": []
                },
                {
                    "path": "2",
                    "title": "会员管理",
                    "icon": "fa-user-md",
                    "children": [
                        {
                            "path": "/2-1",
                            "title": "会员档案",
                            "linkUrl": "member.html",
                            "children": []
                        },
                        {
                            "path": "/2-2",
                            "title": "体检上传",
                            "children": []
                        },
                        {
                            "path": "/2-3",
                            "title": "会员统计",
                            "linkUrl": "all-item-list.html",
                            "children": []
                        },
                    ]
                },
                {
                    "path": "3",
                    "title": "预约管理",
                    "icon": "fa-tty",
                    "children": [
                        {
                            "path": "/3-1",
                            "title": "预约列表",
                            "linkUrl": "ordersettinglist.html",
                            "children": []
                        },
                        {
                            "path": "/3-2",
                            "title": "预约设置",
                            "linkUrl": "ordersetting.html",
                            "children": []
                        },
                        {
                            "path": "/3-3",
                            "title": "套餐管理",
                            "linkUrl": "setmeal.html",
                            "children": []
                        },
                        {
                            "path": "/3-4",
                            "title": "检查组管理",
                            "linkUrl": "checkgroup.html",
                            "children": []
                        },
                        {
                            "path": "/3-5",
                            "title": "检查项管理",
                            "linkUrl": "checkitem.html",
                            "children": []
                        },
                    ]
                },
                {
                    "path": "4",
                    "title": "健康评估",
                    "icon": "fa-stethoscope",
                    "children": [
                        {
                            "path": "/4-1",
                            "title": "中医体质辨识",
                            "linkUrl": "all-medical-list.html",
                            "children": []
                        },
                    ]
                },
                {
                    "path": "5",     //菜单项所对应的路由路径
                    "title": "统计分析",     //菜单项名称
                    "icon": "fa-heartbeat",
                    "children": [//是否有子菜单,若没有,则为[]
                        {
                            "path": "/5-1",
                            "title": "会员数量统计",
                            "linkUrl": "report_member.html",
                            "children": []
                        },
                        {
                            "path": "/5-2",
                            "title": "套餐预约占比统计",
                            "linkUrl": "report_setmeal.html",
                            "children": []
                        },
                        {
                            "path": "/5-3",
                            "title": "运营数据统计",
                            "linkUrl": "report_business.html",
                            "children": []
                        }
                    ]
                }
            ]
        },
        created(){
            axios.get("/user/getUsername.do").then((res)=>{
                if (res.data.flag){
                    this.username=res.data.data.username
                }
            });
            axios.get("/user/getMenus.do").then((res)=>{
                if (res.data.flag){
                    this.menuList=res.data.data

                    console.log(this.menuList);
                }
            });
        },
    });
    $(function () {
        var wd = 200;
        $(".el-main").css('width', $('body').width() - wd + 'px');
    });
</script>
</html>

controller

   @RequestMapping("/getMenus")
    public Result getMenus(){
        Object user =  SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        System.out.println(user);
        if (user!=null){
            com.ybb.pojo.User user1 = userService.findByUserName(((User)user).getUsername());

            List<Map<String,Object>>maps = userService.findUserMenu(user1.getId());
            return new Result(true, MessageConstant.GET_MENU_SUCCESS,maps);
        }
        return new Result(false,MessageConstant.GET_MENU_FAIL);

    }

service
要根据前面username来查数据库,拿到id,就可以操作了

public interface UserService {

      User findByUserName(String username);

     //根据用户id查询到套餐数据
     List<Map<String,Object>> findUserMenu(Integer id);
}

serviceImpl

package com.ybb.service.Impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ybb.dao.MenuDao;
import com.ybb.dao.PermissionDao;
import com.ybb.dao.RoleDao;
import com.ybb.dao.UserDao;
import com.ybb.pojo.Menu;
import com.ybb.pojo.Permission;
import com.ybb.pojo.Role;
import com.ybb.pojo.User;
import com.ybb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * Description :
 * Version :1.0
 */
@Service(interfaceClass = UserService.class)
@Transactional
public class UserServiceImpl implements UserService {

     @Autowired
     private UserDao userDao;

     @Autowired
     private RoleDao roleDao;

     @Autowired
     private PermissionDao permissionDao;
     //根据用户名查询书库获取用户信息和关联的角色信息,同时需要查询角色关联的权限信息

    @Override
    public User findByUserName(String username) {
        User user = userDao.findByUserName(username);
        if (user==null){
            return null;
        }
        Integer userId = user.getId();
        //根据用户ID查询对应的角色
        Set<Role> roles = roleDao.findByUserId(userId);
        for (Role role : roles) {
            //角色ID,去查询关联权限
            Integer roleId = role.getId();
            Set<Permission> permissions = permissionDao.findByRoleId(roleId);
            role.setPermissions(permissions);
        }
        user.setRoles(roles);
        return user;
    }

    @Autowired
    private MenuDao menuDao;

    @Override
    public List<Map<String,Object>> findUserMenu(Integer id) {
        //根据用户传入的id查询中间表,找到对应的角色id
        Role role = roleDao.findByRole(id);
        //先根据父菜单找到子菜单,再根据父菜单的id拿到子菜单,放入父菜单的属性中
        List<Map<String, Object>> maps = menuDao.parentMenus(role.getId());
        for (Map<String, Object> map : maps) {
            Integer parentId = (Integer) map.get("id");

            List<Map<String,String>> sonmaps =new ArrayList<>();
            sonmaps=  menuDao.sonMenus(parentId);
            map.put("children",sonmaps);
        }
        return maps;

    }
}
permissiondao

```java
public interface PermissionDao {

    Set<Permission> findByRoleId(Integer RoleId);

}

permissiondao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ybb.dao.PermissionDao">
    <select id="findByRoleId" resultType="com.ybb.pojo.Permission" parameterType="int">
        SELECT p.* FROM t_permission p,t_role_permission rp
        where p.id=rp.permission_id and rp.role_id=#{RoleId}
    </select>
</mapper>
menuDao

```java
public interface MenuDao {

  List<Map<String,Object>> parentMenus(Integer id);

  List<Map<String,String>>sonMenus(Integer id);

}

menuDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ybb.dao.MenuDao">
    <select id="parentMenus" resultType="java.util.Map" parameterType="int">
      SELECT tm.id id,tm.path path,tm.name title,tm.icon icon
      FROM t_role_menu trm,t_menu tm
      where trm.menu_id=tm.id  and trm.role_id=#{id}  and tm.level=1
          </select>

    <select id="sonMenus" resultType="java.util.Map" parameterType="int">
          SELECT t2.path path,t2.name title,t2.linkUrl linkUrl
          FROM t_menu t1,t_menu t2
          where t1.id=t2.parentMenuId  and t1.id=#{id};
    </select>
</mapper>
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值