init
This commit is contained in:
@@ -19,7 +19,7 @@ public class ApiResponse<T> {
|
||||
}
|
||||
|
||||
public static <T> ApiResponse<T> success(String message, T data) {
|
||||
return new ApiResponse<>(0, message, data);
|
||||
return new ApiResponse<>(200, message, data);
|
||||
}
|
||||
|
||||
public static <T> ApiResponse<T> error(int code, String message) {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.whu.edu.LyStatistic.statistic.config;
|
||||
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.addAllowedHeader("*");
|
||||
config.addAllowedMethod("*");
|
||||
config.setAllowCredentials(true); // 如果需要携带 Cookie
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
|
||||
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
|
||||
bean.setOrder(0); // 设置为最优先,优先于 Shiro
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.whu.edu.LyStatistic.statistic.controller;
|
||||
|
||||
import com.whu.edu.LyStatistic.statistic.Util.ApiResponse;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.TaskStatisticResult;
|
||||
import com.whu.edu.LyStatistic.statistic.service.OrgStatisticService;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/org-statistics")
|
||||
public class OrgStatisticController {
|
||||
|
||||
private final OrgStatisticService orgStatisticService;
|
||||
|
||||
public OrgStatisticController(OrgStatisticService orgStatisticService) {
|
||||
this.orgStatisticService = orgStatisticService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ApiResponse<Map<String, TaskStatisticResult>> getOrgStatistics(
|
||||
@RequestParam String orgName,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime time) {
|
||||
|
||||
List<String> tables = Arrays.asList("roottable1");
|
||||
Map<String, TaskStatisticResult> result =
|
||||
orgStatisticService.getOrgTaskStatistics(orgName, time, tables);
|
||||
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.whu.edu.LyStatistic.statistic.controller;
|
||||
|
||||
import com.whu.edu.LyStatistic.statistic.Util.ApiResponse;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.TaskStatisticResult;
|
||||
import com.whu.edu.LyStatistic.statistic.service.*;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class StatisticController {
|
||||
|
||||
private final OrgStatisticService orgStatisticService;
|
||||
private final DistrictStatisticService districtStatisticService;
|
||||
private final UserStatisticService userStatisticService ;
|
||||
private final UnitInfoService unitInfoService;
|
||||
public StatisticController(OrgStatisticService orgStatisticService, DistrictStatisticService districtStatisticService,UserStatisticService userStatisticService,UnitInfoService unitInfoService) {
|
||||
this.orgStatisticService = orgStatisticService;
|
||||
this.districtStatisticService = districtStatisticService;
|
||||
this.userStatisticService = userStatisticService;
|
||||
this.unitInfoService = unitInfoService;
|
||||
}
|
||||
@GetMapping("/org-statistics")
|
||||
public ApiResponse<Map<String, TaskStatisticResult>> getOrgStatistics(
|
||||
@RequestParam String orgName,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
|
||||
|
||||
Map<String, TaskStatisticResult> result =
|
||||
orgStatisticService.getOrgTaskStatistics(orgName, startTime, endTime);
|
||||
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按区/镇统计任务数量和人员参与情况
|
||||
*
|
||||
* @param district 区名称,可选
|
||||
* @param village 镇名称,可选
|
||||
* @return 统一返回格式
|
||||
*/
|
||||
@GetMapping("/district-statistics")
|
||||
public ApiResponse<Map<String, TaskStatisticResult>> getDistrictStatistics(
|
||||
@RequestParam(required = false) String district,
|
||||
@RequestParam(required = false) String village,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
|
||||
|
||||
Map<String, TaskStatisticResult> result =
|
||||
districtStatisticService.getDistrictTaskStatistics(district, village, startTime, endTime);
|
||||
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按人名和时间统计任务情况(遍历全部 schema)
|
||||
*
|
||||
* @param username 模糊人名,可选
|
||||
* @return 每个 schema 的统计结果
|
||||
*/
|
||||
@GetMapping("/user-statistics")
|
||||
public ApiResponse<Map<String, TaskStatisticResult>> getUserStatistics(
|
||||
@RequestParam(required = false) String username,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime startTime,
|
||||
@RequestParam(required = false)
|
||||
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime endTime) {
|
||||
Map<String, TaskStatisticResult> result =
|
||||
userStatisticService.getUserTaskStatistics(username,startTime, endTime);
|
||||
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
@GetMapping("/dropdown-options")
|
||||
public ApiResponse<Map<String, List<String>>> getDropdownOptions() {
|
||||
Map<String, List<String>> result = unitInfoService.getDropdownOptions();
|
||||
return ApiResponse.success(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.whu.edu.LyStatistic.statistic.dto;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 根表任务实体类,对应 roottable1。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RootTask implements Serializable {
|
||||
private Long id;
|
||||
private Long collector;
|
||||
private Long reviewer;
|
||||
}
|
||||
@@ -11,6 +11,9 @@ import java.util.List;
|
||||
@NoArgsConstructor
|
||||
public class TaskStatisticResult {
|
||||
private String schema;
|
||||
private Integer totalCount;
|
||||
private List<UserStatistic> userStatistics;
|
||||
private int totalRootCount;
|
||||
private int totalT1sub1Count;
|
||||
private int totalT1sub2Count;
|
||||
private int totalT1sub3Count;
|
||||
}
|
||||
@@ -9,5 +9,9 @@ import lombok.NoArgsConstructor;
|
||||
@NoArgsConstructor
|
||||
public class UserStatistic {
|
||||
private String username;
|
||||
private Integer taskCount;
|
||||
// private Integer taskCount;
|
||||
private int rootCount; // 小班数量(roottable1)
|
||||
private int t1sub1Count; // 样地数量
|
||||
private int t1sub2Count; // 样木数量
|
||||
private int t1sub3Count; // 灌木数量
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.whu.edu.LyStatistic.statistic.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class UserTaskCount {
|
||||
private Long userId;
|
||||
private Integer count;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.whu.edu.LyStatistic.statistic.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface DistrictSchemaMapper {
|
||||
/**
|
||||
* 根据区/镇获取 schema 列表
|
||||
* 如果 village 为 null,则返回该区下所有 schema
|
||||
*/
|
||||
List<String> findSchemasByDistrictAndVillage(@Param("district") String district,
|
||||
@Param("village") String village);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.whu.edu.LyStatistic.statistic.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface SchemaMapper {
|
||||
/**
|
||||
* 查询所有 schema 名称
|
||||
*/
|
||||
List<String> findAllSchemas();
|
||||
}
|
||||
@@ -1,25 +1,48 @@
|
||||
package com.whu.edu.LyStatistic.statistic.mapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import com.whu.edu.LyStatistic.statistic.dto.RootTask;
|
||||
import org.apache.ibatis.annotations.MapKey;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.UserTaskCount;
|
||||
@Mapper
|
||||
import java.util.Map;
|
||||
|
||||
public interface TaskStatisticMapper {
|
||||
|
||||
/**
|
||||
* 统计 collector 数量
|
||||
* 查询根表任务(支持时间范围 + 人员过滤)
|
||||
*/
|
||||
List<UserTaskCount> countByCollector(@Param("schema") String schema,
|
||||
@Param("table") String table,
|
||||
@Param("timeParam") LocalDateTime timeParam,
|
||||
@Param("userIds") List<Long> userIds);
|
||||
List<RootTask> findRootTasksByTimeRange(
|
||||
@Param("schema") String schema,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime,
|
||||
@Param("userIds") List<Long> userIds
|
||||
);
|
||||
|
||||
/**
|
||||
* 统计 reviewer 数量
|
||||
* 统计子表数量,返回每个 parentID 对应的数量
|
||||
*/
|
||||
List<UserTaskCount> countByReviewer(@Param("schema") String schema,
|
||||
@Param("table") String table,
|
||||
@Param("timeParam") LocalDateTime timeParam,
|
||||
@Param("userIds") List<Long> userIds);
|
||||
List<Map<String, Object>> countGroupByParent(@Param("schema") String schema,
|
||||
@Param("table") String table,
|
||||
@Param("column") String column,
|
||||
@Param("parentIds") List<Long> parentIds);
|
||||
|
||||
/**
|
||||
* 查询子表 ID 列表,并按 parentID 分组
|
||||
*/
|
||||
@MapKey("parentid")
|
||||
List<Map<String, Object>> findSubIdsGroupByParent(@Param("schema") String schema,
|
||||
@Param("table") String table,
|
||||
@Param("column") String column,
|
||||
@Param("parentIds") List<Long> parentIds);
|
||||
|
||||
|
||||
/**
|
||||
* 查询 t1sub2 子表数量,单个 parentID
|
||||
*/
|
||||
Integer countByParentId(@Param("schema") String schema,
|
||||
@Param("table") String table,
|
||||
@Param("column") String column,
|
||||
@Param("parentId") Long parentId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.whu.edu.LyStatistic.statistic.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface UnitInfoMapper {
|
||||
|
||||
List<String> findDistinctDistricts();
|
||||
|
||||
List<String> findDistinctVillages();
|
||||
|
||||
List<String> findDistinctUnits();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.whu.edu.LyStatistic.statistic.service;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.TaskStatisticResult;
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.DistrictSchemaMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class DistrictStatisticService {
|
||||
|
||||
private final TaskStatisticService taskStatisticService;
|
||||
private final DistrictSchemaMapper districtSchemaMapper;
|
||||
|
||||
public DistrictStatisticService(TaskStatisticService taskStatisticService,
|
||||
DistrictSchemaMapper districtSchemaMapper) {
|
||||
this.taskStatisticService = taskStatisticService;
|
||||
this.districtSchemaMapper = districtSchemaMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区/镇任务统计
|
||||
*
|
||||
* @param district 区名称,可为空
|
||||
* @param village 镇名称,可为空
|
||||
*/
|
||||
public Map<String, TaskStatisticResult> getDistrictTaskStatistics(String district,
|
||||
String village,
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime) {
|
||||
// 1. 找出该区/镇对应的全部 schema
|
||||
List<String> schemas = districtSchemaMapper.findSchemasByDistrictAndVillage(district, village);
|
||||
|
||||
Map<String, TaskStatisticResult> resultMap = new HashMap<>();
|
||||
|
||||
// 2. 遍历 schema,调用通用统计方法
|
||||
for (String schema : schemas) {
|
||||
TaskStatisticResult stat = taskStatisticService.getStatistics(schema, startTime, endTime, null);
|
||||
resultMap.put(schema, stat);
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
@@ -21,24 +21,19 @@ public class OrgStatisticService {
|
||||
/**
|
||||
* 按单位和时间统计任务信息
|
||||
* @param orgName 单位名称
|
||||
* @param timeParam 截止时间
|
||||
* @param tables 根表及子表
|
||||
* @return Map<schema, TaskStatisticResult>
|
||||
*/
|
||||
public Map<String, TaskStatisticResult> getOrgTaskStatistics(String orgName,
|
||||
LocalDateTime timeParam,
|
||||
List<String> tables) {
|
||||
// 1. 获取该单位对应的所有 schema
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime) {
|
||||
// 1. 找到该单位对应的 schema 列表
|
||||
List<String> schemas = orgSchemaMapper.findSchemasByOrgName(orgName);
|
||||
if (schemas == null || schemas.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, TaskStatisticResult> resultMap = new HashMap<>();
|
||||
|
||||
// 2. 循环每个 schema 调用通用统计
|
||||
Map<String, TaskStatisticResult> resultMap = new LinkedHashMap<>();
|
||||
// 2. 对每个 schema 执行统计方法
|
||||
for (String schema : schemas) {
|
||||
TaskStatisticResult result = taskStatisticService.getStatistics(schema, timeParam, null, tables);
|
||||
resultMap.put(schema, result);
|
||||
TaskStatisticResult stat = taskStatisticService.getStatistics(schema, startTime, endTime, null);
|
||||
resultMap.put(schema, stat);
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
|
||||
@@ -1,31 +1,39 @@
|
||||
package com.whu.edu.LyStatistic.statistic.service;
|
||||
|
||||
import com.whu.edu.LyStatistic.statistic.dto.*;
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.TaskStatisticMapper;
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.UserStaffMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.UserTaskCount;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.TaskStatisticResult;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.UserStatistic;
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.TaskStatisticMapper;
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.UserStaffMapper;
|
||||
import com.whu.edu.LyStatistic.statistic.dto.UserStaff;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Service
|
||||
public class TaskStatisticService {
|
||||
|
||||
private final TaskStatisticMapper taskStatisticMapper;
|
||||
private final UserStaffMapper userStaffMapper;
|
||||
@Autowired
|
||||
private UserStaffMapper userStaffMapper;
|
||||
|
||||
public TaskStatisticService(TaskStatisticMapper taskStatisticMapper, UserStaffMapper userStaffMapper) {
|
||||
this.taskStatisticMapper = taskStatisticMapper;
|
||||
this.userStaffMapper = userStaffMapper;
|
||||
}
|
||||
@Autowired
|
||||
private TaskStatisticMapper taskStatisticMapper;
|
||||
|
||||
/**
|
||||
* 按 schema 和时间区间统计任务数据
|
||||
*
|
||||
* @param schema 数据库 schema 名称
|
||||
* @param startTime 起始时间(可选)
|
||||
* @param endTime 截止时间(可选)
|
||||
* @param nameLike 人名模糊查询(可选)
|
||||
*/
|
||||
public TaskStatisticResult getStatistics(String schema,
|
||||
LocalDateTime timeParam,
|
||||
String nameLike,
|
||||
List<String> tables) {
|
||||
LocalDateTime startTime,
|
||||
LocalDateTime endTime,
|
||||
String nameLike) {
|
||||
|
||||
// 1. 查询模糊匹配的人员ID(若有)
|
||||
// 1️⃣ 模糊匹配人员ID
|
||||
List<Long> userIds = null;
|
||||
if (nameLike != null && !nameLike.isEmpty()) {
|
||||
userIds = userStaffMapper.findByNameLike(nameLike)
|
||||
@@ -34,38 +42,125 @@ public class TaskStatisticService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 2. 按schema统计任务量(collector+reviewer)
|
||||
Map<Long, Integer> countMap = new HashMap<>();
|
||||
|
||||
for (String table : tables) {
|
||||
List<UserTaskCount> collectorCounts = taskStatisticMapper.countByCollector(schema, table, timeParam, userIds);
|
||||
List<UserTaskCount> reviewerCounts = taskStatisticMapper.countByReviewer(schema, table, timeParam, userIds);
|
||||
|
||||
for (UserTaskCount c : collectorCounts) {
|
||||
countMap.merge(c.getUserId(), c.getCount(), Integer::sum);
|
||||
}
|
||||
for (UserTaskCount r : reviewerCounts) {
|
||||
countMap.merge(r.getUserId(), r.getCount(), Integer::sum);
|
||||
}
|
||||
// 2️⃣ 查询根表记录(支持时间区间)
|
||||
List<RootTask> rootTasks = taskStatisticMapper.findRootTasksByTimeRange(schema, startTime, endTime, userIds);
|
||||
if (rootTasks.isEmpty()) {
|
||||
return new TaskStatisticResult(schema, Collections.emptyList(), 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
if (countMap.isEmpty()) {
|
||||
return new TaskStatisticResult(schema, 0, Collections.emptyList());
|
||||
}
|
||||
|
||||
// 3. 查询所有 userId 对应 username
|
||||
List<Long> allUserIds = new ArrayList<>(countMap.keySet());
|
||||
Map<Long, String> idToName = userStaffMapper.findByIds(allUserIds)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(UserStaff::getId, UserStaff::getUsername));
|
||||
|
||||
// 4. 构造结果:username -> count
|
||||
List<UserStatistic> userStats = countMap.entrySet().stream()
|
||||
.map(e -> new UserStatistic(idToName.getOrDefault(e.getKey(), "未知用户"), e.getValue()))
|
||||
// 3️⃣ 获取所有根表ID
|
||||
List<Long> rootIds = rootTasks.stream()
|
||||
.map(RootTask::getId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int total = countMap.values().stream().mapToInt(Integer::intValue).sum();
|
||||
// 4️⃣ 查询子表计数
|
||||
Map<Long, Integer> t1sub1Map = safeCountByParent(schema, "t1sub1", rootIds);
|
||||
Map<Long, Integer> t1sub3Map = safeCountByParent(schema, "t1sub3", rootIds);
|
||||
|
||||
return new TaskStatisticResult(schema, total, userStats);
|
||||
// 4.1️⃣ t1sub2 层级统计
|
||||
List<Map<String, Object>> sub1List = safeFindSubIds(schema, "t1sub1", rootIds);
|
||||
Map<Long, List<Long>> rootToSub1Ids = rootIds.stream()
|
||||
.collect(Collectors.toMap(
|
||||
rid -> rid,
|
||||
rid -> sub1List.stream()
|
||||
.filter(m -> m.get("parentid") != null &&
|
||||
rid.equals(((Number) m.get("parentid")).longValue()))
|
||||
.map(m -> ((Number) m.get("ID")).longValue())
|
||||
.collect(Collectors.toList())
|
||||
));
|
||||
|
||||
Map<Long, Integer> t1sub2Map = new HashMap<>();
|
||||
for (Map.Entry<Long, List<Long>> entry : rootToSub1Ids.entrySet()) {
|
||||
int total = 0;
|
||||
for (Long sub1Id : entry.getValue()) {
|
||||
Integer count = safeCountByParentId(schema, "t1sub2", sub1Id);
|
||||
total += (count != null) ? count : 0;
|
||||
}
|
||||
t1sub2Map.put(entry.getKey(), total);
|
||||
}
|
||||
|
||||
// 5️⃣ 汇总用户统计(排除 null 和 -1)
|
||||
Map<Long, UserStatistic> userStats = new HashMap<>();
|
||||
for (RootTask task : rootTasks) {
|
||||
Long rootId = task.getId();
|
||||
if (rootId == null) continue;
|
||||
|
||||
Stream.of(task.getCollector(), task.getReviewer())
|
||||
.filter(uid -> uid != null && uid != -1)
|
||||
.forEach(uid -> {
|
||||
UserStatistic stat = userStats.computeIfAbsent(uid, k -> new UserStatistic());
|
||||
stat.setRootCount(stat.getRootCount() + 1);
|
||||
stat.setT1sub1Count(stat.getT1sub1Count() + t1sub1Map.getOrDefault(rootId, 0));
|
||||
stat.setT1sub2Count(stat.getT1sub2Count() + t1sub2Map.getOrDefault(rootId, 0));
|
||||
stat.setT1sub3Count(stat.getT1sub3Count() + t1sub3Map.getOrDefault(rootId, 0));
|
||||
});
|
||||
}
|
||||
|
||||
// 6️⃣ 填充用户名
|
||||
Map<Long, String> idToName = new HashMap<>();
|
||||
if (!userStats.isEmpty()) {
|
||||
userIds = new ArrayList<>(userStats.keySet());
|
||||
List<UserStaff> userList = userStaffMapper.findByIds(userIds);
|
||||
if (userList != null && !userList.isEmpty()) {
|
||||
idToName = userList.stream()
|
||||
.filter(u -> u.getId() != null)
|
||||
.collect(Collectors.toMap(
|
||||
UserStaff::getId,
|
||||
UserStaff::getUsername,
|
||||
(a, b) -> a // 避免重复键
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
final Map<Long, String> nameMap = idToName; // ✅ 实际 final,可安全用于 lambda
|
||||
|
||||
List<UserStatistic> results = userStats.entrySet().stream()
|
||||
.map(e -> {
|
||||
UserStatistic stat = e.getValue();
|
||||
stat.setUsername(nameMap.getOrDefault(e.getKey(), "未知用户"));
|
||||
return stat;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 7️⃣ 总量统计
|
||||
int totalRootCount = rootTasks.size();
|
||||
int totalT1sub1Count = t1sub1Map.values().stream().mapToInt(Integer::intValue).sum();
|
||||
int totalT1sub2Count = t1sub2Map.values().stream().mapToInt(Integer::intValue).sum();
|
||||
int totalT1sub3Count = t1sub3Map.values().stream().mapToInt(Integer::intValue).sum();
|
||||
|
||||
return new TaskStatisticResult(schema, results,
|
||||
totalRootCount, totalT1sub1Count, totalT1sub2Count, totalT1sub3Count);
|
||||
}
|
||||
|
||||
// 🧩 安全封装:防止 schema 无表时报错
|
||||
private Map<Long, Integer> safeCountByParent(String schema, String table, List<Long> rootIds) {
|
||||
try {
|
||||
return taskStatisticMapper.countGroupByParent(schema, table, "parentID", rootIds)
|
||||
.stream()
|
||||
.filter(m -> m.get("parentid") != null)
|
||||
.collect(Collectors.toMap(
|
||||
m -> ((Number) m.get("parentid")).longValue(),
|
||||
m -> ((Number) m.getOrDefault("count", 0)).intValue()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> safeFindSubIds(String schema, String table, List<Long> rootIds) {
|
||||
try {
|
||||
return taskStatisticMapper.findSubIdsGroupByParent(schema, table, "parentID", rootIds);
|
||||
} catch (Exception e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private Integer safeCountByParentId(String schema, String table, Long parentId) {
|
||||
try {
|
||||
return taskStatisticMapper.countByParentId(schema, table, "parentID", parentId);
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.whu.edu.LyStatistic.statistic.service;
|
||||
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.UnitInfoMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class UnitInfoService {
|
||||
|
||||
private final UnitInfoMapper unitInfoMapper;
|
||||
|
||||
public UnitInfoService(UnitInfoMapper unitInfoMapper) {
|
||||
this.unitInfoMapper = unitInfoMapper;
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getDropdownOptions() {
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("districts", unitInfoMapper.findDistinctDistricts());
|
||||
map.put("villages", unitInfoMapper.findDistinctVillages());
|
||||
map.put("units", unitInfoMapper.findDistinctUnits());
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.whu.edu.LyStatistic.statistic.service;
|
||||
|
||||
import com.whu.edu.LyStatistic.statistic.dto.TaskStatisticResult;
|
||||
import com.whu.edu.LyStatistic.statistic.mapper.SchemaMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class UserStatisticService {
|
||||
|
||||
private final TaskStatisticService taskStatisticService;
|
||||
private final SchemaMapper schemaMapper;
|
||||
|
||||
public UserStatisticService(TaskStatisticService taskStatisticService,
|
||||
SchemaMapper schemaMapper) {
|
||||
this.taskStatisticService = taskStatisticService;
|
||||
this.schemaMapper = schemaMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按人名和时间统计任务数量
|
||||
*
|
||||
* @param username 模糊人名,可选
|
||||
* @return 各 schema 的统计结果
|
||||
*/
|
||||
public Map<String, TaskStatisticResult> getUserTaskStatistics(String username, LocalDateTime startTime,
|
||||
LocalDateTime endTime) {
|
||||
// 查询所有 schema
|
||||
List<String> schemas = schemaMapper.findAllSchemas();
|
||||
|
||||
Map<String, TaskStatisticResult> resultMap = new HashMap<>();
|
||||
for (String schema : schemas) {
|
||||
// 调用通用统计方法
|
||||
TaskStatisticResult statistic = taskStatisticService.getStatistics(schema, startTime, endTime, username);
|
||||
resultMap.put(schema, statistic);
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ server.port=9001
|
||||
server.address=0.0.0.0
|
||||
spring.datasource.host=120.48.89.193
|
||||
spring.datasource.port=5432
|
||||
spring.datasource.database=tj_lydc
|
||||
spring.datasource.database=lydc_statistic
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
spring.datasource.url=jdbc:postgresql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.database}?useSSL=true&allowMultiQueries=true
|
||||
spring.datasource.username=postgres
|
||||
|
||||
25
src/main/resources/mapper/DistrictSchemaMapper.xml
Normal file
25
src/main/resources/mapper/DistrictSchemaMapper.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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.whu.edu.LyStatistic.statistic.mapper.DistrictSchemaMapper">
|
||||
|
||||
<!--
|
||||
根据 district 和 village 获取对应的 schema 列表
|
||||
如果 village 为 null,则返回该 district 下所有 schema
|
||||
schema_name 字段为数据库中存储 schema 名称的字段
|
||||
-->
|
||||
<select id="findSchemasByDistrictAndVillage" resultType="string">
|
||||
SELECT schema_code
|
||||
FROM public.unit_info
|
||||
WHERE 1=1
|
||||
<if test="district != null">
|
||||
AND district = #{district}
|
||||
</if>
|
||||
<if test="village != null">
|
||||
AND village = #{village}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
14
src/main/resources/mapper/SchemaMapper.xml
Normal file
14
src/main/resources/mapper/SchemaMapper.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?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.whu.edu.LyStatistic.statistic.mapper.SchemaMapper">
|
||||
|
||||
<!-- 查询全部 schema -->
|
||||
<select id="findAllSchemas" resultType="string">
|
||||
SELECT schema_code
|
||||
FROM public.unit_info
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -4,36 +4,79 @@
|
||||
|
||||
<mapper namespace="com.whu.edu.LyStatistic.statistic.mapper.TaskStatisticMapper">
|
||||
|
||||
<select id="countByCollector" parameterType="map" resultType="com.whu.edu.LyStatistic.statistic.dto.UserTaskCount">
|
||||
SELECT collector AS user_id, COUNT(*) AS count
|
||||
FROM "${schema}"."${table}" t
|
||||
WHERE t.collector != -1
|
||||
<!-- 根表记录 -->
|
||||
<select id="findRootTasks" resultType="com.whu.edu.LyStatistic.statistic.dto.RootTask">
|
||||
SELECT "ID" AS id,
|
||||
"collector" AS collector,
|
||||
"reviewer" AS reviewer
|
||||
FROM "${schema}".roottable1
|
||||
WHERE 1=1
|
||||
<if test="timeParam != null">
|
||||
AND update_time <= #{timeParam}
|
||||
AND create_time >= #{timeParam}
|
||||
</if>
|
||||
<if test="userIds != null and userIds.size() > 0">
|
||||
AND collector IN
|
||||
AND ("collector" IN
|
||||
<foreach collection="userIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
OR "reviewer" IN
|
||||
<foreach collection="userIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>)
|
||||
</if>
|
||||
</select>
|
||||
<select id="findRootTasksByTimeRange" parameterType="map" resultType="com.whu.edu.LyStatistic.statistic.dto.RootTask">
|
||||
SELECT "ID" AS id,
|
||||
"collector" AS collector,
|
||||
"reviewer" AS reviewer,
|
||||
update_time
|
||||
FROM "${schema}".roottable1
|
||||
WHERE 1=1
|
||||
<if test="startTime != null">
|
||||
AND update_time >= #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
AND update_time <= #{endTime}
|
||||
</if>
|
||||
<if test="userIds != null and userIds.size() > 0">
|
||||
AND (collector IN
|
||||
<foreach collection="userIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
OR reviewer IN
|
||||
<foreach collection="userIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>)
|
||||
</if>
|
||||
GROUP BY collector
|
||||
</select>
|
||||
|
||||
<select id="countByReviewer" parameterType="map" resultType="com.whu.edu.LyStatistic.statistic.dto.UserTaskCount">
|
||||
SELECT reviewer AS user_id, COUNT(*) AS count
|
||||
FROM "${schema}"."${table}" t
|
||||
WHERE t.reviewer != -1
|
||||
<if test="timeParam != null">
|
||||
AND update_time <= #{timeParam}
|
||||
</if>
|
||||
<if test="userIds != null and userIds.size() > 0">
|
||||
AND reviewer IN
|
||||
<foreach collection="userIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</if>
|
||||
GROUP BY reviewer
|
||||
<!-- 子表分组计数 -->
|
||||
<select id="countGroupByParent" resultType="map">
|
||||
SELECT "${column}" AS parentid,
|
||||
COUNT(*) AS count
|
||||
FROM "${schema}".${table}
|
||||
WHERE "${column}" IN
|
||||
<foreach collection="parentIds" item="pid" open="(" separator="," close=")">
|
||||
#{pid}
|
||||
</foreach>
|
||||
GROUP BY "${column}"
|
||||
</select>
|
||||
|
||||
<!-- 子表 ID 列表,并按 parentID 分组 -->
|
||||
<select id="findSubIdsGroupByParent" resultType="map">
|
||||
SELECT "${column}" AS parentid, "ID"
|
||||
FROM "${schema}".${table}
|
||||
WHERE "${column}" IN
|
||||
<foreach collection="parentIds" item="pid" open="(" separator="," close=")">
|
||||
#{pid}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<!-- t1sub2 单个 parentID 计数 -->
|
||||
<select id="countByParentId" resultType="int">
|
||||
SELECT COUNT(*)
|
||||
FROM "${schema}".${table}
|
||||
WHERE "${column}" = #{parentId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
34
src/main/resources/mapper/UnitInfoMapper.xml
Normal file
34
src/main/resources/mapper/UnitInfoMapper.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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.whu.edu.LyStatistic.statistic.mapper.UnitInfoMapper">
|
||||
|
||||
<select id="findDistinctDistricts" resultType="string">
|
||||
<![CDATA[
|
||||
SELECT DISTINCT district
|
||||
FROM public.unit_info
|
||||
WHERE district IS NOT NULL AND district <> ''
|
||||
ORDER BY district
|
||||
]]>
|
||||
</select>
|
||||
|
||||
<select id="findDistinctVillages" resultType="string">
|
||||
<![CDATA[
|
||||
SELECT DISTINCT village
|
||||
FROM public.unit_info
|
||||
WHERE village IS NOT NULL AND village <> ''
|
||||
ORDER BY village
|
||||
]]>
|
||||
</select>
|
||||
|
||||
<select id="findDistinctUnits" resultType="string">
|
||||
<![CDATA[
|
||||
SELECT DISTINCT unit_name
|
||||
FROM public.unit_info
|
||||
WHERE unit_name IS NOT NULL AND unit_name <> ''
|
||||
ORDER BY unit_name
|
||||
]]>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<!-- 根据用户名模糊查询 -->
|
||||
<select id="findByNameLike" resultType="com.whu.edu.LyStatistic.statistic.dto.UserStaff">
|
||||
SELECT id, real_name
|
||||
SELECT id, real_name AS username
|
||||
FROM public.user_staff
|
||||
WHERE real_name ILIKE CONCAT('%', #{name}, '%')
|
||||
</select>
|
||||
@@ -20,6 +20,4 @@
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user