From e68e71b883ae12b79d585b85f1a68bed15f9b925 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 27 Jul 2026 11:29:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E9=87=91=E4=BC=9A=E5=91=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ndMemberBranchUnionApprovalController.java | 2 +- .../controller/FundMemberHisController.java | 7 +- .../controller/FundMemberPayController.java | 199 ++++++++++++ .../controller/FundMemberQueryController.java | 3 +- .../FundMemberRetiredApprovalController.java | 104 +++++++ .../controller/FundMemberWriteController.java | 10 +- .../member/mode/FundMemberPayImportTemp.java | 20 ++ .../fund/member/models/FundMemberPay.java | 65 ++++ .../member/service/FundMemberPayService.java | 54 ++++ .../member/service/FundMemberService.java | 7 + .../impl/FundMemberPayServiceImpl.java | 285 ++++++++++++++++++ .../service/impl/FundMemberServiceImpl.java | 10 + .../fund/member/vo/FundMemberPayPageForm.java | 23 ++ .../config/model/MutualMemberConfig.java | 5 + .../MedicalMutualAidConfigService.java | 16 +- .../MedicalMutualAidConfigServiceImpl.java | 40 ++- .../components/plugins/sysImport/index.vue | 44 ++- .../fund/member/payRecord/index.html | 206 +++++++++++++ .../fund/member/query/index.html | 12 +- .../fund/member/retiredApproval/index.html | 129 ++++++++ .../fund/member/write/index.html | 17 +- .../medicalMutualAid/config/index.html | 25 +- .../member/branchUnionApproval/index.html | 26 ++ .../dayofficework/fund/member/mine/index.html | 8 + .../dayofficework/fund/member/mine/info.js | 42 +++ .../fund/member/retiredApproval/index.html | 25 ++ .../member/schoolUnionApproval/index.html | 26 ++ .../fund/member/write/index.html | 50 +++ 28 files changed, 1411 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberPayController.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberRetiredApprovalController.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/mode/FundMemberPayImportTemp.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/models/FundMemberPay.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberPayService.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberPayServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/vo/FundMemberPayPageForm.java create mode 100644 src/main/resources/views/platform/zhgh/dayofficework/fund/member/payRecord/index.html create mode 100644 src/main/resources/views/platform/zhgh/dayofficework/fund/member/retiredApproval/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/fund/member/branchUnionApproval/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/fund/member/mine/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/fund/member/mine/info.js create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/fund/member/retiredApproval/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/fund/member/schoolUnionApproval/index.html create mode 100644 src/main/resources/views/platform/zhghh5/dayofficework/fund/member/write/index.html diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberBranchUnionApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberBranchUnionApprovalController.java index 8748802..5d84ae7 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberBranchUnionApprovalController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberBranchUnionApprovalController.java @@ -78,7 +78,7 @@ public class FundMemberBranchUnionApprovalController { $condition """); Cnd cnd = Cnd.NEW(); - cnd.and("t.taskName", "in", List.of("fgh", "ltx")); + cnd.and("t.taskName", "=", "fgh"); if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId())); } diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberHisController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberHisController.java index c513d7b..c416b34 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberHisController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberHisController.java @@ -35,10 +35,11 @@ public class FundMemberHisController { @At @SaCheckPermission("fundMember.his") public Result pageData(PageForm pageForm, Integer year, String unionId) { + // 同一会员可能存在多次入会记录,加入时间只取最新一条,避免子查询返回多行。 Sql sql = Sqls.create(""" SELECT his.*, - (SELECT changeTime FROM fund_member_change_record WHERE loginName = his.loginName AND isJoin = 1 ORDER BY changeTime DESC) joinTime + (SELECT changeTime FROM fund_member_change_record WHERE loginName = his.loginName AND isJoin = 1 ORDER BY changeTime DESC LIMIT 1) joinTime FROM fund_member_his his $condition @@ -46,8 +47,8 @@ public class FundMemberHisController { Cnd cnd = Cnd.NEW(); if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) { SqlExpressionGroup seg = new SqlExpressionGroup(); - seg.orLike("username", pageForm.getSearchKeyword()); - seg.orLike("loginname", pageForm.getSearchKeyword()); + seg.orLike("userName", pageForm.getSearchKeyword()); + seg.orLike("loginName", pageForm.getSearchKeyword()); cnd.and(seg); } cnd.andEX("year", "=", year); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberPayController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberPayController.java new file mode 100644 index 0000000..5f7568b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberPayController.java @@ -0,0 +1,199 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.controller; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.result.Result; +import com.budwk.app.base.utils.CommonDownloadUtil; +import com.budwk.app.zhgh.dayofficework.fund.member.mode.FundMemberPayImportTemp; +import com.budwk.app.zhgh.dayofficework.fund.member.models.FundMemberPay; +import com.budwk.app.zhgh.dayofficework.fund.member.service.FundMemberPayService; +import com.budwk.app.zhgh.dayofficework.fund.member.vo.FundMemberPayPageForm; +import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.config.model.MutualMemberConfig; +import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.config.service.MedicalMutualAidConfigService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.poi.ss.usermodel.Workbook; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.AdaptBy; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 基金会员缴费管理。 + */ +@IocBean +@At("/platform/fundMember/payRecord") +@Ok("json:full") +@Api(tags = "基金会员缴费管理") +public class FundMemberPayController { + + @Inject + private FundMemberPayService fundMemberPayService; + @Inject + private MedicalMutualAidConfigService medicalMutualAidConfigService; + + @At("") + @Ok("beetl:/platform/zhgh/dayofficework/fund/member/payRecord/index.html") + @SaCheckPermission("fundMember.payRecord") + public void index() { + } + + @At + @ApiOperation("缴费记录分页查询") + @SaCheckPermission("fundMember.payRecord") + public Result pageData(FundMemberPayPageForm pageForm) { + Sql sql = fundMemberPayService.buildPageSql(pageForm); + Pagination pagination = fundMemberPayService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + return Result.success(pagination); + } + + /** + * 查询生成指定年度缴费名单时实际采用的月缴费金额,供前端确认提示展示。 + * + * @param year 缴费年度 + * @return 实际匹配到的会员缴费配置年度和每月缴费金额 + */ + @At + @ApiOperation("查询年度缴费配置") + @SaCheckPermission("fundMember.payRecord") + public Result memberConfig(Integer year) { + MutualMemberConfig memberConfig = medicalMutualAidConfigService.getMemberConfigForPay(year); + if (memberConfig == null || memberConfig.getMonthAmount() == null + || memberConfig.getMonthAmount().signum() <= 0) { + return Result.error("未维护有效的会员缴费配置,请先在医疗互助配置中设置每月缴费金额"); + } + return Result.success(NutMap.NEW() + .addv("year", memberConfig.getYear()) + .addv("monthAmount", memberConfig.getMonthAmount())); + } + + @At + @ApiOperation("生成年度缴费名单") + @SLog(tag = "基金会员缴费管理", msg = "生成年度缴费名单") + @SaCheckPermission("fundMember.payRecord") + public Result createPayList(Integer year) { + int count = fundMemberPayService.createPayList(year); + return Result.success("成功生成" + count + "条缴费记录"); + } + + @At + @ApiOperation("设置缴费状态") + @SLog(tag = "基金会员缴费管理", msg = "设置缴费状态") + @SaCheckPermission("fundMember.payRecord") + public Result updatePayed(String id, Boolean isPayed) { + if (ObjectUtil.isEmpty(id) || isPayed == null) { + return Result.error("参数错误"); + } + fundMemberPayService.updatePayed(id, isPayed); + return Result.success(); + } + + @At + @ApiOperation("清空当年缴费名单") + @SLog(tag = "基金会员缴费管理", msg = "清空年度缴费名单") + @SaCheckPermission("fundMember.payRecord") + public Result clearPayList(Integer year) { + fundMemberPayService.clearCurrentYearPayList(year); + return Result.success(); + } + + @At + @Ok("void") + @ApiOperation("下载缴费导入模板") + @SaCheckPermission("fundMember.payRecord") + public void downloadImportTemp(HttpServletResponse response) { + List exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("年度", "year", 12)); + exportEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + exportEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, new ArrayList<>()); + CommonDownloadUtil.download("基金会员缴费导入模板.xlsx", workbook, response); + } + + @At + @Ok("void") + @ApiOperation("导出缴费记录") + @SaCheckPermission("fundMember.payRecord") + public void exportExcel(FundMemberPayPageForm pageForm, HttpServletResponse response) { + Sql sql = fundMemberPayService.buildPageSql(pageForm); + List records = fundMemberPayService.listMap(sql); + records.forEach(record -> record.put("payState", record.getBoolean("isPayed") ? "已缴费" : "未缴费")); + List exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("年度", "year", 12)); + exportEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + exportEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + exportEntities.add(new ExcelExportEntity("性别", "sex", 10)); + exportEntities.add(new ExcelExportEntity("会员类别", "aidFundMemberType", 20)); + exportEntities.add(new ExcelExportEntity("所属单位", "unitName", 30)); + exportEntities.add(new ExcelExportEntity("所属工会", "unionName", 30)); + exportEntities.add(new ExcelExportEntity("缴费金额", "money", 15)); + exportEntities.add(new ExcelExportEntity("缴费状态", "payState", 15)); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, records); + CommonDownloadUtil.download(pageForm.getYear() + "年基金会员缴费记录.xlsx", workbook, response); + } + + @At + @ApiOperation("导入缴费记录") + @SLog(tag = "基金会员缴费管理", msg = "导入缴费记录") + @SaCheckPermission("fundMember.payRecord") + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + public Result doImport(TempFile file, Integer year) { + if (file == null || year == null) { + return Result.error("文件和缴费年度不能为空"); + } + List importRows = ExcelImportUtil.importExcel( + file.getFile(), FundMemberPayImportTemp.class, new ImportParams()); + if (importRows.isEmpty()) { + return Result.error("导入文件没有缴费记录"); + } + for (int i = 0; i < importRows.size(); i++) { + FundMemberPayImportTemp importRow = importRows.get(i); + int rowNumber = i + 2; + // 页面选择的年度与模板年度必须一致,防止将缴费状态写入错误年度。 + if (importRow.getYear() == null) { + return Result.error("第" + rowNumber + "行年度不能为空"); + } + if (!year.equals(importRow.getYear())) { + return Result.error("第" + rowNumber + "行年度与当前选择的缴费年度不一致"); + } + if (cn.hutool.core.util.StrUtil.isBlank(importRow.getLoginName())) { + return Result.error("第" + rowNumber + "行工号不能为空"); + } + } + List loginNames = importRows.stream() + .map(FundMemberPayImportTemp::getLoginName) + .collect(Collectors.toList()); + List errorLoginNames = fundMemberPayService.markPaidByLoginNames(year, loginNames); + // 无论是否存在异常都返回导入统计,前端据 errorCount 决定提示类型。 + NutMap result = NutMap.NEW(); + result.setv("totalCount", importRows.size()); + result.setv("successCount", importRows.size() - errorLoginNames.size()); + result.setv("errorCount", errorLoginNames.size()); + result.setv("errorList", errorLoginNames.stream() + .map(loginName -> NutMap.NEW().addv("工号", loginName).addv("错误原因", "未找到该年度缴费记录")) + .collect(Collectors.toList())); + return Result.success(result); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberQueryController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberQueryController.java index 8c528a6..70c3121 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberQueryController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberQueryController.java @@ -113,9 +113,8 @@ public class FundMemberQueryController { @SaCheckPermission("fundMember.query") @Ok("void") @ApiOperation("导出登记汇总Excel") - public void exportExcel(Integer year, String unionId, HttpServletResponse response) { + public void exportExcel(String unionId, HttpServletResponse response) { Cnd cnd = Cnd.NEW(); - cnd.and("YEAR(submitTime)", "=", year); if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) { cnd.and("unionId", "=", SecurityUtil.getUnionId()); } else { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberRetiredApprovalController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberRetiredApprovalController.java new file mode 100644 index 0000000..a790095 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberRetiredApprovalController.java @@ -0,0 +1,104 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaMode; +import cn.hutool.core.util.StrUtil; +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.flow.enums.ProcessTaskStateEnum; +import com.budwk.app.web.commons.auth.utils.AuthUtil; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.dayofficework.fund.member.service.FundMemberService; +import io.swagger.annotations.Api; +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.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +import java.util.List; + +/** + * 基金会员离退休审核。 + */ +@IocBean +@At("/platform/fundMember/retiredApproval") +@Ok("json:full") +@Api("基金会员-离退休审核") +public class FundMemberRetiredApprovalController { + + @Inject + private FundMemberService fundMemberService; + + @At("") + @Ok("beetl:/platform/zhgh/dayofficework/fund/member/retiredApproval/index.html") + @SaCheckPermission("fundMember.retiredApproval") + public void index() { + } + + @At("/h5") + @Ok("beetl:/platform/zhghh5/dayofficework/fund/member/retiredApproval/index.html") + @SaCheckPermission("h5.fundMember.retiredApproval") + public void h5() { + } + + @At + @SaCheckPermission(value = {"fundMember.retiredApproval", "h5.fundMember.retiredApproval"}, mode = SaMode.OR) + public Result pageData(PageForm pageForm, boolean approval) { + Sql sql = Sqls.create(""" + SELECT + info.*, + 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 fund_member_apply info ON info.id = ins.businessNo + 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(); + cnd.and("t.taskName", "=", "ltx"); + if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) { + 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.isNotBlank(pageForm.getSearchKeyword())) { + SqlExpressionGroup searchGroup = new SqlExpressionGroup(); + searchGroup.orLike("info.loginName", pageForm.getSearchKeyword()); + searchGroup.orLike("info.userName", pageForm.getSearchKeyword()); + cnd.and(searchGroup); + } + cnd.groupBy("t.id"); + cnd.desc("t.createdAt"); + sql.setCondition(cnd); + Pagination pagination = fundMemberService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + return Result.success(pagination); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberWriteController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberWriteController.java index 3054357..bacbf8f 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberWriteController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/controller/FundMemberWriteController.java @@ -77,6 +77,7 @@ public class FundMemberWriteController { @SLog(tag = "基金会员-填写申请", msg = "提交申请") public Result submit(@Param("data") FundMemberApply fundMember) { fundMemberService.validateCurrentUserNotFundMember(); + fundMemberService.validateApplyForm(fundMember); if (StrUtil.isBlank(fundMember.getId())) { fundMemberService.validateApply(); } @@ -88,6 +89,8 @@ public class FundMemberWriteController { args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode()); args.set(FlowConst.FORM_DATA, fundMember); args.set(FlowConst.TASK_FORM_DATA_PREFIX + "userState", fundMember.getUserState()); + // 会员类别作为流程条件变量,供 JJHY 的离退休、分工会审核分支使用。 + args.set(FlowConst.TASK_FORM_DATA_PREFIX + "aidFundMemberType", fundMember.getAidFundMemberType()); ProcessInstance instance = flowEngine.startProcessInstanceByKey("JJHY", fundMember.getId(), SecurityUtil.getUserId(), args); // 自动完成第一个申请任务 @@ -105,6 +108,7 @@ public class FundMemberWriteController { @SLog(tag = "基金会员-填写申请", msg = "重新提交申请") public Result submitAgain(@Param("data") FundMemberApply fundMember, @Param("taskId") Long taskId) { fundMemberService.validateCurrentUserNotFundMember(); + fundMemberService.validateApplyForm(fundMember); if (StrUtil.isBlank(fundMember.getId())) { fundMemberService.validateApply(); } @@ -113,12 +117,16 @@ public class FundMemberWriteController { Dict dict = Dict.create(); dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId); dict.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.RE_APPLY.getCode()); + // 退回后重新提交时同步表单与条件变量,避免分支仍使用首次提交的会员类别。 + dict.set(FlowConst.FORM_DATA, fundMember); + dict.set(FlowConst.TASK_FORM_DATA_PREFIX + "userState", fundMember.getUserState()); + dict.set(FlowConst.TASK_FORM_DATA_PREFIX + "aidFundMemberType", fundMember.getAidFundMemberType()); flowCommonService.executeTask(dict); return Result.success(); } @At - @SaCheckPermission(value = {"fundMember.write", "fundMember.mine", "fundMember.branchUnionApproval", "fundMember.schoolUnionApproval", "h5.fundMember.write", "h5.fundMember.mine", "h5.fundMember.branchUnionApproval", "h5.fundMember.schoolUnionApproval"}, mode = SaMode.OR) + @SaCheckPermission(value = {"fundMember.write", "fundMember.mine", "fundMember.branchUnionApproval", "fundMember.retiredApproval", "fundMember.schoolUnionApproval", "h5.fundMember.write", "h5.fundMember.mine", "h5.fundMember.branchUnionApproval", "h5.fundMember.retiredApproval", "h5.fundMember.schoolUnionApproval"}, mode = SaMode.OR) @ApiOperation("获取申请信息") public Result info(@Param("id") String id) { FundMemberApply box = dao.fetch(FundMemberApply.class, id); diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/mode/FundMemberPayImportTemp.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/mode/FundMemberPayImportTemp.java new file mode 100644 index 0000000..23994a9 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/mode/FundMemberPayImportTemp.java @@ -0,0 +1,20 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.mode; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +/** + * 基金会员缴费导入模板。 + */ +@Data +public class FundMemberPayImportTemp { + + @Excel(name = "年度") + private Integer year; + + @Excel(name = "工号") + private String loginName; + + @Excel(name = "姓名") + private String userName; +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/models/FundMemberPay.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/models/FundMemberPay.java new file mode 100644 index 0000000..1b264b8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/models/FundMemberPay.java @@ -0,0 +1,65 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.models; + +import com.budwk.app.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.ColDefine; +import org.nutz.dao.entity.annotation.ColType; +import org.nutz.dao.entity.annotation.Column; +import org.nutz.dao.entity.annotation.Comment; +import org.nutz.dao.entity.annotation.Default; +import org.nutz.dao.entity.annotation.Index; +import org.nutz.dao.entity.annotation.Name; +import org.nutz.dao.entity.annotation.Table; +import org.nutz.dao.entity.annotation.TableIndexes; +import org.nutz.dao.entity.annotation.TableMeta; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.math.BigDecimal; + +/** + * 基金会员年度缴费记录。 + */ +@Data +@Table("fund_member_pay") +@TableMeta("{'mysql-charset':'utf8mb4'}") +@TableIndexes({ + @Index(name = "UK_FUND_MEMBER_PAY_USER_YEAR", fields = {"userId", "year"}, unique = true), + @Index(name = "IDX_FUND_MEMBER_PAY_YEAR", fields = {"year"}, unique = false) +}) +@EqualsAndHashCode(callSuper = true) +@Comment("基金会员年度缴费记录") +public class FundMemberPay extends BaseModel { + + @Name + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("用户ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String userId; + + @Column + @Comment("年度") + @ColDefine(type = ColType.INT) + private Integer year; + + @Column + @Comment("缴费金额") + @ColDefine(customType = "decimal(10,2)") + private BigDecimal money; + + @Column + @Comment("是否已缴费") + @Default("0") + @ColDefine(type = ColType.BOOLEAN) + private Boolean isPayed; + + @Column + @Comment("基金会员类别") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String aidFundMemberType; +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberPayService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberPayService.java new file mode 100644 index 0000000..1b5a12b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberPayService.java @@ -0,0 +1,54 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.service; + +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.dayofficework.fund.member.models.FundMemberPay; +import com.budwk.app.zhgh.dayofficework.fund.member.vo.FundMemberPayPageForm; +import org.nutz.dao.sql.Sql; + +import java.util.List; + +/** + * 基金会员缴费管理服务。 + */ +public interface FundMemberPayService extends BaseService { + + /** + * 生成指定年度的基金会员缴费名单。 + * + * @param year 缴费年度 + * @return 新增的缴费记录数量 + */ + int createPayList(Integer year); + + /** + * 构建缴费记录分页及导出共用查询。 + * + * @param pageForm 查询条件 + * @return 缴费记录查询 SQL + */ + Sql buildPageSql(FundMemberPayPageForm pageForm); + + /** + * 修改单条缴费记录的缴费状态。 + * + * @param id 缴费记录 ID + * @param isPayed 是否已缴费 + */ + void updatePayed(String id, Boolean isPayed); + + /** + * 清空本年度全部基金会员缴费记录。 + * + * @param year 缴费年度,必须为当前年度 + */ + void clearCurrentYearPayList(Integer year); + + /** + * 根据导入工号批量标记缴费状态。 + * + * @param year 缴费年度 + * @param loginNames 导入工号集合 + * @return 未找到对应年度缴费记录的工号集合 + */ + List markPaidByLoginNames(Integer year, List loginNames); +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberService.java index 0b12f71..599e2cb 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberService.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/FundMemberService.java @@ -22,6 +22,13 @@ public interface FundMemberService extends BaseService { */ void validateCurrentUserNotFundMember(); + /** + * 校验基金会员申请业务字段。 + * + * @param fundMember 基金会员申请信息 + */ + void validateApplyForm(FundMemberApply fundMember); + /** * 修改大病基金会员类别。 * diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberPayServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberPayServiceImpl.java new file mode 100644 index 0000000..6913c28 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberPayServiceImpl.java @@ -0,0 +1,285 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.service.impl; + +import cn.hutool.core.date.DateUtil; +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.sys.models.Sys_user; +import com.budwk.app.web.commons.auth.utils.AuthUtil; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.dayofficework.fund.member.models.FundMemberChangeRecord; +import com.budwk.app.zhgh.dayofficework.fund.member.models.FundMemberPay; +import com.budwk.app.zhgh.dayofficework.fund.member.service.FundMemberPayService; +import com.budwk.app.zhgh.dayofficework.fund.member.vo.FundMemberPayPageForm; +import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.apply.model.MutualApply; +import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.config.model.MutualMemberConfig; +import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.config.service.MedicalMutualAidConfigService; +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.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 基金会员缴费管理服务实现。 + */ +@IocBean(args = {"refer:dao"}) +public class FundMemberPayServiceImpl extends BaseServiceImpl implements FundMemberPayService { + + @Inject + private MedicalMutualAidConfigService medicalMutualAidConfigService; + + public FundMemberPayServiceImpl(Dao dao) { + super(dao); + } + + @Override + public int createPayList(Integer year) { + if (year == null) { + throw new RuntimeException("缴费年度不能为空"); + } + if (count(Cnd.where(FundMemberPay::getYear, "=", year)) > 0) { + throw new RuntimeException(year + "年缴费名单已生成,请勿重复生成"); + } + MutualMemberConfig memberConfig = medicalMutualAidConfigService.getMemberConfigForPay(year); + if (memberConfig == null || memberConfig.getMonthAmount() == null + || memberConfig.getMonthAmount().compareTo(BigDecimal.ZERO) <= 0) { + throw new RuntimeException("未维护有效的会员缴费配置,请先在医疗互助配置中设置每月缴费金额"); + } + if (memberConfig.getHalfPriceYear() == null || memberConfig.getHalfPriceYear() <= 0) { + throw new RuntimeException("会员缴费配置的缴费减半年限必须大于 0"); + } + + List members = dao().query(Sys_user.class, + Cnd.where(Sys_user::getAidFundMember, "=", true)); + if (members.isEmpty()) { + return 0; + } + + List loginNames = members.stream().map(Sys_user::getLoginname).collect(Collectors.toList()); + List joinRecords = dao().query(FundMemberChangeRecord.class, + Cnd.where(FundMemberChangeRecord::getLoginName, "in", loginNames) + .and(FundMemberChangeRecord::getIsJoin, "=", true) + .asc(FundMemberChangeRecord::getChangeTime)); + Map joinTimeMap = new HashMap<>(); + for (FundMemberChangeRecord joinRecord : joinRecords) { + // 同一会员可能存在多次加入记录,按时间升序覆盖后保留最近一次实际入会时间。 + joinTimeMap.put(joinRecord.getLoginName(), joinRecord.getChangeTime()); + } + List approvedApplies = dao().query(MutualApply.class, + Cnd.where(MutualApply::getLoginName, "in", loginNames) + .and(MutualApply::getStatus, "=", 1) + .desc(MutualApply::getSubmitTime)); + Map latestApplyTimeMap = new HashMap<>(); + for (MutualApply approvedApply : approvedApplies) { + Date submitTime = approvedApply.getSubmitTime(); + if (submitTime == null || toLocalDate(submitTime).getYear() > year) { + continue; + } + latestApplyTimeMap.merge(approvedApply.getLoginName(), submitTime, + (oldTime, newTime) -> newTime.after(oldTime) ? newTime : oldTime); + } + + List payList = members.stream().map(member -> { + BigDecimal money = calculatePayMoney(year, joinTimeMap.get(member.getLoginname()), + latestApplyTimeMap.get(member.getLoginname()), memberConfig); + if (money.compareTo(BigDecimal.ZERO) <= 0) { + return null; + } + FundMemberPay pay = new FundMemberPay(); + pay.setUserId(member.getId()); + pay.setYear(year); + pay.setMoney(money); + pay.setIsPayed(false); + pay.setAidFundMemberType(member.getAidFundMemberType()); + return pay; + }).filter(java.util.Objects::nonNull).collect(Collectors.toList()); + if (payList.isEmpty()) { + return 0; + } + dao().fastInsert(payList); + return payList.size(); + } + + /** + * 按缴费年度、实际入会年月和会员缴费配置计算缴费金额。 + * 缺少历史入会记录的存量会员按全年收费;入会当年按入会当月(含)至年末的月份数收费。 + * 入会后已满配置年限,且中间存在已审核医疗互助申请时,从最近申请年份重新计算减半年限。 + * + * @param payYear 缴费年度 + * @param joinTime 最近一次实际入会时间 + * @param latestApplyTime 最近一次已审核医疗互助申请提交时间 + * @param memberConfig 会员缴费配置 + * @return 应缴金额;缴费年度早于入会年度时返回 0 + */ + private BigDecimal calculatePayMoney(Integer payYear, Date joinTime, Date latestApplyTime, + MutualMemberConfig memberConfig) { + BigDecimal money = calculateBasePayMoney(payYear, joinTime, memberConfig.getMonthAmount()); + if (money.compareTo(BigDecimal.ZERO) > 0 + && shouldApplyHalfPrice(payYear, joinTime, latestApplyTime, memberConfig.getHalfPriceYear())) { + return money.divide(BigDecimal.valueOf(2)); + } + return money; + } + + /** + * 按入会时间计算未优惠前的年度应缴金额。 + */ + private BigDecimal calculateBasePayMoney(Integer payYear, Date joinTime, BigDecimal monthlyPayAmount) { + if (joinTime == null) { + return monthlyPayAmount.multiply(BigDecimal.valueOf(12)); + } + LocalDate joinDate = toLocalDate(joinTime); + if (payYear < joinDate.getYear()) { + return BigDecimal.ZERO; + } + if (payYear > joinDate.getYear()) { + return monthlyPayAmount.multiply(BigDecimal.valueOf(12)); + } + int payMonths = 13 - joinDate.getMonthValue(); + return monthlyPayAmount.multiply(BigDecimal.valueOf(payMonths)); + } + + /** + * 判断是否达到减半年限:从入会年份起算,最近一次已审核医疗互助申请会重置起算年份。 + */ + private boolean shouldApplyHalfPrice(Integer payYear, Date joinTime, Date latestApplyTime, Integer halfPriceYear) { + if (joinTime == null || halfPriceYear == null || halfPriceYear <= 0) { + return false; + } + int startYear = toLocalDate(joinTime).getYear(); + if (latestApplyTime != null) { + startYear = Math.max(startYear, toLocalDate(latestApplyTime).getYear()); + } + return payYear - startYear >= halfPriceYear; + } + + /** + * 将历史日期统一转换为本地日期,避免年度判断受时区影响。 + */ + private LocalDate toLocalDate(Date date) { + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + } + + @Override + public Sql buildPageSql(FundMemberPayPageForm pageForm) { + Sql sql = Sqls.create(""" + SELECT + pay.id, + pay.year, + pay.money, + pay.isPayed, + pay.aidFundMemberType, + u.id AS userId, + u.loginname AS loginName, + u.username AS userName, + u.sex, + u.unitName, + u.unionName, + joinRecord.joinTime + FROM + fund_member_pay pay + LEFT JOIN vw_user u ON u.id = pay.userId + LEFT JOIN ( + SELECT loginName, MAX(changeTime) AS joinTime + FROM fund_member_change_record + WHERE isJoin = 1 + GROUP BY loginName + ) joinRecord ON joinRecord.loginName = u.loginname + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("pay.year", "=", pageForm.getYear()); + cnd.andEX("pay.isPayed", "=", pageForm.getIsPayed()); + cnd.andEX("pay.aidFundMemberType", "=", pageForm.getAidFundMemberType()); + cnd.andEX("u.unionId", "=", pageForm.getUnionId()); + cnd.andEX("u.unitId", "=", pageForm.getUnitId()); + if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) { + SqlExpressionGroup searchGroup = new SqlExpressionGroup(); + searchGroup.orLike("u.loginname", pageForm.getSearchKeyword()); + searchGroup.orLike("u.username", pageForm.getSearchKeyword()); + cnd.and(searchGroup); + } + if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) { + cnd.and("u.unionId", "=", SecurityUtil.getUnionId()); + } + cnd.desc("u.unitCode"); + cnd.asc("u.loginname"); + sql.setCondition(cnd); + return sql; + } + + @Override + public void updatePayed(String id, Boolean isPayed) { + FundMemberPay pay = fetch(id); + if (pay == null) { + throw new RuntimeException("缴费记录不存在"); + } + update(Chain.make("isPayed", isPayed), Cnd.where(FundMemberPay::getId, "=", id)); + } + + @Override + public void clearCurrentYearPayList(Integer year) { + if (year == null) { + throw new RuntimeException("缴费年度不能为空"); + } + if (year != DateUtil.thisYear()) { + throw new RuntimeException("仅允许清空本年度缴费名单"); + } + clear(Cnd.where(FundMemberPay::getYear, "=", year)); + } + + @Override + public List markPaidByLoginNames(Integer year, List loginNames) { + if (year == null) { + throw new RuntimeException("缴费年度不能为空"); + } + if (loginNames == null || loginNames.isEmpty()) { + return Collections.emptyList(); + } + Set distinctLoginNames = loginNames.stream() + .filter(StrUtil::isNotBlank) + .map(String::trim) + .collect(Collectors.toSet()); + if (distinctLoginNames.isEmpty()) { + return Collections.emptyList(); + } + + List users = dao().query(Sys_user.class, + Cnd.where(Sys_user::getLoginname, "in", new ArrayList<>(distinctLoginNames))); + Map userMap = users.stream() + .collect(Collectors.toMap(Sys_user::getLoginname, Function.identity())); + List userIds = users.stream().map(Sys_user::getId).collect(Collectors.toList()); + List payList = userIds.isEmpty() ? Collections.emptyList() : query( + Cnd.where(FundMemberPay::getYear, "=", year) + .and(FundMemberPay::getUserId, "in", userIds)); + Set paidUserIds = payList.stream().map(FundMemberPay::getUserId).collect(Collectors.toSet()); + if (!paidUserIds.isEmpty()) { + update(Chain.make("isPayed", true), + Cnd.where(FundMemberPay::getYear, "=", year) + .and(FundMemberPay::getUserId, "in", new ArrayList<>(paidUserIds))); + } + + return distinctLoginNames.stream() + .filter(loginName -> !userMap.containsKey(loginName) + || !paidUserIds.contains(userMap.get(loginName).getId())) + .sorted() + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberServiceImpl.java index 956b7a0..a641e76 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/service/impl/FundMemberServiceImpl.java @@ -54,6 +54,16 @@ public class FundMemberServiceImpl extends BaseServiceImpl impl } } + @Override + public void validateApplyForm(FundMemberApply fundMember) { + if (fundMember == null || StrUtil.isBlank(fundMember.getAidFundMemberType())) { + throw new RuntimeException("会员类别不能为空"); + } + if ("退休".equals(fundMember.getAidFundMemberType()) && fundMember.getRetireTime() == null) { + throw new RuntimeException("会员类别为退休时,退休时间不能为空"); + } + } + @Override public void updateAidFundMemberType(String loginName, String aidFundMemberType) { if (StrUtil.isBlank(loginName)) { diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/vo/FundMemberPayPageForm.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/vo/FundMemberPayPageForm.java new file mode 100644 index 0000000..406e3a7 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/member/vo/FundMemberPayPageForm.java @@ -0,0 +1,23 @@ +package com.budwk.app.zhgh.dayofficework.fund.member.vo; + +import com.budwk.app.base.param.PageForm; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 基金会员缴费记录查询参数。 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class FundMemberPayPageForm extends PageForm { + + private Integer year; + + private String unionId; + + private String unitId; + + private String aidFundMemberType; + + private Boolean isPayed; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/model/MutualMemberConfig.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/model/MutualMemberConfig.java index db590e3..b13ac10 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/model/MutualMemberConfig.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/model/MutualMemberConfig.java @@ -23,6 +23,11 @@ public class MutualMemberConfig { @Comment("主键") private Long id; + /** 配置所属年度,用于生成对应年度的基金会员缴费名单。 */ + @Column("year") + @Comment("年度") + private Integer year; + /** 每月缴纳互助金额。 */ @Column("month_amount") @Comment("每月缴纳互助金额(元)") diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/MedicalMutualAidConfigService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/MedicalMutualAidConfigService.java index d91a398..82f74df 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/MedicalMutualAidConfigService.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/MedicalMutualAidConfigService.java @@ -93,11 +93,21 @@ public interface MedicalMutualAidConfigService extends BaseService void deleteBonus(Long bonusId); /** - * 查询会员缴费配置,未配置时返回页面默认值。 + * 查询指定年度的会员缴费配置。 * - * @return 会员缴费配置 + * @param year 配置年度 + * @return 对应年度的会员缴费配置;未配置时返回 null */ - MutualMemberConfig getMemberConfig(); + MutualMemberConfig getMemberConfig(Integer year); + + /** + * 查询生成缴费名单应使用的会员缴费配置。 + * 优先使用缴费年度配置,未配置时使用最新年度配置。 + * + * @param payYear 缴费年度 + * @return 可用于生成名单的会员缴费配置;未配置时返回 null + */ + MutualMemberConfig getMemberConfigForPay(Integer payYear); /** * 保存会员缴费配置。 diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/impl/MedicalMutualAidConfigServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/impl/MedicalMutualAidConfigServiceImpl.java index 44dff45..dad996b 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/impl/MedicalMutualAidConfigServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/config/service/impl/MedicalMutualAidConfigServiceImpl.java @@ -49,7 +49,7 @@ public class MedicalMutualAidConfigServiceImpl extends BaseServiceImpl config.getYear() != null) + .findFirst() + .orElse(null); + } + + /** + * 按年度保存会员缴费配置,同一年只保留一条记录。 */ @Override public MutualMemberConfig saveMemberConfig(MutualMemberConfig memberConfig) { if (memberConfig == null) { throw new BaseException("会员缴费配置不能为空"); } - MutualMemberConfig oldConfig = dao().fetch(MutualMemberConfig.class, Cnd.NEW()); - if (oldConfig != null && memberConfig.getId() == null) { + if (memberConfig.getYear() == null) { + throw new BaseException("会员缴费配置年度不能为空"); + } + MutualMemberConfig oldConfig = getMemberConfig(memberConfig.getYear()); + if (oldConfig != null && (memberConfig.getId() == null || !oldConfig.getId().equals(memberConfig.getId()))) { memberConfig.setId(oldConfig.getId()); } return dao().insertOrUpdate(memberConfig); diff --git a/src/main/resources/static/components/plugins/sysImport/index.vue b/src/main/resources/static/components/plugins/sysImport/index.vue index dd63436..51e3ce8 100644 --- a/src/main/resources/static/components/plugins/sysImport/index.vue +++ b/src/main/resources/static/components/plugins/sysImport/index.vue @@ -111,6 +111,12 @@ module.exports = { errorList: 0 } }, + clearImportFile() { + this.$set(this.importData, "fileList", []) + if (this.$refs.upload) { + this.$refs.upload.clearFiles() + } + }, doImport() { if (this.importData.fileList.length === 0) { this.$message.error({ @@ -122,6 +128,10 @@ module.exports = { const data = new FormData() data.append("isFlag", this.importData.isFlag) data.append("businessId", this.business_id) + // 部分业务导入需要页面上下文参数(如缴费年度),有值时一并提交。 + if (this.importData.year) { + data.append("year", this.importData.year) + } this.importData.fileList.forEach((val) => { data.append("file", val.raw, val.raw.name) }) @@ -132,20 +142,28 @@ module.exports = { background: "rgba(0, 0, 0, 0.7)" }) this.$axios.post(this.post_url, data).then((res) => { - loading.close() - if (res.code === 0) { - if (res.data) { - this.$message.warning("导入失败") - this.errorInfoData = res.data - this.$emit("flush") - } else { - this.$message.success("导入成功") - this.$emit("flush") - this.resetImportData() - } - } else { - this.$message.warning("导入失败") + if (res.code !== 0) { + this.$message.error(res.msg || "导入失败") + return } + // 导入接口统一返回统计数据,先回显统计再按错误数量提示结果。 + if (res.data) { + this.errorInfoData = res.data + } + if (res.data && Number(res.data.errorCount) > 0) { + this.$message.warning("导入完成,存在异常记录") + this.$emit("flush") + return + } + this.$message.success("导入成功") + this.$emit("flush") + // 成功后仅清除文件,保留本次导入统计供用户核对。 + this.clearImportFile() + }).catch(() => { + this.$message.error("导入失败,请稍后重试") + }).finally(() => { + // 请求成功、校验失败或网络异常时都必须关闭导入遮罩。 + loading.close() }) }, exportErrors() { diff --git a/src/main/resources/views/platform/zhgh/dayofficework/fund/member/payRecord/index.html b/src/main/resources/views/platform/zhgh/dayofficework/fund/member/payRecord/index.html new file mode 100644 index 0000000..a3e3259 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/dayofficework/fund/member/payRecord/index.html @@ -0,0 +1,206 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 全部 + 已缴费 + 未缴费 + + 生成年度名单 + 导入缴费记录 + 导出名单 + 清空{{pageForm.year}}年缴费名单 + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/src/main/resources/views/platform/zhgh/dayofficework/fund/member/query/index.html b/src/main/resources/views/platform/zhgh/dayofficework/fund/member/query/index.html index cb985bd..e53bb5a 100644 --- a/src/main/resources/views/platform/zhgh/dayofficework/fund/member/query/index.html +++ b/src/main/resources/views/platform/zhgh/dayofficework/fund/member/query/index.html @@ -83,6 +83,9 @@ layout("/layouts/platform.html"){ code="USER_AID_FUND_MEMBER_TYPE" style="width: 100%" @change="onAidFundMemberTypeChange(row)"> +