diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/controller/FirmReportsController.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/controller/FirmReportsController.java index 772c471..f6b3ccb 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/controller/FirmReportsController.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/controller/FirmReportsController.java @@ -143,64 +143,15 @@ public class FirmReportsController { throw new IllegalArgumentException("月份必须在1-12之间"); } - // 使用指定的年月创建日期对象进行判断 - Month targetMonth = Month.of(month); - int dayOfMonth = 1; // 默认使用月份第一天进行判断 - - // 第一季度:1月-3月,或4月1日-4月4日 - if (targetMonth.getValue() < 4 || (targetMonth.getValue() == 4 && dayOfMonth < 5)) { - return 1; - } - // 第二季度:4月5日-6月30日,或7月1日-7月4日 - else if ((targetMonth.getValue() == 4 && dayOfMonth >= 5) || - (targetMonth.getValue() > 4 && targetMonth.getValue() < 7) || - (targetMonth.getValue() == 7 && dayOfMonth < 5)) { - return 2; - } - // 第三季度:7月5日-9月30日,或10月1日-10月4日 - else if ((targetMonth.getValue() == 7 && dayOfMonth >= 5) || - (targetMonth.getValue() > 7 && targetMonth.getValue() < 10) || - (targetMonth.getValue() == 10 && dayOfMonth < 5)) { - return 3; - } - // 第四季度:10月5日-12月31日(包含跨年情况) - else { - return 4; - } + return (month - 1) / 3 + 1; } /** * 根据当前日期判断所属季度(已考虑跨年情况) - * 第一季度:1月1日-4月4日 - * 第二季度:4月5日-7月4日 - * 第三季度:7月5日-10月4日 - * 第四季度:10月5日-12月31日 * @return 季度编号(1-4) */ private int getCurrentQuarter() { LocalDate today = LocalDate.now(); - Month month = today.getMonth(); - int dayOfMonth = today.getDayOfMonth(); - - // 第一季度:1月-3月,或4月1日-4月4日 - if (month.getValue() < 4 || (month.getValue() == 4 && dayOfMonth < 5)) { - return 1; - } - // 第二季度:4月5日-6月30日,或7月1日-7月4日 - else if ((month.getValue() == 4 && dayOfMonth >= 5) || - (month.getValue() > 4 && month.getValue() < 7) || - (month.getValue() == 7 && dayOfMonth < 5)) { - return 2; - } - // 第三季度:7月5日-9月30日,或10月1日-10月4日 - else if ((month.getValue() == 7 && dayOfMonth >= 5) || - (month.getValue() > 7 && month.getValue() < 10) || - (month.getValue() == 10 && dayOfMonth < 5)) { - return 3; - } - // 第四季度:10月5日-12月31日(包含跨年情况) - else { - return 4; - } + return (today.getMonthValue() - 1) / 3 + 1; } } diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/dao/ServiceApplicationsDao.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/dao/ServiceApplicationsDao.java index c37ee53..99ebf02 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/dao/ServiceApplicationsDao.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/dao/ServiceApplicationsDao.java @@ -174,6 +174,11 @@ public interface ServiceApplicationsDao extends BaseMapper getLawyerActivityDetail(@Param("userId") Long userId, @Param("queryForm") LawyerStatisticsQueryFormPage queryForm); + /** + * 批量查询多个律师的活动统计(避免N+1查询) + */ + List getLawyerActivityDetailBatch(@Param("userIds") List userIds, @Param("queryForm") LawyerStatisticsQueryFormPage queryForm); + /** * 查询律所列表(分页,按活动总数排序) */ @@ -240,4 +245,9 @@ public interface ServiceApplicationsDao extends BaseMapper queryByFirmIdAndTimeRange(@Param("firmId") Long firmId, @Param("startTime") String startTime, @Param("endTime") String endTime); + + /** + * 获取指定前缀的最大备案编号 + */ + String getMaxFilingNo(@Param("prefix") String prefix); } diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/entity/ServiceApplicationsEntity.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/entity/ServiceApplicationsEntity.java index fd502a7..34a5425 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/entity/ServiceApplicationsEntity.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/entity/ServiceApplicationsEntity.java @@ -123,10 +123,15 @@ public class ServiceApplicationsEntity { private LocalDateTime associationAuditTime; /** - * 备案编号 + * 备案编号(原有 recordNo 被用作案件编号/案号,因此新建 filingNo 作为真正的备案编号) */ private String recordNo; + /** + * 备案编号 + */ + private String filingNo; + /** * 备案状态:0-未备案,1-已备案 */ diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/LawyerStatisticsQueryForm.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/LawyerStatisticsQueryForm.java index 262882d..80d69ac 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/LawyerStatisticsQueryForm.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/LawyerStatisticsQueryForm.java @@ -34,4 +34,20 @@ public class LawyerStatisticsQueryForm { private String endTime; private Long userId; + + /** + * 排序字段,可选值: + * quarterlyServiceDuration - 季度累计公益服务时长 + * quarterlyServiceCost - 季度累计公益服务成本 + * annualServiceDuration - 年度累计公益服务时长 + * annualServiceCost - 年度累计公益服务成本 + */ + @Schema(description = "排序字段") + private String sortField; + + /** + * 排序方向:asc - 升序,desc - 降序 + */ + @Schema(description = "排序方向:asc/desc") + private String sortOrder; } \ No newline at end of file diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceApplicationsQueryForm.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceApplicationsQueryForm.java index 1bce797..d42de82 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceApplicationsQueryForm.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceApplicationsQueryForm.java @@ -125,10 +125,15 @@ public class ServiceApplicationsQueryForm extends PageParam { private String associationAuditTimeEnd; /** - * 备案编号 + * 案件编号/案号 */ private String recordNo; + /** + * 备案编号 + */ + private String filingNo; + /** * 备案状态:0-未备案,1-已备案 */ diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/vo/ServiceApplicationsVO.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/vo/ServiceApplicationsVO.java index 658b6e7..7baf8b4 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/vo/ServiceApplicationsVO.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/vo/ServiceApplicationsVO.java @@ -84,9 +84,12 @@ public class ServiceApplicationsVO { @Schema(description = "协会审核时间") private LocalDateTime associationAuditTime; - @Schema(description = "备案编号") + @Schema(description = "案件编号/案号") private String recordNo; + @Schema(description = "备案编号") + private String filingNo; + @Schema(description = "备案状态:0-未备案,1-已备案") private Integer recordStatus; diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/service/ServiceApplicationsService.java b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/service/ServiceApplicationsService.java index f8dc128..bd8adec 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/service/ServiceApplicationsService.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/module/service/service/ServiceApplicationsService.java @@ -71,8 +71,6 @@ import java.time.LocalDateTime; import java.util.*; import java.util.function.Function; - - /** * 服务申报 Service * @@ -105,7 +103,7 @@ public class ServiceApplicationsService { PositionService positionService; @Resource private DictService dictService; - + @Resource private FirmReportsDao firmReportsDao; @@ -114,6 +112,7 @@ public class ServiceApplicationsService { /** * 案号重复性校验(用于提交操作) + * * @param addForm 提交表单 */ private void validateRecordNoUniquenessForSubmit(ServiceApplicationsAddForm addForm) { @@ -121,19 +120,20 @@ public class ServiceApplicationsService { if (!"TIME".equals(addForm.getServiceType())) { return; } - + String recordNo = addForm.getRecordNo(); if (recordNo == null || recordNo.trim().isEmpty()) { return; } - + Long currentUserId = AdminRequestUtil.getRequestUser().getEmployeeId(); - + if (addForm.getApplicationId() == null) { // 新增操作:检查案号是否已存在 List existingRecords = serviceApplicationsDao.selectByRecordNo(recordNo); if (!existingRecords.isEmpty()) { - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + + UserErrorCode.HAS_EXIST1.getMsg()); } } else { // 编辑操作:检查案号是否被其他用户使用并且本人也不能使用 @@ -141,33 +141,37 @@ public class ServiceApplicationsService { if (!existingRecords.isEmpty()) { // 检查是否是当前用户的记录 boolean isCurrentUserRecord = existingRecords.stream() - .anyMatch(record -> record.getUserId().equals(currentUserId)); - + .anyMatch(record -> record.getUserId().equals(currentUserId)); + if (!isCurrentUserRecord || existingRecords.size() > 1) { // 如果不是当前用户的记录,或者有多条记录(包括当前用户),则不允许 - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + + UserErrorCode.HAS_EXIST1.getMsg()); } } } } - //查看详情 + // 查看详情 public ServiceApplicationsVO queryDetail(Long applicationId) { ServiceApplicationsVO serviceApplicationsVO = new ServiceApplicationsVO(); ServiceApplicationsEntity item = serviceApplicationsDao.selectById(applicationId); SmartBeanUtil.copyProperties(item, serviceApplicationsVO); if (item.getFirmId() != null) { - serviceApplicationsVO.setDepartmentName(departmentService.queryByFirmId(item.getFirmId()).getDepartmentName()); + serviceApplicationsVO + .setDepartmentName(departmentService.queryByFirmId(item.getFirmId()).getDepartmentName()); } - if (item.getUserId() != null){ + if (item.getUserId() != null) { serviceApplicationsVO.setUserName(employeeService.queryById(item.getUserId()).getActualName()); } - if (item.getFirmAuditUser() != null){ - serviceApplicationsVO.setFirmAuditUserName(employeeService.queryById(item.getFirmAuditUser()).getActualName()); + if (item.getFirmAuditUser() != null) { + serviceApplicationsVO + .setFirmAuditUserName(employeeService.queryById(item.getFirmAuditUser()).getActualName()); } if (item.getActivityCategoryId() != null) { - serviceApplicationsVO.setActivityCategory(categoryService.queryById(item.getActivityCategoryId()).getCategoryName()); + serviceApplicationsVO + .setActivityCategory(categoryService.queryById(item.getActivityCategoryId()).getCategoryName()); } if (item.getActivityNameId() != null) { serviceApplicationsVO.setActivityName(goodsService.queryById(item.getActivityNameId()).getGoodsName()); @@ -178,18 +182,17 @@ public class ServiceApplicationsService { return serviceApplicationsVO; } - /** * 分页查询 */ public PageResult queryPage(ServiceApplicationsQueryForm queryForm) { List longs = new ArrayList<>(); Page page = SmartPageUtil.convert2PageQuery(queryForm); - //根据用户角色的查询数据范围来查询数据 + // 根据用户角色的查询数据范围来查询数据 RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); List roleIdList = roleEmployeeService.getRoleIdList(requestUser.getUserId()); String roleCode = AdminRequestUtil.getRoleCode(roleIdList); - + // 检查角色类型 boolean isAssociationRole = AdminRequestUtil.isAssociationRole(roleIdList); boolean isFirmRole = AdminRequestUtil.isFirmRole(roleIdList); // 律所主任或行政 @@ -210,9 +213,11 @@ public class ServiceApplicationsService { // 获取自己部门范围内的数据 List departmentEmployees = new ArrayList<>(); if (DataScopeViewTypeEnum.ME.getValue().equals(oneByRoleId)) { - departmentEmployees = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.ME, requestUser.getUserId()); + departmentEmployees = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.ME, + requestUser.getUserId()); } else if (DataScopeViewTypeEnum.DEPARTMENT.getValue().equals(oneByRoleId)) { - departmentEmployees = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.DEPARTMENT, requestUser.getUserId()); + departmentEmployees = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.DEPARTMENT, + requestUser.getUserId()); } // 确保包含当前用户ID,以便能看到自己创建的数据 @@ -230,9 +235,11 @@ public class ServiceApplicationsService { // 律所普通用户:只能看到自己提交的数据,包括所有firmAuditStatus状态 Integer oneByRoleId = dataScopeViewService.getOneByRoleId(roleIdList.get(0).getRoleId()); if (DataScopeViewTypeEnum.ME.getValue().equals(oneByRoleId)) { - longs = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.ME, requestUser.getUserId()); + longs = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.ME, + requestUser.getUserId()); } else if (DataScopeViewTypeEnum.DEPARTMENT.getValue().equals(oneByRoleId)) { - longs = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.DEPARTMENT, requestUser.getUserId()); + longs = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.DEPARTMENT, + requestUser.getUserId()); } // 确保普通用户至少能看到自己的数据,如果longs为空或不包含当前用户ID,则添加当前用户ID if (longs == null) { @@ -251,15 +258,15 @@ public class ServiceApplicationsService { } List list = serviceApplicationsDao.queryPage(page, queryForm); if (!CollectionUtils.isEmpty(list)) { - //翻译单位名称和用户名称 + // 翻译单位名称和用户名称 list.forEach(item -> { if (item.getFirmId() != null) { item.setDepartmentName(departmentService.queryByFirmId(item.getFirmId()).getDepartmentName()); } - if (item.getUserId() != null){ + if (item.getUserId() != null) { item.setUserName(employeeService.queryById(item.getUserId()).getActualName()); } - if (item.getFirmAuditUser() != null){ + if (item.getFirmAuditUser() != null) { item.setFirmAuditUserName(employeeService.queryById(item.getFirmAuditUser()).getActualName()); } if (item.getActivityCategoryId() != null) { @@ -271,16 +278,16 @@ public class ServiceApplicationsService { if (item.getPositionId() != null) { item.setPositionName(positionService.queryById(item.getPositionId()).getPositionName()); } - //协会审核人 + // 协会审核人 if (item.getAssociationAuditUser() != null) { - item.setAssociationAuditUserName(employeeService.queryById(item.getAssociationAuditUser()).getActualName()); + item.setAssociationAuditUserName( + employeeService.queryById(item.getAssociationAuditUser()).getActualName()); } }); } return SmartPageUtil.convert2PageResult(page, list); } - public PageResult queryPageReport(@Valid ServiceApplicationsQueryForm queryForm) { Page page = SmartPageUtil.convert2PageQuery(queryForm); RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); @@ -295,15 +302,15 @@ public class ServiceApplicationsService { } List list = serviceApplicationsDao.queryPage(page, queryForm); if (!CollectionUtils.isEmpty(list)) { - //翻译单位名称和用户名称 + // 翻译单位名称和用户名称 list.forEach(item -> { if (item.getFirmId() != null) { item.setDepartmentName(departmentService.queryByFirmId(item.getFirmId()).getDepartmentName()); } - if (item.getUserId() != null){ + if (item.getUserId() != null) { item.setUserName(employeeService.queryById(item.getUserId()).getActualName()); } - if (item.getFirmAuditUser() != null){ + if (item.getFirmAuditUser() != null) { item.setFirmAuditUserName(employeeService.queryById(item.getFirmAuditUser()).getActualName()); } if (item.getActivityCategoryId() != null) { @@ -315,9 +322,10 @@ public class ServiceApplicationsService { if (item.getPositionId() != null) { item.setPositionName(positionService.queryById(item.getPositionId()).getPositionName()); } - //协会审核人 + // 协会审核人 if (item.getAssociationAuditUser() != null) { - item.setAssociationAuditUserName(employeeService.queryById(item.getAssociationAuditUser()).getActualName()); + item.setAssociationAuditUserName( + employeeService.queryById(item.getAssociationAuditUser()).getActualName()); } }); } @@ -329,24 +337,28 @@ public class ServiceApplicationsService { */ public ResponseDTO add(ServiceApplicationsAddForm addForm) { - ServiceApplicationsEntity serviceApplicationsEntity = SmartBeanUtil.copy(addForm, ServiceApplicationsEntity.class); - if(addForm.getApplicationId() == null) { - //新增的时候判断活动类型查询案号有没有存在 - if("TIME".equals(addForm.getServiceType())) { - List serviceApplicationsVOS = serviceApplicationsDao.selectByRecordNo(addForm.getRecordNo()); - if (!serviceApplicationsVOS.isEmpty()){ - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg()+serviceApplicationsVOS.get(0).getUserName()+UserErrorCode.HAS_EXIST1.getMsg()); + ServiceApplicationsEntity serviceApplicationsEntity = SmartBeanUtil.copy(addForm, + ServiceApplicationsEntity.class); + if (addForm.getApplicationId() == null) { + // 新增的时候判断活动类型查询案号有没有存在 + if ("TIME".equals(addForm.getServiceType())) { + List serviceApplicationsVOS = serviceApplicationsDao + .selectByRecordNo(addForm.getRecordNo()); + if (!serviceApplicationsVOS.isEmpty()) { + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + + serviceApplicationsVOS.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); } } serviceApplicationsDao.insert(serviceApplicationsEntity); - }else { - //修改的时候判断活动类型查询案号别人有没有创建 - if("TIME".equals(addForm.getServiceType())) { - //当前登录人的ID + } else { + // 修改的时候判断活动类型查询案号别人有没有创建 + if ("TIME".equals(addForm.getServiceType())) { + // 当前登录人的ID Long userId = AdminRequestUtil.getRequestUser().getEmployeeId(); // 编辑操作:检查案号是否被其他用户使用并且本人也不能使用 - List existingRecords = serviceApplicationsDao.selectByRecordNo(addForm.getRecordNo()); + List existingRecords = serviceApplicationsDao + .selectByRecordNo(addForm.getRecordNo()); if (!existingRecords.isEmpty()) { // 检查是否是当前用户的记录 boolean isCurrentUserRecord = existingRecords.stream() @@ -354,7 +366,8 @@ public class ServiceApplicationsService { if (!isCurrentUserRecord || existingRecords.size() > 1) { // 如果不是当前用户的记录,或者有多条记录(包括当前用户),则不允许 - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); } } } @@ -368,12 +381,13 @@ public class ServiceApplicationsService { * */ public ResponseDTO update(ServiceApplicationsUpdateForm updateForm) { - //判断活动类型查询案号有没有存在 - if("TIME".equals(updateForm.getServiceType())) { - //当前登录人的ID + // 判断活动类型查询案号有没有存在 + if ("TIME".equals(updateForm.getServiceType())) { + // 当前登录人的ID Long userId = AdminRequestUtil.getRequestUser().getEmployeeId(); // 编辑操作:检查案号是否被其他用户使用并且本人也不能使用 - List existingRecords = serviceApplicationsDao.selectByRecordNo(updateForm.getRecordNo()); + List existingRecords = serviceApplicationsDao + .selectByRecordNo(updateForm.getRecordNo()); if (!existingRecords.isEmpty()) { // 检查是否是当前用户的记录 boolean isCurrentUserRecord = existingRecords.stream() @@ -381,51 +395,59 @@ public class ServiceApplicationsService { if (!isCurrentUserRecord || existingRecords.size() > 1) { // 如果不是当前用户的记录,或者有多条记录(包括当前用户),则不允许 - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + + UserErrorCode.HAS_EXIST1.getMsg()); } } } - ServiceApplicationsEntity serviceApplicationsEntity = SmartBeanUtil.copy(updateForm, ServiceApplicationsEntity.class); - //serviceApplicationsEntity.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); + ServiceApplicationsEntity serviceApplicationsEntity = SmartBeanUtil.copy(updateForm, + ServiceApplicationsEntity.class); + // serviceApplicationsEntity.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); serviceApplicationsDao.updateById(serviceApplicationsEntity); - + return ResponseDTO.ok(); } - + /** * 发送审核结果通知 - * @param entity 服务申请实体 - * @param auditStatus 审核状态 - * @param auditOpinion 审核意见 + * + * @param entity 服务申请实体 + * @param auditStatus 审核状态 + * @param auditOpinion 审核意见 * @param isAssociationReview 是否为协会审核(true=协会审核,false=律所审核) */ - private void sendAuditNotification(ServiceApplicationsEntity entity, Integer auditStatus, String auditOpinion, boolean isAssociationReview) { + private void sendAuditNotification(ServiceApplicationsEntity entity, Integer auditStatus, String auditOpinion, + boolean isAssociationReview) { try { boolean isPass = ReviewEnum.PASS.getValue().equals(auditStatus); String statusText = isPass ? "通过" : "拒绝"; String reviewerType = isAssociationReview ? "律协" : "律所"; - + // 获取律师姓名 String lawyerName = "律师"; if (entity.getUserId() != null) { - net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity employee = employeeDao.selectById(entity.getUserId()); + net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity employee = employeeDao + .selectById(entity.getUserId()); if (employee != null) { lawyerName = employee.getActualName(); } } - + // 构建服务简介(显示活动时间) String serviceBrief = ""; if (entity.getServiceStart() != null && entity.getServiceEnd() != null) { - java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"); - serviceBrief = entity.getServiceStart().format(formatter) + " 至 " + entity.getServiceEnd().format(formatter); + java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter + .ofPattern("yyyy-MM-dd"); + serviceBrief = entity.getServiceStart().format(formatter) + " 至 " + + entity.getServiceEnd().format(formatter); } else if (entity.getServiceStart() != null) { - java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"); + java.time.format.DateTimeFormatter formatter = java.time.format.DateTimeFormatter + .ofPattern("yyyy-MM-dd"); serviceBrief = entity.getServiceStart().format(formatter) + " 开始"; } else { serviceBrief = "服务申报"; } - + String title; if (isAssociationReview) { if (isPass) { @@ -439,13 +461,14 @@ public class ServiceApplicationsService { // 律所审核完成:发给律师(个人) title = "你的服务申报「" + serviceBrief + "」律所" + statusText; } - + net.lab1024.sa.base.module.support.message.domain.MessageSendForm sendForm = new net.lab1024.sa.base.module.support.message.domain.MessageSendForm(); - sendForm.setMessageType(net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum.AUDIT.getValue()); + sendForm.setMessageType( + net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum.AUDIT.getValue()); sendForm.setReceiverUserType(net.lab1024.sa.base.common.enumeration.UserTypeEnum.ADMIN_EMPLOYEE.getValue()); sendForm.setTitle(title); sendForm.setDataId(entity.getApplicationId()); - + // 构建审核意见(显示律所和律协双方的意见) String firmOpinion = entity.getFirmAuditOpinion(); String associationOpinion = entity.getAssociationAuditOpinion(); @@ -456,7 +479,7 @@ public class ServiceApplicationsService { if (associationOpinion != null && !associationOpinion.trim().isEmpty()) { opinions.append("\n律协审核意见:").append(associationOpinion); } - + if (isAssociationReview) { if (isPass) { // 律协通过:发给服务填报人(个人) @@ -488,28 +511,33 @@ public class ServiceApplicationsService { log.error("发送审核通知失败: {}", e.getMessage(), e); } } - + /** * 发送通知给律所管理员(主任和行政) */ - private void sendNotificationsToFirmAdmins(Long firmId, net.lab1024.sa.base.module.support.message.domain.MessageSendForm baseSendForm) { + private void sendNotificationsToFirmAdmins(Long firmId, + net.lab1024.sa.base.module.support.message.domain.MessageSendForm baseSendForm) { sendNotificationsToFirmAdmins(firmId, baseSendForm, null); } - + /** * 发送通知给律所管理员(主任和行政) + * * @param customContent 自定义消息内容(如果为null则使用baseSendForm中的内容) */ - private void sendNotificationsToFirmAdmins(Long firmId, net.lab1024.sa.base.module.support.message.domain.MessageSendForm baseSendForm, String customContent) { - if (firmId == null) return; - - List employees = employeeDao.selectByDepartmentId(firmId, false); + private void sendNotificationsToFirmAdmins(Long firmId, + net.lab1024.sa.base.module.support.message.domain.MessageSendForm baseSendForm, String customContent) { + if (firmId == null) + return; + + List employees = employeeDao + .selectByDepartmentId(firmId, false); for (net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity emp : employees) { Long empId = emp.getEmployeeId(); List empRoles = roleEmployeeService.getRoleIdList(empId); boolean isCto = AdminRequestUtil.isFirmDirectorRole(empRoles); boolean isStaff = AdminRequestUtil.isFirmStaffRole(empRoles); - + if (isCto || isStaff) { net.lab1024.sa.base.module.support.message.domain.MessageSendForm sendForm = new net.lab1024.sa.base.module.support.message.domain.MessageSendForm(); SmartBeanUtil.copyProperties(baseSendForm, sendForm); @@ -529,17 +557,19 @@ public class ServiceApplicationsService { // 案号重复性校验 validateRecordNoUniquenessForSubmit(addForm); - if (null == addForm.getApplicationId()){ + if (null == addForm.getApplicationId()) { // 新增提交 ServiceApplicationsEntity serviceApplications = new ServiceApplicationsEntity(); SmartBeanUtil.copyProperties(addForm, serviceApplications); serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); serviceApplications.setReportTime(LocalDateTime.now()); serviceApplicationsDao.insert(serviceApplications); - serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue()); - }else { + serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), + ReviewEnum.APPROVAL.getValue()); + } else { // 编辑提交(二次提交/驳回后重新提交) - ServiceApplicationsEntity serviceApplications = serviceApplicationsDao.selectById(addForm.getApplicationId()); + ServiceApplicationsEntity serviceApplications = serviceApplicationsDao + .selectById(addForm.getApplicationId()); SmartBeanUtil.copyProperties(addForm, serviceApplications); serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); // 首次从草稿/已有记录提交时补提交时间;二次提交保持原有提交时间不变。 @@ -547,15 +577,17 @@ public class ServiceApplicationsService { serviceApplications.setReportTime(LocalDateTime.now()); } serviceApplicationsDao.updateById(serviceApplications); - serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue()); + serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), + ReviewEnum.APPROVAL.getValue()); } return ResponseDTO.ok(); } + /** * 批量删除 */ public ResponseDTO batchDelete(List idList) { - if (CollectionUtils.isEmpty(idList)){ + if (CollectionUtils.isEmpty(idList)) { return ResponseDTO.ok(); } @@ -567,7 +599,7 @@ public class ServiceApplicationsService { * 单个删除 */ public ResponseDTO delete(Long applicationId) { - if (null == applicationId){ + if (null == applicationId) { return ResponseDTO.ok(); } @@ -580,12 +612,12 @@ public class ServiceApplicationsService { // 预加载转换器缓存 List categoryList = categoryService.getAllCategory(); List goodsList = goodsService.getAllGoods(); - + // 获取当前用户信息 RequestUser requestUser = AdminRequestUtil.getRequestUser(); List employeesInDepartment = new ArrayList<>(); List departmentList = new ArrayList<>(); - + if (requestUser != null) { EmployeeEntity currentUser = employeeService.queryById(requestUser.getUserId()); if (currentUser != null) { @@ -599,13 +631,13 @@ public class ServiceApplicationsService { } } } - + // 更新转换器缓存 ActivityCategoryConverter.updateCategoryCache(categoryList); ActivityNameConverter.updateActivityCache(goodsList); EmployeeNameConverter.updateEmployeeNameCache(employeesInDepartment); OrganizationNameConverter.updateOrganizationNameCache(departmentList); - + List dataList; try { dataList = EasyExcel.read(file.getInputStream()).head(ServiceApplicationsTemplateVO.class) @@ -662,11 +694,11 @@ public class ServiceApplicationsService { /** * 服务申报模板 */ - public void downloadTemplate(HttpServletResponse response ) { + public void downloadTemplate(HttpServletResponse response) { try { // 创建模板数据列表 List templateList = new ArrayList<>(); - + // 添加示例数据作为第一行 ServiceApplicationsTemplateVO exampleVO = new ServiceApplicationsTemplateVO(); exampleVO.setUserId("张三"); @@ -677,7 +709,7 @@ public class ServiceApplicationsService { exampleVO.setBeneficiaryCount(50); exampleVO.setServiceStart(LocalDateTime.of(2025, 1, 15, 9, 0, 0)); exampleVO.setServiceEnd(LocalDateTime.of(2025, 1, 15, 17, 0, 0)); - //exampleVO.setReportTime(LocalDateTime.now()); + // exampleVO.setReportTime(LocalDateTime.now()); exampleVO.setServiceDuration(8.0); exampleVO.setOrganizerName("北京市司法局"); exampleVO.setOrganizerContact("李主任"); @@ -692,7 +724,8 @@ public class ServiceApplicationsService { // 预填充用户信息(根据实际业务需要) EmployeeEntity employeeEntity = employeeService.queryById(requestUser.getUserId()); templateVO.setUserId(employeeEntity.getActualName()); - templateVO.setFirmId(departmentService.queryByFirmId(employeeEntity.getDepartmentId()).getDepartmentName()); + templateVO.setFirmId( + departmentService.queryByFirmId(employeeEntity.getDepartmentId()).getDepartmentName()); templateList.add(templateVO); } @@ -715,17 +748,19 @@ public class ServiceApplicationsService { // 获取当前用户相关数据用于下拉列表 List organizationNames = new ArrayList<>(); List employeeNames = new ArrayList<>(); - + if (requestUser != null) { // 获取当前用户所在机构 EmployeeEntity currentUser = employeeService.queryById(requestUser.getUserId()); if (currentUser != null) { // 当前用户的机构名称 - String currentUserOrganization = departmentService.queryByFirmId(currentUser.getDepartmentId()).getDepartmentName(); + String currentUserOrganization = departmentService.queryByFirmId(currentUser.getDepartmentId()) + .getDepartmentName(); organizationNames.add(currentUserOrganization); - + // 获取当前机构下的所有员工 - List employeesInDepartment = employeeService.getByDepartmentId(currentUser.getDepartmentId()); + List employeesInDepartment = employeeService + .getByDepartmentId(currentUser.getDepartmentId()); if (employeesInDepartment != null) { employeeNames = employeesInDepartment.stream() .map(EmployeeEntity::getActualName) @@ -738,21 +773,24 @@ public class ServiceApplicationsService { EasyExcel.write(response.getOutputStream(), ServiceApplicationsTemplateVO.class) .autoCloseStream(false) .sheet("服务申报模板") - .registerWriteHandler(new DropdownSheetWriteHandler(categoryNames, goodsNames, organizationNames, employeeNames)) + .registerWriteHandler( + new DropdownSheetWriteHandler(categoryNames, goodsNames, organizationNames, employeeNames)) .doWrite(templateList); } catch (Exception e) { log.error("模板下载失败", e); - throw new BusinessException("模板下载失败:" + (e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName() + " occurred")); + throw new BusinessException( + "模板下载失败:" + (e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName() + " occurred")); } } /** * 批量提交 + * * @param idList * @return */ public ResponseDTO batchSubmit(List idList) { - if (CollectionUtils.isEmpty(idList)){ + if (CollectionUtils.isEmpty(idList)) { return ResponseDTO.ok(); } @@ -762,54 +800,55 @@ public class ServiceApplicationsService { /** * 批量上报 + * * @param idList * @return */ public ResponseDTO batchSubmitAsFirm(List idList) { - if (CollectionUtils.isEmpty(idList)){ + if (CollectionUtils.isEmpty(idList)) { return ResponseDTO.ok(); } // 获取当前用户信息 RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); List roleIdList = roleEmployeeService.getRoleIdList(requestUser.getUserId()); - + // 检查是否是律所角色(主任或行政) boolean isFirmRole = AdminRequestUtil.isFirmRole(roleIdList); if (!isFirmRole) { return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } - + Long targetFirmId = null; LocalDateTime firstReportTime = null; - + // 查询这些记录的详细信息,进行权限和状态校验 for (Long id : idList) { ServiceApplicationsEntity record = serviceApplicationsDao.selectById(id); if (record == null) { return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST, "记录ID:" + id + "不存在"); } - + // 记录律所ID和上报时间(用于后续成本校验) if (targetFirmId == null) { targetFirmId = record.getFirmId(); firstReportTime = record.getReportTime(); } - + // 校验1:只能上报本所的数据 if (!record.getFirmId().equals(requestUser.getDepartmentId())) { return ResponseDTO.error(UserErrorCode.NO_PERMISSION, "只能上报本所的数据"); } - + // 校验2:执业机构审核状态必须是已通过(3) if (!ReviewEnum.PASS.getValue().equals(record.getFirmAuditStatus())) { return ResponseDTO.error(UserErrorCode.PARAM_ERROR, "记录ID:" + id + "未通过执业机构审核,无法上报"); } - + // 校验3:协会审核状态必须是未提交(0)或被驳回(4) Integer associationStatus = record.getAssociationAuditStatus(); - if (!ReviewEnum.NOSUBMIT.getValue().equals(associationStatus) && - !ReviewEnum.REFUSE.getValue().equals(associationStatus)) { + if (!ReviewEnum.NOSUBMIT.getValue().equals(associationStatus) && + !ReviewEnum.REFUSE.getValue().equals(associationStatus)) { return ResponseDTO.error(UserErrorCode.PARAM_ERROR, "记录ID:" + id + "已上报或正在审核中,无法重复上报"); } } @@ -820,47 +859,55 @@ public class ServiceApplicationsService { int reportMonth = firstReportTime.getMonthValue(); int reportQuarter = (reportMonth - 1) / 3 + 1; - List unsubmittedQuarters = firmReportsDao.findUnsubmittedEarlierQuarters(targetFirmId.intValue(), reportYear, reportQuarter); + List unsubmittedQuarters = firmReportsDao.findUnsubmittedEarlierQuarters(targetFirmId.intValue(), + reportYear, reportQuarter); if (unsubmittedQuarters != null && !unsubmittedQuarters.isEmpty()) { String quarterNames = String.join("、", unsubmittedQuarters); return ResponseDTO.userErrorParam( - "请先提交" + quarterNames + "的成本报表后,再批量上报服务数据"); + "请先提交" + quarterNames + "的成本报表后,再批量上报服务数据"); } } - + serviceApplicationsDao.batchSubmitAsAssociation(idList, ReviewEnum.APPROVAL.getValue()); - + return ResponseDTO.ok(); } public ResponseDTO addSubmit(@Valid ServiceApplicationsAddForm addForm) { - //ServiceApplicationsEntity serviceApplicationsEntity = SmartBeanUtil.copy(addForm, ServiceApplicationsEntity.class); - //serviceApplicationsEntity.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); - //serviceApplicationsEntity.setReportTime(LocalDateTime.now()); - + // ServiceApplicationsEntity serviceApplicationsEntity = + // SmartBeanUtil.copy(addForm, ServiceApplicationsEntity.class); + // serviceApplicationsEntity.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); + // serviceApplicationsEntity.setReportTime(LocalDateTime.now()); + // 检查当前用户角色是否为CEO - /*RequestUser requestUser = AdminRequestUtil.getRequestUser(); - List roles = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId()); - if (!roles.isEmpty()) { - String roleCode = roles.get(0).getRoleCode(); - // 如果是CEO角色创建申报,默认通过律所审核和协会审核 - if (UserTypeEnum.CEO.getDesc().equals(roleCode)) { - serviceApplicationsEntity.setFirmAuditStatus(ReviewEnum.PASS.getValue()); - serviceApplicationsEntity.setFirmAuditUser(requestUser.getUserId()); - serviceApplicationsEntity.setFirmAuditTime(LocalDateTime.now()); - serviceApplicationsEntity.setAssociationAuditStatus(ReviewEnum.PASS.getValue()); - serviceApplicationsEntity.setAssociationAuditUser(requestUser.getUserId()); - serviceApplicationsEntity.setAssociationAuditTime(LocalDateTime.now()); - } - }*/ - - if (null == addForm.getApplicationId()){ - //判断活动类型查询案号有没有存在 - if("TIME".equals(addForm.getServiceType())) { - List serviceApplicationsEntity = serviceApplicationsDao.selectByRecordNo(addForm.getRecordNo()); - if (!serviceApplicationsEntity.isEmpty()){ - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg()+serviceApplicationsEntity.get(0).getUserName()+UserErrorCode.HAS_EXIST1.getMsg()); + /* + * RequestUser requestUser = AdminRequestUtil.getRequestUser(); + * List roles = + * roleEmployeeService.getRoleIdList(requestUser.getEmployeeId()); + * if (!roles.isEmpty()) { + * String roleCode = roles.get(0).getRoleCode(); + * // 如果是CEO角色创建申报,默认通过律所审核和协会审核 + * if (UserTypeEnum.CEO.getDesc().equals(roleCode)) { + * serviceApplicationsEntity.setFirmAuditStatus(ReviewEnum.PASS.getValue()); + * serviceApplicationsEntity.setFirmAuditUser(requestUser.getUserId()); + * serviceApplicationsEntity.setFirmAuditTime(LocalDateTime.now()); + * serviceApplicationsEntity.setAssociationAuditStatus(ReviewEnum.PASS.getValue( + * )); + * serviceApplicationsEntity.setAssociationAuditUser(requestUser.getUserId()); + * serviceApplicationsEntity.setAssociationAuditTime(LocalDateTime.now()); + * } + * } + */ + + if (null == addForm.getApplicationId()) { + // 判断活动类型查询案号有没有存在 + if ("TIME".equals(addForm.getServiceType())) { + List serviceApplicationsEntity = serviceApplicationsDao + .selectByRecordNo(addForm.getRecordNo()); + if (!serviceApplicationsEntity.isEmpty()) { + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + + serviceApplicationsEntity.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); } } ServiceApplicationsEntity serviceApplications = new ServiceApplicationsEntity(); @@ -868,13 +915,15 @@ public class ServiceApplicationsService { serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); serviceApplications.setReportTime(LocalDateTime.now()); serviceApplicationsDao.insert(serviceApplications); - serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue()); - }else { - //判断活动类型查询案号有没有存在 - if("TIME".equals(addForm.getServiceType())) { + serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), + ReviewEnum.APPROVAL.getValue()); + } else { + // 判断活动类型查询案号有没有存在 + if ("TIME".equals(addForm.getServiceType())) { Long userId = AdminRequestUtil.getRequestUser().getEmployeeId(); // 编辑操作:检查案号是否被其他用户使用并且本人也不能使用 - List existingRecords = serviceApplicationsDao.selectByRecordNo(addForm.getRecordNo()); + List existingRecords = serviceApplicationsDao + .selectByRecordNo(addForm.getRecordNo()); if (!existingRecords.isEmpty()) { // 检查是否是当前用户的记录 boolean isCurrentUserRecord = existingRecords.stream() @@ -882,18 +931,21 @@ public class ServiceApplicationsService { if (!isCurrentUserRecord || existingRecords.size() > 1) { // 如果不是当前用户的记录,或者有多条记录(包括当前用户),则不允许 - throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); + throw new BusinessException(UserErrorCode.HAS_EXIST.getMsg() + + existingRecords.get(0).getUserName() + UserErrorCode.HAS_EXIST1.getMsg()); } } } - ServiceApplicationsEntity serviceApplications = serviceApplicationsDao.selectById(addForm.getApplicationId()); + ServiceApplicationsEntity serviceApplications = serviceApplicationsDao + .selectById(addForm.getApplicationId()); SmartBeanUtil.copyProperties(addForm, serviceApplications); serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue()); if (serviceApplications.getReportTime() == null) { serviceApplications.setReportTime(LocalDateTime.now()); } serviceApplicationsDao.updateById(serviceApplications); - serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue()); + serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), + ReviewEnum.APPROVAL.getValue()); } return ResponseDTO.ok(); @@ -911,15 +963,16 @@ public class ServiceApplicationsService { log.warn("审核失败:用户无角色, employeeId={}", requestUser.getEmployeeId()); return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } - - log.info("审核请求:applicationId={}, 用户角色={}, firmAuditStatus={}, associationAuditStatus={}, auditResult={}", - updateForm.getApplicationId(), - roles.get(0).getRoleCode(), - updateForm.getFirmAuditStatus(), - updateForm.getAssociationAuditStatus(), - updateForm.getAuditResult()); - - ServiceApplicationsEntity serviceApplicationsEntity = serviceApplicationsDao.selectById(updateForm.getApplicationId()); + + log.info("审核请求:applicationId={}, 用户角色={}, firmAuditStatus={}, associationAuditStatus={}, auditResult={}", + updateForm.getApplicationId(), + roles.get(0).getRoleCode(), + updateForm.getFirmAuditStatus(), + updateForm.getAssociationAuditStatus(), + updateForm.getAuditResult()); + + ServiceApplicationsEntity serviceApplicationsEntity = serviceApplicationsDao + .selectById(updateForm.getApplicationId()); if (serviceApplicationsEntity == null) { return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); } @@ -943,13 +996,23 @@ public class ServiceApplicationsService { if (auditResult == null) { return ResponseDTO.userErrorParam("审核结果不能为空"); } - + // 设置协会审核状态 serviceApplicationsEntity.setAssociationAuditStatus(auditResult); serviceApplicationsEntity.setAssociationAuditUser(requestUser.getEmployeeId()); serviceApplicationsEntity.setAssociationAuditTime(LocalDateTime.now()); serviceApplicationsEntity.setAssociationAuditOpinion(updateForm.getAssociationAuditOpinion()); + // 当协会审核通过时,自动生成唯一备案编号并将状态标记为已备案 + if (ReviewEnum.PASS.getValue().equals(auditResult)) { + if (serviceApplicationsEntity.getRecordStatus() == null + || serviceApplicationsEntity.getRecordStatus() != 1) { + serviceApplicationsEntity.setRecordStatus(1); + serviceApplicationsEntity.setRecordTime(LocalDateTime.now()); + serviceApplicationsEntity.setFilingNo(generateFilingNo()); + } + } + serviceApplicationsDao.updateById(serviceApplicationsEntity); // 当协会审核通过时,更新成本管理表中的实际公益成本和比例 @@ -958,7 +1021,8 @@ public class ServiceApplicationsService { } // 发送通知:律协审核结果通知给填报人 - sendAuditNotification(serviceApplicationsEntity, auditResult, updateForm.getAssociationAuditOpinion(), true); + sendAuditNotification(serviceApplicationsEntity, auditResult, updateForm.getAssociationAuditOpinion(), + true); } // ============================================================ // 律所审核(律所角色:主任/行政) @@ -973,7 +1037,7 @@ public class ServiceApplicationsService { log.warn("律所审核失败:firmAuditStatus和auditResult都为空"); return ResponseDTO.userErrorParam("审核结果不能为空"); } - + // 设置律所审核状态 serviceApplicationsEntity.setFirmAuditStatus(auditResult); serviceApplicationsEntity.setFirmAuditUser(requestUser.getEmployeeId()); @@ -995,7 +1059,7 @@ public class ServiceApplicationsService { return ResponseDTO.ok(); } - + /** * 更新成本管理表中的实际公益成本和比例 * 财务逻辑: @@ -1032,26 +1096,27 @@ public class ServiceApplicationsService { int reportMonth = reportTime.getMonthValue(); int costYear = reportTime.getYear(); int costQuarter = (reportMonth - 1) / 3 + 1; - - log.info("更新成本:firmId={}, reportTime={}, reportMonth={}, 成本归属年份={}, 成本归属季度=Q{}", - firmId, reportTime, reportMonth, costYear, costQuarter); - + + log.info("更新成本:firmId={}, reportTime={}, reportMonth={}, 成本归属年份={}, 成本归属季度=Q{}", + firmId, reportTime, reportMonth, costYear, costQuarter); + // ============================================================ // 查询该律所该成本年份的所有季度记录 // ============================================================ List allQuarterReports = new ArrayList<>(); for (int quarter = 1; quarter <= 4; quarter++) { - List quarterReports = firmReportsDao.selectByFirmIdYearAndQuarter(firmId.intValue(), costYear, String.valueOf(quarter)); + List quarterReports = firmReportsDao.selectByFirmIdYearAndQuarter(firmId.intValue(), + costYear, String.valueOf(quarter)); if (CollectionUtils.isNotEmpty(quarterReports)) { allQuarterReports.addAll(quarterReports); } } - + if (CollectionUtils.isEmpty(allQuarterReports)) { log.warn("更新成本失败:未找到成本管理记录, firmId={}, costYear={}", firmId, costYear); return; } - + // ============================================================ // 计算全年实际公益成本(四个季度通过审核的成本之和) // ============================================================ @@ -1060,13 +1125,13 @@ public class ServiceApplicationsService { BigDecimal quarterCost = calculateActualPublicWelfareCost(firmId, costYear, quarter); annualActualCost = annualActualCost.add(quarterCost); } - + // 转换为万元 BigDecimal annualActualCostInWan = annualActualCost.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); - - log.info("更新成本:firmId={}, costYear={}, 全年实际公益成本={}元, 折合{}万元", - firmId, costYear, annualActualCost, annualActualCostInWan); - + + log.info("更新成本:firmId={}, costYear={}, 全年实际公益成本={}元, 折合{}万元", + firmId, costYear, annualActualCost, annualActualCostInWan); + // ============================================================ // 计算全年营业收入(四个季度之和) // ============================================================ @@ -1076,7 +1141,7 @@ public class ServiceApplicationsService { annualRevenue = annualRevenue.add(report.getRevenue()); } } - + log.info("更新成本:firmId={}, costYear={}, 全年营业收入={}万元", firmId, costYear, annualRevenue); // ============================================================ @@ -1085,15 +1150,15 @@ public class ServiceApplicationsService { BigDecimal annualCostIncomeRatio = BigDecimal.ZERO; if (annualRevenue.compareTo(BigDecimal.ZERO) > 0) { annualCostIncomeRatio = annualActualCostInWan.divide(annualRevenue, 4, RoundingMode.HALF_UP) - .multiply(new BigDecimal(100)) - .setScale(2, RoundingMode.HALF_UP); - + .multiply(new BigDecimal(100)) + .setScale(2, RoundingMode.HALF_UP); + // 上限25% if (annualCostIncomeRatio.compareTo(new BigDecimal("25.00")) > 0) { annualCostIncomeRatio = new BigDecimal("25.00"); } } - + log.info("更新成本:firmId={}, costYear={}, 全年实际成本收入比={}%", firmId, costYear, annualCostIncomeRatio); // ============================================================ @@ -1111,33 +1176,56 @@ public class ServiceApplicationsService { break; } } - + if (targetQuarterReport != null) { // 计算当前季度的实际公益成本(元转万元) BigDecimal quarterActualCost = calculateActualPublicWelfareCost(firmId, costYear, costQuarter); - BigDecimal quarterActualCostInWan = quarterActualCost.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); - + BigDecimal quarterActualCostInWan = quarterActualCost.divide(new BigDecimal("10000"), 2, + RoundingMode.HALF_UP); + // 更新当前季度的实际公益成本 targetQuarterReport.setActualPublicWelfareCost(quarterActualCostInWan); - - // 更新当前季度的全年累计实际成本收入比 - targetQuarterReport.setActualCostIncomeRatio(annualCostIncomeRatio); - + + // 计算截止到该季度末的累计营业收入 + BigDecimal cumulativeRevenue = BigDecimal.ZERO; + for (FirmReportsEntity report : allQuarterReports) { + String quarterStr = report.getDeclareQuarter(); + int q = quarterStr != null ? Integer.parseInt(quarterStr) : 0; + if (q > 0 && q <= costQuarter && report.getRevenue() != null) { + cumulativeRevenue = cumulativeRevenue.add(report.getRevenue()); + } + } + + // 计算该季度的实际成本收入比 = 本季度实际成本 / 截止本季度末累计收入 + BigDecimal quarterActualCostIncomeRatio = BigDecimal.ZERO; + if (cumulativeRevenue.compareTo(BigDecimal.ZERO) > 0) { + quarterActualCostIncomeRatio = quarterActualCostInWan.divide(cumulativeRevenue, 4, RoundingMode.HALF_UP) + .multiply(new BigDecimal(100)) + .setScale(2, RoundingMode.HALF_UP); + if (quarterActualCostIncomeRatio.compareTo(new BigDecimal("25.00")) > 0) { + quarterActualCostIncomeRatio = new BigDecimal("25.00"); + } + } + + // 更新当前季度的实际成本收入比 + targetQuarterReport.setActualCostIncomeRatio(quarterActualCostIncomeRatio); + firmReportsDao.updateById(targetQuarterReport); - - log.info("更新季度成本:firmId={}, costYear={}, quarter={}, 季度实际成本={}万元, 全年实际成本收入比={}%", - firmId, costYear, costQuarter, quarterActualCostInWan, annualCostIncomeRatio); + + log.info("更新季度成本:firmId={}, costYear={}, quarter={}, 季度实际成本={}万元, 截止当前季度累计营业收入={}万元, 实际成本收入比={}%", + firmId, costYear, costQuarter, quarterActualCostInWan, cumulativeRevenue, quarterActualCostIncomeRatio); } else { log.warn("更新成本失败:未找到季度记录, firmId={}, costYear={}, quarter={}", firmId, costYear, costQuarter); } - + log.info("更新成本成功:firmId={}, costYear={}, quarter={}", firmId, costYear, costQuarter); } - + /** * 计算实际公益成本(用于后端审核/驳回时计算实际成本) - * @param firmId 律所ID - * @param year 年份 + * + * @param firmId 律所ID + * @param year 年份 * @param quarter 季度 * @return 实际公益成本 */ @@ -1145,24 +1233,25 @@ public class ServiceApplicationsService { // 计算季度的开始和结束月份 int startMonth = (quarter - 1) * 3 + 1; int endMonth = startMonth + 2; - + // 计算实际公益成本 BigDecimal actualCost = BigDecimal.ZERO; - + for (int month = startMonth; month <= endMonth; month++) { // 查询该月份的已审核通过的服务申请 ServiceApplicationsQueryForm queryForm = new ServiceApplicationsQueryForm(); queryForm.setFirmId(firmId); - + // 设置月份的时间范围 LocalDateTime monthStart = LocalDateTime.of(year, month, 1, 0, 0, 0); LocalDateTime monthEnd = monthStart.plusMonths(1).minusSeconds(1); queryForm.setStartTime(monthStart.toString()); queryForm.setEndTime(monthEnd.toString()); - + // 查询已审核通过的服务申请 - List serviceApplications = serviceApplicationsDao.queryByFirmIdAndTimeRange(firmId, monthStart.toString(), monthEnd.toString()); - + List serviceApplications = serviceApplicationsDao.queryByFirmIdAndTimeRange(firmId, + monthStart.toString(), monthEnd.toString()); + // 计算成本 DictEntity dictItem = dictService.getOne("FILECOST"); if (dictItem != null) { @@ -1179,14 +1268,19 @@ public class ServiceApplicationsService { } catch (NumberFormatException e) { fixedHours = 0; } + } else { + fixedHours = application.getServiceDuration() != null ? application.getServiceDuration() : 0; } BigDecimal cost = BigDecimal.valueOf(fixedHours * Long.valueOf(dictItem.getRemark())); actualCost = actualCost.add(cost); } else if ("AMOUT".equals(serviceType)) { - BigDecimal amount = application.getServiceAmount() != null ? application.getServiceAmount() : BigDecimal.ZERO; + BigDecimal amount = application.getServiceAmount() != null ? application.getServiceAmount() + : BigDecimal.ZERO; actualCost = actualCost.add(amount); } else if ("DICT".equals(serviceType)) { - double duration = application.getServiceDuration() != null ? application.getServiceDuration() : 0; + double duration = application.getServiceDuration() != null + ? application.getServiceDuration() + : 0; BigDecimal cost = BigDecimal.valueOf(duration * Long.valueOf(dictItem.getRemark())); actualCost = actualCost.add(cost); } @@ -1194,26 +1288,93 @@ public class ServiceApplicationsService { } } } - + return actualCost; } + /** + * 计算预上报公益成本(用于律所成本填报时预上报成本计算) + * 只统计律所审核通过的服务申请(firmAuditStatus = 3),不需要律协审核通过 + * + * @param firmId 律所ID + * @param year 年份 + * @param quarter 季度 + * @return 预上报公益成本 + */ + private BigDecimal calculatePreReportPublicWelfareCost(Long firmId, int year, int quarter) { + // 计算季度的开始和结束月份 + int startMonth = (quarter - 1) * 3 + 1; + int endMonth = startMonth + 2; + + // 计算预上报公益成本 + BigDecimal preReportCost = BigDecimal.ZERO; + + for (int month = startMonth; month <= endMonth; month++) { + // 设置月份的时间范围 + LocalDateTime monthStart = LocalDateTime.of(year, month, 1, 0, 0, 0); + LocalDateTime monthEnd = monthStart.plusMonths(1).minusSeconds(1); + + // 查询该月份的服务申请 + List serviceApplications = serviceApplicationsDao.queryByFirmIdAndTimeRange(firmId, + monthStart.toString(), monthEnd.toString()); + + // 计算成本 + DictEntity dictItem = dictService.getOne("FILECOST"); + if (dictItem != null) { + for (ServiceApplicationsVO application : serviceApplications) { + // 统计律所审核通过的服务申请(firmAuditStatus = 3) + if (application.getFirmAuditStatus() == ReviewEnum.PASS.getValue()) { + String serviceType = application.getServiceType(); + if ("TIME".equals(serviceType)) { + double fixedHours = 0; + String activityPrice = application.getActivityPrice(); + if (activityPrice != null && !activityPrice.isEmpty() && !activityPrice.contains("-")) { + try { + fixedHours = Double.parseDouble(activityPrice); + } catch (NumberFormatException e) { + fixedHours = 0; + } + } else { + fixedHours = application.getServiceDuration() != null ? application.getServiceDuration() : 0; + } + BigDecimal cost = BigDecimal.valueOf(fixedHours * Long.valueOf(dictItem.getRemark())); + preReportCost = preReportCost.add(cost); + } else if ("AMOUT".equals(serviceType)) { + BigDecimal amount = application.getServiceAmount() != null ? application.getServiceAmount() + : BigDecimal.ZERO; + preReportCost = preReportCost.add(amount); + } else if ("DICT".equals(serviceType)) { + double duration = application.getServiceDuration() != null + ? application.getServiceDuration() + : 0; + BigDecimal cost = BigDecimal.valueOf(duration * Long.valueOf(dictItem.getRemark())); + preReportCost = preReportCost.add(cost); + } + } + } + } + } + + return preReportCost; + } + /** * 根据用户权限屏蔽成本数据 + * * @param statisticsList 统计数据列表 */ private void maskCostDataForUser(List statisticsList) { if (statisticsList == null || statisticsList.isEmpty()) { return; } - + RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); if (requestUser == null) { // 用户未登录,屏蔽所有成本数据 statisticsList.forEach(this::clearCostData); return; } - + // 检查用户的costVisibleFlag权限 Boolean costVisibleFlag = requestUser.getCostVisibleFlag(); if (costVisibleFlag == null || !costVisibleFlag) { @@ -1222,16 +1383,17 @@ public class ServiceApplicationsService { } // 如果有权限,则保持原数据不变 } - + /** * 清空成本相关数据 + * * @param statisticsVO 统计VO对象 */ private void clearCostData(LawyerStatisticsVO statisticsVO) { if (statisticsVO != null) { statisticsVO.setQuarterlyServiceCost(BigDecimal.ZERO); statisticsVO.setAnnualServiceCost(BigDecimal.ZERO); - + // 如果有律师服务列表,也需要清空其中的成本数据 if (statisticsVO.getLawyerServiceVOList() != null) { statisticsVO.getLawyerServiceVOList().forEach(lawyerService -> { @@ -1267,7 +1429,8 @@ public class ServiceApplicationsService { /** * 律所统计(分页) */ - public PageResult getLawyerStatisticsByDepartmentPage(@Valid LawyerStatisticsQueryFormPage queryForm) { + public PageResult getLawyerStatisticsByDepartmentPage( + @Valid LawyerStatisticsQueryFormPage queryForm) { // 应用权限控制 applyUserPermissionControl(queryForm); @@ -1283,7 +1446,8 @@ public class ServiceApplicationsService { LawyerStatisticsQueryFormPage annualQueryFormPage = createAnnualQueryFormPage(queryForm); // 分页查询律所年度统计数据(使用年度时间范围) - List annualStatistics = serviceApplicationsDao.getdepartmentStatisticsPage(page, annualQueryFormPage); + List annualStatistics = serviceApplicationsDao.getdepartmentStatisticsPage(page, + annualQueryFormPage); if (!annualStatistics.isEmpty()) { // 处理统计数据(季度数据、律师明细等) @@ -1305,7 +1469,7 @@ public class ServiceApplicationsService { LawyerStatisticsQueryForm annualQueryForm = createAnnualQueryForm(queryForm); return serviceApplicationsDao.getdepartmentStatistics(annualQueryForm); } - + /** * 创建年度查询表单 */ @@ -1348,7 +1512,7 @@ public class ServiceApplicationsService { return annualQueryForm; } - + /** * 创建年度查询表单(分页类型) */ @@ -1372,22 +1536,35 @@ public class ServiceApplicationsService { return annualQueryFormPage; } - + /** * 处理统计数据 */ - private void processStatistics(List annualStatistics, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem) { + private void processStatistics(List annualStatistics, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem) { // 获取季度统计数据(如果有季度条件) List quarterlyStatistics = getQuarterlyStatistics(queryForm); - + // 处理每个律所的统计数据 for (LawyerStatisticsVO annualStat : annualStatistics) { processDepartmentStatistics(annualStat, queryForm, dictItem, quarterlyStatistics); } + + // 按年度累计服务成本降序排序 + annualStatistics.sort((a, b) -> { + BigDecimal costA = a.getAnnualServiceCost() != null ? a.getAnnualServiceCost() : BigDecimal.ZERO; + BigDecimal costB = b.getAnnualServiceCost() != null ? b.getAnnualServiceCost() : BigDecimal.ZERO; + int costCompare = costB.compareTo(costA); + if (costCompare != 0) return costCompare; + // 成本相同时按律所名称排序 + if (a.getFirmName() != null && b.getFirmName() != null) { + return a.getFirmName().compareTo(b.getFirmName()); + } + return 0; + }); } - + /** * 获取季度统计数据 */ @@ -1395,11 +1572,11 @@ public class ServiceApplicationsService { if (queryForm.getQuarter() == null) { return new ArrayList<>(); } - + LawyerStatisticsQueryForm quarterlyQueryForm = createQuarterlyQueryForm(queryForm); return serviceApplicationsDao.getdepartmentStatistics(quarterlyQueryForm); } - + /** * 创建季度查询表单 */ @@ -1408,89 +1585,90 @@ public class ServiceApplicationsService { quarterlyQueryForm.setYear(queryForm.getYear()); quarterlyQueryForm.setQuarter(queryForm.getQuarter()); quarterlyQueryForm.setFirmId(queryForm.getFirmId()); - + // 设置季度时间范围 LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), queryForm.getQuarter()); LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(queryForm.getYear(), queryForm.getQuarter()); quarterlyQueryForm.setStartTime(quarterStart.toString()); quarterlyQueryForm.setEndTime(quarterEnd.toString()); - + return quarterlyQueryForm; } - + /** * 处理单个律所的统计数据 */ - private void processDepartmentStatistics(LawyerStatisticsVO annualStat, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem, - List quarterlyStatistics) { + private void processDepartmentStatistics(LawyerStatisticsVO annualStat, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem, + List quarterlyStatistics) { // 处理年度数据 processAnnualData(annualStat, queryForm, dictItem); - + // 处理季度数据 processQuarterlyData(annualStat, queryForm, dictItem, quarterlyStatistics); - + // 处理律师详细数据 processLawyerDetails(annualStat, queryForm, dictItem); } - + /** * 处理年度数据 */ - private void processAnnualData(LawyerStatisticsVO annualStat, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem) { + private void processAnnualData(LawyerStatisticsVO annualStat, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem) { // 计算年度成本 calculateAnnualCost(annualStat, dictItem); - + // 添加金额类型数据 addAmountDataToAnnualCost(annualStat, queryForm); } - + /** * 计算年度成本 */ private void calculateAnnualCost(LawyerStatisticsVO annualStat, DictEntity dictItem) { - BigDecimal annualCost = BigDecimal.valueOf(annualStat.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark())); + BigDecimal annualCost = BigDecimal + .valueOf(annualStat.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark())); annualStat.setAnnualServiceCost(annualCost); } - + /** * 添加金额类型数据到年度成本 */ private void addAmountDataToAnnualCost(LawyerStatisticsVO annualStat, LawyerStatisticsQueryForm queryForm) { LawyerStatisticsQueryForm amountQueryForm = new LawyerStatisticsQueryForm(); amountQueryForm.setFirmId(annualStat.getFirmId()); - + // 设置年度时间范围 String yearStart = queryForm.getYear() + "-01-01"; String yearEnd = queryForm.getYear() + "-12-31"; amountQueryForm.setStartTime(yearStart); amountQueryForm.setEndTime(yearEnd); - + BigDecimal annualAmount = serviceApplicationsDao.getServiceAmount(amountQueryForm); if (annualAmount != null && annualAmount.compareTo(BigDecimal.ZERO) > 0) { annualStat.setAnnualServiceCost(annualStat.getAnnualServiceCost().add(annualAmount)); } } - + /** * 处理季度数据 */ - private void processQuarterlyData(LawyerStatisticsVO annualStat, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem, - List quarterlyStatistics) { + private void processQuarterlyData(LawyerStatisticsVO annualStat, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem, + List quarterlyStatistics) { if (queryForm.getQuarter() == null) { annualStat.setQuarterlyServiceDuration(0.00); annualStat.setQuarterlyServiceCost(BigDecimal.ZERO); return; } - + // 查找对应的季度数据 LawyerStatisticsVO quarterlyStat = findQuarterlyStatByFirmId(quarterlyStatistics, annualStat.getFirmId()); - + if (quarterlyStat != null) { annualStat.setQuarterlyServiceDuration(quarterlyStat.getAnnualServiceDuration()); calculateQuarterlyCost(annualStat, dictItem); @@ -1500,62 +1678,63 @@ public class ServiceApplicationsService { annualStat.setQuarterlyServiceCost(BigDecimal.ZERO); } } - + /** * 根据律所ID查找季度数据 */ private LawyerStatisticsVO findQuarterlyStatByFirmId(List quarterlyStatistics, Long firmId) { return quarterlyStatistics.stream() - .filter(stat -> firmId.equals(stat.getFirmId())) - .findFirst() - .orElse(null); + .filter(stat -> firmId.equals(stat.getFirmId())) + .findFirst() + .orElse(null); } - + /** * 计算季度成本 */ private void calculateQuarterlyCost(LawyerStatisticsVO annualStat, DictEntity dictItem) { - BigDecimal quarterlyCost = BigDecimal.valueOf(annualStat.getQuarterlyServiceDuration() * Long.valueOf(dictItem.getRemark())); + BigDecimal quarterlyCost = BigDecimal + .valueOf(annualStat.getQuarterlyServiceDuration() * Long.valueOf(dictItem.getRemark())); annualStat.setQuarterlyServiceCost(quarterlyCost); } - + /** * 添加季度金额数据 */ private void addQuarterlyAmountData(LawyerStatisticsVO annualStat, LawyerStatisticsQueryForm queryForm) { LawyerStatisticsQueryForm quarterlyAmountQueryForm = new LawyerStatisticsQueryForm(); quarterlyAmountQueryForm.setFirmId(annualStat.getFirmId()); - + // 设置季度时间范围 LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), queryForm.getQuarter()); LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(queryForm.getYear(), queryForm.getQuarter()); quarterlyAmountQueryForm.setStartTime(quarterStart.toString()); quarterlyAmountQueryForm.setEndTime(quarterEnd.toString()); - + BigDecimal quarterlyAmount = serviceApplicationsDao.getServiceAmount(quarterlyAmountQueryForm); if (quarterlyAmount != null && quarterlyAmount.compareTo(BigDecimal.ZERO) > 0) { annualStat.setQuarterlyServiceCost(annualStat.getQuarterlyServiceCost().add(quarterlyAmount)); } } - + /** * 处理律师详细数据 */ - private void processLawyerDetails(LawyerStatisticsVO annualStat, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem) { + private void processLawyerDetails(LawyerStatisticsVO annualStat, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem) { // 查询律师年度统计信息 List lawyerAnnualStats = getLawyerAnnualStats(annualStat.getFirmId(), queryForm); - + // 查询律师季度统计信息(如果有季度条件) List lawyerQuarterlyStats = getLawyerQuarterlyStats(annualStat.getFirmId(), queryForm); - + // 处理律师统计数据 processLawyerStats(lawyerAnnualStats, lawyerQuarterlyStats, queryForm, dictItem); - + annualStat.setLawyerServiceVOList(lawyerAnnualStats); } - + /** * 查询律师年度统计信息 */ @@ -1563,16 +1742,16 @@ public class ServiceApplicationsService { ServiceLawyerQueryForm serviceLawyerQueryForm = new ServiceLawyerQueryForm(); serviceLawyerQueryForm.setFirmId(firmId); serviceLawyerQueryForm.setYear(queryForm.getYear()); - + // 设置年度时间范围 String yearStart = queryForm.getYear() + "-01-01"; String yearEnd = queryForm.getYear() + "-12-31"; serviceLawyerQueryForm.setStartTime(yearStart); serviceLawyerQueryForm.setEndTime(yearEnd); - + return serviceApplicationsDao.getLawyerStatisticsWithParam(serviceLawyerQueryForm); } - + /** * 查询律师季度统计信息 */ @@ -1580,85 +1759,87 @@ public class ServiceApplicationsService { if (queryForm.getQuarter() == null) { return new ArrayList<>(); } - + ServiceLawyerQueryForm lawyerQuarterlyQueryForm = new ServiceLawyerQueryForm(); lawyerQuarterlyQueryForm.setFirmId(firmId); lawyerQuarterlyQueryForm.setYear(queryForm.getYear()); - + // 设置季度时间范围 LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), queryForm.getQuarter()); LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(queryForm.getYear(), queryForm.getQuarter()); lawyerQuarterlyQueryForm.setStartTime(quarterStart.toString()); lawyerQuarterlyQueryForm.setEndTime(quarterEnd.toString()); - + return serviceApplicationsDao.getLawyerStatisticsWithParam(lawyerQuarterlyQueryForm); } - + /** * 处理律师统计数据 */ - private void processLawyerStats(List lawyerAnnualStats, - List lawyerQuarterlyStats, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem) { + private void processLawyerStats(List lawyerAnnualStats, + List lawyerQuarterlyStats, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem) { Map lawyerQuarterlyMap = lawyerQuarterlyStats.stream() - .collect(Collectors.toMap(ServiceLawyerImportForm::getUserId, Function.identity())); - + .collect(Collectors.toMap(ServiceLawyerImportForm::getUserId, Function.identity())); + for (ServiceLawyerImportForm lawyerAnnual : lawyerAnnualStats) { // 计算律师年度成本 calculateLawyerAnnualCost(lawyerAnnual, dictItem, queryForm); - + // 设置律师季度数据 setLawyerQuarterlyData(lawyerAnnual, lawyerQuarterlyMap, queryForm, dictItem); } } - + /** * 计算律师年度成本 */ - private void calculateLawyerAnnualCost(ServiceLawyerImportForm lawyerAnnual, - DictEntity dictItem, - LawyerStatisticsQueryForm queryForm) { - BigDecimal lawyerAnnualCost = BigDecimal.valueOf(lawyerAnnual.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark())); + private void calculateLawyerAnnualCost(ServiceLawyerImportForm lawyerAnnual, + DictEntity dictItem, + LawyerStatisticsQueryForm queryForm) { + BigDecimal lawyerAnnualCost = BigDecimal + .valueOf(lawyerAnnual.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark())); lawyerAnnual.setAnnualServiceCost(lawyerAnnualCost); - + // 查询律师年度amount类型金额 LawyerStatisticsQueryForm lawyerAmountQueryForm = new LawyerStatisticsQueryForm(); lawyerAmountQueryForm.setUserId(lawyerAnnual.getUserId()); - + // 设置年度时间范围 String yearStart = queryForm.getYear() + "-01-01"; String yearEnd = queryForm.getYear() + "-12-31"; lawyerAmountQueryForm.setStartTime(yearStart); lawyerAmountQueryForm.setEndTime(yearEnd); - + BigDecimal lawyerAnnualAmount = serviceApplicationsDao.getServiceAmount(lawyerAmountQueryForm); if (lawyerAnnualAmount != null && lawyerAnnualAmount.compareTo(BigDecimal.ZERO) > 0) { lawyerAnnual.setAnnualServiceCost(lawyerAnnual.getAnnualServiceCost().add(lawyerAnnualAmount)); } } - + /** * 设置律师季度数据 */ - private void setLawyerQuarterlyData(ServiceLawyerImportForm lawyerAnnual, - Map lawyerQuarterlyMap, - LawyerStatisticsQueryForm queryForm, - DictEntity dictItem) { + private void setLawyerQuarterlyData(ServiceLawyerImportForm lawyerAnnual, + Map lawyerQuarterlyMap, + LawyerStatisticsQueryForm queryForm, + DictEntity dictItem) { ServiceLawyerImportForm lawyerQuarterly = lawyerQuarterlyMap.get(lawyerAnnual.getUserId()); - + if (lawyerQuarterly != null && queryForm.getQuarter() != null) { lawyerAnnual.setQuarterlyServiceDuration(lawyerQuarterly.getAnnualServiceDuration()); - - BigDecimal lawyerQuarterlyCost = BigDecimal.valueOf(lawyerQuarterly.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark())); + + BigDecimal lawyerQuarterlyCost = BigDecimal + .valueOf(lawyerQuarterly.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark())); lawyerAnnual.setQuarterlyServiceCost(lawyerQuarterlyCost); - + // 查询律师季度金额类型数据 LawyerStatisticsQueryForm quarterlyAmountQueryForm = new LawyerStatisticsQueryForm(); quarterlyAmountQueryForm.setUserId(lawyerAnnual.getUserId()); quarterlyAmountQueryForm.setStartTime(queryForm.getStartTime()); quarterlyAmountQueryForm.setEndTime(queryForm.getEndTime()); - + BigDecimal lawyerQuarterlyAmount = serviceApplicationsDao.getServiceAmount(quarterlyAmountQueryForm); if (lawyerQuarterlyAmount != null && lawyerQuarterlyAmount.compareTo(BigDecimal.ZERO) > 0) { lawyerAnnual.setQuarterlyServiceCost(lawyerAnnual.getQuarterlyServiceCost().add(lawyerQuarterlyAmount)); @@ -1671,10 +1852,11 @@ public class ServiceApplicationsService { /** * 律所查询条件封装 + * * @param queryForms * @return */ - public LawyerStatisticsQueryForm getQueryForm(LawyerStatisticsQueryFormList queryForms){ + public LawyerStatisticsQueryForm getQueryForm(LawyerStatisticsQueryFormList queryForms) { LawyerStatisticsQueryForm queryForm = new LawyerStatisticsQueryForm(); BeanUtil.copyProperties(queryForms, queryForm); // 如果没有指定季度,则使用年度范围,否则使用季度范围 @@ -1695,6 +1877,7 @@ public class ServiceApplicationsService { } return queryForm; } + public void exportLawyerByDepartment(ServiceLawyerQueryForm queryForm, HttpServletResponse response) { // 如果没有指定季度,则使用年度范围,否则使用季度范围 if (queryForm.getQuarter() == null) { @@ -1710,17 +1893,22 @@ public class ServiceApplicationsService { queryForm.setStartTime(quarterStart.toString()); queryForm.setEndTime(quarterEnd.toString()); } - List lawyerStatisticsWithParamYear = serviceApplicationsDao.getDepartmentStatisticsWithParam(queryForm); + List lawyerStatisticsWithParamYear = serviceApplicationsDao + .getDepartmentStatisticsWithParam(queryForm); if (!lawyerStatisticsWithParamYear.isEmpty()) { LawyerStatisticsQueryForm queryForm1 = SmartBeanUtil.copy(queryForm, LawyerStatisticsQueryForm.class); monthStatisticsDepartment(queryForm1, null, lawyerStatisticsWithParamYear); } - //屏蔽成本数据(导出专用) + // 屏蔽成本数据(导出专用) maskCostDataForLawyerExport(lawyerStatisticsWithParamYear); - //写入数据到文件 - exportExcel(response, "律所统计信息.xlsx", "律所统计信息", ServiceDepartmentImportForm.class, lawyerStatisticsWithParamYear); + // 写入数据到文件 + exportExcel(response, "律所统计信息.xlsx", "律所统计信息", ServiceDepartmentImportForm.class, + lawyerStatisticsWithParamYear); } - /** 导出专用的成本数据屏蔽方法(ServiceDepartmentImportForm) + + /** + * 导出专用的成本数据屏蔽方法(ServiceDepartmentImportForm) + * * @param statisticsList 统计数据列表 */ private void maskCostDataForLawyerExport(List statisticsList) { @@ -1746,6 +1934,7 @@ public class ServiceApplicationsService { /** * 清空律师统计数据的成本相关数据 + * * @param statisticsVO 律师统计对象 */ private void clearCostForLawyer(ServiceDepartmentImportForm statisticsVO) { @@ -1755,8 +1944,10 @@ public class ServiceApplicationsService { } } - /** 导出专用的成本数据屏蔽方法(针对ServiceLawyerImportForm) - * @param statisticsList 统计数据列表 + /** + * 导出专用的成本数据屏蔽方法(针对ServiceLawyerImportForm) + * + * @param statisticsList 统计数据列表 */ private void maskCostDataForExport(List statisticsList) { if (statisticsList == null || statisticsList.isEmpty()) { @@ -1781,6 +1972,7 @@ public class ServiceApplicationsService { /** * 清空律师统计数据的成本相关数据 + * * @param statisticsVO 律师统计对象 */ private void clearCostDataForLawyer(ServiceLawyerImportForm statisticsVO) { @@ -1790,7 +1982,6 @@ public class ServiceApplicationsService { } } - /** * 批量审核 * 前端统一传递 auditResult 字段(3=通过,4=拒绝) @@ -1803,37 +1994,39 @@ public class ServiceApplicationsService { if (roles.isEmpty()) { return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } - + String applicationIds = updateForm.getApplicationIds(); if (applicationIds == null || applicationIds.trim().isEmpty()) { return ResponseDTO.ok(); } - + // 统一从 auditResult 获取审核结果(前端传 auditResult,值为 3=通过 或 4=拒绝) Integer auditResult = updateForm.getAuditResult(); if (auditResult == null) { return ResponseDTO.userErrorParam("审核结果不能为空"); } - + String[] fileKeyArray = applicationIds.split(","); List fileKeyList = Arrays.asList(fileKeyArray); - + // 设置审核时间 String reviewTime = LocalDateTime.now().toString(); String auditOpinion = updateForm.getAuditRemark(); boolean isAssociationReview = AdminRequestUtil.isAssociationRole(roles); - + // ============================================================ // 律协批量审核(协会角色:CEO/律协) // ============================================================ if (isAssociationReview) { - serviceApplicationsDao.batchReviewAsAssociation(fileKeyList, auditResult, requestUser.getEmployeeId(), reviewTime, auditOpinion); + serviceApplicationsDao.batchReviewAsAssociation(fileKeyList, auditResult, requestUser.getEmployeeId(), + reviewTime, auditOpinion); } // ============================================================ // 律所批量审核(律所角色:主任/行政) // ============================================================ else if (AdminRequestUtil.isFirmRole(roles)) { - serviceApplicationsDao.batchReviewAsFirm(fileKeyList, auditResult, requestUser.getEmployeeId(), reviewTime, auditOpinion); + serviceApplicationsDao.batchReviewAsFirm(fileKeyList, auditResult, requestUser.getEmployeeId(), reviewTime, + auditOpinion); } // ============================================================ // 无权限 @@ -1841,7 +2034,7 @@ public class ServiceApplicationsService { else { return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } - + // 批量发送通知和更新成本 for (String applicationId : fileKeyList) { try { @@ -1852,19 +2045,21 @@ public class ServiceApplicationsService { updateActualCostInFirmReports(entity); } // 发送通知 - String opinion = isAssociationReview ? updateForm.getAssociationAuditOpinion() : updateForm.getFirmAuditOpinion(); + String opinion = isAssociationReview ? updateForm.getAssociationAuditOpinion() + : updateForm.getFirmAuditOpinion(); sendAuditNotification(entity, auditResult, opinion, isAssociationReview); } } catch (Exception e) { log.error("批量审核发送通知失败, applicationId={}: {}", applicationId, e.getMessage()); } } - + return ResponseDTO.ok(); } /** * 获取服务上报费用 + * * @param queryForm * @return */ @@ -1888,7 +2083,7 @@ public class ServiceApplicationsService { } List roles = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId()); boolean isAssociationOrAdmin = AdminRequestUtil.isAssociationRole(roles) - || UserTypeEnum.Admin.getDesc().equals(AdminRequestUtil.getRoleCode(roles)); + || UserTypeEnum.Admin.getDesc().equals(AdminRequestUtil.getRoleCode(roles)); if (!isAssociationOrAdmin) { queryForm.setFirmId(requestUser.getDepartmentId()); } @@ -1897,59 +2092,61 @@ public class ServiceApplicationsService { int year = queryForm.getYear(); Integer quarter = queryForm.getQuarter(); Integer month = queryForm.getMonth(); - + if (firmId == null || year == 0) { return BigDecimal.ZERO; } - + BigDecimal totalCost; - + // ============================================================ // 根据传入参数决定计算范围 // ============================================================ if (month != null && month > 0) { // 计算单月成本 totalCost = calculateMonthlyCost(firmId, year, month); - log.info("获取月度成本:firmId={}, year={}, month={}, 成本={}元", - firmId, year, month, totalCost); + log.info("获取月度成本:firmId={}, year={}, month={}, 成本={}元", + firmId, year, month, totalCost); } else if (quarter != null && quarter > 0) { - // 计算单季成本 - totalCost = calculateActualPublicWelfareCost(firmId, year, quarter); - log.info("获取季度成本:firmId={}, year={}, quarter={}, 成本={}元", - firmId, year, quarter, totalCost); + // 计算单季成本(预上报成本:只需要律所审核通过) + totalCost = calculatePreReportPublicWelfareCost(firmId, year, quarter); + log.info("获取季度预上报成本:firmId={}, year={}, quarter={}, 成本={}元", + firmId, year, quarter, totalCost); } else { - // 计算全年累计成本(四个季度之和) + // 计算全年累计成本(四个季度之和,律协审核通过) totalCost = BigDecimal.ZERO; for (int q = 1; q <= 4; q++) { BigDecimal quarterCost = calculateActualPublicWelfareCost(firmId, year, q); totalCost = totalCost.add(quarterCost); } - log.info("获取全年累计成本:firmId={}, year={}, 全年累计={}元", - firmId, year, totalCost); + log.info("获取全年累计实际成本:firmId={}, year={}, 全年累计={}元", + firmId, year, totalCost); } - + // 转换为万元 BigDecimal costInWan = totalCost.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); - + return costInWan; } - + /** * 计算单月的实际公益成本(元) + * * @param firmId 律所ID - * @param year 年份 - * @param month 月份(1-12) + * @param year 年份 + * @param month 月份(1-12) * @return 实际公益成本(元) */ private BigDecimal calculateMonthlyCost(Long firmId, int year, int month) { BigDecimal actualCost = BigDecimal.ZERO; - + // 查询该月份的服务申请 LocalDateTime monthStart = LocalDateTime.of(year, month, 1, 0, 0, 0); LocalDateTime monthEnd = monthStart.plusMonths(1).minusSeconds(1); - - List serviceApplications = serviceApplicationsDao.queryByFirmIdAndTimeRange(firmId, monthStart.toString(), monthEnd.toString()); - + + List serviceApplications = serviceApplicationsDao.queryByFirmIdAndTimeRange(firmId, + monthStart.toString(), monthEnd.toString()); + // 获取每小时成本配置 DictEntity dictItem = dictService.getOne("FILECOST"); if (dictItem != null) { @@ -1966,21 +2163,25 @@ public class ServiceApplicationsService { } catch (NumberFormatException e) { fixedHours = 0; } + } else { + fixedHours = application.getServiceDuration() != null ? application.getServiceDuration() : 0; } BigDecimal cost = BigDecimal.valueOf(fixedHours * Long.valueOf(dictItem.getRemark())); actualCost = actualCost.add(cost); } else if ("AMOUT".equals(serviceType)) { - BigDecimal amount = application.getServiceAmount() != null ? application.getServiceAmount() : BigDecimal.ZERO; + BigDecimal amount = application.getServiceAmount() != null ? application.getServiceAmount() + : BigDecimal.ZERO; actualCost = actualCost.add(amount); } else if ("DICT".equals(serviceType)) { - double duration = application.getServiceDuration() != null ? application.getServiceDuration() : 0; + double duration = application.getServiceDuration() != null ? application.getServiceDuration() + : 0; BigDecimal cost = BigDecimal.valueOf(duration * Long.valueOf(dictItem.getRemark())); actualCost = actualCost.add(cost); } } } } - + return actualCost; } @@ -1991,7 +2192,7 @@ public class ServiceApplicationsService { @Transactional public ResponseDTO batchReviewByDepartmentId(@Valid ServiceApplicationsUpdateForm updateForm) { RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); - + // 统一从 auditResult 获取审核结果 Integer auditResult = updateForm.getAuditResult(); if (auditResult == null) { @@ -2005,12 +2206,11 @@ public class ServiceApplicationsService { } List affectedApplications = serviceApplicationsDao.selectList( - new LambdaQueryWrapper() - .eq(ServiceApplicationsEntity::getFirmId, updateForm.getFirmId()) - .eq(ServiceApplicationsEntity::getAssociationAuditStatus, ReviewEnum.APPROVAL.getValue()) - .eq(ServiceApplicationsEntity::getDeletedFlag, 0) - ); - + new LambdaQueryWrapper() + .eq(ServiceApplicationsEntity::getFirmId, updateForm.getFirmId()) + .eq(ServiceApplicationsEntity::getAssociationAuditStatus, ReviewEnum.APPROVAL.getValue()) + .eq(ServiceApplicationsEntity::getDeletedFlag, 0)); + String auditOpinion = updateForm.getAuditRemark(); if (auditOpinion == null) { auditOpinion = updateForm.getAssociationAuditOpinion(); @@ -2038,10 +2238,10 @@ public class ServiceApplicationsService { } public Long queryNoReview() { - //查询上个月是否有未审核的数据,注意跨年情况 + // 查询上个月是否有未审核的数据,注意跨年情况 RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); Long departmentId = requestUser.getDepartmentId(); - + // 检查审批数据查看范围(1=只看有成本的律所,2=只看无成本的律所) Integer costReportViewOnly = requestUser.getCostReportViewOnly(); if (costReportViewOnly != null && costReportViewOnly == 1) { @@ -2050,7 +2250,7 @@ public class ServiceApplicationsService { if (costReportViewOnly != null && costReportViewOnly == 2) { return serviceApplicationsDao.queryNoReviewWithoutCostFilter(); } - + return serviceApplicationsDao.queryNoReview(departmentId); } @@ -2067,19 +2267,20 @@ public class ServiceApplicationsService { log.warn("驳回失败:用户无角色, employeeId={}", requestUser.getEmployeeId()); return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } - - ServiceApplicationsEntity serviceApplicationsEntity = serviceApplicationsDao.selectById(updateForm.getApplicationId()); + + ServiceApplicationsEntity serviceApplicationsEntity = serviceApplicationsDao + .selectById(updateForm.getApplicationId()); if (serviceApplicationsEntity == null) { return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); } - + // 权限验证:如果只能查看成本填报律所的数据,需要验证该数据是否属于有成本查看权限的律所 if (Boolean.TRUE.equals(requestUser.getCostReportViewOnly())) { if (!isFirmHasCostPermission(serviceApplicationsEntity.getFirmId())) { return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } } - + // ============================================================ // 律协驳回(协会角色:CEO/律协) // ============================================================ @@ -2093,7 +2294,7 @@ public class ServiceApplicationsService { log.warn("律协驳回失败:associationAuditStatus和auditResult都为空"); return ResponseDTO.userErrorParam("审核结果不能为空"); } - + // 设置协会审核状态 serviceApplicationsEntity.setAssociationAuditStatus(auditResult); serviceApplicationsEntity.setAssociationAuditUser(requestUser.getEmployeeId()); @@ -2122,7 +2323,7 @@ public class ServiceApplicationsService { log.warn("律所驳回失败:firmAuditStatus和auditResult都为空"); return ResponseDTO.userErrorParam("审核结果不能为空"); } - + // 设置律所审核状态 serviceApplicationsEntity.setFirmAuditStatus(auditResult); serviceApplicationsEntity.setFirmAuditUser(requestUser.getEmployeeId()); @@ -2141,38 +2342,41 @@ public class ServiceApplicationsService { log.warn("驳回失败:用户角色不是律协或律所, 角色={}", roles.get(0).getRoleCode()); return ResponseDTO.error(UserErrorCode.NO_PERMISSION); } - + return ResponseDTO.ok(); } /** * 发送驳回/拒绝通知 - * @param entity 服务申报实体 + * + * @param entity 服务申报实体 * @param isAssociationReject true=协会驳回,发给律所主任和行政;false=律所拒绝,发给服务创建人 */ private void sendNoReviewNotification(ServiceApplicationsEntity entity, boolean isAssociationReject) { try { String reviewerType = isAssociationReject ? "律协" : "律所"; String statusText = isAssociationReject ? "驳回" : "拒绝"; - + // 获取律师姓名 String lawyerName = "律师"; if (entity.getUserId() != null) { - net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity employee = employeeDao.selectById(entity.getUserId()); + net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity employee = employeeDao + .selectById(entity.getUserId()); if (employee != null) { lawyerName = employee.getActualName(); } } - + // 构建服务简介 - String serviceBrief = entity.getServiceContent() != null && entity.getServiceContent().length() > 20 - ? entity.getServiceContent().substring(0, 20) + "..." - : (entity.getServiceContent() != null ? entity.getServiceContent() : "服务申报"); - + String serviceBrief = entity.getServiceContent() != null && entity.getServiceContent().length() > 20 + ? entity.getServiceContent().substring(0, 20) + "..." + : (entity.getServiceContent() != null ? entity.getServiceContent() : "服务申报"); + String title = "服务申报被" + reviewerType + statusText; net.lab1024.sa.base.module.support.message.domain.MessageSendForm sendForm = new net.lab1024.sa.base.module.support.message.domain.MessageSendForm(); - sendForm.setMessageType(net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum.AUDIT.getValue()); + sendForm.setMessageType( + net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum.AUDIT.getValue()); sendForm.setReceiverUserType(net.lab1024.sa.base.common.enumeration.UserTypeEnum.ADMIN_EMPLOYEE.getValue()); sendForm.setTitle(title); sendForm.setDataId(entity.getApplicationId()); @@ -2190,7 +2394,8 @@ public class ServiceApplicationsService { if (isAssociationReject) { // 律协驳回:发给律所主任和行政(消息中包含律师姓名) - String adminContent = "律师" + lawyerName + "的服务申报「" + serviceBrief + "」已被" + reviewerType + statusText + "。" + opinions; + String adminContent = "律师" + lawyerName + "的服务申报「" + serviceBrief + "」已被" + reviewerType + statusText + + "。" + opinions; sendForm.setContent(adminContent); sendNotificationsToFirmAdmins(entity.getFirmId(), sendForm); } else { @@ -2205,18 +2410,18 @@ public class ServiceApplicationsService { } } - /** * Excel下拉列表处理器 */ public static class DropdownSheetWriteHandler implements SheetWriteHandler { - + private final List categoryNames; private final List goodsNames; private final List organizationNames; private final List employeeNames; - - public DropdownSheetWriteHandler(List categoryNames, List goodsNames, List organizationNames, List employeeNames) { + + public DropdownSheetWriteHandler(List categoryNames, List goodsNames, + List organizationNames, List employeeNames) { this.categoryNames = categoryNames; this.goodsNames = goodsNames; this.organizationNames = organizationNames; @@ -2227,9 +2432,9 @@ public class ServiceApplicationsService { public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { Sheet sheet = writeSheetHolder.getSheet(); Workbook workbook = writeWorkbookHolder.getWorkbook(); - + DataValidationHelper validationHelper = sheet.getDataValidationHelper(); - + // 为活动类别列创建下拉列表 (D列,索引为3) - 在ServiceApplicationsTemplateVO中是第4个字段 if (categoryNames != null && !categoryNames.isEmpty()) { try { @@ -2242,29 +2447,29 @@ public class ServiceApplicationsService { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 如果hiddenSheet仍然为null,创建一个新的 if (hiddenSheet == null) { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 在辅助Sheet中创建类别选项 Row categoryRow = hiddenSheet.createRow(0); for (int i = 0; i < Math.min(categoryNames.size(), 50); i++) { // 限制选项数量防止Excel限制 Cell cell = categoryRow.createCell(i); cell.setCellValue(categoryNames.get(i)); } - + // 创建名称定义 Name categoryListName = workbook.createName(); categoryListName.setNameName("CategoryList"); // 修正公式,确保正确引用范围 int lastColIndex = Math.min(categoryNames.size() - 1, 49); - char lastColChar = (char)('A' + lastColIndex); + char lastColChar = (char) ('A' + lastColIndex); String categoryFormula = "HiddenOptions!$A$1:$" + lastColChar + "$1"; categoryListName.setRefersToFormula(categoryFormula); - + // 创建数据验证 DataValidationConstraint constraint = validationHelper.createFormulaListConstraint("CategoryList"); CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, 3, 3); // D列是索引3 @@ -2276,7 +2481,7 @@ public class ServiceApplicationsService { log.error("创建活动类别下拉列表失败", e); } } - + // 为活动名称列创建下拉列表 (E列,索引为4) - 在ServiceApplicationsTemplateVO中是第5个字段 if (goodsNames != null && !goodsNames.isEmpty()) { try { @@ -2289,29 +2494,29 @@ public class ServiceApplicationsService { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 如果hiddenSheet仍然为null,创建一个新的 if (hiddenSheet == null) { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 在辅助Sheet中创建商品选项(使用第二行) Row goodsRow = hiddenSheet.createRow(1); for (int i = 0; i < Math.min(goodsNames.size(), 50); i++) { // 限制选项数量防止Excel限制 Cell cell = goodsRow.createCell(i); cell.setCellValue(goodsNames.get(i)); } - + // 创建名称定义 Name goodsListName = workbook.createName(); goodsListName.setNameName("GoodsList"); // 修正公式,确保正确引用范围 int lastColIndex = Math.min(goodsNames.size() - 1, 49); - char lastColChar = (char)('A' + lastColIndex); + char lastColChar = (char) ('A' + lastColIndex); String goodsFormula = "HiddenOptions!$A$2:$" + lastColChar + "$2"; goodsListName.setRefersToFormula(goodsFormula); - + // 创建数据验证 DataValidationConstraint constraint = validationHelper.createFormulaListConstraint("GoodsList"); CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, 4, 4); // E列是索引4 @@ -2323,7 +2528,7 @@ public class ServiceApplicationsService { log.error("创建活动名称下拉列表失败", e); } } - + // 为执业机构列创建下拉列表 (C列,索引为2) - 在ServiceApplicationsTemplateVO中是第3个字段 if (organizationNames != null && !organizationNames.isEmpty()) { try { @@ -2336,29 +2541,29 @@ public class ServiceApplicationsService { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 如果hiddenSheet仍然为null,创建一个新的 if (hiddenSheet == null) { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 在辅助Sheet中创建机构选项(使用第三行) Row orgRow = hiddenSheet.createRow(2); for (int i = 0; i < Math.min(organizationNames.size(), 50); i++) { // 限制选项数量防止Excel限制 Cell cell = orgRow.createCell(i); cell.setCellValue(organizationNames.get(i)); } - + // 创建名称定义 Name orgListName = workbook.createName(); orgListName.setNameName("OrgList"); // 修正公式,确保正确引用范围 int lastColIndex = Math.min(organizationNames.size() - 1, 49); - char lastColChar = (char)('A' + lastColIndex); + char lastColChar = (char) ('A' + lastColIndex); String orgFormula = "HiddenOptions!$A$3:$" + lastColChar + "$3"; orgListName.setRefersToFormula(orgFormula); - + // 创建数据验证 DataValidationConstraint constraint = validationHelper.createFormulaListConstraint("OrgList"); CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, 2, 2); // C列是索引2 @@ -2370,7 +2575,7 @@ public class ServiceApplicationsService { log.error("创建执业机构下拉列表失败", e); } } - + // 为姓名列创建下拉列表 (A列,索引为0) - 在ServiceApplicationsTemplateVO中是第1个字段 if (employeeNames != null && !employeeNames.isEmpty()) { try { @@ -2383,29 +2588,29 @@ public class ServiceApplicationsService { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 如果hiddenSheet仍然为null,创建一个新的 if (hiddenSheet == null) { hiddenSheet = workbook.createSheet("HiddenOptions"); workbook.setSheetHidden(workbook.getSheetIndex(hiddenSheet), true); // 隐藏辅助工作表 } - + // 在辅助Sheet中创建员工姓名选项(使用第四行) Row empRow = hiddenSheet.createRow(3); for (int i = 0; i < Math.min(employeeNames.size(), 50); i++) { // 限制选项数量防止Excel限制 Cell cell = empRow.createCell(i); cell.setCellValue(employeeNames.get(i)); } - + // 创建名称定义 Name empListName = workbook.createName(); empListName.setNameName("EmpList"); // 修正公式,确保正确引用范围 int lastColIndex = Math.min(employeeNames.size() - 1, 49); - char lastColChar = (char)('A' + lastColIndex); + char lastColChar = (char) ('A' + lastColIndex); String empFormula = "HiddenOptions!$A$4:$" + lastColChar + "$4"; empListName.setRefersToFormula(empFormula); - + // 创建数据验证 DataValidationConstraint constraint = validationHelper.createFormulaListConstraint("EmpList"); CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, 0, 0); // A列是索引0 @@ -2437,16 +2642,17 @@ public class ServiceApplicationsService { */ public List getLawyerStatistics(LawyerStatisticsQueryForm queryForm) { DictEntity fileCostDict = dictService.getOne("FILECOST"); - + // 应用权限控制 applyUserPermissionControl(queryForm); - + // 设置年度时间范围 setAnnualTimeRange(queryForm); - + // 统计当前年度的律师数据(无分页) - List lawyerStatisticsList = serviceApplicationsDao.getLawyerStatisticsWithParamYearNoPage(queryForm); - + List lawyerStatisticsList = serviceApplicationsDao + .getLawyerStatisticsWithParamYearNoPage(queryForm); + // 处理统计数据 if (!lawyerStatisticsList.isEmpty()) { // 处理有服务时长类型数据的律师统计 @@ -2455,19 +2661,78 @@ public class ServiceApplicationsService { // 处理只有金额类型数据的律师统计 processLawyersWithAmountOnly(lawyerStatisticsList, queryForm, fileCostDict); } - + // 根据用户权限控制成本数据显示 maskCostDataForUser(lawyerStatisticsList); + + // 根据参数对结果进行排序 + sortLawyerStatistics(lawyerStatisticsList, queryForm); + return lawyerStatisticsList; } - + + /** + * 根据参数对律师统计列表进行排序 + * @param list 律师统计列表 + * @param queryForm 查询参数(包含 sortField 和 sortOrder) + */ + private void sortLawyerStatistics(List list, LawyerStatisticsQueryForm queryForm) { + if (list == null || list.isEmpty()) { + return; + } + String sortField = queryForm.getSortField(); + String sortOrder = queryForm.getSortOrder(); + if (sortField == null || sortField.isEmpty() || sortOrder == null || sortOrder.isEmpty()) { + return; + } + // 校验排序字段合法性(防止SQL注入/拼错) + if (!isValidSortField(sortField)) { + return; + } + boolean isAsc = "asc".equalsIgnoreCase(sortOrder); + list.sort((a, b) -> { + Comparable va = getSortFieldValue(a, sortField); + Comparable vb = getSortFieldValue(b, sortField); + if (va == null && vb == null) return 0; + if (va == null) return 1; + if (vb == null) return -1; + int cmp = va.compareTo(vb); + return isAsc ? cmp : -cmp; + }); + } + + private boolean isValidSortField(String field) { + return "quarterlyServiceDuration".equals(field) + || "quarterlyServiceCost".equals(field) + || "annualServiceDuration".equals(field) + || "annualServiceCost".equals(field); + } + + @SuppressWarnings("unchecked") + private Comparable getSortFieldValue(LawyerStatisticsVO vo, String field) { + switch (field) { + case "quarterlyServiceDuration": + Double qsd = vo.getQuarterlyServiceDuration(); + return qsd == null ? 0.0 : qsd; + case "quarterlyServiceCost": + return vo.getQuarterlyServiceCost() == null ? java.math.BigDecimal.ZERO : vo.getQuarterlyServiceCost(); + case "annualServiceDuration": + Double asd = vo.getAnnualServiceDuration(); + return asd == null ? 0.0 : asd; + case "annualServiceCost": + return vo.getAnnualServiceCost() == null ? java.math.BigDecimal.ZERO : vo.getAnnualServiceCost(); + default: + return 0; + } + } + /** * 应用用户权限控制 */ private void applyUserPermissionControl(LawyerStatisticsQueryForm queryForm) { RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); List roleList = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId()); - if (AdminRequestUtil.isFirmRole(roleList)){ + if (AdminRequestUtil.isFirmRole(roleList)) { queryForm.setFirmId(requestUser.getDepartmentId()); } } @@ -2478,7 +2743,7 @@ public class ServiceApplicationsService { private void applyUserPermissionControl(LawyerStatisticsQueryFormPage queryForm) { RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); List roleList = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId()); - if (AdminRequestUtil.isFirmRole(roleList)){ + if (AdminRequestUtil.isFirmRole(roleList)) { queryForm.setFirmId(requestUser.getDepartmentId()); } } @@ -2527,17 +2792,17 @@ public class ServiceApplicationsService { queryForm.setEndTime(yearStartAndEnd.getEndTime()); } } - + /** * 处理有服务时长类型数据的律师统计 */ - private void processLawyersWithServiceDuration(List lawyerStatisticsList, - LawyerStatisticsQueryForm queryForm, - DictEntity fileCostDict) { + private void processLawyersWithServiceDuration(List lawyerStatisticsList, + LawyerStatisticsQueryForm queryForm, + DictEntity fileCostDict) { for (LawyerStatisticsVO statisticsVO : lawyerStatisticsList) { // 计算年度服务成本(服务时长 + 金额类型) calculateAnnualServiceCost(statisticsVO, queryForm, fileCostDict); - + // 只有在有季度查询条件时才计算季度服务成本 if (queryForm.getQuarter() != null) { calculateQuarterlyServiceCost(statisticsVO, queryForm, fileCostDict); @@ -2548,13 +2813,13 @@ public class ServiceApplicationsService { } } } - + /** * 计算年度服务成本 */ - private void calculateAnnualServiceCost(LawyerStatisticsVO statisticsVO, - LawyerStatisticsQueryForm queryForm, - DictEntity fileCostDict) { + private void calculateAnnualServiceCost(LawyerStatisticsVO statisticsVO, + LawyerStatisticsQueryForm queryForm, + DictEntity fileCostDict) { // 检查字典项是否为空 if (fileCostDict == null || fileCostDict.getRemark() == null) { log.warn("FILECOST字典项为空或remark字段为空,无法计算服务时长成本"); @@ -2562,11 +2827,10 @@ public class ServiceApplicationsService { } else { // 基于服务时长计算成本 BigDecimal serviceDurationCost = BigDecimal.valueOf( - statisticsVO.getAnnualServiceDuration() * Long.valueOf(fileCostDict.getRemark()) - ); + statisticsVO.getAnnualServiceDuration() * Long.valueOf(fileCostDict.getRemark())); statisticsVO.setAnnualServiceCost(serviceDurationCost); } - + // 统计金额类型数据 LawyerStatisticsQueryForm amountQueryForm = createAmountQueryForm(queryForm, statisticsVO.getUserId()); BigDecimal amount = serviceApplicationsDao.getServiceAmount(amountQueryForm); @@ -2574,26 +2838,25 @@ public class ServiceApplicationsService { statisticsVO.setAnnualServiceCost(statisticsVO.getAnnualServiceCost().add(amount)); } } - + /** * 计算季度服务成本 */ - private void calculateQuarterlyServiceCost(LawyerStatisticsVO statisticsVO, - LawyerStatisticsQueryForm queryForm, - DictEntity fileCostDict) { + private void calculateQuarterlyServiceCost(LawyerStatisticsVO statisticsVO, + LawyerStatisticsQueryForm queryForm, + DictEntity fileCostDict) { LawyerStatisticsQueryForm quarterQueryForm = createQuarterQueryForm(queryForm, statisticsVO.getUserId()); - + // 查询该律师的季度数据 LawyerStatisticsVO quarterData = serviceApplicationsDao.getLawyerStatistic(quarterQueryForm); if (quarterData != null && quarterData.getQuarterlyServiceDuration() != null) { statisticsVO.setQuarterlyServiceDuration(quarterData.getQuarterlyServiceDuration()); - + // 基于服务时长计算季度成本 BigDecimal quarterServiceDurationCost = BigDecimal.valueOf( - quarterData.getQuarterlyServiceDuration() * Long.valueOf(fileCostDict.getRemark()) - ); + quarterData.getQuarterlyServiceDuration() * Long.valueOf(fileCostDict.getRemark())); statisticsVO.setQuarterlyServiceCost(quarterServiceDurationCost); - + // 统计季度金额类型数据 BigDecimal quarterAmount = serviceApplicationsDao.getServiceAmount(quarterQueryForm); if (quarterAmount != null) { @@ -2605,37 +2868,37 @@ public class ServiceApplicationsService { statisticsVO.setQuarterlyServiceCost(BigDecimal.ZERO); } } - + /** * 处理只有金额类型数据的律师统计 */ - private void processLawyersWithAmountOnly(List resultList, - LawyerStatisticsQueryForm queryForm, - DictEntity fileCostDict) { + private void processLawyersWithAmountOnly(List resultList, + LawyerStatisticsQueryForm queryForm, + DictEntity fileCostDict) { // 查询只有金额类型数据的律师 List amountOnlyLawyers = findLawyersWithAmountOnly(queryForm); - + if (!amountOnlyLawyers.isEmpty()) { resultList.addAll(amountOnlyLawyers); } } - + /** * 查找只有金额类型数据的律师 */ private List findLawyersWithAmountOnly(LawyerStatisticsQueryForm queryForm) { // 查询按律师统计的年度金额数据 List amountOnlyLawyers = serviceApplicationsDao.getLawyerAmountStatistics(queryForm); - + if (!amountOnlyLawyers.isEmpty()) { log.info("发现 {} 个只有金额类型数据的律师", amountOnlyLawyers.size()); - + // 处理每个律师的季度金额数据 for (LawyerStatisticsVO lawyer : amountOnlyLawyers) { // 设置服务时长为0(只有金额类型数据) lawyer.setAnnualServiceDuration(0.0); lawyer.setQuarterlyServiceDuration(0.0); - + // 只有在有季度参数时才查询季度金额数据 if (queryForm.getQuarter() != null) { LawyerStatisticsQueryForm quarterQueryForm = createQuarterQueryForm(queryForm, lawyer.getUserId()); @@ -2650,10 +2913,10 @@ public class ServiceApplicationsService { } } } - + return amountOnlyLawyers; } - + /** * 创建金额查询表单 */ @@ -2667,7 +2930,7 @@ public class ServiceApplicationsService { amountQueryForm.setEndTime(originalForm.getEndTime()); return amountQueryForm; } - + /** * 创建季度查询表单 */ @@ -2676,37 +2939,40 @@ public class ServiceApplicationsService { quarterQueryForm.setYear(originalForm.getYear()); quarterQueryForm.setQuarter(originalForm.getQuarter()); quarterQueryForm.setUserId(userId); - + // 设置季度时间范围(只有在有季度参数时才设置具体季度范围) if (quarterQueryForm.getQuarter() != null) { - LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(quarterQueryForm.getYear(), quarterQueryForm.getQuarter()); - LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(quarterQueryForm.getYear(), quarterQueryForm.getQuarter()); + LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(quarterQueryForm.getYear(), + quarterQueryForm.getQuarter()); + LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(quarterQueryForm.getYear(), + quarterQueryForm.getQuarter()); quarterQueryForm.setStartTime(quarterStart.toString()); quarterQueryForm.setEndTime(quarterEnd.toString()); } - + return quarterQueryForm; } /** * 导出律师统计信息 + * * @param queryForm */ public void exportLawyer(ServiceLawyerQueryForm queryForm, HttpServletResponse response) { RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); List roleList = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId()); - + // 应用权限控制和查询条件 - if (AdminRequestUtil.isFirmRole(roleList)){ + if (AdminRequestUtil.isFirmRole(roleList)) { // 律所主任或行政只能查看自己的部门的数据 queryForm.setFirmId(requestUser.getDepartmentId()); } // 管理员可以看到所有数据,但仍应尊重用户指定的查询条件 DictEntity one = dictService.getOne("FILECOST"); - + // 保存原始的查询条件,用于年度数据查询 ServiceLawyerQueryForm annualQueryForm = SmartBeanUtil.copy(queryForm, ServiceLawyerQueryForm.class); - + // 如果没有指定季度,则使用年度范围,否则使用季度范围(仅用于季度数据查询) if (queryForm.getQuarter() == null) { TimeVo yearStartAndEnd = DateTimeUtil.getYearStartAndEnd(queryForm.getYear()); @@ -2729,12 +2995,14 @@ public class ServiceApplicationsService { annualQueryForm.setEndTime(yearStartAndEnd.getEndTime()); annualQueryForm.setQuarter(null); } - //律师年度数据查询使用完整的年度范围 - List lawyerStatisticsWithParamYear = serviceApplicationsDao.getLawyerStatisticsWithParam(annualQueryForm); + // 律师年度数据查询使用完整的年度范围 + List lawyerStatisticsWithParamYear = serviceApplicationsDao + .getLawyerStatisticsWithParam(annualQueryForm); if (!lawyerStatisticsWithParamYear.isEmpty()) { for (ServiceLawyerImportForm serviceLawyerImportForm : lawyerStatisticsWithParamYear) { - serviceLawyerImportForm.setAnnualServiceCost(BigDecimal.valueOf(serviceLawyerImportForm.getAnnualServiceDuration() * Long.valueOf(one.getRemark()))); - + serviceLawyerImportForm.setAnnualServiceCost(BigDecimal + .valueOf(serviceLawyerImportForm.getAnnualServiceDuration() * Long.valueOf(one.getRemark()))); + // 查询该律师的年度特殊金额 LawyerStatisticsQueryForm annualAmountQueryForm = new LawyerStatisticsQueryForm(); annualAmountQueryForm.setYear(queryForm.getYear()); @@ -2743,39 +3011,44 @@ public class ServiceApplicationsService { TimeVo yearStartAndEnd = DateTimeUtil.getYearStartAndEnd(queryForm.getYear()); annualAmountQueryForm.setStartTime(yearStartAndEnd.getStartTime()); annualAmountQueryForm.setEndTime(yearStartAndEnd.getEndTime()); - + // 添加年度特殊金额 BigDecimal annualAmount = serviceApplicationsDao.getServiceAmount(annualAmountQueryForm); if (annualAmount != null) { - serviceLawyerImportForm.setAnnualServiceCost(serviceLawyerImportForm.getAnnualServiceCost().add(annualAmount)); + serviceLawyerImportForm + .setAnnualServiceCost(serviceLawyerImportForm.getAnnualServiceCost().add(annualAmount)); } - + // 直接为每个律师查询季度数据 LawyerStatisticsQueryForm quarterQueryForm = new LawyerStatisticsQueryForm(); quarterQueryForm.setYear(queryForm.getYear()); quarterQueryForm.setQuarter(queryForm.getQuarter()); quarterQueryForm.setUserId(serviceLawyerImportForm.getUserId()); - + // 设置季度时间范围 if (quarterQueryForm.getQuarter() == null) { // 没有选择季度时,季度数据设为0 serviceLawyerImportForm.setQuarterlyServiceDuration(0.0); serviceLawyerImportForm.setQuarterlyServiceCost(BigDecimal.ZERO); } else { - LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(quarterQueryForm.getYear(), quarterQueryForm.getQuarter()); - LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(quarterQueryForm.getYear(), quarterQueryForm.getQuarter()); + LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(quarterQueryForm.getYear(), + quarterQueryForm.getQuarter()); + LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(quarterQueryForm.getYear(), + quarterQueryForm.getQuarter()); quarterQueryForm.setStartTime(quarterStart.toString()); quarterQueryForm.setEndTime(quarterEnd.toString()); - + // 查询该律师的季度数据 LawyerStatisticsVO quarterData = serviceApplicationsDao.getLawyerStatistic(quarterQueryForm); if (quarterData != null && quarterData.getQuarterlyServiceDuration() != null) { serviceLawyerImportForm.setQuarterlyServiceDuration(quarterData.getQuarterlyServiceDuration()); - serviceLawyerImportForm.setQuarterlyServiceCost(BigDecimal.valueOf(quarterData.getQuarterlyServiceDuration() * Long.valueOf(one.getRemark()))); + serviceLawyerImportForm.setQuarterlyServiceCost(BigDecimal + .valueOf(quarterData.getQuarterlyServiceDuration() * Long.valueOf(one.getRemark()))); // 统计季度特殊金额 BigDecimal quarterAmount = serviceApplicationsDao.getServiceAmount(quarterQueryForm); if (quarterAmount != null) { - serviceLawyerImportForm.setQuarterlyServiceCost(serviceLawyerImportForm.getQuarterlyServiceCost().add(quarterAmount)); + serviceLawyerImportForm.setQuarterlyServiceCost( + serviceLawyerImportForm.getQuarterlyServiceCost().add(quarterAmount)); } } else { // 如果没有季度数据,设置季度成本为0 @@ -2787,17 +3060,29 @@ public class ServiceApplicationsService { } maskCostDataForExport(lawyerStatisticsWithParamYear); - //写入数据到文件 + // 按年度累计服务成本降序排序 + lawyerStatisticsWithParamYear.sort((a, b) -> { + int costCompare = b.getAnnualServiceCost().compareTo(a.getAnnualServiceCost()); + if (costCompare != 0) return costCompare; + // 成本相同时按律师名称排序 + if (a.getLawyerName() != null && b.getLawyerName() != null) { + return a.getLawyerName().compareTo(b.getLawyerName()); + } + return 0; + }); + // 写入数据到文件 exportExcel(response, "律师统计信息.xlsx", "律师统计信息", ServiceLawyerImportForm.class, lawyerStatisticsWithParamYear); } - - public void monthStatisticsDepartment(LawyerStatisticsQueryForm originalQueryForm, List lawyerStatisticsVOPageResult,List lawyerStatisticsWithParamYear) { + public void monthStatisticsDepartment(LawyerStatisticsQueryForm originalQueryForm, + List lawyerStatisticsVOPageResult, + List lawyerStatisticsWithParamYear) { DictEntity dictItem = dictService.getOne("FILECOST"); if (lawyerStatisticsVOPageResult != null) { for (LawyerStatisticsVO statisticsVO : lawyerStatisticsVOPageResult) { // 创建新的查询表单对象以避免修改原始对象 - LawyerStatisticsQueryForm queryForm = SmartBeanUtil.copy(originalQueryForm, LawyerStatisticsQueryForm.class); + LawyerStatisticsQueryForm queryForm = SmartBeanUtil.copy(originalQueryForm, + LawyerStatisticsQueryForm.class); queryForm.setFirmId(statisticsVO.getFirmId()); if (queryForm.getQuarter() == null) { // 如果没有指定季度,使用上一季度的时间范围 @@ -2806,25 +3091,28 @@ public class ServiceApplicationsService { String quarterEnd = startQuarter.getEndTime(); queryForm.setStartTime(quarterStart + " 00:00:00"); queryForm.setEndTime(quarterEnd + " 23:59:59"); - } else{ - //根据季度获取季度的开始时间和结束时间 - LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), queryForm.getQuarter()); - //结束时间 + } else { + // 根据季度获取季度的开始时间和结束时间 + LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), + queryForm.getQuarter()); + // 结束时间 LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(queryForm.getYear(), queryForm.getQuarter()); queryForm.setStartTime(quarterStart.toString()); queryForm.setEndTime(quarterEnd.toString()); } queryForm.setUserId(statisticsVO.getUserId()); - //计算年度累计服务成本 - statisticsVO.setAnnualServiceCost(BigDecimal.valueOf(statisticsVO.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark()))); - //查询amount类型的金额,然后添加到服务成本中 + // 计算年度累计服务成本 + statisticsVO.setAnnualServiceCost(BigDecimal + .valueOf(statisticsVO.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark()))); + // 查询amount类型的金额,然后添加到服务成本中 BigDecimal amount = serviceApplicationsDao.getServiceAmount(queryForm); - //季度服务时间范围 + // 季度服务时间范围 LawyerStatisticsVO quarterStatisticsVO = serviceApplicationsDao.getdepartmentMothStatistic(queryForm); if (quarterStatisticsVO != null && quarterStatisticsVO.getQuarterlyServiceDuration() != null) { statisticsVO.setQuarterlyServiceDuration(quarterStatisticsVO.getQuarterlyServiceDuration()); - //计算季度累计服务成本 - statisticsVO.setQuarterlyServiceCost(BigDecimal.valueOf(quarterStatisticsVO.getQuarterlyServiceDuration() * Long.valueOf(dictItem.getRemark()))); + // 计算季度累计服务成本 + statisticsVO.setQuarterlyServiceCost(BigDecimal.valueOf( + quarterStatisticsVO.getQuarterlyServiceDuration() * Long.valueOf(dictItem.getRemark()))); } else { // 如果没有季度数据,设置季度成本为0而不是null statisticsVO.setQuarterlyServiceDuration(0.0); @@ -2837,7 +3125,7 @@ public class ServiceApplicationsService { } else { statisticsVO.setAnnualServiceCost(amount); } - }else { + } else { BigDecimal currentQuarterlyCost = statisticsVO.getQuarterlyServiceCost(); if (currentQuarterlyCost != null) { statisticsVO.setQuarterlyServiceCost(currentQuarterlyCost.add(amount)); @@ -2846,13 +3134,13 @@ public class ServiceApplicationsService { } } } - }else if (lawyerStatisticsWithParamYear != null) { + } else if (lawyerStatisticsWithParamYear != null) { for (ServiceDepartmentImportForm statisticsVO : lawyerStatisticsWithParamYear) { // 为每个律所单独构建季度查询条件 LawyerStatisticsQueryForm queryForm = new LawyerStatisticsQueryForm(); queryForm.setYear(originalQueryForm.getYear()); queryForm.setQuarter(originalQueryForm.getQuarter()); - + if (queryForm.getQuarter() == null) { // 如果没有指定季度,使用上一季度的时间范围 TimeVo startQuarter = DateTimeUtil.getStartQuarter(); @@ -2860,25 +3148,28 @@ public class ServiceApplicationsService { String quarterEnd = startQuarter.getEndTime(); queryForm.setStartTime(quarterStart + " 00:00:00"); queryForm.setEndTime(quarterEnd + " 23:59:59"); - } else{ - //根据季度获取季度的开始时间和结束时间 - LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), queryForm.getQuarter()); - //结束时间 + } else { + // 根据季度获取季度的开始时间和结束时间 + LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), + queryForm.getQuarter()); + // 结束时间 LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(queryForm.getYear(), queryForm.getQuarter()); queryForm.setStartTime(quarterStart.toString()); queryForm.setEndTime(quarterEnd.toString()); } queryForm.setFirmId(statisticsVO.getFirmId()); - - //计算年度累计服务成本 - statisticsVO.setAnnualServiceCost(BigDecimal.valueOf(statisticsVO.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark()))); + + // 计算年度累计服务成本 + statisticsVO.setAnnualServiceCost(BigDecimal + .valueOf(statisticsVO.getAnnualServiceDuration() * Long.valueOf(dictItem.getRemark()))); BigDecimal amount = serviceApplicationsDao.getServiceAmount(queryForm); - //季度服务时间范围 + // 季度服务时间范围 LawyerStatisticsVO quarterStatisticsVO = serviceApplicationsDao.getdepartmentMothStatistic(queryForm); if (quarterStatisticsVO != null && quarterStatisticsVO.getQuarterlyServiceDuration() != null) { statisticsVO.setQuarterlyServiceDuration(quarterStatisticsVO.getQuarterlyServiceDuration()); - //计算季度累计服务成本 - statisticsVO.setQuarterlyServiceCost(BigDecimal.valueOf(quarterStatisticsVO.getQuarterlyServiceDuration() * Long.valueOf(dictItem.getRemark()))); + // 计算季度累计服务成本 + statisticsVO.setQuarterlyServiceCost(BigDecimal.valueOf( + quarterStatisticsVO.getQuarterlyServiceDuration() * Long.valueOf(dictItem.getRemark()))); } else { // 如果没有季度数据,设置季度成本为0而不是null statisticsVO.setQuarterlyServiceDuration(0.0); @@ -2891,7 +3182,7 @@ public class ServiceApplicationsService { } else { statisticsVO.setAnnualServiceCost(amount); } - }else { + } else { BigDecimal currentQuarterlyCost = statisticsVO.getQuarterlyServiceCost(); if (currentQuarterlyCost != null) { statisticsVO.setQuarterlyServiceCost(currentQuarterlyCost.add(amount)); @@ -2906,7 +3197,7 @@ public class ServiceApplicationsService { LawyerStatisticsQueryForm queryForm = new LawyerStatisticsQueryForm(); queryForm.setYear(originalQueryForm.getYear()); queryForm.setQuarter(originalQueryForm.getQuarter()); - + if (queryForm.getQuarter() == null) { // 如果没有指定季度,使用上一季度的时间范围 TimeVo startQuarter = DateTimeUtil.getStartQuarter(); @@ -2914,15 +3205,15 @@ public class ServiceApplicationsService { String quarterEnd = startQuarter.getEndTime(); queryForm.setStartTime(quarterStart + " 00:00:00"); queryForm.setEndTime(quarterEnd + " 23:59:59"); - } else{ - //根据季度获取季度的开始时间和结束时间 + } else { + // 根据季度获取季度的开始时间和结束时间 LocalDateTime quarterStart = DateTimeEnum.getQuarterStart(queryForm.getYear(), queryForm.getQuarter()); - //结束时间 + // 结束时间 LocalDateTime quarterEnd = DateTimeEnum.getQuarterEnd(queryForm.getYear(), queryForm.getQuarter()); queryForm.setStartTime(quarterStart.toString()); queryForm.setEndTime(quarterEnd.toString()); } - + // 即使没有统计数据,也要查询可能存在的 amount 数据 BigDecimal amount = serviceApplicationsDao.getServiceAmount(queryForm); if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) { @@ -2933,16 +3224,17 @@ public class ServiceApplicationsService { } } - /** * 通用Excel导出功能 - * @param response HttpServletResponse - * @param fileName 文件名 + * + * @param response HttpServletResponse + * @param fileName 文件名 * @param sheetName 工作表名 - * @param clazz Excel实体类 - * @param data 数据列表 + * @param clazz Excel实体类 + * @param data 数据列表 */ - public void exportExcel(HttpServletResponse response, String fileName, String sheetName, Class clazz, List data) { + public void exportExcel(HttpServletResponse response, String fileName, String sheetName, Class clazz, + List data) { try { // 设置响应头 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); @@ -2964,20 +3256,21 @@ public class ServiceApplicationsService { /** * 服务上报统计 + * * @return */ - public PageResult getServiceReportStatistics(ServiceApplicationsQueryForm queryForm) { + public PageResult getServiceReportStatistics(ServiceApplicationsQueryForm queryForm) { Page page = SmartPageUtil.convert2PageQuery(queryForm); - + // 添加权限控制:检查审批数据查看范围(1=只看有成本的律所,2=只看无成本的律所) RequestEmployee requestUser = AdminRequestUtil.getRequestUser(); Integer costReportViewOnly = requestUser.getCostReportViewOnly(); if (costReportViewOnly != null && (costReportViewOnly == 1 || costReportViewOnly == 2)) { queryForm.setCostReportViewOnly(costReportViewOnly); } - + // 如果没有指定季度,则使用年度范围,否则使用季度范围 - if (queryForm.getQuarter() == null ) { + if (queryForm.getQuarter() == null) { // 如果用户指定了年份,则使用指定年份,否则使用当前年份 int targetYear = queryForm.getYear() != null ? queryForm.getYear() : DateTimeUtil.getCurrentYear(); String yearStart = targetYear + "-01-01"; @@ -3010,27 +3303,46 @@ public class ServiceApplicationsService { Page page = SmartPageUtil.convert2PageQuery(queryForm); List lawyerList = serviceApplicationsDao.getLawyerActivityCount(page, queryForm); - // 第二阶段:查询每个律师的活动统计 + // 第二阶段:批量查询所有律师的活动统计(避免N+1查询) if (lawyerList != null && !lawyerList.isEmpty()) { + // 收集所有律师的用户ID + List userIds = lawyerList.stream() + .map(LawyerActivityCountVO::getUserId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + // 一次性批量查询所有律师的活动统计 + Map> lawyerActivityMap = new HashMap<>(); + if (!userIds.isEmpty()) { + List allActivityStats = serviceApplicationsDao + .getLawyerActivityDetailBatch(userIds, queryForm); + if (allActivityStats != null) { + // 按 userId 分组 + for (LawyerActivityCountVO stat : allActivityStats) { + lawyerActivityMap + .computeIfAbsent(stat.getUserId(), k -> new ArrayList<>()) + .add(stat); + } + } + } + + // 组装每个律师的活动数据 for (LawyerActivityCountVO lawyer : lawyerList) { - // 查询该律师的所有活动统计 - List activityStats = - serviceApplicationsDao.getLawyerActivityDetail(lawyer.getUserId(), queryForm); - + List activityStats = lawyerActivityMap.getOrDefault(lawyer.getUserId(), Collections.emptyList()); + List activityList = new ArrayList<>(); int totalCount = 0; - + if (activityStats != null && !activityStats.isEmpty()) { for (LawyerActivityCountVO stat : activityStats) { - LawyerActivityCountVO.ActivityParticipationVO activityVO = - new LawyerActivityCountVO.ActivityParticipationVO(); + LawyerActivityCountVO.ActivityParticipationVO activityVO = new LawyerActivityCountVO.ActivityParticipationVO(); activityVO.setActivityId(stat.getActivityId()); activityVO.setCount(stat.getCount() != null ? stat.getCount() : 0); activityList.add(activityVO); totalCount += activityVO.getCount(); } } - + lawyer.setActivityList(activityList); lawyer.setTotalCount(totalCount); } @@ -3072,34 +3384,33 @@ public class ServiceApplicationsService { // 处理每个律所的统计 for (FirmActivityCountVO firm : firmList) { // 查询该律所下的所有律师 - List firmLawyers = - serviceApplicationsDao.getLawyersByFirmId(firm.getFirmId(), queryForm); - + List firmLawyers = serviceApplicationsDao.getLawyersByFirmId(firm.getFirmId(), + queryForm); + // 为每个律师查询活动统计 if (firmLawyers != null && !firmLawyers.isEmpty()) { for (LawyerActivityCountVO lawyer : firmLawyers) { // 查询该律师的所有活动统计 - List activityStats = - serviceApplicationsDao.getLawyerActivityDetail(lawyer.getUserId(), queryForm); - + List activityStats = serviceApplicationsDao + .getLawyerActivityDetail(lawyer.getUserId(), queryForm); + List activityList = new ArrayList<>(); int lawyerTotalCount = 0; - + if (activityStats != null && !activityStats.isEmpty()) { for (LawyerActivityCountVO stat : activityStats) { - LawyerActivityCountVO.ActivityParticipationVO activityVO = - new LawyerActivityCountVO.ActivityParticipationVO(); + LawyerActivityCountVO.ActivityParticipationVO activityVO = new LawyerActivityCountVO.ActivityParticipationVO(); activityVO.setActivityId(stat.getActivityId()); activityVO.setCount(stat.getCount() != null ? stat.getCount() : 0); activityList.add(activityVO); lawyerTotalCount += activityVO.getCount(); } } - + lawyer.setActivityList(activityList); lawyer.setTotalCount(lawyerTotalCount); } - + // 按律师的活动总次数降序排序 firmLawyers.sort((a, b) -> { int countA = a.getTotalCount() != null ? a.getTotalCount() : 0; @@ -3107,7 +3418,7 @@ public class ServiceApplicationsService { return Integer.compare(countB, countA); }); } - + firm.setLawyerList(firmLawyers); // 累加律师的参与次数到律所 @@ -3129,8 +3440,7 @@ public class ServiceApplicationsService { int totalCount = 0; List activityList = new ArrayList<>(); for (Map.Entry entry : firmActivityCount.entrySet()) { - FirmActivityCountVO.ActivityParticipationVO vo = - new FirmActivityCountVO.ActivityParticipationVO(); + FirmActivityCountVO.ActivityParticipationVO vo = new FirmActivityCountVO.ActivityParticipationVO(); vo.setActivityId(entry.getKey()); vo.setActivityName(getGoodsNameById(allGoods, entry.getKey())); vo.setCount(entry.getValue()); @@ -3199,7 +3509,7 @@ public class ServiceApplicationsService { // 查询所有活动及其分类信息 List allGoods = goodsService.getAllGoods(); Map goodsMap = allGoods.stream() - .collect(Collectors.toMap(GoodsEntity::getGoodsId, g -> g)); + .collect(Collectors.toMap(GoodsEntity::getGoodsId, g -> g)); // 获取活动分类信息 Map categoryMap = getActivityCategoryMap(allGoods); @@ -3225,8 +3535,7 @@ public class ServiceApplicationsService { // 添加活动 if (record.getActivityId() != null && record.getCount() != null) { - LawyerActivityCountVO.ActivityParticipationVO activity = - new LawyerActivityCountVO.ActivityParticipationVO(); + LawyerActivityCountVO.ActivityParticipationVO activity = new LawyerActivityCountVO.ActivityParticipationVO(); activity.setActivityId(record.getActivityId()); activity.setActivityName(record.getActivityName()); activity.setCount(record.getCount()); @@ -3289,11 +3598,10 @@ public class ServiceApplicationsService { // 按列元数据顺序填充数据 Map activityCountMap = lawyer.getActivityList().stream() - .collect(Collectors.toMap( - LawyerActivityCountVO.ActivityParticipationVO::getActivityId, - LawyerActivityCountVO.ActivityParticipationVO::getCount, - (v1, v2) -> v1 - )); + .collect(Collectors.toMap( + LawyerActivityCountVO.ActivityParticipationVO::getActivityId, + LawyerActivityCountVO.ActivityParticipationVO::getCount, + (v1, v2) -> v1)); // 预先按分类计算合计值 Map categorySubtotalMap = new LinkedHashMap<>(); @@ -3337,11 +3645,10 @@ public class ServiceApplicationsService { int activityTotal = 0; for (LawyerActivityCountVO lawyer : lawyerMap.values()) { Map activityCountMap = lawyer.getActivityList().stream() - .collect(Collectors.toMap( - LawyerActivityCountVO.ActivityParticipationVO::getActivityId, - LawyerActivityCountVO.ActivityParticipationVO::getCount, - (v1, v2) -> v1 - )); + .collect(Collectors.toMap( + LawyerActivityCountVO.ActivityParticipationVO::getActivityId, + LawyerActivityCountVO.ActivityParticipationVO::getCount, + (v1, v2) -> v1)); activityTotal += activityCountMap.getOrDefault(meta.activityId, 0); } categoryGrandTotalMap.merge(meta.categoryName, activityTotal, Integer::sum); @@ -3357,11 +3664,10 @@ public class ServiceApplicationsService { int activityTotal = 0; for (LawyerActivityCountVO lawyer : lawyerMap.values()) { Map activityCountMap = lawyer.getActivityList().stream() - .collect(Collectors.toMap( - LawyerActivityCountVO.ActivityParticipationVO::getActivityId, - LawyerActivityCountVO.ActivityParticipationVO::getCount, - (v1, v2) -> v1 - )); + .collect(Collectors.toMap( + LawyerActivityCountVO.ActivityParticipationVO::getActivityId, + LawyerActivityCountVO.ActivityParticipationVO::getCount, + (v1, v2) -> v1)); activityTotal += activityCountMap.getOrDefault(meta.activityId, 0); } totalRow.add(activityTotal); @@ -3376,18 +3682,17 @@ public class ServiceApplicationsService { // 创建样式策略 HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy( - getHeadStyle(), - getContentStyle() - ); + getHeadStyle(), + getContentStyle()); // 创建写入Sheet并注册合并处理器 WriteSheet writeSheet = EasyExcel.writerSheet("律师公益活动统计") - .head(head) - .registerWriteHandler(styleStrategy) - .registerWriteHandler(new SimpleColumnWidthStyleStrategy(12)) - .registerWriteHandler(new SubtotalMergeHandler(columnMetaList, 3)) - .registerWriteHandler(new CustomRowHeightHandler((short) 500)) - .build(); + .head(head) + .registerWriteHandler(styleStrategy) + .registerWriteHandler(new SimpleColumnWidthStyleStrategy(12)) + .registerWriteHandler(new SubtotalMergeHandler(columnMetaList, 3)) + .registerWriteHandler(new CustomRowHeightHandler((short) 500)) + .build(); excelWriter.write(data, writeSheet); excelWriter.finish(); log.info("Excel写入完成,准备输出到响应流"); @@ -3433,7 +3738,7 @@ public class ServiceApplicationsService { public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { Sheet sheet = writeSheetHolder.getSheet(); Workbook workbook = writeWorkbookHolder.getWorkbook(); - + // 创建边框样式 CellStyle borderStyle = workbook.createCellStyle(); borderStyle.setBorderTop(BorderStyle.THIN); @@ -3476,7 +3781,8 @@ public class ServiceApplicationsService { if (currentCategory == null || !meta.categoryName.equals(currentCategory)) { if (currentCategory != null && categoryStartCol >= 0 && activityCount > 1) { - CellRangeAddress region = new CellRangeAddress(0, 0, categoryStartCol, categoryStartCol + activityCount - 1); + CellRangeAddress region = new CellRangeAddress(0, 0, categoryStartCol, + categoryStartCol + activityCount - 1); sheet.addMergedRegionUnsafe(region); setRegionBorder(sheet, region, borderStyle); } @@ -3489,7 +3795,8 @@ public class ServiceApplicationsService { } if (currentCategory != null && categoryStartCol >= 0 && activityCount > 1) { - CellRangeAddress region = new CellRangeAddress(0, 0, categoryStartCol, categoryStartCol + activityCount - 1); + CellRangeAddress region = new CellRangeAddress(0, 0, categoryStartCol, + categoryStartCol + activityCount - 1); sheet.addMergedRegionUnsafe(region); setRegionBorder(sheet, region, borderStyle); } @@ -3500,7 +3807,7 @@ public class ServiceApplicationsService { sheet.addMergedRegionUnsafe(region); setRegionBorder(sheet, region, borderStyle); } - + /** * 为合并区域设置边框 */ @@ -3520,7 +3827,7 @@ public class ServiceApplicationsService { } } } - + /** * 获取表头样式 - 字体不换行 */ @@ -3534,7 +3841,7 @@ public class ServiceApplicationsService { headStyle.setWriteFont(headFont); return headStyle; } - + /** * 获取内容样式 - 字体不换行,居中对齐 */ @@ -3548,17 +3855,17 @@ public class ServiceApplicationsService { contentStyle.setWriteFont(contentFont); return contentStyle; } - + /** * 自定义行高处理器 - 确保所有行高度一致 */ private static class CustomRowHeightHandler implements SheetWriteHandler { private final short rowHeight; - + CustomRowHeightHandler(short rowHeight) { this.rowHeight = rowHeight; } - + @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { Sheet sheet = writeSheetHolder.getSheet(); @@ -3566,7 +3873,7 @@ public class ServiceApplicationsService { sheet.setDefaultRowHeightInPoints(rowHeight / 20f); } } - + /** * 获取活动分类映射 */ @@ -3574,20 +3881,21 @@ public class ServiceApplicationsService { Map categoryMap = new HashMap<>(); // 获取所有分类ID Set categoryIds = goodsList.stream() - .map(GoodsEntity::getCategoryId) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - + .map(GoodsEntity::getCategoryId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + // 查询所有分类 List categories = categoryService.getAllCategory(); Map categoryNameMap = categories.stream() - .collect(Collectors.toMap(CategoryEntity::getCategoryId, CategoryEntity::getCategoryName, (v1, v2) -> v1)); - + .collect(Collectors.toMap(CategoryEntity::getCategoryId, CategoryEntity::getCategoryName, + (v1, v2) -> v1)); + // 构建分类映射 for (Long categoryId : categoryIds) { categoryMap.put(categoryId, categoryNameMap.getOrDefault(categoryId, "未分类")); } - + return categoryMap; } @@ -3620,8 +3928,7 @@ public class ServiceApplicationsService { // 添加活动 if (record.getActivityId() != null && record.getCount() != null) { - FirmActivityCountVO.ActivityParticipationVO activity = - new FirmActivityCountVO.ActivityParticipationVO(); + FirmActivityCountVO.ActivityParticipationVO activity = new FirmActivityCountVO.ActivityParticipationVO(); activity.setActivityId(record.getActivityId()); activity.setActivityName(record.getActivityName()); activity.setCount(record.getCount()); @@ -3633,7 +3940,7 @@ public class ServiceApplicationsService { // 查询所有活动及其分类信息 List allGoods = goodsService.getAllGoods(); Map goodsMap = allGoods.stream() - .collect(Collectors.toMap(GoodsEntity::getGoodsId, g -> g)); + .collect(Collectors.toMap(GoodsEntity::getGoodsId, g -> g)); // 获取活动分类信息 Map categoryMap = getActivityCategoryMap(allGoods); @@ -3689,11 +3996,10 @@ public class ServiceApplicationsService { // 按列元数据顺序填充数据 Map activityCountMap = firm.getActivityList().stream() - .collect(Collectors.toMap( - FirmActivityCountVO.ActivityParticipationVO::getActivityId, - FirmActivityCountVO.ActivityParticipationVO::getCount, - (v1, v2) -> v1 - )); + .collect(Collectors.toMap( + FirmActivityCountVO.ActivityParticipationVO::getActivityId, + FirmActivityCountVO.ActivityParticipationVO::getCount, + (v1, v2) -> v1)); // 预先按分类计算合计值 Map categorySubtotalMap = new LinkedHashMap<>(); @@ -3735,11 +4041,10 @@ public class ServiceApplicationsService { int activityTotal = 0; for (FirmActivityCountVO firm : firmMap.values()) { Map activityCountMap = firm.getActivityList().stream() - .collect(Collectors.toMap( - FirmActivityCountVO.ActivityParticipationVO::getActivityId, - FirmActivityCountVO.ActivityParticipationVO::getCount, - (v1, v2) -> v1 - )); + .collect(Collectors.toMap( + FirmActivityCountVO.ActivityParticipationVO::getActivityId, + FirmActivityCountVO.ActivityParticipationVO::getCount, + (v1, v2) -> v1)); activityTotal += activityCountMap.getOrDefault(meta.activityId, 0); } categoryGrandTotalMap.merge(meta.categoryName, activityTotal, Integer::sum); @@ -3755,11 +4060,10 @@ public class ServiceApplicationsService { int activityTotal = 0; for (FirmActivityCountVO firm : firmMap.values()) { Map activityCountMap = firm.getActivityList().stream() - .collect(Collectors.toMap( - FirmActivityCountVO.ActivityParticipationVO::getActivityId, - FirmActivityCountVO.ActivityParticipationVO::getCount, - (v1, v2) -> v1 - )); + .collect(Collectors.toMap( + FirmActivityCountVO.ActivityParticipationVO::getActivityId, + FirmActivityCountVO.ActivityParticipationVO::getCount, + (v1, v2) -> v1)); activityTotal += activityCountMap.getOrDefault(meta.activityId, 0); } totalRow.add(activityTotal); @@ -3771,18 +4075,17 @@ public class ServiceApplicationsService { // 创建样式策略 HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy( - getHeadStyle(), - getContentStyle() - ); + getHeadStyle(), + getContentStyle()); // 创建写入Sheet WriteSheet writeSheet = EasyExcel.writerSheet("律所公益活动统计") - .head(head) - .registerWriteHandler(styleStrategy) - .registerWriteHandler(new SimpleColumnWidthStyleStrategy(12)) - .registerWriteHandler(new SubtotalMergeHandler(columnMetaList, 3)) - .registerWriteHandler(new CustomRowHeightHandler((short) 500)) - .build(); + .head(head) + .registerWriteHandler(styleStrategy) + .registerWriteHandler(new SimpleColumnWidthStyleStrategy(12)) + .registerWriteHandler(new SubtotalMergeHandler(columnMetaList, 3)) + .registerWriteHandler(new CustomRowHeightHandler((short) 500)) + .build(); excelWriter.write(data, writeSheet); } catch (IOException e) { log.error("导出律所活动统计失败", e); @@ -3798,10 +4101,10 @@ public class ServiceApplicationsService { return "未知活动"; } return goodsList.stream() - .filter(g -> g != null && goodsId.equals(g.getGoodsId())) - .map(GoodsEntity::getGoodsName) - .findFirst() - .orElse("未知活动"); + .filter(g -> g != null && goodsId.equals(g.getGoodsId())) + .map(GoodsEntity::getGoodsName) + .findFirst() + .orElse("未知活动"); } /** @@ -3822,7 +4125,7 @@ public class ServiceApplicationsService { queryForm.setFirmId(requestUser.getDepartmentId()); } // CEO可以看所有,不需要设置过滤条件 - + // 设置查询条件(如果前端没有传,则不设置) if (queryForm.getServiceStart() != null) { queryForm.setServiceStart(queryForm.getServiceStart()); @@ -3912,4 +4215,28 @@ public class ServiceApplicationsService { } return serviceApplicationsDao.countFirmWithCostPermission(firmId) > 0; } + + /** + * 生成唯一备案编号 (格式:GY + 年份 + 6位流水号) + */ + private synchronized String generateFilingNo() { + int currentYear = java.time.LocalDate.now().getYear(); + String prefix = "GY" + currentYear; + + // 查出该前缀下当前数据库中最大的备案编号 + String maxFilingNo = serviceApplicationsDao.getMaxFilingNo(prefix); + if (maxFilingNo == null) { + return prefix + "000001"; + } + + try { + // 截取后6位序列号 + String seqStr = maxFilingNo.substring(maxFilingNo.length() - 6); + int nextSeq = Integer.parseInt(seqStr) + 1; + return prefix + String.format("%06d", nextSeq); + } catch (Exception e) { + log.error("生成备案编号解析最大备案编号失败, maxFilingNo={}", maxFilingNo, e); + return prefix + String.format("%06d", (int) (Math.random() * 900000) + 100000); + } + } } diff --git a/yun-admin/src/main/java/net/lab1024/sa/admin/util/DateTimeUtil.java b/yun-admin/src/main/java/net/lab1024/sa/admin/util/DateTimeUtil.java index 03e81dc..a90aff8 100644 --- a/yun-admin/src/main/java/net/lab1024/sa/admin/util/DateTimeUtil.java +++ b/yun-admin/src/main/java/net/lab1024/sa/admin/util/DateTimeUtil.java @@ -27,29 +27,8 @@ public class DateTimeUtil { */ public static String getCurrentQuarter() { LocalDate today = LocalDate.now(); - Month month = today.getMonth(); - int dayOfMonth = today.getDayOfMonth(); - - // 判断当前时间是不是小于4月5号,是则为第一季度 - if (month.getValue() < 4 || (month.getValue() == 4 && dayOfMonth < 5)) { - return "Q1"; - } - // 判断当前时间是不是大于4月5号小于7月5号,是则为第二季度 - else if ((month.getValue() == 4 && dayOfMonth >= 5) || - (month.getValue() > 4 && month.getValue() < 7) || - (month.getValue() == 7 && dayOfMonth < 5)) { - return "Q2"; - } - // 判断当前时间是不是大于7月5号小于10月5号,是则为第三季度 - else if ((month.getValue() == 7 && dayOfMonth >= 5) || - (month.getValue() > 7 && month.getValue() < 10) || - (month.getValue() == 10 && dayOfMonth < 5)) { - return "Q3"; - } - // 判断当前时间是不是大于10月5号小于第二年的1月5号,是则为第四季度 - else { - return "Q4"; - } + int quarter = (today.getMonthValue() - 1) / 3 + 1; + return "Q" + quarter; } /** diff --git a/yun-admin/src/main/resources/dev/application.yaml b/yun-admin/src/main/resources/dev/application.yaml index 2ed69b9..c038772 100644 --- a/yun-admin/src/main/resources/dev/application.yaml +++ b/yun-admin/src/main/resources/dev/application.yaml @@ -16,6 +16,11 @@ server: servlet: context-path: / +# 文件上传大小限制(50MB) +spring.servlet.multipart: + max-file-size: 50MB + max-request-size: 50MB + # 环境 spring: profiles: diff --git a/yun-admin/src/main/resources/mapper/service/ServiceApplicationsMapper.xml b/yun-admin/src/main/resources/mapper/service/ServiceApplicationsMapper.xml index a9cb5ec..ec495bb 100644 --- a/yun-admin/src/main/resources/mapper/service/ServiceApplicationsMapper.xml +++ b/yun-admin/src/main/resources/mapper/service/ServiceApplicationsMapper.xml @@ -25,6 +25,7 @@ t_service_applications.association_audit_user, t_service_applications.association_audit_time, t_service_applications.record_no, + t_service_applications.filing_no, t_service_applications.record_status, t_service_applications.record_time, t_service_applications.update_time, @@ -122,6 +123,9 @@ and position_id = #{queryForm.positionId} + + and filing_no like CONCAT('%', #{queryForm.filingNo}, '%') + AND ( @@ -305,117 +309,146 @@ LEFT JOIN t_department d ON tsa.firm_id = d.department_id WHERE tsa.deleted_flag = 0 AND tsa.association_audit_status = 3 - GROUP BY tsa.user_id, tsa.certificate_number, e.actual_name - ORDER BY e.actual_name + GROUP BY tsa.user_id, tsa.certificate_number + ORDER BY annualServiceDuration DESC, tsa.user_id ASC, e.actual_name + ORDER BY annualServiceDuration DESC, userId ASC + - SELECT DISTINCT - tsa.user_id AS userId, - e.actual_name AS lawyerName, - d.department_id AS firmId, - d.department_name AS firmName, - tsa.certificate_number AS certificateNumber, - COALESCE(stats.totalCount, 0) AS totalCount - FROM t_service_applications tsa - LEFT JOIN t_employee e ON tsa.user_id = e.employee_id - LEFT JOIN t_department d ON tsa.firm_id = d.department_id - LEFT JOIN ( - SELECT - user_id, + SELECT + stats.user_id AS userId, + stats.lawyerName AS lawyerName, + stats.firmId AS firmId, + stats.firmName AS firmName, + stats.certificateNumber AS certificateNumber, + stats.totalCount AS totalCount + FROM ( + SELECT + tsa.user_id AS user_id, + MAX(e.actual_name) AS lawyerName, + MAX(tsa.firm_id) AS firmId, + MAX(d.department_name) AS firmName, + MAX(tsa.certificate_number) AS certificateNumber, COUNT(*) AS totalCount - FROM t_service_applications - WHERE deleted_flag = 0 - AND association_audit_status = 3 - - AND report_time >= #{queryForm.startTime} - - - AND report_time <= #{queryForm.endTime} - - GROUP BY user_id - ) stats ON tsa.user_id = stats.user_id - WHERE tsa.deleted_flag = 0 - AND tsa.association_audit_status = 3 - - AND tsa.firm_id = #{queryForm.firmId} - - ORDER BY totalCount DESC, tsa.user_id + FROM t_service_applications tsa + LEFT JOIN t_employee e ON tsa.user_id = e.employee_id + LEFT JOIN t_department d ON tsa.firm_id = d.department_id + + tsa.deleted_flag = 0 + AND tsa.association_audit_status = 3 + + AND tsa.report_time >= #{queryForm.startTime} + + + AND tsa.report_time <= #{queryForm.endTime} + + + AND tsa.firm_id = #{queryForm.firmId} + + + GROUP BY tsa.user_id + ) stats + ORDER BY totalCount DESC, stats.user_id @@ -992,6 +1036,33 @@ ORDER BY g.goods_id + + + + + + diff --git a/yun-admin/src/main/resources/pre/application.yaml b/yun-admin/src/main/resources/pre/application.yaml index 62588c0..cbcdefe 100644 --- a/yun-admin/src/main/resources/pre/application.yaml +++ b/yun-admin/src/main/resources/pre/application.yaml @@ -16,6 +16,11 @@ server: servlet: context-path: / +# 文件上传大小限制(50MB) +spring.servlet.multipart: + max-file-size: 50MB + max-request-size: 50MB + # 环境 spring: profiles: diff --git a/yun-admin/src/main/resources/prod/application.yaml b/yun-admin/src/main/resources/prod/application.yaml index 423b847..197eb58 100644 --- a/yun-admin/src/main/resources/prod/application.yaml +++ b/yun-admin/src/main/resources/prod/application.yaml @@ -16,6 +16,11 @@ server: servlet: context-path: / +# 文件上传大小限制(50MB) +spring.servlet.multipart: + max-file-size: 50MB + max-request-size: 50MB + # 环境 spring: profiles: diff --git a/yun-admin/src/main/resources/test/application.yaml b/yun-admin/src/main/resources/test/application.yaml index 9591fdd..0a84187 100644 --- a/yun-admin/src/main/resources/test/application.yaml +++ b/yun-admin/src/main/resources/test/application.yaml @@ -16,6 +16,11 @@ server: servlet: context-path: / +# 文件上传大小限制(50MB) +spring.servlet.multipart: + max-file-size: 50MB + max-request-size: 50MB + # 环境 spring: profiles: diff --git a/yun-base/src/main/resources/dev/yun-base.yaml b/yun-base/src/main/resources/dev/yun-base.yaml index 07b0ccd..600fe65 100644 --- a/yun-base/src/main/resources/dev/yun-base.yaml +++ b/yun-base/src/main/resources/dev/yun-base.yaml @@ -1,10 +1,10 @@ spring: # 数据库连接信息 datasource: - url: jdbc:mysql://127.0.0.1:3306/lawyer_welfare?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai + url: jdbc:p6spy:mysql://8.148.67.92:3306/lawyer_welfare?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai username: root - password: root123456 - driver-class-name: com.mysql.cj.jdbc.Driver + password: sdy@2025# + driver-class-name: com.p6spy.engine.spy.P6SpyDriver initial-size: 2 min-idle: 2 max-active: 10 @@ -67,8 +67,8 @@ spring: # 上传文件和请求大小 servlet: multipart: - max-file-size: 20MB # 单个文件的最大大小 - max-request-size: 10MB # 整个请求的最大大小 + max-file-size: 50MB # 单个文件的最大大小 + max-request-size: 50MB # 整个请求的最大大小 # 缓存实现类型 cache: diff --git a/yun-base/src/main/resources/pre/yun-base.yaml b/yun-base/src/main/resources/pre/yun-base.yaml index 98731e0..fed4bab 100644 --- a/yun-base/src/main/resources/pre/yun-base.yaml +++ b/yun-base/src/main/resources/pre/yun-base.yaml @@ -67,8 +67,8 @@ spring: # 上传文件和请求大小 servlet: multipart: - max-file-size: 20MB # 单个文件的最大大小 - max-request-size: 10MB # 整个请求的最大大小 + max-file-size: 50MB # 单个文件的最大大小 + max-request-size: 50MB # 整个请求的最大大小 # 缓存实现类型 cache: diff --git a/yun-base/src/main/resources/prod/yun-base.yaml b/yun-base/src/main/resources/prod/yun-base.yaml index 506a175..82f3173 100644 --- a/yun-base/src/main/resources/prod/yun-base.yaml +++ b/yun-base/src/main/resources/prod/yun-base.yaml @@ -66,8 +66,8 @@ spring: # 上传文件和请求大小 servlet: multipart: - max-file-size: 20MB # 单个文件的最大大小 - max-request-size: 10MB # 整个请求的最大大小 + max-file-size: 50MB # 单个文件的最大大小 + max-request-size: 50MB # 整个请求的最大大小 # 缓存实现类型 cache: diff --git a/yun-base/src/main/resources/test/yun-base.yaml b/yun-base/src/main/resources/test/yun-base.yaml index 98731e0..fed4bab 100644 --- a/yun-base/src/main/resources/test/yun-base.yaml +++ b/yun-base/src/main/resources/test/yun-base.yaml @@ -67,8 +67,8 @@ spring: # 上传文件和请求大小 servlet: multipart: - max-file-size: 20MB # 单个文件的最大大小 - max-request-size: 10MB # 整个请求的最大大小 + max-file-size: 50MB # 单个文件的最大大小 + max-request-size: 50MB # 整个请求的最大大小 # 缓存实现类型 cache: