Apache ECharts
Apache ECharts介绍:
Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。
官网地址:https://echarts.apache.org/zh/index.html
Apache ECharts入门程序:
进入官网,按照官方给的步骤:


<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title>ECharts</title><!-- 引入刚刚下载的 ECharts 文件 --><script src="echarts.js"></script></head><body><!-- 为 ECharts 准备一个定义了宽高的 DOM --><div id="main" style="width: 600px;height:400px;"></div><script type="text/javascript">// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('main'));// 指定图表的配置项和数据var option = {title: {text: 'ECharts 入门示例'},tooltip: {},legend: {data: ['销量']},xAxis: {data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']},yAxis: {},series: [{name: '销量',type: 'bar',data: [5, 20, 36, 10, 10, 20]}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);</script></body>
</html>

营业额统计:
业务规则及接口设计:
- 营业额指订单状态为已完成的订单金额合计
- 基于可视化报表的折线图展示营业额数据,X轴为日期,Y轴为营业额
- 根据时间选择区间,展示每天的营业额数据

前端想展示数据,也要设计接口从后端获取数据。


返回数据这一块,因为是前端来展示数据,所以我们提供的数据是要依照前端的规则。
具体代码实现:
Controll层:
@Autowiredprivate ReportService reportService;/*** 营业额统计* @param begin* @param end* @return*/@GetMapping("/turnoverStatistics")@ApiOperation("营业额统计")public Result<TurnoverReportVO> turnoverStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("营业额统计");TurnoverReportVO turnoverReportVO = reportService.turnoverStatistics(begin,end);return Result.success(turnoverReportVO);}
这里有个小细节,就是查询统计营业额,前端传的参数是日期的起始时间和结束时间,
格式是yyyy-MM-dd这种形式,所以,我们也要用这种形式来进行接收。
@DateTimeFormat(pattern = "yyyy-MM-dd"),就用到了这个方法。
Service层:
package com.sky.service.impl;import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.service.ReportService;
import com.sky.vo.TurnoverReportVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.validation.constraints.Min;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class ReportServiceImpl implements ReportService {@Autowiredprivate OrderMapper orderMapper;@Overridepublic TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {//封装TurnoverReportVO的dateList对象List<LocalDate> datelist = new ArrayList<>();datelist.add(begin);while(!begin.equals(end)){//将日期加到list集合中begin = begin.plusDays(1);datelist.add(begin);}String datejoin = StringUtils.join(datelist, ",");//封装TurnoverReportVO的turnoverList对象List<Double> turnoverlist = new ArrayList<>();for (LocalDate localDate : datelist) {//查询date日期对应的营业额数据,营业额是指:状态为“已完成”的订单金额合计LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(localDate,LocalTime.MAX);//select sum(amount) from orders where order_time > ? and order_time < ? and status = 5Map map = new HashMap();map.put("begin",beginTime);map.put("end",endTime);map.put("status", Orders.COMPLETED);Double turnover = orderMapper.TurnoverOfSum(map);turnover = turnover==null?0.0:turnover;turnoverlist.add(turnover);}for (Double v : turnoverlist) {System.out.println("今日份营业额:"+ v);}//封装TurnoverReportVO对象TurnoverReportVO turnoverReportVO = new TurnoverReportVO();turnoverReportVO.setDateList(datejoin);turnoverReportVO.setTurnoverList(StringUtils.join(turnoverlist,","));return turnoverReportVO;}
}
思路:
我们观察TurnoverReportVO对象里面有两个值,dateList,turnoverList
一个是日期列表,一个是营业额列表。
我们观察前端页面也能看成

横坐标:是日期 纵坐标:是营业额。
所以我们Service层的思路就很简单了
1:封装dateList对象
创建一个LocalDate的列表,然后通过LocalDate提供的库函数plusDay,将日期由begin一直加到end,并且TurnoverReportVO对象中的dateList对象是一个String,所以我们再调用String.utils的方法对这个列表进行逗号分割。
2:封装turnoverList对象
我们已经有了每一天的日期了,我们需要每一天的营业额(当然这里也不一定是每一天的,我们前端界面是可以选择的,有可能是一周,也有可能是一个月)。
这个turnoverList对象的封装就需要查询数据库了
select sum(amout) from orders where order_time > ? and order_time < ? and status = 5
我们创建一个map对象里面有beginTime,endTime,status,然后传到mapper层,查询数据中的数据。
3:最后再封装TurnoverReportVO对象返回。
Mapper层及注解:
/*** 动态查询营业额* @param map* @return*/Double TurnoverOfSum(Map map);
<select id="TurnoverOfSum" resultType="java.lang.Double">select sum(amount) from sky_take_out.orders<where><if test="begin != null">and order_time > #{begin}</if><if test="end != null">and order_Time < #{end}</if><if test="status != null"> and status = #{status} </if></where></select>
用户统计:
业务规则及接口设计:

业务规则:
- 基于可视化报表的折线图展示用户数据,X轴为日期,Y轴为用户数
- 根据时间选择区间,展示每天的用户总量和新增用户量数据


用户统计和上面的不同点就是我们的返回值有三个列表:
- dateList
- newUserList
- totalUserList
具体代码实现:
整体的思路和上面的营业额统计差不多
Controll层:
/*** 用户数量统计* @param begin* @param end* @return*/@GetMapping("/userStatistics")@ApiOperation("用户数量统计")public Result<UserReportVO> userStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("用户数量统计");UserReportVO userReportVO = reportService.userStatistics(begin,end);return Result.success(userReportVO);}
Service层:
/*** 用户数量统计* @param begin* @param end* @return*/@Overridepublic UserReportVO userStatistics(LocalDate begin, LocalDate end) {//封装UserReportVO的dateList对象List<LocalDate> dateList = new ArrayList<>();while (!begin.equals(end)){dateList.add(begin);begin = begin.plusDays(1);}String datejoin = StringUtils.join(dateList, ",");//封装UserReportVO的totalUserList对象//select count(id) from user where create_time < endTime//封装UserReportVO的newUserList对象//select count(id) from user where create_time > beginTime and create_time < endTimeList<Integer> totalUserList = new ArrayList<>();List<Integer> newUserList = new ArrayList<>();for (LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date,LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);Map map = new HashMap();map.put("end",endTime);Integer totalUser = userMapper.UserofSum(map);map.put("begin",beginTime);Integer newUser = userMapper.UserofSum(map);totalUserList.add(totalUser);newUserList.add(newUser);}String totaluserjoin = StringUtils.join(totalUserList, ",");String newluserjoin = StringUtils.join(newUserList, ",");UserReportVO userReportVO = new UserReportVO();userReportVO.setDateList(datejoin);userReportVO.setTotalUserList(totaluserjoin);userReportVO.setNewUserList(newluserjoin);return userReportVO;}
这里Service层的业务就是封装三个列表
要想封装这个用户,我们需要去调userMapper
我们想要知道总共的用户的sql是:
//select count(id) from user where create_time < endTime
截至到这个end时间时候的用户数量。
而新增用户的sql是:
//select count(id) from user where create_time > beginTime and create_time < endTime
我们要给这个新增确定一个日期范围。
userMapper及注解:
Integer UserofSum(Map map);
<select id="UserofSum" resultType="java.lang.Integer">select count(id) from sky_take_out.user<where><if test="begin != null">and create_time > #{begin}</if><if test="end != null">and create_time < #{end}</if></where></select>
订单统计:
业务规则及接口设计:

业务规则:
- 有效订单指状态为 “已完成” 的订单
- 基于可视化报表的折线图展示订单数据,X轴为日期,Y轴为订单数量
- 根据时间选择区间,展示每天的订单总数和有效订单数
- 展示所选时间区间内的有效订单数、总订单数、订单完成率,订单完成率 = 有效订单数 / 总订单数 * 100%
具体的代码实现:
Controll层:
/*** 订单统计* @param begin* @param end* @return*/@GetMapping("/ordersStatistics")@ApiOperation("订单统计")public Result<OrderReportVO> orderStatistics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("订单统计");OrderReportVO orderReportVO = reportService.ordersStatistics(begin,end);return Result.success(orderReportVO);}
Service层:
/*** 订单统计* @param begin* @param end* @return*/@Overridepublic OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {//封装OrderReportVO的dateList对象List<LocalDate> dateList = new ArrayList<>();while (!begin.equals(end)){dateList.add(begin);begin = begin.plusDays(1);}String datejoin = StringUtils.join(dateList, ",");//封装OrderReportVO的orderCountList对象//封装OrderReportVO的validOrderCountList对象List<Integer> orderCountList = new ArrayList<>();List<Integer> validOrderCountList = new ArrayList<>();for (LocalDate date : dateList) {LocalDateTime beginTime = LocalDateTime.of(date,LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(date,LocalTime.MAX);Map map = new HashMap();map.put("begin",beginTime);map.put("end",endTime);Integer totalorders = orderMapper.OrdersofSum(map);map.put("status",Orders.COMPLETED);Integer validorders = orderMapper.OrdersofSum(map);orderCountList.add(totalorders);validOrderCountList.add(validorders);}String totaljoin = StringUtils.join(orderCountList, ",");String validjoin = StringUtils.join(validOrderCountList,",");//计算时间区间内的订单总数量Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();//计算时间区间内的有效订单数量Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();//计算订单完成率Double orderCompletionRate = 0.0;if(totalOrderCount!=0){orderCompletionRate = validOrderCount.doubleValue()/totalOrderCount.doubleValue();}OrderReportVO orderReportVO = new OrderReportVO();orderReportVO.setDateList(datejoin);orderReportVO.setOrderCountList(totaljoin);orderReportVO.setValidOrderCountList(validjoin);orderReportVO.setTotalOrderCount(totalOrderCount);orderReportVO.setValidOrderCount(validOrderCount);orderReportVO.setOrderCompletionRate(orderCompletionRate);return orderReportVO;}
Mapper层及注解:
/*** 订单统计* @param map* @return*/Integer OrdersofSum(Map map);
<select id="OrdersofSum" resultType="java.lang.Integer">select count(id) from sky_take_out.orders<where><if test="begin != null">and order_time > #{begin}</if><if test="end != null">and order_Time < #{end}</if><if test="status != null">and status=#{status}</if></where></select>
销量排名统计(TOP10):
业务规则及接口设计:

业务规则:
- 根据时间选择区间,展示销量前10的商品(包括菜品和套餐)
- 基于可视化报表的柱状图降序展示商品销量
- 此处的销量为商品销售的份数
具体的代码实现:
Controll层:
/*** TOP10销量统计* @param begin* @param end* @return*/@GetMapping("/top10")@ApiOperation("TOP10销量统计")public Result<SalesTop10ReportVO> Top10Statostics(@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,@DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end){log.info("TOP10销量统计");SalesTop10ReportVO salesTop10ReportVO = reportService.Top10Statostics(begin,end);return Result.success(salesTop10ReportVO);}
Service层:
/*** TOP10销量统计* @param begin* @param end* @return*/@Overridepublic SalesTop10ReportVO Top10Statostics(LocalDate begin, LocalDate end) {LocalDateTime beginTime = LocalDateTime.of(begin,LocalTime.MIN);LocalDateTime endTime = LocalDateTime.of(end,LocalTime.MAX);System.out.println("开始时间是:"+beginTime);System.out.println("结束时间是:"+endTime);List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.GetTop10(beginTime,endTime);List<String> names = goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());String nameList = StringUtils.join(names, ",");List<Integer> numbers = goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());String numberList = StringUtils.join(numbers, ",");SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();salesTop10ReportVO.setNameList(nameList);salesTop10ReportVO.setNumberList(numberList);return salesTop10ReportVO;}
这题的从sql语句开始分析比较简单
select od.name,sum(od.number) number from order_detail od,orders o
where od.order_id = o.id and o.status = 5 and o.order_time < 2024-05-04 and o.order_time > 2024-05-10
group by od.name
order by number desc
limit 0,10
根据传入的时间范围来获取数据。
Mapper层及注解:
/*** TOP10销量统计* @param beginTime* @param endTime* @return*/List<GoodsSalesDTO> GetTop10(LocalDateTime beginTime, LocalDateTime endTime);
<select id="GetTop10" resultType="com.sky.dto.GoodsSalesDTO">select od.name,sum(od.number) numberfrom sky_take_out.order_detail od,sky_take_out.orders owhere od.order_id = o.id and o.status = 5<if test="beginTime != null">and o.order_time > #{beginTime}</if><if test="endTime != null">and o.order_Time < #{endTime}</if>group by od.nameorder by number desclimit 0,10</select>
结果展示:

相关文章:
Apache ECharts
Apache ECharts介绍: Apache ECharts 是一款基于 Javascript 的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。 官网地址:https://echarts.apache.org/zh/index.html Apache ECh…...
超详细的胎教级Stable Diffusion使用教程(四)
这套课程分为五节课,会系统性的介绍sd的全部功能和实操案例,让你打下坚实牢靠的基础 一、为什么要学Stable Diffusion,它究竟有多强大? 二、三分钟教你装好Stable Diffusion 三、小白快速上手Stable Diffusion 四、Stable dif…...
串口属性中的BM延时计时器问题
如果使用程序修改则需要修改注册表对应位置如下 第一个示例(217) 第二个示例(219) 需要注意的事情是修改前必须点查看串口名称(例如上图是com5) 程序修改: 有没有办法以编程方式更改USB <…...
PyQt6--Python桌面开发(8.QPlainTextEdit纯文本控件)
QPlainTextEdit纯文本控件...
Java | Leetcode Java题解之第83题删除排序链表中的重复元素
题目: 题解: class Solution {public ListNode deleteDuplicates(ListNode head) {if (head null) {return head;}ListNode cur head;while (cur.next ! null) {if (cur.val cur.next.val) {cur.next cur.next.next;} else {cur cur.next;}}return…...
重生奇迹mu再生宝石怎么用有什么用
重生奇迹mu再生宝石有2个用处: 1、在玛雅哥布林处给380装备加PVP属性4追4以上的380级装备,守护宝石一颗,再生宝石一颗,成功得到PVP装备,失败宝石消失,装备无变化; 2、给非套装点强化属性用法跟祝福,灵魂,生命一样直接往装备上敲,成功得到随机强化属性一…...
pdf 文件版面分析--pdfplumber (python 文档解析提取)
pdfplumber 的特点 1、它是一个纯 python 第三方库,适合 python 3.x 版本 2、它用来查看pdf各类信息,能有效提取文本、表格 3、它不支持修改或生成pdf,也不支持对pdf扫描件的处理 import glob import pdfplumber import re from collection…...
PostgreSQL的学习心得和知识总结(一百四十三)|深入理解PostgreSQL数据库之Support event trigger for logoff
目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《PostgreSQL数据库内核分析》 2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》 3、PostgreSQL数据库仓库…...
https免费证书获取
获取免费证书的网址: Certbot 1. 进入你的linux系统,先安装snapd, yum install snapd 2. 启动snapd service snapd start 3.安装 Certbot snap install --classic certbot 注意如下出现此错误时,需要先建立snap 软连接后&am…...
C语言 | Leetcode C语言题解之第74题搜索二维矩阵
题目: 题解: bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) {int m matrixSize, n matrixColSize[0];int low 0, high m * n - 1;while (low < high) {int mid (high - low) / 2 low;int x matrix[mid /…...
杰发科技AC7840——软件Sent_HAL39X
0. 序 使用PWM模拟Sent测试下7840的软件sent功能。 参考链接:SENT协议应用笔记 - TechPlus汽车工坊的文章 - 知乎 SENT协议 1. Sent功能测试 使用提供的软件Sent代码在7840上测试,接收数据OK 2. 参考资料 3. 数据解析 我们个根据上述参考资料尝试解析…...
IOS 开发 - block 使用详解
1.Blobk的定义 block的写法相对难记,不必司机应被,只需要在xcode里打出"inlineBlock"--回车, 系统会自动帮你把基础版写法给你匹配出来 //Block的基础声明//等号""之前是blobk的声明,等号“”后面是block的实现/*returnType:返回类型(void、int、String *…...
BUU-[极客大挑战 2019]Http
考察点 信息收集 http构造请求数据包 题目 解题步骤 参考文章:https://zhuanlan.zhihu.com/p/367051798 查看源代码 发现有一个a标签,但是οnclick"return false"就是点击后不会去跳转到Secret.php的页面 所以我就自己拼接url http://no…...
开发Web3 ETF的技术难点
开发Web3 ETF(Exchange-Traded Fund,交易所交易基金)软件时,需要注意以下几个关键问题。开发Web3 ETF软件是一个复杂的过程,涉及到金融、法律和技术多个领域的专业知识。开发团队需要综合考虑上述问题,以确…...
【K8s】Kubectl 常用命令梳理
Kubectl常用命令梳理 下面包含大致涵盖命令只需要替换对应的Pod \ NameSpace 查看 命名空间 是 ’worktest2‘ 下 名字包括 ’todo‘的所有 Pod kubectl -n worktest2 get pod|grep todo查看 所有命名空间下 名字包括 ’todo‘的所有 Pod kubectl get pods --all-namespace…...
机器学习-监督学习
监督学习是机器学习和人工智能中的一个重要分支,它涉及使用已标记的数据集来训练算法,以便对数据进行分类或准确预测结果。监督学习的核心在于通过输入数据(特征)和输出数据(标签或类别)之间的关系…...
搭建Docker私服镜像仓库Harbor
1、概述 Harbor是由VMware公司开源的企业级的Docker Registry管理项目,它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。 Harbor 的所有组件都在 Dcoker 中部署,所以 Harbor 可使用 Docker Compose 快速部署。 …...
SpringBoot自定义初始化sql文件 支持多类型数据库
我在resources目录下有init.sql初始化sql语句 指定sql文件的地址 sql内容如下: /*角色表*/ INSERT INTO #{schema}ccc_base_role (id, create_time, create_user_id, is_delete, role_name, status, update_time, update_user_id) VALUES(b89e30d81acb88448d412…...
nginx--FastCGI
CGI 概念 nginx通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给Nginx并回收进程(下次处理有需要新建),最后nginx在返回给客户端…...
【数据结构】浅谈
✨✨✨专栏:数据结构 🧑🎓个人主页:SWsunlight 目录 一、概念: 二、物理结构: 1、顺序存储结构: 2、链式存储结构: 3、数据索引存储结构: 4、数据散列存储结构…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
