提案整改

This commit is contained in:
2026-04-24 15:26:30 +08:00
parent 3207e0a594
commit 79f9cf9123
65 changed files with 2561 additions and 419 deletions
@@ -129,7 +129,8 @@ public class AidFundApplyController {
}
//如果有两个工号并且有一个工号已经是会员就不让他申请了
if (userList.size() >= 2) {
int size = userList.stream().filter(Sys_user::getAidFundMember).toList().size();
// 历史用户数据中 aidFundMember 可能为空,这里只统计明确为基金会员的工号,避免空值自动拆箱报错
int size = userList.stream().filter(sysUser -> Boolean.TRUE.equals(sysUser.getAidFundMember())).toList().size();
if (size > 0) {
return Result.success(Map.of("disabled", true, "label", "请用新工号登陆办理申请业务!"));
}
@@ -149,7 +150,7 @@ public class AidFundApplyController {
aidFundMemberChangeRecord.setUserId(SecurityUtil.getUserId());
Sys_user user = dao.fetch(Sys_user.class, SecurityUtil.getUserId());
if (StrUtil.isBlank(aidFundMemberChangeRecord.getId())) aidFundMemberChangeRecord.setApplyTime(new Date());
if (user.getAidFundMember() == AidFundMemberMode.NORMAL.getCode()) {
if (Boolean.TRUE.equals(user.getAidFundMember())) {
aidFundMemberChangeRecord.setChangeType("AIDFUND_MEMBER_CHANGE_TYPE_FOUR");
} else {
aidFundMemberChangeRecord.setChangeType("AIDFUND_MEMBER_CHANGE_TYPE_ONE");
@@ -159,7 +160,8 @@ public class AidFundApplyController {
Dict args = Dict.create();
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
args.set(FlowConst.FORM_DATA, aidFundMemberChangeRecord);
args.set("aidFundMemberUserType", user.getAidFundMemberUserType());
// 流程变量中的基金会员类型以本次申请提交值为准,避免继续使用用户表中的旧值。
args.set("aidFundMemberUserType", aidFundMemberChangeRecord.getAidFundMemberUserType());
ProcessInstance instance = flowEngine.startProcessInstanceByKey("JJHY", aidFundMemberChangeRecord.getId(), SecurityUtil.getUserId(), args);
// 自动完成第一个申请任务
@@ -194,7 +196,7 @@ public class AidFundApplyController {
us.username,
us.loginname,
us.mobile,
us.aidFundMemberUserType,
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
us.arrivalAtSchoolDate,
us.sex,
us.unitName,
@@ -76,14 +76,17 @@ public class AidFundApplyMineController {
@Param(value = "year") Integer year) {
Sql sql = Sqls.create("""
SELECT
info.*,
info.id,
info.userId,
info.changeType,
info.applyTime,
us.arrivalAtSchoolDate,
us.mobile,
us.loginname loginName,
us.username userName,
us.unitName,
us.unionName,
us.aidFundMemberUserType,
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
us.sex,
ins.id AS instanceId,
ins.businessNo,
@@ -113,6 +116,8 @@ public class AidFundApplyMineController {
cnd.andEX("year(info.applyTime)", "=", year);
cnd.and("info.userId", "=", SecurityUtil.getUserId());
// 管理端代操作产生的记录不属于“我的申请”,历史空值按普通申请处理。
cnd.andEX("IFNULL(info.adminOperate, 0)", "=", 0);
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
@@ -58,7 +58,6 @@ public class AidFundChangeRecordController {
us.mobile,
us.unitName,
us.unionName,
us.aidFundMemberUserType,
ins.id AS instanceId,
ins.businessNo,
ins.state instanceState,
@@ -1,24 +1,24 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.AidFundMemberChangeRecordService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -27,6 +27,8 @@ import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
@@ -44,8 +46,6 @@ public class AidFundFoundationAuditController {
@Inject
private AidFundMemberChangeRecordService changeRecordService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/medicalMutualAid/aidFund/foundationAudit/index.html")
@SaCheckPermission("medicalMutualAid.aidFund.foundationAudit")
@@ -61,79 +61,8 @@ public class AidFundFoundationAuditController {
@At
@ApiOperation("分页查询")
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
public Result pageData(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "aidFundMemberUserType") String aidFundMemberUserType,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId,
@Param(value = "changeType") String changeType,
@Param(value = "approval") Boolean approval) {
Sql sql = Sqls.create("""
SELECT
info.*,
us.arrivalAtSchoolDate,
us.mobile,
us.loginname loginName,
us.username userName,
us.unitName,
us.unionName,
us.aidFundMemberUserType,
us.sex,
ins.id AS instanceId,
ins.businessNo,
ins.state instanceState,
ins.variable instanceVariable,
ins.processDefineId instanceProcessDefineId,
t.id taskId,
t.taskName AS taskKey,
t.displayName taskName,
t.taskType,
t.performType taskPerformType,
t.taskState,
t.finishTime,
t.taskParentId,
t.variable taskVariable,
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
FROM
wf_process_task t
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN aid_fund_member_change_record info ON info.id = ins.businessNo
LEFT JOIN vw_user us ON us.id = info.userId
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
$condition
""");
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or("us.loginname", "like", "%" + pageForm.getSearchKeyword() + "%");
seg.or("us.username", "like", "%" + pageForm.getSearchKeyword() + "%");
cnd.and(seg);
}
cnd.andEX("YEAR(info.applyTime)", "=", year);
cnd.andEX("us.aidFundMemberUserType", "=", aidFundMemberUserType);
cnd.andEX("us.unionId", "=", unionId);
cnd.andEX("us.unitId", "=", unitId);
cnd.andEX("info.changeType", "=", changeType);
cnd.and("t.taskName", "=", "85c7d148-44f5-4333-b854-ab225357fd3e");
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
if (approval) {
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
} else {
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
}
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.desc("info.applyTime");
} else {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
}
cnd.groupBy("t.id");
sql.setCondition(cnd);
public Result pageData(AidFundPageForm pageForm) {
Sql sql = changeRecordService.getFoundationAuditSql(pageForm);
Pagination<NutMap> pageVO = changeRecordService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
List<NutMap> list = pageVO.getList();
@@ -144,6 +73,39 @@ public class AidFundFoundationAuditController {
return Result.success(pageVO);
}
/**
* 导出互管会审核页面申请记录。
*
* @param pageForm 页面筛选参数,和列表页查询条件保持一致
* @param response HTTP 响应对象,用于输出 Excel 文件流
*/
@At
@Ok("void")
@ApiOperation("导出申请记录")
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
public void exportApplyRecord(AidFundPageForm pageForm, HttpServletResponse response) {
List<NutMap> listMap = changeRecordService.getFoundationAuditExportList(pageForm);
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("工号", "loginName", 20));
entityList.add(new ExcelExportEntity("姓名", "userName", 20));
entityList.add(new ExcelExportEntity("性别", "sex", 15));
entityList.add(new ExcelExportEntity("电话", "mobile", 20));
entityList.add(new ExcelExportEntity("工会", "unionName", 20));
entityList.add(new ExcelExportEntity("单位", "unitName", 20));
entityList.add(new ExcelExportEntity("入校时间", "arrivalAtSchoolDate", 20));
entityList.add(new ExcelExportEntity("基金会员类型", "aidFundMemberUserType", 20));
entityList.add(new ExcelExportEntity("缴纳金额", "money", 20));
entityList.add(new ExcelExportEntity("变更类型", "changeType", 20));
entityList.add(new ExcelExportEntity("申请时间", "applyTime", 20));
entityList.add(new ExcelExportEntity("审核状态", "approvalStatus", 20));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, listMap);
String fileName = (pageForm.getYear() == null ? "" : pageForm.getYear()) + "基金会员审核记录.xlsx";
CommonDownloadUtil.download(fileName, workbook, response);
}
@At
@ApiOperation("查询需要缴费多少")
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
@@ -163,4 +125,23 @@ public class AidFundFoundationAuditController {
return Result.success();
}
/**
* 批量审核互管会待办记录。
*
* @param param 统一的审批参数,包含审批意见和审核动作
* @param ids 勾选的申请记录 ID 数组
* @return 批量审核结果统计
*/
@At
@SLog(tag = "基金会员", msg = "互管会批量审核基金会员记录")
@Aop(TransAop.READ_COMMITTED)
@ApiOperation("批量审核")
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
public Result batchExecuteTask(@Param("data") String param, @Param("ids") String[] ids) {
if (ids == null || ids.length == 0 || StrUtil.isBlank(param)) {
return Result.error("参数错误");
}
return Result.success(changeRecordService.batchExecuteTask(param, ids));
}
}
@@ -10,18 +10,12 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.mode.AidFundMemberMode;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
@@ -35,7 +29,6 @@ import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -79,55 +72,32 @@ public class AidFundManageController {
@ApiOperation("分页查询")
@SaCheckPermission("medicalMutualAid.aidFund.manage")
public Result pageData(AidFundPageForm pageForm) {
Sql sql = Sqls.create("""
SELECT
id,
loginname,
username,
sex,
arrivalAtSchoolDate,
unitName,
unionName,
aidFundMemberUserType,
aidFundMemberJoinTime
FROM
vw_user
$condition
""");
Cnd cnd = Cnd.NEW();
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
if (AuthUtil.hasRole(RoleConstant.RETIREMENT_WORKPLACE.name())) {
cnd.and(Sys_user::getAidFundMemberUserType, "=", "离退休人员");
} else {
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
}
}
if (pageForm.getNotPayedCurrentYear()) {
cnd.and("id", "in", Sqls.create("SELECT userid FROM `aid_fund_member_pay` where `year` = YEAR(CURDATE()) and isPayed = 0"));
}
cnd.andEX(Sys_user::getAidFundMemberUserType, "=", pageForm.getAidFundMemberUserType());
cnd.andEX(View_user::getUnionId, "=", pageForm.getUnionId());
cnd.andEX(View_user::getUnitId, "=", pageForm.getUnitId());
sql.setCondition(cnd);
cnd.and(Sys_user::getAidFundMember, "=", AidFundMemberMode.NORMAL.getCode());
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("loginname", pageForm.getSearchKeyword());
seg.orLike("username", pageForm.getSearchKeyword());
cnd.and(seg);
}
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.desc("unitCode");
} else {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
}
sql.setCondition(cnd);
Pagination pagination = userService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
Sql sql = aidFundMemberService.getManageSql(pageForm);
Pagination pagination = aidFundMemberService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
return Result.success(pagination);
}
@At
@SaCheckPermission("medicalMutualAid.aidFund.manage")
@Ok("void")
@ApiOperation("导出会员名单")
public void exportMemberList(AidFundPageForm pageForm, HttpServletResponse response) {
List<NutMap> listMap = aidFundMemberService.listMap(aidFundMemberService.getManageSql(pageForm));
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("姓名", "username", 20));
entityList.add(new ExcelExportEntity("工号", "loginname", 20));
entityList.add(new ExcelExportEntity("性别", "sex", 20));
entityList.add(new ExcelExportEntity("会员类型", "aidFundMemberUserType", 20));
entityList.add(new ExcelExportEntity("单位", "unitName", 20));
entityList.add(new ExcelExportEntity("工会", "unionName", 20));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, listMap);
CommonDownloadUtil.download("会员名单.xlsx", workbook, response);
}
@At
@SaCheckPermission("medicalMutualAid.aidFund.manage")
@@ -198,9 +168,12 @@ public class AidFundManageController {
return Result.error("请选择要退会的人员");
}
List<AidFundMemberChangeRecord> recordArrayList = new ArrayList<>();
List<Sys_user> sysUserList = userService.query(Cnd.where("id", "in", ids));
for (String id : ids) {
Sys_user user = sysUserList.stream().filter(sysUser -> sysUser.getId().equals(id)).findFirst().orElse(null);
AidFundMemberChangeRecord record = new AidFundMemberChangeRecord()
.setUserId(id)
.setAidFundMemberUserType(user.getAidFundMemberUserType())
.setApplyTime(new Date())
.setChangeType("AIDFUND_MEMBER_CHANGE_TYPE_SEVEN");
recordArrayList.add(record);
@@ -220,25 +193,7 @@ public class AidFundManageController {
if (ObjectUtil.isEmpty(ids) || StrUtil.isBlank(changeType)) {
return Result.error("参数错误");
}
List<AidFundMemberChangeRecord> recordArrayList = new ArrayList<>();
for (String id : ids) {
AidFundMemberChangeRecord record = new AidFundMemberChangeRecord()
.setUserId(id)
.setApplyTime(new Date())
.setChangeType(changeType);
recordArrayList.add(record);
}
Chain add;
if (changeType.equals("AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
//会员退休
add = Chain.make("aidFundMemberUserType", "离退休人员");
} else {
add = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
.add("aidFundMemberQuitTime", new Date());
}
userService.update(add, Cnd.where("id", "in", ids));
userService.insert(recordArrayList);
aidFundMemberService.doBatchChangeTypeByAdmin(ids, changeType);
return Result.success();
}
@@ -258,21 +213,10 @@ public class AidFundManageController {
@ApiOperation("变更基金会员")
@Aop(TransAop.READ_COMMITTED)
public Result doEditChangeType(String userId, String changeType) {
AidFundMemberChangeRecord record = new AidFundMemberChangeRecord()
.setUserId(userId)
.setApplyTime(new Date())
.setChangeType(changeType);
aidFundMemberService.insert(record);
Chain add;
if (changeType.equals("AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
//会员退休
add = Chain.make("aidFundMemberUserType", "离退休人员");
} else {
add = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
.add("aidFundMemberQuitTime", new Date());
if (StrUtil.isBlank(userId) || StrUtil.isBlank(changeType)) {
return Result.error("参数错误");
}
userService.update(add, Cnd.where("id", "=", userId));
aidFundMemberService.doEditChangeTypeByAdmin(userId, changeType);
return Result.success();
}
@@ -63,14 +63,17 @@ public class AidFundRetirementAuditController {
@Param(value = "approval") Boolean approval) {
Sql sql = Sqls.create("""
SELECT
info.*,
info.id,
info.userId,
info.changeType,
info.applyTime,
us.arrivalAtSchoolDate,
us.mobile,
us.loginname loginName,
us.username userName,
us.unitName,
us.unionName,
us.aidFundMemberUserType,
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
us.sex,
ins.id AS instanceId,
ins.businessNo,
@@ -106,7 +109,7 @@ public class AidFundRetirementAuditController {
cnd.and(seg);
}
cnd.andEX("YEAR(info.applyTime)", "=", year);
cnd.andEX("us.aidFundMemberUserType", "=", aidFundMemberUserType);
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", aidFundMemberUserType);
cnd.andEX("info.changeType", "=", changeType);
cnd.and("t.taskName", "=", "f756c818-6bb7-4f50-b8fa-24390fc7b0b8");
@@ -65,14 +65,17 @@ public class AidFundUnionAuditController {
@Param(value = "approval") Boolean approval) {
Sql sql = Sqls.create("""
SELECT
info.*,
info.id,
info.userId,
info.changeType,
info.applyTime,
us.arrivalAtSchoolDate,
us.mobile,
us.loginname loginName,
us.username userName,
us.unitName,
us.unionName,
us.aidFundMemberUserType,
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
us.sex,
ins.id AS instanceId,
ins.businessNo,
@@ -108,7 +111,7 @@ public class AidFundUnionAuditController {
cnd.and(seg);
}
cnd.andEX("YEAR(info.applyTime)", "=", year);
cnd.andEX("us.aidFundMemberUserType", "=", aidFundMemberUserType);
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", aidFundMemberUserType);
cnd.andEX("info.changeType", "=", changeType);
cnd.and("t.taskName", "=", "06ed1d6d-5f96-485f-9150-ed1ef4a082d6");
@@ -38,10 +38,20 @@ public class AidFundMemberChangeRecord extends BaseModel {
@ColDefine(type = ColType.VARCHAR, width = 50)
private String changeType;
@Column
@Comment("申请时选择的基金会员类型(dict")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String aidFundMemberUserType;
@Column
@Comment("申请时间")
@ColDefine(type = ColType.DATETIME)
private Date applyTime;
@Column
@Comment("是否系统管理员操作")
@ColDefine(type = ColType.BOOLEAN)
private Boolean adminOperate;
}
@@ -22,6 +22,9 @@ public class AidFundPageForm extends PageForm {
private String changeType;
private Integer year;
//是否已审核
private Boolean approval;
//是否扣款null全部、1已缴费、0未缴费
private Integer isPayed;
}
@@ -1,6 +1,8 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
import org.nutz.dao.sql.Sql;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberPay;
import org.nutz.lang.util.NutMap;
@@ -9,10 +11,53 @@ import java.util.List;
public interface AidFundMemberChangeRecordService extends BaseService<AidFundMemberChangeRecord> {
/**
* 构建互管会审核页面查询 SQL。
*
* @param pageForm 页面筛选参数,包含年度、姓名/工号、工会、单位、会员类型、变更类型和审核状态
* @return 可直接用于分页或导出的查询 SQL
*/
Sql getFoundationAuditSql(AidFundPageForm pageForm);
/**
* 查询互管会审核页面导出数据。
*
* @param pageForm 页面筛选参数,和列表页保持一致
* @return 导出所需的列表数据,每条记录对应一条基金会员变更申请
*/
List<NutMap> getFoundationAuditExportList(AidFundPageForm pageForm);
/**
* 执行流程审核动作。
*
* @param param 流程提交参数 JSON,包含提交流程所需的任务、意见和业务字段
* @param id 基金会员变更记录 ID
*/
void executeTask( String param, String id);
/**
* 批量执行互管会审核任务。
*
* @param param 流程提交参数 JSON,包含统一的审批意见和提交类型
* @param ids 选中的基金会员变更记录 ID 数组
* @return 批量审核结果,包含成功数、失败数和失败原因
*/
NutMap batchExecuteTask(String param, String[] ids);
/**
* 计算基金会员应补缴金额。
*
* @param arrivalAtSchoolDate 入校时间,格式为 yyyy-MM-dd
* @param userId 用户 ID,空值时默认取当前登录人
* @return 当前规则下计算出的应缴金额
*/
int getPayMoney(String arrivalAtSchoolDate,String userId);
/**
* 查询用户历年缴费记录。
*
* @param userId 用户 ID,空值时默认取当前登录人
* @return 用户及其旧工号对应的缴费记录列表
*/
List<AidFundMemberPay> getUserPayRecordList(String userId);
}
@@ -2,6 +2,8 @@ package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
import org.nutz.dao.sql.Sql;
import org.nutz.lang.util.NutMap;
import java.util.List;
@@ -31,5 +33,30 @@ public interface AidFundMemberService extends BaseService {
Double getPayMoney(Sys_user user, Integer year);
/**
* 获取基金会员台账列表查询SQL。
*
* @param pageForm 页面查询条件,包含会员类型、工会、单位、关键字、排序及未缴费筛选参数
* @return 与基金会员台账页面一致的查询SQL
*/
Sql getManageSql(AidFundPageForm pageForm);
List<NutMap> findChangeRecordList(String userId);
/**
* 管理端批量变更基金会员状态,并记录“系统管理员操作”来源。
*
* @param ids 需要变更的用户ID数组,来自台账页面勾选行
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
*/
void doBatchChangeTypeByAdmin(String[] ids, String changeType);
/**
* 管理端对单个用户执行“变更”操作,并记录“系统管理员操作”来源。
*
* @param userId 被变更的用户ID
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
*/
void doEditChangeTypeByAdmin(String userId, String changeType);
}
@@ -3,20 +3,34 @@ package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.flow.service.FlowCommonService;
import com.budwk.app.flow.service.ProcessTaskService;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.mode.AidFundMemberMode;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberPay;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.AidFundMemberChangeRecordService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -33,6 +47,9 @@ import java.util.*;
*/
@IocBean(args = {"refer:dao"})
public class AidFundMemberChangeRecordServiceImpl extends BaseServiceImpl<AidFundMemberChangeRecord> implements AidFundMemberChangeRecordService {
private static final String FOUNDATION_AUDIT_TASK_NAME = "85c7d148-44f5-4333-b854-ab225357fd3e";
private static final String CHANGE_TYPE_JOIN = "AIDFUND_MEMBER_CHANGE_TYPE_ONE";
public AidFundMemberChangeRecordServiceImpl(Dao dao) {
super(dao);
}
@@ -41,21 +58,228 @@ public class AidFundMemberChangeRecordServiceImpl extends BaseServiceImpl<AidFun
@Inject
private FlowCommonService flowCommonService;
@Inject
private ProcessTaskService processTaskService;
@Inject
private SysDictService sysDictService;
@Override
public Sql getFoundationAuditSql(AidFundPageForm pageForm) {
Sql sql = Sqls.create("""
SELECT
info.id,
info.userId,
info.changeType,
info.applyTime,
us.arrivalAtSchoolDate,
us.mobile,
us.loginname loginName,
us.username userName,
us.unitName,
us.unionName,
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
us.sex,
ins.id AS instanceId,
ins.businessNo,
ins.state instanceState,
ins.variable instanceVariable,
ins.processDefineId instanceProcessDefineId,
t.id taskId,
t.taskName AS taskKey,
t.displayName taskName,
t.taskType,
t.performType taskPerformType,
t.taskState,
t.finishTime,
t.taskParentId,
t.variable taskVariable,
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
FROM
wf_process_task t
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
LEFT JOIN aid_fund_member_change_record info ON info.id = ins.businessNo
LEFT JOIN vw_user us ON us.id = info.userId
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
$condition
""");
Cnd cnd = Cnd.NEW();
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or("us.loginname", "like", "%" + pageForm.getSearchKeyword() + "%");
seg.or("us.username", "like", "%" + pageForm.getSearchKeyword() + "%");
cnd.and(seg);
}
cnd.andEX("YEAR(info.applyTime)", "=", pageForm.getYear());
// 新申请优先按变更表中的基金会员类型筛选,历史数据为空时兜底用户表。
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", pageForm.getAidFundMemberUserType());
cnd.andEX("us.unionId", "=", pageForm.getUnionId());
cnd.andEX("us.unitId", "=", pageForm.getUnitId());
cnd.andEX("info.changeType", "=", pageForm.getChangeType());
cnd.and("t.taskName", "=", FOUNDATION_AUDIT_TASK_NAME);
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())){
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
}
if (Boolean.TRUE.equals(pageForm.getApproval())) {
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
} else {
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
}
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.desc("info.applyTime");
} else {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
}
cnd.groupBy("t.id");
sql.setCondition(cnd);
return sql;
}
@Override
public List<NutMap> getFoundationAuditExportList(AidFundPageForm pageForm) {
List<NutMap> list = listMap(getFoundationAuditSql(pageForm));
Map<String, String> memberTypeMap = getDictNameMap("AIDFUND_MEMBER_USER_TYPE");
Map<String, String> changeTypeMap = getDictNameMap("AIDFUND_MEMBER_CHANGE_TYPE");
list.forEach(map -> {
String arrivalAtSchoolDate = map.getString("arrivalAtSchoolDate");
String changeType = map.getString("changeType");
map.put("approvalStatus", ObjectUtil.equals(map.getInt("taskState"), ProcessTaskStateEnum.DOING.getCode()) ? "未审核" : "已审核");
map.put("aidFundMemberUserType", memberTypeMap.getOrDefault(map.getString("aidFundMemberUserType"), map.getString("aidFundMemberUserType")));
map.put("changeType", changeTypeMap.getOrDefault(changeType, changeType));
map.put("arrivalAtSchoolDate", StrUtil.isBlank(arrivalAtSchoolDate) ? "" : DateUtil.format(DateUtil.parse(arrivalAtSchoolDate), "yyyy-MM-dd"));
map.put("applyTime", map.getTime("applyTime") == null ? "" : DateUtil.formatDateTime(map.getTime("applyTime")));
// 仅加入基金时需要计算补缴金额,其他变更类型保持空白,避免误导为固定收费。
map.put("money", ObjectUtil.equals(changeType, CHANGE_TYPE_JOIN) && StrUtil.isNotBlank(arrivalAtSchoolDate)
? getPayMoney(arrivalAtSchoolDate, map.getString("userId")) : "");
});
return list;
}
private Map<String, String> getDictNameMap(String dictCode) {
return sysDictService.getSubListByCode(dictCode).stream().collect(HashMap::new, (map, dict) -> map.put(dict.getCode(), dict.getName()), HashMap::putAll);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void executeTask(String param, String id) {
Dict args = Json.fromJson(Dict.class, param);
executeTask(args, id);
}
@Override
@Aop(TransAop.READ_COMMITTED)
public NutMap batchExecuteTask(String param, String[] ids) {
NutMap result = NutMap.NEW();
if (ArrayUtil.isEmpty(ids)) {
return result.setv("successCount", 0).setv("failCount", 0).setv("failMessages", List.of("请选择需要审核的记录"));
}
Dict baseArgs = Json.fromJson(Dict.class, param);
List<ProcessTask> doingTasks = processTaskService.getDoingTaskByBizIdTaskName(Arrays.asList(ids), FOUNDATION_AUDIT_TASK_NAME);
Map<String, ProcessTask> taskMap = new HashMap<>();
List<Long> instanceIds = doingTasks.stream().map(ProcessTask::getProcessInstanceId).filter(Objects::nonNull).distinct().toList();
Map<Long, String> businessNoMap = new HashMap<>();
if (CollectionUtil.isNotEmpty(instanceIds)) {
List<ProcessInstance> instances = dao().query(ProcessInstance.class, Cnd.where(ProcessInstance::getId, "in", instanceIds));
instances.forEach(instance -> businessNoMap.put(instance.getId(), instance.getBusinessNo()));
}
doingTasks.forEach(task -> {
String businessNo = businessNoMap.get(task.getProcessInstanceId());
if (StrUtil.isNotBlank(businessNo)) {
taskMap.put(businessNo, task);
}
});
List<String> failMessages = new ArrayList<>();
int successCount = 0;
for (String id : ids) {
AidFundMemberChangeRecord changeRecord = fetch(id);
if (changeRecord == null) {
failMessages.add(id + ":申请记录不存在");
continue;
}
ProcessTask processTask = taskMap.get(id);
if (processTask == null) {
failMessages.add(resolveRecordName(changeRecord) + ":审核任务不存在或已处理");
continue;
}
if (!processTaskService.isAllowed(processTask, SecurityUtil.getUserId())) {
failMessages.add(resolveRecordName(changeRecord) + ":当前账号无权审核该记录");
continue;
}
try {
Dict args = buildBatchTaskArgs(baseArgs, changeRecord, processTask);
executeTask(args, id);
successCount++;
} catch (Exception e) {
failMessages.add(resolveRecordName(changeRecord) + "" + e.getMessage());
}
}
result.setv("successCount", successCount);
result.setv("failCount", failMessages.size());
result.setv("failMessages", failMessages);
return result;
}
/**
* 批量审核沿用单条审核逻辑,但需要为每条记录补齐流程任务 ID 和加入基金时的入校时间。
*/
private Dict buildBatchTaskArgs(Dict baseArgs, AidFundMemberChangeRecord changeRecord, ProcessTask processTask) {
Dict args = baseArgs.clone();
args.set(FlowConst.PROCESS_TASK_ID_KEY, processTask.getId());
args.set("changeType", changeRecord.getChangeType());
if (ObjectUtil.equals(args.getInt("submitType"), 1) && ObjectUtil.equals(changeRecord.getChangeType(), CHANGE_TYPE_JOIN)) {
Sys_user user = dao().fetch(Sys_user.class, changeRecord.getUserId());
if (user == null || StrUtil.isBlank(user.getArrivalAtSchoolDate())) {
throw new IllegalArgumentException("缺少入校时间,无法批量通过");
}
args.set("arrivalAtSchoolDate", user.getArrivalAtSchoolDate());
}
return args;
}
private String resolveRecordName(AidFundMemberChangeRecord changeRecord) {
Sys_user user = dao().fetch(Sys_user.class, changeRecord.getUserId());
if (user == null || StrUtil.isBlank(user.getUsername())) {
return changeRecord.getId();
}
return user.getUsername();
}
/**
* 统一处理互管会审核通过后的用户状态同步,并继续推进流程任务。
*/
private void executeTask(Dict args, String id) {
AidFundMemberChangeRecord changeRecord = fetch(id);
if (changeRecord == null) {
throw new IllegalArgumentException("申请记录不存在");
}
if (args.getInt("submitType") == 1) {
//如果是通过
if (ObjectUtil.equals(args.getStr("changeType"), "AIDFUND_MEMBER_CHANGE_TYPE_ONE")) {
//如果是加入基金
dao().update(Sys_user.class, Chain.make("arrivalAtSchoolDate", args.getStr("arrivalAtSchoolDate")).add("aidFundMemberJoinTime", new Date())
.add("aidFundMember", AidFundMemberMode.NORMAL.getCode()),
// 审核通过后需要把本次申请的基金会员类型同步回用户表,历史空值则保留用户原值不覆盖。
String aidFundMemberUserType = changeRecord.getAidFundMemberUserType();
// 如果是通过,加入基金需要回写入校时间和入会状态,其他类型按退会逻辑处理。
if (ObjectUtil.equals(args.getStr("changeType"), CHANGE_TYPE_JOIN)) {
if (StrUtil.isBlank(args.getStr("arrivalAtSchoolDate"))) {
throw new IllegalArgumentException("缺少入校时间,无法通过审核");
}
Chain chain = Chain.make("arrivalAtSchoolDate", args.getStr("arrivalAtSchoolDate"))
.add("aidFundMemberJoinTime", new Date())
.add("aidFundMember", AidFundMemberMode.NORMAL.getCode());
if (StrUtil.isNotBlank(aidFundMemberUserType)) {
chain.add("aidFundMemberUserType", aidFundMemberUserType);
}
dao().update(Sys_user.class, chain,
Cnd.where(Sys_user::getId, "=", changeRecord.getUserId()));
} else {
dao().update(Sys_user.class, Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
.add("aidFundMemberQuitTime", new Date()),
Chain chain = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
.add("aidFundMemberQuitTime", new Date());
if (StrUtil.isNotBlank(aidFundMemberUserType)) {
chain.add("aidFundMemberUserType", aidFundMemberUserType);
}
dao().update(Sys_user.class, chain,
Cnd.where(Sys_user::getId, "=", changeRecord.getUserId()));
}
}
@@ -2,18 +2,28 @@ package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.mode.AidFundMemberMode;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberHistory;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberPay;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.AidFundMemberService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
@@ -121,6 +131,62 @@ public class AidFundMemberServiceImpl extends BaseServiceImpl implements AidFund
return (year + 1 - beforeYear) * money + (year - beforeYear) * money * 0.1;
}
/**
* 统一封装基金会员台账列表查询口径,分页查询和导出都复用这里,避免“所见”和“所得”不一致。
*
* @param pageForm 页面查询条件,包含会员类型、工会、单位、关键字、排序及未缴费筛选参数
* @return 基金会员台账查询SQL
*/
@Override
public Sql getManageSql(AidFundPageForm pageForm) {
Sql sql = Sqls.create("""
SELECT
id,
loginname,
username,
sex,
arrivalAtSchoolDate,
unitName,
unionName,
aidFundMemberUserType,
aidFundMemberJoinTime
FROM
vw_user
$condition
""");
Cnd cnd = Cnd.NEW();
// 非系统管理员按现有页面权限口径控制数据范围,确保导出结果与列表展示一致。
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
if (AuthUtil.hasRole(RoleConstant.RETIREMENT_WORKPLACE.name())) {
cnd.and(Sys_user::getAidFundMemberUserType, "=", "离退休人员");
} else {
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
}
}
if (pageForm.getNotPayedCurrentYear()) {
cnd.and("id", "in", Sqls.create("SELECT userid FROM `aid_fund_member_pay` where `year` = YEAR(CURDATE()) and isPayed = 0"));
}
cnd.andEX(Sys_user::getAidFundMemberUserType, "=", pageForm.getAidFundMemberUserType());
cnd.andEX(View_user::getUnionId, "=", pageForm.getUnionId());
cnd.andEX(View_user::getUnitId, "=", pageForm.getUnitId());
cnd.and(Sys_user::getAidFundMember, "=", AidFundMemberMode.NORMAL.getCode());
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("loginname", pageForm.getSearchKeyword());
seg.orLike("username", pageForm.getSearchKeyword());
cnd.and(seg);
}
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.desc("unitCode");
} else {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
}
sql.setCondition(cnd);
return sql;
}
@Override
public List<NutMap> findChangeRecordList(String userId) {
Sql sql = Sqls.create("""
@@ -168,5 +234,93 @@ public class AidFundMemberServiceImpl extends BaseServiceImpl implements AidFund
return listMap(sql);
}
/**
* 管理端批量变更基金会员状态时,统一同步用户表并记录“系统管理员操作”的变更记录。
*
* @param ids 需要变更的用户ID数组,来自台账页面勾选结果
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void doBatchChangeTypeByAdmin(String[] ids, String changeType) {
List<Sys_user> sysUserList = dao().query(Sys_user.class, Cnd.where("id", "in", ids));
List<AidFundMemberChangeRecord> recordArrayList = new ArrayList<>();
for (String id : ids) {
Sys_user user = sysUserList.stream().filter(sysUser -> sysUser.getId().equals(id)).findFirst().orElse(null);
if (user == null) {
continue;
}
recordArrayList.add(buildAdminChangeRecord(user, changeType));
}
updateUserChangeType(ids, changeType);
if (!recordArrayList.isEmpty()) {
dao().insert(recordArrayList);
}
}
/**
* 管理端单个“变更”操作时,统一同步用户表并记录“系统管理员操作”的变更记录。
*
* @param userId 被变更的用户ID
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void doEditChangeTypeByAdmin(String userId, String changeType) {
Sys_user user = dao().fetch(Sys_user.class, userId);
if (user == null) {
return;
}
dao().insert(buildAdminChangeRecord(user, changeType));
updateUserChangeType(new String[]{userId}, changeType);
}
/**
* 管理端变更落记录时,需要明确标记记录来源,避免被“我的申请”误识别为本人发起。
*
* @param user 当前被操作的用户
* @param changeType 变更类型字典值
* @return 已补齐管理员操作标记和会员类型快照的变更记录
*/
private AidFundMemberChangeRecord buildAdminChangeRecord(Sys_user user, String changeType) {
return new AidFundMemberChangeRecord()
.setUserId(user.getId())
.setAidFundMemberUserType(resolveChangeRecordMemberType(user, changeType))
.setApplyTime(new Date())
.setChangeType(changeType)
.setAdminOperate(true);
}
/**
* 退休变更需要把记录中的会员类型同步成退休类型,其余情况沿用当前用户档案中的会员类型。
*
* @param user 当前被操作的用户
* @param changeType 变更类型字典值
* @return 变更记录中应保存的基金会员类型
*/
private String resolveChangeRecordMemberType(Sys_user user, String changeType) {
if (ObjectUtil.equals(changeType, "AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
return "离退休人员";
}
return user.getAidFundMemberUserType();
}
/**
* 管理端“变更”与“批量变更”共用同一套用户表更新规则,确保页面操作口径一致。
*
* @param ids 需要更新的用户ID数组
* @param changeType 变更类型字典值
*/
private void updateUserChangeType(String[] ids, String changeType) {
Chain add;
if (ObjectUtil.equals(changeType, "AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
add = Chain.make("aidFundMemberUserType", "离退休人员");
} else {
add = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
.add("aidFundMemberQuitTime", new Date());
}
dao().update(Sys_user.class, add, Cnd.where("id", "in", ids));
}
}
@@ -73,6 +73,29 @@ public class MedicalCalculateMoneyController {
return Result.success(applyData);
}
@At
@ApiOperation("更新医疗互助补助金额明细")
@SaCheckPermission("medicalMutualAid.medical.calculateMoney")
public Object setGrantsOrUnionInto(String keys, double value) {
//获取申请最新年份
Sql yearSql = Sqls.create("SELECT MAX(YEAR(applyTime)) AS currentYear FROM medical_apply");
yearSql.setCallback(Sqls.callback.longs());
medicalCalculateMoneyService.execute(yearSql);
long year = yearSql.getLong();
MedicalMoneyDetail moneyDetail = medicalCalculateMoneyService.dao().fetch(MedicalMoneyDetail.class, Cnd.where("year", "=", year));
if (Lang.isEmpty(moneyDetail)) {
moneyDetail = new MedicalMoneyDetail();
moneyDetail.setYear((int) year);
}
if (keys.equals("grants")) {
moneyDetail.setSchoolGrants(new BigDecimal(value));
} else if (keys.equals("into")) {
moneyDetail.setUnionInto(new BigDecimal(value));
}
medicalCalculateMoneyService.insertOrUpdate(moneyDetail);
return null;
}
@At
@ApiOperation("按比例修改补助金额")
@@ -0,0 +1,126 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service.MedicalDashBoardService;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardCategoryStatVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardOverviewVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import java.util.List;
/**
* @author Codex
* @description 医疗互助数据看板
*/
@IocBean
@At("/platform/medicalMutualAid/medical/dashboard")
@Api("医疗互助数据看板")
@Ok("json:full")
public class MedicalDashBoardController {
@Inject
private MedicalDashBoardService medicalDashBoardService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/medicalMutualAid/medical/dashboard/index.html")
@SaCheckPermission("medicalMutualAid.medical.dashboard")
public void index() {
}
/**
* 查询医疗互助总览统计。
* 返回值字段说明:
* 1. fundMemberCount:当前基金会员总数
* 2. currentYearApplyCount:本年度已办结申请数
* 3. majorDiseaseApplyCount:重疾已办结申请数
* 4. commonDiseaseApplyCount:普通疾病已办结申请数
* 5. totalSubsidyMoney:补助金额合计
* 6. totalLoveSubsidyMoney:爱心基金金额合计
*
* @return 医疗互助总览统计 VO
*/
@At
@ApiOperation("查询医疗互助总览统计")
@SaCheckPermission("medicalMutualAid.medical.dashboard")
public Result overview() {
MedicalDashboardOverviewVO vo = medicalDashBoardService.getOverview();
return Result.success(vo);
}
/**
* 按工会统计医疗互助已办结申请数据。
* 返回值字段说明:
* 1. tableData:表格使用的工会统计列表
* 2. 列表元素中 applyCount 为已办结申请数,subsidyMoney 为补助金额合计
*
* @return 工会统计结果 VO
*/
@At
@ApiOperation("按工会统计医疗互助数据")
@SaCheckPermission("medicalMutualAid.medical.dashboard")
public Result unionStat() {
MedicalDashboardUnionResultVO vo = medicalDashBoardService.getUnionStat();
return Result.success(vo);
}
/**
* 按在职状态统计医疗互助已办结申请数据。
* 返回列表字段说明:
* 1. code:在职状态编码
* 2. name:在职状态名称
* 3. applyCount:该状态下已办结申请数
* 4. subsidyMoney:该状态下补助金额合计
*
* @return 在职状态统计 VO 列表
*/
@At
@ApiOperation("按在职状态统计医疗互助数据")
@SaCheckPermission("medicalMutualAid.medical.dashboard")
public Result userStateStat() {
List<MedicalDashboardCategoryStatVO> list = medicalDashBoardService.getUserStateStat();
return Result.success(list);
}
/**
* 按人员类型统计医疗互助已办结申请数据。
* 返回列表字段说明:
* 1. code:人员类型编码
* 2. name:人员类型名称
* 3. applyCount:该类型下已办结申请数
* 4. subsidyMoney:该类型下补助金额合计
*
* @return 人员类型统计 VO 列表
*/
@At
@ApiOperation("按人员类型统计医疗互助数据")
@SaCheckPermission("medicalMutualAid.medical.dashboard")
public Result personTypeStat() {
List<MedicalDashboardCategoryStatVO> list = medicalDashBoardService.getPersonTypeStat();
return Result.success(list);
}
/**
* 按疾病类型统计医疗互助已办结申请数据。
* 返回列表字段说明:
* 1. code:疾病类型 ID
* 2. name:疾病名称
* 3. applyCount:该疾病下已办结申请数
* 4. subsidyMoney:该疾病下补助金额合计
*
* @return 疾病类型统计 VO 列表
*/
@At
@ApiOperation("按疾病类型统计医疗互助数据")
@SaCheckPermission("medicalMutualAid.medical.dashboard")
public Result diseaseTypeStat() {
List<MedicalDashboardCategoryStatVO> list = medicalDashBoardService.getDiseaseTypeStat();
return Result.success(list);
}
}
@@ -55,6 +55,7 @@ public class MedicalUnionAuditController {
@SaCheckPermission("medicalMutualAid.medical.unionAudit")
public Result pageData(MedicalPageForm pageForm) {
Cnd cnd = Cnd.NEW();
cnd.and("t.taskName", "=", "a9bbf69c-5edf-4161-a364-47996d212472");
Sql sql = medicalAuditService.getAuditSql(pageForm, cnd);
sql.setCondition(cnd);
@@ -0,0 +1,61 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.model.MedicalApply;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardCategoryStatVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardOverviewVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionResultVO;
import java.util.List;
/**
* @author Codex
* @description 医疗互助数据看板 service
*/
public interface MedicalDashBoardService extends BaseService<MedicalApply> {
/**
* 查询医疗互助数据看板总览数据。
* 返回值包含:
* 1. 已办结申请总数
* 2. 本年度已办结申请数
* 3. 重疾/普通疾病申请数
* 4. 补助金额与爱心基金金额汇总
*
* @return 医疗互助总览统计 VO
*/
MedicalDashboardOverviewVO getOverview();
/**
* 按工会统计医疗互助已办结申请数据。
* 返回值中的 chartData 与 tableData 当前来源相同,
* 便于前端图表和表格按既有字段直接取值。
*
* @return 工会统计结果 VO
*/
MedicalDashboardUnionResultVO getUnionStat();
/**
* 按人员在职状态统计医疗互助已办结申请数据。
* code 为在职状态编码,name 为字典名称。
*
* @return 在职状态统计列表
*/
List<MedicalDashboardCategoryStatVO> getUserStateStat();
/**
* 按人员类型统计医疗互助已办结申请数据。
* code 为人员类型编码,name 为字典名称。
*
* @return 人员类型统计列表
*/
List<MedicalDashboardCategoryStatVO> getPersonTypeStat();
/**
* 按疾病类型统计医疗互助已办结申请数据。
* code 为疾病类型 ID,name 为疾病名称。
*
* @return 疾病类型统计列表
*/
List<MedicalDashboardCategoryStatVO> getDiseaseTypeStat();
}
@@ -186,6 +186,7 @@ public class MedicalApplyServiceImpl extends BaseServiceImpl<MedicalApply> imple
// 查询申请成功的记录
List<NutMap> applyRecords = getApplyRecord(allUserIds);
applyRecords.removeIf(item -> applyId.equals(item.getString("id")));
//是否首次申请 爱心互助基金 重大疾病
boolean isFirstApply = applyRecords.stream().filter(v -> v.getBoolean("isMajorDiseases")).toList().isEmpty();
@@ -230,7 +231,7 @@ public class MedicalApplyServiceImpl extends BaseServiceImpl<MedicalApply> imple
Boolean isBeyondAllMoney = allMoney.compareTo(medicalSetting.getPreviousYearMaxMoney()) > 0;
Sys_user user = dao().fetch(Sys_user.class, SecurityUtil.getUserId());
Sys_user user = dao().fetch(Sys_user.class, applyInfo.getString("userId"));
boolean fullTenYears = DateUtil.thisYear() - Integer.parseInt(user.getAidFundDeductTime()) >= 10;
boolean fullFifYears = DateUtil.thisYear() - Integer.parseInt(user.getAidFundDeductTime()) >= 15;
@@ -72,7 +72,9 @@ public class MedicalAuditServiceImpl extends BaseServiceImpl<MedicalApply> imple
seg.orLike("us.username", pageForm.getSearchKeyword());
cnd.and(seg);
}
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
if(!SecurityUtil.getUserLoginname().equals("superadmin")){
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
}
cnd.andEX("year(info.applyTime)", "=", pageForm.getYear());
cnd.andEX("info.diseaseId", "=", pageForm.getDiseaseId());
cnd.andEX("us.unionid", "=", pageForm.getUnionId());
@@ -0,0 +1,248 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.model.MedicalApply;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service.MedicalDashBoardService;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardCategoryStatVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardOverviewVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionResultVO;
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionStatVO;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* @author Codex
* @description 医疗互助数据看板 service 实现
*/
@IocBean(args = {"refer:dao"})
public class MedicalDashBoardServiceImpl extends BaseServiceImpl<MedicalApply> implements MedicalDashBoardService {
public MedicalDashBoardServiceImpl(Dao dao) {
super(dao);
}
@Override
public MedicalDashboardOverviewVO getOverview() {
Sql sql = Sqls.create("""
SELECT
(SELECT COUNT(1) FROM sys_user WHERE aidFundMember = 1) AS fundMemberCount,
COUNT(DISTINCT CASE WHEN YEAR(info.applyTime) = YEAR(NOW()) THEN info.id END) AS currentYearApplyCount,
COUNT(DISTINCT CASE WHEN type.isMajorDiseases = 1 THEN info.id END) AS majorDiseaseApplyCount,
COUNT(DISTINCT CASE WHEN type.isMajorDiseases = 0 THEN info.id END) AS commonDiseaseApplyCount,
COALESCE(SUM(info.subsidyMoney), 0) AS totalSubsidyMoney,
COALESCE(SUM(info.loveSubsidyMoney), 0) AS totalLoveSubsidyMoney
FROM
medical_apply info
INNER JOIN wf_process_instance ins ON ins.businessNo = info.id
LEFT JOIN medical_disease_type type ON type.id = info.diseaseId
WHERE
ins.state = @state
""");
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
NutMap data = fetchOne(sql);
MedicalDashboardOverviewVO vo = new MedicalDashboardOverviewVO();
vo.setFundMemberCount(data.getLong("fundMemberCount", 0L));
vo.setCurrentYearApplyCount(data.getLong("currentYearApplyCount", 0L));
vo.setMajorDiseaseApplyCount(data.getLong("majorDiseaseApplyCount", 0L));
vo.setCommonDiseaseApplyCount(data.getLong("commonDiseaseApplyCount", 0L));
vo.setTotalSubsidyMoney(getBigDecimalValue(data, "totalSubsidyMoney"));
vo.setTotalLoveSubsidyMoney(getBigDecimalValue(data, "totalLoveSubsidyMoney"));
return vo;
}
@Override
public MedicalDashboardUnionResultVO getUnionStat() {
Sql sql = Sqls.create("""
SELECT
un.id AS unionId,
un.`name` AS unionName,
un.unionCode AS unionCode,
COUNT(applyInfo.id) AS applyCount,
COALESCE(SUM(applyInfo.subsidyMoney), 0) AS subsidyMoney
FROM
sys_union un
LEFT JOIN vw_user us ON us.unionId = un.id
LEFT JOIN (
SELECT
info.id,
info.userId,
info.subsidyMoney
FROM
medical_apply info
INNER JOIN wf_process_instance ins ON ins.businessNo = info.id
WHERE
ins.state = @state
) applyInfo ON applyInfo.userId = us.id
GROUP BY
un.id, un.`name`, un.unionCode
ORDER BY
un.unionCode
""");
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
List<MedicalDashboardUnionStatVO> list = toUnionStatList(listMap(sql));
MedicalDashboardUnionResultVO resultVO = new MedicalDashboardUnionResultVO();
resultVO.setTableData(new ArrayList<>(list));
return resultVO;
}
@Override
public List<MedicalDashboardCategoryStatVO> getUserStateStat() {
Sql sql = Sqls.create("""
SELECT
dict.`code` AS code,
dict.`name` AS name,
COUNT(info.id) AS applyCount,
COALESCE(SUM(info.subsidyMoney), 0) AS subsidyMoney
FROM
sys_dict dict
LEFT JOIN sys_dict parent ON parent.id = dict.parentId
LEFT JOIN vw_user us ON us.userState = dict.`code`
LEFT JOIN medical_apply info ON info.userId = us.id
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id AND ins.state = @state
WHERE
parent.`code` = 'USER_STATE'
AND ins.id IS NOT NULL
GROUP BY
dict.`code`, dict.`name`, dict.location
ORDER BY
dict.location
""");
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
return toCategoryStatList(listMap(sql));
}
@Override
public List<MedicalDashboardCategoryStatVO> getPersonTypeStat() {
Sql sql = Sqls.create("""
SELECT
dict.`code` AS code,
dict.`name` AS name,
COUNT(info.id) AS applyCount,
COALESCE(SUM(info.subsidyMoney), 0) AS subsidyMoney
FROM
sys_dict dict
LEFT JOIN sys_dict parent ON parent.id = dict.parentId
LEFT JOIN vw_user us ON us.personType = dict.`code`
LEFT JOIN medical_apply info ON info.userId = us.id
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id AND ins.state = @state
WHERE
parent.`code` = 'USER_PERSON_TYPE'
AND ins.id IS NOT NULL
GROUP BY
dict.`code`, dict.`name`, dict.location
ORDER BY
dict.location
""");
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
return toCategoryStatList(listMap(sql));
}
@Override
public List<MedicalDashboardCategoryStatVO> getDiseaseTypeStat() {
Sql sql = Sqls.create("""
SELECT
type.id AS code,
type.diseaseName AS name,
COUNT(info.id) AS applyCount,
COALESCE(SUM(info.subsidyMoney), 0) AS subsidyMoney
FROM
medical_disease_type type
LEFT JOIN medical_apply info ON info.diseaseId = type.id
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id AND ins.state = @state
WHERE
ins.id IS NOT NULL
GROUP BY
type.id, type.diseaseName, type.diseaseCode
ORDER BY
type.diseaseCode
""");
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
return toCategoryStatList(listMap(sql));
}
/**
* 执行单行统计 SQL。
* 该方法用于处理总览类统计,返回结果仅一行。
*
* @param sql 已设置好查询参数的 SQL 对象
* @return 单行统计数据,字段不存在时返回空 NutMap,避免上层空指针
*/
private NutMap fetchOne(Sql sql) {
sql.setCallback(Sqls.callback.map());
dao().execute(sql);
Object result = sql.getResult();
if (result instanceof NutMap) {
return (NutMap) result;
}
return NutMap.NEW();
}
/**
* 将工会统计查询结果转换为 VO。
*
* @param dataList SQL 查询返回的 map 列表,字段需包含 unionId、unionName、unionCode、applyCount、subsidyMoney
* @return 工会统计 VO 列表
*/
private List<MedicalDashboardUnionStatVO> toUnionStatList(List<NutMap> dataList) {
List<MedicalDashboardUnionStatVO> list = new ArrayList<>();
for (NutMap data : dataList) {
MedicalDashboardUnionStatVO vo = new MedicalDashboardUnionStatVO();
vo.setUnionId(data.getString("unionId"));
vo.setUnionName(data.getString("unionName"));
vo.setUnionCode(data.getString("unionCode"));
vo.setApplyCount(data.getLong("applyCount", 0L));
vo.setSubsidyMoney(getBigDecimalValue(data, "subsidyMoney"));
list.add(vo);
}
return list;
}
/**
* 将通用分类统计查询结果转换为 VO。
*
* @param dataList SQL 查询返回的 map 列表,字段需包含 code、name、applyCount、subsidyMoney
* @return 分类统计 VO 列表
*/
private List<MedicalDashboardCategoryStatVO> toCategoryStatList(List<NutMap> dataList) {
List<MedicalDashboardCategoryStatVO> list = new ArrayList<>();
for (NutMap data : dataList) {
MedicalDashboardCategoryStatVO vo = new MedicalDashboardCategoryStatVO();
vo.setCode(data.getString("code"));
vo.setName(data.getString("name"));
vo.setApplyCount(data.getLong("applyCount", 0L));
vo.setSubsidyMoney(getBigDecimalValue(data, "subsidyMoney"));
list.add(vo);
}
return list;
}
/**
* 从 NutMap 中安全读取金额字段。
* SQL 聚合查询返回的金额字段有时会是 BigDecimal、Double、Long 或字符串,
* 因此这里统一做一次转换,避免 controller/service 层重复判空和类型判断。
*
* @param data NutMap 查询结果对象
* @param key 金额字段名
* @return 对应金额,字段为空时返回 0
*/
private BigDecimal getBigDecimalValue(NutMap data, String key) {
Object value = data.get(key);
if (value == null) {
return BigDecimal.ZERO;
}
if (value instanceof BigDecimal) {
return (BigDecimal) value;
}
return new BigDecimal(String.valueOf(value));
}
}
@@ -0,0 +1,43 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author Codex
* @description 医疗互助数据看板总览统计返回值
*/
@Data
public class MedicalDashboardOverviewVO {
/**
* 当前基金会员总数
*/
private Long fundMemberCount;
/**
* 本年度已办结申请数
*/
private Long currentYearApplyCount;
/**
* 已办结重疾申请数
*/
private Long majorDiseaseApplyCount;
/**
* 已办结普通疾病申请数
*/
private Long commonDiseaseApplyCount;
/**
* 已办结补助金额合计
*/
private BigDecimal totalSubsidyMoney;
/**
* 已办结爱心基金金额合计
*/
private BigDecimal totalLoveSubsidyMoney;
}
@@ -0,0 +1,19 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
import lombok.Data;
import java.util.List;
/**
* @author Codex
* @description 医疗互助按工会统计返回值
*/
@Data
public class MedicalDashboardUnionResultVO {
/**
* 表格数据。
* 当前页面仅保留工会统计表格,因此只返回表格所需列表。
*/
private List<MedicalDashboardUnionStatVO> tableData;
}
@@ -0,0 +1,38 @@
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author Codex
* @description 医疗互助按工会统计返回值
*/
@Data
public class MedicalDashboardUnionStatVO {
/**
* 工会ID
*/
private String unionId;
/**
* 工会名称
*/
private String unionName;
/**
* 工会编码
*/
private String unionCode;
/**
* 已办结申请数
*/
private Long applyCount;
/**
* 已办结补助金额合计
*/
private BigDecimal subsidyMoney;
}