feat(oa): 添加仪表板功能模块

- 新增仪表板控制器、服务接口及其实现类- 创建仪表板相关的数据传输对象(DTO)
- 设计并实现仪表板数据的获取和统计逻辑
- 添加仪表板数据的数据库访问接口和映射文件
This commit is contained in:
2025-09-17 16:46:18 +08:00
parent 0346e09dd3
commit c3812b6c51
11 changed files with 904 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
package com.gear.oa.controller;
import com.gear.common.core.controller.BaseController;
import com.gear.common.core.domain.R;
import com.gear.oa.domain.vo.dashboard.DashboardOverviewVO;
import com.gear.oa.service.IGearDashboardService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 仪表板控制器
*
* @author Joshi
* @date 2025-09-17
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/oa/dashboard")
public class GearDashboardController extends BaseController {
private final IGearDashboardService dashboardService;
/**
* 获取仪表板总览数据
*
* @return 仪表板总览数据
*/
@GetMapping("/overview")
public R<DashboardOverviewVO> getDashboardOverview() {
DashboardOverviewVO overview = dashboardService.getDashboardOverview();
return R.ok(overview);
}
}

View File

@@ -0,0 +1,43 @@
package com.gear.oa.domain.vo.dashboard;
import lombok.Data;
import java.math.BigDecimal;
/**
* 日趋势数据VO
*
* @author Joshi
* @date 2025-09-17
*/
@Data
public class DailyTrendVO {
/**
* 日期格式MM-dd
*/
private String date;
/**
* 数值(订单数量或薪资金额)
*/
private BigDecimal value;
/**
* 标签(用于显示)
*/
private String label;
public DailyTrendVO() {}
public DailyTrendVO(String date, BigDecimal value) {
this.date = date;
this.value = value;
this.label = date;
}
public DailyTrendVO(String date, BigDecimal value, String label) {
this.date = date;
this.value = value;
this.label = label;
}
}

View File

@@ -0,0 +1,35 @@
package com.gear.oa.domain.vo.dashboard;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 仪表板总览VO
*
* @author Joshi
* @date 2025-09-17
*/
@Data
public class DashboardOverviewVO {
/**
* 订单统计数据
*/
private OrderStatisticsVO orderStatistics;
/**
* 薪资支出统计数据
*/
private SalaryStatisticsVO salaryStatistics;
/**
* 库存排行数据
*/
private List<StockRankingVO> stockRanking;
/**
* 其他统计数据
*/
private OtherStatisticsVO otherStatistics;
}

View File

@@ -0,0 +1,45 @@
package com.gear.oa.domain.vo.dashboard;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 订单统计VO
*
* @author Joshi
* @date 2025-09-17
*/
@Data
public class OrderStatisticsVO {
/**
* 今日订单数
*/
private Integer todayOrderCount;
/**
* 本周订单数
*/
private Integer weekOrderCount;
/**
* 本月订单数
*/
private Integer monthOrderCount;
/**
* 近一周订单数量趋势7天数据
*/
private List<DailyTrendVO> weeklyTrend;
/**
* 订单总金额(本周)
*/
private BigDecimal weekTotalAmount;
/**
* 与上周对比增长率
*/
private BigDecimal growthRate;
}

View File

@@ -0,0 +1,54 @@
package com.gear.oa.domain.vo.dashboard;
import lombok.Data;
import java.math.BigDecimal;
/**
* 其他统计数据VO
*
* @author Joshi
* @date 2025-09-17
*/
@Data
public class OtherStatisticsVO {
/**
* 活跃客户数
*/
private Integer activeCustomerCount;
/**
* 待处理订单数
*/
private Integer pendingOrderCount;
/**
* 库存预警数量
*/
private Integer lowStockCount;
/**
* 本月营收
*/
private BigDecimal monthlyRevenue;
/**
* 员工总数
*/
private Integer totalEmployeeCount;
/**
* 今日出勤率
*/
private BigDecimal todayAttendanceRate;
/**
* 产品总数
*/
private Integer totalProductCount;
/**
* 供应商总数
*/
private Integer totalSupplierCount;
}

View File

@@ -0,0 +1,45 @@
package com.gear.oa.domain.vo.dashboard;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
* 薪资统计VO
*
* @author Joshi
* @date 2025-09-17
*/
@Data
public class SalaryStatisticsVO {
/**
* 今日薪资支出
*/
private BigDecimal todaySalary;
/**
* 本周薪资支出
*/
private BigDecimal weekSalary;
/**
* 本月薪资支出
*/
private BigDecimal monthSalary;
/**
* 近一周薪资支出趋势7天数据
*/
private List<DailyTrendVO> weeklyTrend;
/**
* 与上周对比增长率
*/
private BigDecimal growthRate;
/**
* 平均日薪资支出
*/
private BigDecimal avgDailySalary;
}

View File

@@ -0,0 +1,69 @@
package com.gear.oa.domain.vo.dashboard;
import lombok.Data;
import java.math.BigDecimal;
/**
* 库存排行VO
*
* @author Joshi
* @date 2025-09-17
*/
@Data
public class StockRankingVO {
/**
* 排名
*/
private Integer rank;
/**
* 物品ID
*/
private Long itemId;
/**
* 物品名称
*/
private String itemName;
/**
* 物品编号
*/
private String itemCode;
/**
* 物品类型raw_material/product
*/
private String itemType;
/**
* 物品类型名称
*/
private String itemTypeName;
/**
* 库存数量
*/
private BigDecimal quantity;
/**
* 单位
*/
private String unit;
/**
* 仓库名称
*/
private String warehouseName;
/**
* 产品分类(如果是产品)
*/
private String categoryName;
/**
* 负责人
*/
private String owner;
}

View File

@@ -0,0 +1,118 @@
package com.gear.oa.mapper;
import com.gear.oa.domain.vo.dashboard.StockRankingVO;
import org.apache.ibatis.annotations.Mapper;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* 仪表板数据访问层
*
* @author Joshi
* @date 2025-09-17
*/
@Mapper
public interface GearDashboardMapper {
/**
* 获取今日订单数
*/
Integer getTodayOrderCount();
/**
* 获取本周订单数
*/
Integer getWeekOrderCount();
/**
* 获取本月订单数
*/
Integer getMonthOrderCount();
/**
* 获取上周订单数
*/
Integer getLastWeekOrderCount();
/**
* 获取本周订单总金额
*/
BigDecimal getWeekOrderAmount();
/**
* 获取近一周订单趋势
*/
List<Map<String, Object>> getWeeklyOrderTrend();
/**
* 获取今日薪资支出
*/
BigDecimal getTodaySalary();
/**
* 获取本周薪资支出
*/
BigDecimal getWeekSalary();
/**
* 获取本月薪资支出
*/
BigDecimal getMonthSalary();
/**
* 获取上周薪资支出
*/
BigDecimal getLastWeekSalary();
/**
* 获取近一周薪资趋势
*/
List<Map<String, Object>> getWeeklySalaryTrend();
/**
* 获取库存排行前10
*/
List<StockRankingVO> getStockRanking();
/**
* 获取活跃客户数
*/
Integer getActiveCustomerCount();
/**
* 获取待处理订单数
*/
Integer getPendingOrderCount();
/**
* 获取库存预警数量
*/
Integer getLowStockCount();
/**
* 获取本月营收
*/
BigDecimal getMonthlyRevenue();
/**
* 获取员工总数
*/
Integer getTotalEmployeeCount();
/**
* 获取今日出勤率
*/
BigDecimal getTodayAttendanceRate();
/**
* 获取产品总数
*/
Integer getTotalProductCount();
/**
* 获取供应商总数
*/
Integer getTotalSupplierCount();
}

View File

@@ -0,0 +1,19 @@
package com.gear.oa.service;
import com.gear.oa.domain.vo.dashboard.DashboardOverviewVO;
/**
* 仪表板服务接口
*
* @author Joshi
* @date 2025-09-17
*/
public interface IGearDashboardService {
/**
* 获取仪表板总览数据
*
* @return 仪表板总览数据
*/
DashboardOverviewVO getDashboardOverview();
}

View File

@@ -0,0 +1,211 @@
package com.gear.oa.service.impl;
import com.gear.oa.domain.vo.dashboard.*;
import com.gear.oa.mapper.GearDashboardMapper;
import com.gear.oa.service.IGearDashboardService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 仪表板服务实现类
*
* @author Joshi
* @date 2025-09-17
*/
@Service
@RequiredArgsConstructor
public class GearDashboardServiceImpl implements IGearDashboardService {
private final GearDashboardMapper dashboardMapper;
@Override
public DashboardOverviewVO getDashboardOverview() {
DashboardOverviewVO overview = new DashboardOverviewVO();
// 获取订单统计数据
overview.setOrderStatistics(getOrderStatistics());
// 获取薪资统计数据
overview.setSalaryStatistics(getSalaryStatistics());
// 获取库存排行数据
overview.setStockRanking(getStockRanking());
// 获取其他统计数据
overview.setOtherStatistics(getOtherStatistics());
return overview;
}
/**
* 获取订单统计数据
*/
private OrderStatisticsVO getOrderStatistics() {
OrderStatisticsVO statistics = new OrderStatisticsVO();
// 获取今日、本周、本月订单数
statistics.setTodayOrderCount(dashboardMapper.getTodayOrderCount());
statistics.setWeekOrderCount(dashboardMapper.getWeekOrderCount());
statistics.setMonthOrderCount(dashboardMapper.getMonthOrderCount());
// 获取本周订单总金额
statistics.setWeekTotalAmount(dashboardMapper.getWeekOrderAmount());
// 获取近一周订单趋势
List<Map<String, Object>> weeklyData = dashboardMapper.getWeeklyOrderTrend();
statistics.setWeeklyTrend(convertToTrendList(weeklyData));
// 计算增长率
Integer lastWeekCount = dashboardMapper.getLastWeekOrderCount();
statistics.setGrowthRate(calculateGrowthRate(statistics.getWeekOrderCount(), lastWeekCount));
return statistics;
}
/**
* 获取薪资统计数据
*/
private SalaryStatisticsVO getSalaryStatistics() {
SalaryStatisticsVO statistics = new SalaryStatisticsVO();
// 获取今日、本周、本月薪资支出
statistics.setTodaySalary(dashboardMapper.getTodaySalary());
statistics.setWeekSalary(dashboardMapper.getWeekSalary());
statistics.setMonthSalary(dashboardMapper.getMonthSalary());
// 获取近一周薪资趋势
List<Map<String, Object>> weeklyData = dashboardMapper.getWeeklySalaryTrend();
statistics.setWeeklyTrend(convertToTrendList(weeklyData));
// 计算增长率
BigDecimal lastWeekSalary = dashboardMapper.getLastWeekSalary();
statistics.setGrowthRate(calculateGrowthRate(statistics.getWeekSalary(), lastWeekSalary));
// 计算平均日薪资
if (statistics.getWeekSalary() != null) {
statistics.setAvgDailySalary(statistics.getWeekSalary().divide(new BigDecimal(7), 2, RoundingMode.HALF_UP));
}
return statistics;
}
/**
* 获取库存排行数据
*/
private List<StockRankingVO> getStockRanking() {
List<StockRankingVO> rankings = dashboardMapper.getStockRanking();
// 设置排名
for (int i = 0; i < rankings.size(); i++) {
rankings.get(i).setRank(i + 1);
// 设置物品类型名称
String itemType = rankings.get(i).getItemType();
if ("product".equals(itemType)) {
rankings.get(i).setItemTypeName("产品");
} else if ("raw_material".equals(itemType)) {
rankings.get(i).setItemTypeName("原材料");
}
}
return rankings;
}
/**
* 获取其他统计数据
*/
private OtherStatisticsVO getOtherStatistics() {
OtherStatisticsVO statistics = new OtherStatisticsVO();
statistics.setActiveCustomerCount(dashboardMapper.getActiveCustomerCount());
statistics.setPendingOrderCount(dashboardMapper.getPendingOrderCount());
statistics.setLowStockCount(dashboardMapper.getLowStockCount());
statistics.setMonthlyRevenue(dashboardMapper.getMonthlyRevenue());
statistics.setTotalEmployeeCount(dashboardMapper.getTotalEmployeeCount());
statistics.setTodayAttendanceRate(dashboardMapper.getTodayAttendanceRate());
statistics.setTotalProductCount(dashboardMapper.getTotalProductCount());
statistics.setTotalSupplierCount(dashboardMapper.getTotalSupplierCount());
return statistics;
}
/**
* 转换趋势数据
*/
private List<DailyTrendVO> convertToTrendList(List<Map<String, Object>> data) {
List<DailyTrendVO> trends = new ArrayList<>();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
for (Map<String, Object> item : data) {
DailyTrendVO trend = new DailyTrendVO();
// 处理日期
Object dateObj = item.get("date");
if (dateObj instanceof LocalDate) {
trend.setDate(((LocalDate) dateObj).format(formatter));
} else if (dateObj instanceof String) {
trend.setDate((String) dateObj);
}
// 处理数值
Object valueObj = item.get("value");
if (valueObj instanceof BigDecimal) {
trend.setValue((BigDecimal) valueObj);
} else if (valueObj instanceof Integer) {
trend.setValue(new BigDecimal((Integer) valueObj));
} else if (valueObj instanceof Long) {
trend.setValue(new BigDecimal((Long) valueObj));
}
trend.setLabel(trend.getDate());
trends.add(trend);
}
return trends;
}
/**
* 计算增长率
*/
private BigDecimal calculateGrowthRate(Object current, Object previous) {
if (current == null || previous == null) {
return BigDecimal.ZERO;
}
BigDecimal currentValue = convertToBigDecimal(current);
BigDecimal previousValue = convertToBigDecimal(previous);
if (previousValue.compareTo(BigDecimal.ZERO) == 0) {
return currentValue.compareTo(BigDecimal.ZERO) > 0 ? new BigDecimal(100) : BigDecimal.ZERO;
}
return currentValue.subtract(previousValue)
.divide(previousValue, 4, RoundingMode.HALF_UP)
.multiply(new BigDecimal(100))
.setScale(2, RoundingMode.HALF_UP);
}
/**
* 转换为BigDecimal
*/
private BigDecimal convertToBigDecimal(Object value) {
if (value instanceof BigDecimal) {
return (BigDecimal) value;
} else if (value instanceof Integer) {
return new BigDecimal((Integer) value);
} else if (value instanceof Long) {
return new BigDecimal((Long) value);
} else if (value instanceof String) {
return new BigDecimal((String) value);
}
return BigDecimal.ZERO;
}
}