|
|
@@ -0,0 +1,187 @@
|
|
|
+package org.jeecg.modules.system.app.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.jeecg.modules.system.app.mapper.DataBoardMapper;
|
|
|
+import org.jeecg.modules.system.app.service.IDataBoardService;
|
|
|
+import org.jeecg.modules.system.app.vo.DataBoardVO;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.Year;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.List;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 数据看板Service实现
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class DataBoardServiceImpl implements IDataBoardService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private DataBoardMapper dataBoardMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DataBoardVO.OverviewVO overview() {
|
|
|
+ DataBoardVO.OverviewVO vo = new DataBoardVO.OverviewVO();
|
|
|
+ // 注册用户数
|
|
|
+ vo.setRegisteredUsers(dataBoardMapper.countRegisteredUsers());
|
|
|
+
|
|
|
+ LocalDate now = LocalDate.now();
|
|
|
+ DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+ // 累计(不传时间)
|
|
|
+ vo.setCumulative(buildStats(null, null));
|
|
|
+
|
|
|
+ // 今年
|
|
|
+ String yearStart = now.withDayOfYear(1).format(fmt) + " 00:00:00";
|
|
|
+ String yearEnd = now.format(fmt) + " 23:59:59";
|
|
|
+ vo.setThisYear(buildStats(yearStart, yearEnd));
|
|
|
+
|
|
|
+ // 本月
|
|
|
+ String monthStart = now.withDayOfMonth(1).format(fmt) + " 00:00:00";
|
|
|
+ String monthEnd = now.format(fmt) + " 23:59:59";
|
|
|
+ vo.setThisMonth(buildStats(monthStart, monthEnd));
|
|
|
+
|
|
|
+ // 今日
|
|
|
+ String todayStart = now.format(fmt) + " 00:00:00";
|
|
|
+ String todayEnd = now.format(fmt) + " 23:59:59";
|
|
|
+ vo.setToday(buildStats(todayStart, todayEnd));
|
|
|
+
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<DataBoardVO.SchoolOverviewVO> schoolOverview() {
|
|
|
+ return dataBoardMapper.schoolOverview();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<DataBoardVO.SchoolMonthlyVO> schoolMonthly(String siteId, Integer year) {
|
|
|
+ if (StrUtil.isEmpty(siteId)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ int resolvedYear = (year != null) ? year : Year.now().getValue();
|
|
|
+ return dataBoardMapper.schoolMonthly(siteId, resolvedYear);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DataBoardVO.SchoolReservationPageVO schoolReservationPage(
|
|
|
+ String siteIds, Integer timeRange, String startDate, String endDate,
|
|
|
+ Integer pageNo, Integer pageSize) {
|
|
|
+
|
|
|
+ // 解析学校IDs
|
|
|
+ List<String> siteIdList = null;
|
|
|
+ if (siteIds != null && !siteIds.isEmpty()) {
|
|
|
+ siteIdList = Arrays.stream(siteIds.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(s -> !s.isEmpty())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据timeRange计算日期范围
|
|
|
+ String[] dateRange = resolveDateRange(timeRange, startDate, endDate);
|
|
|
+ String resolvedStart = dateRange[0];
|
|
|
+ String resolvedEnd = dateRange[1];
|
|
|
+
|
|
|
+ // 查询总学校数
|
|
|
+ Long total = dataBoardMapper.schoolReservationCount(siteIdList, resolvedStart, resolvedEnd);
|
|
|
+
|
|
|
+ // 分页查询
|
|
|
+ List<DataBoardVO.SchoolReservationVO> allRecords = dataBoardMapper.schoolReservationPage(
|
|
|
+ siteIdList, resolvedStart, resolvedEnd);
|
|
|
+
|
|
|
+ // 手动分页
|
|
|
+ int fromIndex = (pageNo - 1) * pageSize;
|
|
|
+ int toIndex = Math.min(fromIndex + pageSize, allRecords.size());
|
|
|
+ List<DataBoardVO.SchoolReservationVO> pagedRecords;
|
|
|
+ if (fromIndex >= allRecords.size()) {
|
|
|
+ pagedRecords = Collections.emptyList();
|
|
|
+ } else {
|
|
|
+ pagedRecords = allRecords.subList(fromIndex, toIndex);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算履约率
|
|
|
+ for (DataBoardVO.SchoolReservationVO record : pagedRecords) {
|
|
|
+ record.setFulfillmentRate(calcFulfillmentRate(record.getReservationCount(), record.getEntryCount()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 合计
|
|
|
+ DataBoardVO.StatsVO totalStats = dataBoardMapper.schoolReservationTotal(
|
|
|
+ siteIdList, resolvedStart, resolvedEnd);
|
|
|
+
|
|
|
+ DataBoardVO.SchoolReservationPageVO result = new DataBoardVO.SchoolReservationPageVO();
|
|
|
+ result.setRecords(pagedRecords);
|
|
|
+ result.setTotal(total);
|
|
|
+ result.setCurrent((long) pageNo);
|
|
|
+ result.setSize((long) pageSize);
|
|
|
+ result.setTotalReservationCount(totalStats != null ? totalStats.getReservationCount() : 0L);
|
|
|
+ result.setTotalEntryCount(totalStats != null ? totalStats.getEntryCount() : 0L);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<DataBoardVO.SchoolOptionVO> listSchools() {
|
|
|
+ return dataBoardMapper.listSchools();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建预约/入场统计
|
|
|
+ */
|
|
|
+ private DataBoardVO.StatsVO buildStats(String startDate, String endDate) {
|
|
|
+ DataBoardVO.StatsVO stats = new DataBoardVO.StatsVO();
|
|
|
+ stats.setReservationCount(dataBoardMapper.countReservations(startDate, endDate));
|
|
|
+ stats.setEntryCount(dataBoardMapper.countEntries(startDate, endDate));
|
|
|
+ return stats;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据时间范围类型解析日期区间
|
|
|
+ * @param timeRange 0-不限 1-今年 2-本月 3-自定义
|
|
|
+ */
|
|
|
+ private String[] resolveDateRange(Integer timeRange, String startDate, String endDate) {
|
|
|
+ if (timeRange == null || timeRange == 0) {
|
|
|
+ return new String[]{null, null};
|
|
|
+ }
|
|
|
+ LocalDate now = LocalDate.now();
|
|
|
+ DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ switch (timeRange) {
|
|
|
+ case 1: // 今年
|
|
|
+ return new String[]{
|
|
|
+ now.withDayOfYear(1).format(fmt) + " 00:00:00",
|
|
|
+ now.format(fmt) + " 23:59:59"
|
|
|
+ };
|
|
|
+ case 2: // 本月
|
|
|
+ return new String[]{
|
|
|
+ now.withDayOfMonth(1).format(fmt) + " 00:00:00",
|
|
|
+ now.format(fmt) + " 23:59:59"
|
|
|
+ };
|
|
|
+ case 3: // 自定义
|
|
|
+ String resolvedStart = (startDate != null && !startDate.isEmpty()) ? startDate + " 00:00:00" : null;
|
|
|
+ String resolvedEnd = (endDate != null && !endDate.isEmpty()) ? endDate + " 23:59:59" : null;
|
|
|
+ return new String[]{resolvedStart, resolvedEnd};
|
|
|
+ default:
|
|
|
+ return new String[]{null, null};
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算履约率 = 入场人数 / 预约人数 * 100%
|
|
|
+ */
|
|
|
+ private String calcFulfillmentRate(Long reservationCount, Long entryCount) {
|
|
|
+ if (reservationCount == null || reservationCount == 0) {
|
|
|
+ return "0.00%";
|
|
|
+ }
|
|
|
+ BigDecimal rate = BigDecimal.valueOf(entryCount)
|
|
|
+ .multiply(BigDecimal.valueOf(100))
|
|
|
+ .divide(BigDecimal.valueOf(reservationCount), 2, RoundingMode.HALF_UP);
|
|
|
+ return rate + "%";
|
|
|
+ }
|
|
|
+}
|