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

tech2024-12-12  6

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开始的,写入的时候注意位置,写完后注意设置响应格式,然后关流。

权限控制菜单动态展示

分析

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

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

数据模型是数组对象,然后对象里套了个数组,这里用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>
最新回复(0)