diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/impl/IndexServiceImpl.java b/server/like-admin/src/main/java/com/mdd/admin/service/impl/IndexServiceImpl.java index 7268fa37..cba1c2a4 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/impl/IndexServiceImpl.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/impl/IndexServiceImpl.java @@ -4,21 +4,14 @@ import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.mdd.admin.service.IIndexService; import com.mdd.common.config.GlobalConfig; -import com.mdd.common.entity.StudentInfo; -import com.mdd.common.entity.Teacher; -import com.mdd.common.mapper.StudentInfoMapper; -import com.mdd.common.mapper.TeacherMapper; +import com.mdd.common.service.EnrollmentStaticService; import com.mdd.common.util.ConfigUtils; import com.mdd.common.util.ListUtils; -import com.mdd.common.util.TimeUtils; import com.mdd.common.util.UrlUtils; import com.mdd.common.util.YmlUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import java.util.*; /** @@ -28,18 +21,15 @@ import java.util.*; public class IndexServiceImpl implements IIndexService { @Resource - private StudentInfoMapper studentInfoMapper; - - @Resource - private TeacherMapper teacherMapper; + private EnrollmentStaticService enrollmentStaticService; /** * 控制台数据 * - * @author fzr * @param teacherId 招生老师ID(可选) * @param rangeType 时间区间类型:day / week / month(可选,默认 week) * @return Map + * @author fzr */ @Override public Map index(Integer teacherId, String rangeType) { @@ -58,11 +48,11 @@ public class IndexServiceImpl implements IIndexService { console.put("version", version); // 招生统计数据 - Map enrollmentStats = buildEnrollmentStats(); + Map enrollmentStats = enrollmentStaticService.buildEnrollmentStats(); console.put("today", enrollmentStats); // 招生趋势数据(带筛选条件) - Map enrollmentTrend = buildEnrollmentTrend(teacherId, rangeType); + Map enrollmentTrend = enrollmentStaticService.buildEnrollmentTrend(teacherId, rangeType); console.put("enrollmentTrend", enrollmentTrend); // 常用功能菜单 @@ -121,196 +111,15 @@ public class IndexServiceImpl implements IIndexService { return console; } - /** - * 构建招生统计数据: - * - 总招生数量 - * - 今日招生数量 - * - 本周招生数量 - * - 本月招生数量 - * - * 招生数量定义:student_status = 0 或 1 的学生数量 - */ - private Map buildEnrollmentStats() { - Map stats = new LinkedHashMap<>(); - - // 当前时间 - Date now = new Date(); - stats.put("time", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now)); - - // 总招生数量(所有时间) - long totalCount = studentInfoMapper.selectCount( - new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper() - .in("student_status", 0, 1) - .isNull("delete_time") - ); - - // 今日、本周、本月时间范围 - LocalDate today = LocalDate.now(); - Date todayStart = toDate(today.atStartOfDay()); - Date tomorrowStart = toDate(today.plusDays(1).atStartOfDay()); - - LocalDate weekStartDate = today.minusDays(6); // 最近7天 - Date weekStart = toDate(weekStartDate.atStartOfDay()); - - LocalDate monthStartDate = today.minusDays(29); // 最近30天 - Date monthStart = toDate(monthStartDate.atStartOfDay()); - - long todayCount = countEnrollmentInRange(todayStart, tomorrowStart); - long weekCount = countEnrollmentInRange(weekStart, tomorrowStart); - long monthCount = countEnrollmentInRange(monthStart, tomorrowStart); - - stats.put("total_enroll_count", totalCount); - stats.put("today_enroll_count", todayCount); - stats.put("week_enroll_count", weekCount); - stats.put("month_enroll_count", monthCount); - - return stats; - } - - /** - * 计算时间区间内的招生数量(按 pre_registration_time 筛选) - */ - private long countEnrollmentInRange(Date startTime, Date endTime) { - return studentInfoMapper.selectCount( - new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper() - .in("student_status", 0, 1) - .isNull("delete_time") - .isNotNull("pre_registration_time") - .ge("pre_registration_time", startTime) - .lt("pre_registration_time", endTime) - ); - } - - /** - * 构建招生趋势数据 - * - * @param teacherId 招生老师ID(为空则统计所有老师) - * @param rangeType 时间区间类型:day / week / month - */ - private Map buildEnrollmentTrend(Integer teacherId, String rangeType) { - Map result = new LinkedHashMap<>(); - - if (rangeType == null || rangeType.trim().isEmpty()) { - rangeType = "week"; - } - - LocalDate today = LocalDate.now(); - LocalDate startDate; - - switch (rangeType) { - case "day": - startDate = today; - break; - case "month": - startDate = today.minusDays(29); - break; - case "week": - default: - startDate = today.minusDays(6); - break; - } - - LocalDate endDate = today; - Date startTime = toDate(startDate.atStartOfDay()); - Date endTime = toDate(endDate.plusDays(1).atStartOfDay()); - - // 生成日期列表 - List dateList = new ArrayList<>(); - Map dateIndexMap = new LinkedHashMap<>(); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - int idx = 0; - for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) { - String dateStr = d.format(formatter); - dateList.add(dateStr); - dateIndexMap.put(dateStr, idx++); - } - - // 查询数据库中的统计数据:按日期 + 招生老师分组 - List> rows = studentInfoMapper.selectEnrollmentTrend(startTime, endTime, teacherId); - - // 收集涉及到的老师ID - Set teacherIds = new LinkedHashSet<>(); - for (Map row : rows) { - Object tIdObj = row.get("teacherId"); - if (tIdObj != null) { - teacherIds.add(((Number) tIdObj).intValue()); - } - } - - Map teacherNameMap = new LinkedHashMap<>(); - if (!teacherIds.isEmpty()) { - List teachers = teacherMapper.selectBatchIds(teacherIds); - for (Teacher t : teachers) { - teacherNameMap.put(t.getTeacherId(), t.getTeacherName()); - } - } - - // 构建每个老师的时间序列数据 - Map> teacherSeriesMap = new LinkedHashMap<>(); - for (Integer tId : teacherIds) { - List initList = new ArrayList<>(); - for (int i = 0; i < dateList.size(); i++) { - initList.add(0L); - } - teacherSeriesMap.put(tId, initList); - } - - for (Map row : rows) { - Object dateObj = row.get("statDate"); - Object tIdObj = row.get("teacherId"); - Object countObj = row.get("enrollCount"); - if (dateObj == null || tIdObj == null || countObj == null) { - continue; - } - String dateStr = String.valueOf(dateObj); - Integer tId = ((Number) tIdObj).intValue(); - Integer index = dateIndexMap.get(dateStr); - if (index == null) { - continue; - } - List dataList = teacherSeriesMap.get(tId); - if (dataList == null) { - dataList = new ArrayList<>(); - for (int i = 0; i < dateList.size(); i++) { - dataList.add(0L); - } - teacherSeriesMap.put(tId, dataList); - } - long count = ((Number) countObj).longValue(); - dataList.set(index, count); - } - - // 组装返回给前端的 list 数据 - JSONArray seriesList = new JSONArray(); - for (Map.Entry> entry : teacherSeriesMap.entrySet()) { - Integer tId = entry.getKey(); - List data = entry.getValue(); - JSONObject item = new JSONObject(); - item.put("teacherId", tId); - item.put("name", teacherNameMap.getOrDefault(tId, "未知老师")); - item.put("data", data); - seriesList.add(item); - } - - result.put("date", dateList); - result.put("list", seriesList); - result.put("rangeType", rangeType); - return result; - } - - private Date toDate(java.time.LocalDateTime localDateTime) { - return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); - } - /** * 公共配置 * - * @author fzr * @return Map + * @author fzr */ @Override public Map config() { - Map website = ConfigUtils.get("website"); + Map website = ConfigUtils.get("website"); String copyright = ConfigUtils.get("copyright", "config", ""); String captchaStatus = YmlUtils.get("like.captcha.status"); diff --git a/server/like-common/src/main/java/com/mdd/common/service/EnrollmentStaticService.java b/server/like-common/src/main/java/com/mdd/common/service/EnrollmentStaticService.java new file mode 100644 index 00000000..9c8ba8c4 --- /dev/null +++ b/server/like-common/src/main/java/com/mdd/common/service/EnrollmentStaticService.java @@ -0,0 +1,204 @@ +package com.mdd.common.service; + +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.mdd.common.entity.StudentInfo; +import com.mdd.common.entity.Teacher; +import com.mdd.common.mapper.StudentInfoMapper; +import com.mdd.common.mapper.TeacherMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; + +@Service +public class EnrollmentStaticService { + + @Resource + private StudentInfoMapper studentInfoMapper; + @Resource + private TeacherMapper teacherMapper; + + /** + * 构建招生统计数据: + *

- 总招生数量 + *

- 今日招生数量 + *

- 本周招生数量 + *

- 本月招生数量 + * 招生数量定义:student_status = 0 或 1 的学生数量 + */ + public Map buildEnrollmentStats() { + Map stats = new LinkedHashMap<>(); + + // 当前时间 + Date now = new Date(); + stats.put("time", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(now)); + + // 总招生数量(所有时间) + long totalCount = studentInfoMapper.selectCount( + new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper() + .in("student_status", 0, 1) + .isNull("delete_time") + ); + + // 今日、本周、本月时间范围 + LocalDate today = LocalDate.now(); + Date todayStart = toDate(today.atStartOfDay()); + Date tomorrowStart = toDate(today.plusDays(1).atStartOfDay()); + + LocalDate weekStartDate = today.minusDays(6); // 最近7天 + Date weekStart = toDate(weekStartDate.atStartOfDay()); + + LocalDate monthStartDate = today.minusDays(29); // 最近30天 + Date monthStart = toDate(monthStartDate.atStartOfDay()); + + long todayCount = countEnrollmentInRange(todayStart, tomorrowStart); + long weekCount = countEnrollmentInRange(weekStart, tomorrowStart); + long monthCount = countEnrollmentInRange(monthStart, tomorrowStart); + + stats.put("total_enroll_count", totalCount); + stats.put("today_enroll_count", todayCount); + stats.put("week_enroll_count", weekCount); + stats.put("month_enroll_count", monthCount); + + return stats; + } + + /** + * 构建招生趋势数据 + * + * @param teacherId 招生老师ID(为空则统计所有老师) + * @param rangeType 时间区间类型:day / week / month + */ + public Map buildEnrollmentTrend(Integer teacherId, String rangeType) { + Map result = new LinkedHashMap<>(); + + if (rangeType == null || rangeType.trim().isEmpty()) { + rangeType = "week"; + } + + LocalDate today = LocalDate.now(); + LocalDate startDate; + + switch (rangeType) { + case "day": + startDate = today; + break; + case "month": + startDate = today.minusDays(29); + break; + case "week": + default: + startDate = today.minusDays(6); + break; + } + + LocalDate endDate = today; + Date startTime = toDate(startDate.atStartOfDay()); + Date endTime = toDate(endDate.plusDays(1).atStartOfDay()); + + // 生成日期列表 + List dateList = new ArrayList<>(); + Map dateIndexMap = new LinkedHashMap<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + int idx = 0; + for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) { + String dateStr = d.format(formatter); + dateList.add(dateStr); + dateIndexMap.put(dateStr, idx++); + } + + // 查询数据库中的统计数据:按日期 + 招生老师分组 + List> rows = studentInfoMapper.selectEnrollmentTrend(startTime, endTime, teacherId); + + // 收集涉及到的老师ID + Set teacherIds = new LinkedHashSet<>(); + for (Map row : rows) { + Object tIdObj = row.get("teacherId"); + if (tIdObj != null) { + teacherIds.add(((Number) tIdObj).intValue()); + } + } + + Map teacherNameMap = new LinkedHashMap<>(); + if (!teacherIds.isEmpty()) { + List teachers = teacherMapper.selectBatchIds(teacherIds); + for (Teacher t : teachers) { + teacherNameMap.put(t.getTeacherId(), t.getTeacherName()); + } + } + + // 构建每个老师的时间序列数据 + Map> teacherSeriesMap = new LinkedHashMap<>(); + for (Integer tId : teacherIds) { + List initList = new ArrayList<>(); + for (int i = 0; i < dateList.size(); i++) { + initList.add(0L); + } + teacherSeriesMap.put(tId, initList); + } + + for (Map row : rows) { + Object dateObj = row.get("statDate"); + Object tIdObj = row.get("teacherId"); + Object countObj = row.get("enrollCount"); + if (dateObj == null || tIdObj == null || countObj == null) { + continue; + } + String dateStr = String.valueOf(dateObj); + Integer tId = ((Number) tIdObj).intValue(); + Integer index = dateIndexMap.get(dateStr); + if (index == null) { + continue; + } + List dataList = teacherSeriesMap.get(tId); + if (dataList == null) { + dataList = new ArrayList<>(); + for (int i = 0; i < dateList.size(); i++) { + dataList.add(0L); + } + teacherSeriesMap.put(tId, dataList); + } + long count = ((Number) countObj).longValue(); + dataList.set(index, count); + } + + // 组装返回给前端的 list 数据 + JSONArray seriesList = new JSONArray(); + for (Map.Entry> entry : teacherSeriesMap.entrySet()) { + Integer tId = entry.getKey(); + List data = entry.getValue(); + JSONObject item = new JSONObject(); + item.put("teacherId", tId); + item.put("name", teacherNameMap.getOrDefault(tId, "未知老师")); + item.put("data", data); + seriesList.add(item); + } + + result.put("date", dateList); + result.put("list", seriesList); + result.put("rangeType", rangeType); + return result; + } + + private Date toDate(java.time.LocalDateTime localDateTime) { + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * 计算时间区间内的招生数量(按 pre_registration_time 筛选) + */ + private long countEnrollmentInRange(Date startTime, Date endTime) { + return studentInfoMapper.selectCount( + new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper() + .in("student_status", 0, 1) + .isNull("delete_time") + .isNotNull("pre_registration_time") + .ge("pre_registration_time", startTime) + .lt("pre_registration_time", endTime) + ); + } +} diff --git a/server/like-front/src/main/java/com/mdd/front/controller/StudentInfoController.java b/server/like-front/src/main/java/com/mdd/front/controller/StudentInfoController.java index ec54fb10..29cd51ff 100644 --- a/server/like-front/src/main/java/com/mdd/front/controller/StudentInfoController.java +++ b/server/like-front/src/main/java/com/mdd/front/controller/StudentInfoController.java @@ -1,6 +1,7 @@ package com.mdd.front.controller; import com.mdd.common.core.AjaxResult; +import com.mdd.common.service.EnrollmentStaticService; import com.mdd.front.service.IStudentInfoService; import com.mdd.front.validate.student.PreRegistrationStudentInfoValidate; import io.swagger.annotations.Api; @@ -9,6 +10,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.util.Map; @RestController @RequestMapping("frontapi/student") @@ -16,11 +18,25 @@ import javax.annotation.Resource; public class StudentInfoController { @Resource - private IStudentInfoService IStudentInfoService; + private IStudentInfoService iStudentInfoService; + @Resource + private EnrollmentStaticService enrollmentStaticService; @PostMapping("/add") @ApiOperation(value = "新增预报名学生信息") public AjaxResult addPreRegistrationStudentInfo(@Validated @RequestBody PreRegistrationStudentInfoValidate studentInfoValidate) { - return IStudentInfoService.add(studentInfoValidate); + return iStudentInfoService.add(studentInfoValidate); + } + + @PostMapping("/enrollmentStatistical") + @ApiOperation(value = "招生统计数据") + public AjaxResult> buildEnrollmentStatistical() { + return AjaxResult.success(enrollmentStaticService.buildEnrollmentStats()); + } + + @GetMapping("/enrollmentTrend") + @ApiOperation(value = "招生趋势数据(带筛选条件)") + public AjaxResult> buildEnrollmentTrend(@RequestParam("teacherId") Integer teacherId, @RequestParam("rangeType") String rangeType) { + return AjaxResult.success(enrollmentStaticService.buildEnrollmentTrend(teacherId, rangeType)); } }