diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/dashboard/FundDashBoardController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/dashboard/FundDashBoardController.java index cf4ecd1..7564004 100644 --- a/src/main/java/com/budwk/app/zhgh/dayofficework/fund/dashboard/FundDashBoardController.java +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/fund/dashboard/FundDashBoardController.java @@ -5,7 +5,7 @@ import cn.hutool.core.date.DateUtil; import com.budwk.app.base.result.Result; import com.budwk.app.sys.models.Sys_user; import com.budwk.app.zhgh.dayofficework.fund.member.service.FundMemberService; -import com.budwk.app.zhgh.dayofficework.fund.subsidy.models.FundSubsidy; +import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.apply.model.MutualApply; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.nutz.dao.Cnd; @@ -14,10 +14,10 @@ import org.nutz.dao.Sqls; 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.At; import org.nutz.mvc.annotation.Ok; +import java.math.BigDecimal; import java.util.HashMap; import java.util.List; @@ -61,11 +61,11 @@ public class FundDashBoardController { dao.execute(sql); int newCount = sql.getInt(); - // 医疗补助数 - int subsidyCount = dao.count(FundSubsidy.class, Cnd.NEW()); + // 医疗补助数:按新的互助金申请主表统计申请数量。 + int subsidyCount = dao.count(MutualApply.class, Cnd.NEW()); - // 总补助金额 - int totalSubsidyCost = dao.func(FundSubsidy.class, "sum", "subsidyCost"); + // 医疗补助总金额:按互助金申请主表实际补助金额汇总,保持和审核最终金额一致。 + BigDecimal totalSubsidyCost = sumMutualApplyActualSubsidyAmount(); HashMap map = new HashMap<>(); map.put("count", count); @@ -76,6 +76,30 @@ public class FundDashBoardController { return Result.success(map); } + /** + * 汇总互助金申请主表中的实际补助金额,避免按动态分段明细重复或偏差统计。 + */ + private BigDecimal sumMutualApplyActualSubsidyAmount() { + Sql sql = Sqls.create("SELECT IFNULL(SUM(actual_subsidy_amount), 0) AS totalSubsidyCost FROM tb_mutual_apply"); + sql.setCallback(Sqls.callback.maps()); + dao.execute(sql); + List list = sql.getList(HashMap.class); + if (list == null || list.isEmpty()) { + return BigDecimal.ZERO; + } + Object value = list.get(0).get("totalSubsidyCost"); + if (value == null) { + return BigDecimal.ZERO; + } + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + if (value instanceof Number) { + return BigDecimal.valueOf(((Number) value).doubleValue()); + } + return new BigDecimal(value.toString()); + } + @At @SaCheckPermission("fund.dashBoard") @ApiOperation("各分工会基金会员数") diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/apply/service/impl/MedicalMutualAidApplyServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/apply/service/impl/MedicalMutualAidApplyServiceImpl.java index 5581443..21faaf8 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/apply/service/impl/MedicalMutualAidApplyServiceImpl.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/apply/service/impl/MedicalMutualAidApplyServiceImpl.java @@ -13,6 +13,7 @@ import com.budwk.app.base.param.PageForm; import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.utils.SysOfficeTemplateUtil; import com.budwk.app.zhgh.dayofficework.fund.member.models.FundMemberChangeRecord; +import com.budwk.app.zhgh.dayofficework.fund.member.service.FundMemberService; import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.apply.model.MutualApply; import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.apply.model.MutualApplySubsidy; import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.apply.service.MedicalMutualAidApplyService; @@ -69,6 +70,9 @@ public class MedicalMutualAidApplyServiceImpl extends BaseServiceImpl diseaseTypes = dao().query(MedicalDiseaseType.class, Cnd.NEW().asc("diseaseCode")); + boolean isFundMember = fundMemberService.isCurrentUserFundMember(); return NutMap.NEW() .addv("user", buildCurrentUserPlaceholder()) - .addv("diseaseTypes", diseaseTypes); + .addv("diseaseTypes", diseaseTypes) + .addv("isFundMember", isFundMember); } /** @@ -97,6 +103,10 @@ public class MedicalMutualAidApplyServiceImpl extends BaseServiceImpl buildSummaryExportEntities(List rangeNames) { List exportEntities = new ArrayList<>(); - exportEntities.add(buildSummaryExportEntity("序号", "index", 10)); - exportEntities.add(buildSummaryExportEntity("所在单位", "deptName", 20)); - exportEntities.add(buildSummaryExportEntity("姓名", "userName", 14)); - exportEntities.add(buildSummaryExportEntity("加入\n时间\n(年)", "joinYear", 14)); - exportEntities.add(buildSummaryExportEntity("大病名称\n及病情", "diseaseText", 30)); - exportEntities.add(buildSummaryExportEntity("符合规定发\n票金额\n(元)", "medicalTotalAmount", 20)); + exportEntities.add(buildSummaryExportEntity("序号", "index", 8)); + exportEntities.add(buildSummaryExportEntity("所在单位", "deptName", 15)); + exportEntities.add(buildSummaryExportEntity("姓名", "userName", 10)); + exportEntities.add(buildSummaryExportEntity("加入\n时间\n(年)", "joinYear", 11)); + exportEntities.add(buildSummaryExportEntity("大病名称\n及病情", "diseaseText", 22)); + exportEntities.add(buildSummaryExportEntity("符合规定发\n票金额\n(元)", "medicalTotalAmount", 16)); for (String rangeName : rangeNames) { - exportEntities.add(buildSummaryExportEntity(rangeName, rangeName, 18)); + exportEntities.add(buildSummaryExportEntity(rangeName, rangeName, 14)); } - exportEntities.add(buildSummaryExportEntity("补助小计", "subsidyTotalAmount", 16)); - exportEntities.add(buildSummaryExportEntity("补助\n比例", "bonusRatio", 12)); - exportEntities.add(buildSummaryExportEntity("实际补助金\n额(元)", "actualSubsidyAmount", 18)); - exportEntities.add(buildSummaryExportEntity("备注", "remark", 20)); + exportEntities.add(buildSummaryExportEntity("补助小计", "subsidyTotalAmount", 14)); + exportEntities.add(buildSummaryExportEntity("补助\n比例", "bonusRatio", 9)); + exportEntities.add(buildSummaryExportEntity("实际补助金\n额(元)", "actualSubsidyAmount", 15)); + exportEntities.add(buildSummaryExportEntity("备注", "remark", 14)); return exportEntities; } @@ -673,6 +684,102 @@ public class MedicalMutualAidApplyServiceImpl extends BaseServiceImpl applies, List rangeNames) { + if (workbook == null || workbook.getNumberOfSheets() == 0) { + return; + } + Sheet sheet = workbook.getSheetAt(0); + int rangeColumnCount = rangeNames == null ? 0 : rangeNames.size(); + int totalColumnCount = 10 + rangeColumnCount; + int rangeStartColumn = 6; + int subsidyTotalColumn = rangeStartColumn + rangeColumnCount; + int actualSubsidyColumn = subsidyTotalColumn + 2; + int startRow = sheet.getLastRowNum() + 1; + + appendSummaryTotalRow(sheet, workbook, startRow, applies, rangeNames, subsidyTotalColumn, actualSubsidyColumn); + appendSummaryNoteRow(sheet, workbook, startRow + 1, totalColumnCount); + appendSummarySignRow(sheet, workbook, startRow + 2, totalColumnCount); + appendSummaryUnionRows(sheet, workbook, startRow + 3, totalColumnCount); + } + + /** + * 追加合计行,金额列按当前导出数据汇总,比例和备注列保持空白。 + */ + private void appendSummaryTotalRow(Sheet sheet, Workbook workbook, int rowIndex, List applies, + List rangeNames, int subsidyTotalColumn, int actualSubsidyColumn) { + Row row = getOrCreateRow(sheet, rowIndex); + row.setHeightInPoints(28); + Cell labelCell = getOrCreateCell(row, 1); + labelCell.setCellValue("合计"); + labelCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + + Cell medicalTotalCell = getOrCreateCell(row, 5); + medicalTotalCell.setCellValue(formatExportMoney(sumDouble(applies, "medicalTotalAmount"))); + medicalTotalCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + + for (int i = 0; i < rangeNames.size(); i++) { + Cell cell = getOrCreateCell(row, 6 + i); + cell.setCellValue(formatExportMoney(sumSummaryRangeAmount(applies, rangeNames.get(i)))); + cell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + } + + Cell subsidyTotalCell = getOrCreateCell(row, subsidyTotalColumn); + subsidyTotalCell.setCellValue(formatExportMoney(sumDouble(applies, "subsidyTotalAmount"))); + subsidyTotalCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + + Cell actualSubsidyCell = getOrCreateCell(row, actualSubsidyColumn); + actualSubsidyCell.setCellValue(formatExportMoney(sumDouble(applies, "actualSubsidyAmount"))); + actualSubsidyCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + } + + /** + * 追加导出说明行,内容固定写入并跨整张表宽度展示。 + */ + private void appendSummaryNoteRow(Sheet sheet, Workbook workbook, int rowIndex, int totalColumnCount) { + Row row = getOrCreateRow(sheet, rowIndex); + row.setHeightInPoints(48); + Cell noteCell = getOrCreateCell(row, 0); + noteCell.setCellValue("注: 1. 年度累计超过1万元以上的部分,补助比例采用超额累计计算(即分段进行计算)的方法; 2. 个人第一年年度补助最高限额为10万元,其他年度补助最高限额为5万元;\n3. 对于连续参加互助会5年以上而未申请补助的会员,补助金额增加10%,10年以上未申请补助的会员,补助金额增加15%。"); + noteCell.setCellStyle(buildSummaryFooterNoteStyle(workbook)); + mergeSummaryRegion(sheet, rowIndex, rowIndex, 0, totalColumnCount - 1); + } + + /** + * 追加制表人和审核人占位行,方便导出后线下签署。 + */ + private void appendSummarySignRow(Sheet sheet, Workbook workbook, int rowIndex, int totalColumnCount) { + Row row = getOrCreateRow(sheet, rowIndex); + row.setHeightInPoints(28); + int reviewerColumn = Math.max(totalColumnCount / 3, 1); + Cell makerCell = getOrCreateCell(row, 1); + makerCell.setCellValue("制表人:"); + makerCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + Cell reviewerCell = getOrCreateCell(row, reviewerColumn); + reviewerCell.setCellValue("审核人:"); + reviewerCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + } + + /** + * 追加落款单位和导出日期,日期按中文年月日格式展示。 + */ + private void appendSummaryUnionRows(Sheet sheet, Workbook workbook, int startRowIndex, int totalColumnCount) { + Row unionRow = getOrCreateRow(sheet, startRowIndex); + Row dateRow = getOrCreateRow(sheet, startRowIndex + 1); + unionRow.setHeightInPoints(24); + dateRow.setHeightInPoints(24); + Cell unionCell = getOrCreateCell(unionRow, 0); + unionCell.setCellValue("工会"); + unionCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + Cell dateCell = getOrCreateCell(dateRow, 0); + dateCell.setCellValue(DateUtil.format(new Date(), "yyyy年M月d日")); + dateCell.setCellStyle(buildSummaryFooterCenterStyle(workbook)); + mergeSummaryRegion(sheet, startRowIndex, startRowIndex, 0, totalColumnCount - 1); + mergeSummaryRegion(sheet, startRowIndex + 1, startRowIndex + 1, 0, totalColumnCount - 1); + } + /** * 设置合并表头单元格;此处不设置 CellStyle,规避当前运行环境 POI 版本冲突导致的样式方法错误。 */ @@ -719,6 +826,33 @@ public class MedicalMutualAidApplyServiceImpl extends BaseServiceImpl applies, String fieldName) { + if (applies == null || applies.isEmpty()) { + return 0D; + } + BigDecimal total = BigDecimal.ZERO; + for (MutualApply apply : applies) { + if ("medicalTotalAmount".equals(fieldName)) { + total = total.add(toBigDecimal(apply.getMedicalTotalAmount())); + } else if ("subsidyTotalAmount".equals(fieldName)) { + total = total.add(toBigDecimal(apply.getSubsidyTotalAmount())); + } else if ("actualSubsidyAmount".equals(fieldName)) { + total = total.add(toBigDecimal(apply.getActualSubsidyAmount())); + } + } + return total.doubleValue(); + } + + /** + * 按动态补助区间名称汇总明细金额,保持合计行和动态表头一一对应。 + */ + private Double sumSummaryRangeAmount(List applies, String rangeName) { + if (applies == null || applies.isEmpty() || StrUtil.isBlank(rangeName)) { + return 0D; + } + BigDecimal total = BigDecimal.ZERO; + for (MutualApply apply : applies) { + List subsidies = dao().query(MutualApplySubsidy.class, Cnd.where("applyId", "=", apply.getId()).and("rangeName", "=", rangeName)); + for (MutualApplySubsidy subsidy : subsidies) { + total = total.add(toBigDecimal(subsidy.getSubsidyAmount())); + } + } + return total.doubleValue(); + } + /** * 填充申请保存默认值,提交时状态仍为未审核。 */ @@ -886,6 +1057,15 @@ public class MedicalMutualAidApplyServiceImpl extends BaseServiceImpl= 245 && green >= 245 && blue >= 245); } + /** + * 校验当前登录人必须为基金会员,互助金正式提交入口需要满足该条件。 + */ + private void validateCurrentUserFundMemberForApply() { + if (!fundMemberService.isCurrentUserFundMember()) { + throw new BaseException("本次补助申请仅面向基金会员开放,您目前还不是会员!"); + } + } + /** * 校验“我的申请”导出只能访问当前登录人的申请,避免通过 URL 参数导出他人申请。 */ diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/medical/controller/MedicalDiseaseTypeController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/medical/controller/MedicalDiseaseTypeController.java index 149469b..45307c3 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/medical/controller/MedicalDiseaseTypeController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/medicalMutualAid/medical/controller/MedicalDiseaseTypeController.java @@ -41,7 +41,7 @@ public class MedicalDiseaseTypeController { */ @At @ApiOperation("分页查询疾病类型") - @SaCheckPermission("medicalMutualAid.medical.diseaseType") +// @SaCheckPermission("medicalMutualAid.medical.diseaseType") public Result pageData(PageForm pageForm) { return Result.success(medicalDiseaseTypeService.pageData(pageForm)); } diff --git a/src/main/resources/static/components/plugins/sysSignature/pc.vue b/src/main/resources/static/components/plugins/sysSignature/pc.vue index 415b4da..9760591 100644 --- a/src/main/resources/static/components/plugins/sysSignature/pc.vue +++ b/src/main/resources/static/components/plugins/sysSignature/pc.vue @@ -20,6 +20,10 @@ module.exports = { value: { type: String, default: "" + }, + loadDefault: { + type: Boolean, + default: true } }, watch: { @@ -44,13 +48,17 @@ module.exports = { } }, methods: { - async init() { - const {code, data} = await this.$axios.post("/platform/signature/get") - if (code === 0) { - this.signatureContent = data && data.signature - this.$emit("input", this.signatureContent) - } + init() { this.signatureAddress = origin + "/platform/signature/scanPcCode?id=" + this.id + if (!this.loadDefault || this.value) { + return Promise.resolve() + } + return this.$axios.post("/platform/signature/get").then((resp) => { + if (resp.code === 0) { + this.signatureContent = resp.data && resp.data.signature + this.$emit("input", this.signatureContent) + } + }) }, signatureAgain() { const val = sessionStorage.getItem("h5-scan-code-signature-" + this.id) @@ -58,25 +66,26 @@ module.exports = { this.$emit("input", val) } }, - async mounted() { - await this.init() - webSocketPubSub.subscribe("h5-scan-code-signature", (data) => { - console.info("ws:收到签字成功消息:", data) - this.signatureContent = data.value - this.$emit("input", data.value) - }) + mounted() { + this.init().then(() => { + webSocketPubSub.subscribe("h5-scan-code-signature", (data) => { + console.info("ws:收到签字成功消息:", data) + this.signatureContent = data.value + this.$emit("input", data.value) + }) - // 可选:轮询或 watch ready 状态 - const checkReady = () => { - if (webSocketPubSub.ws && webSocketPubSub.ws.readyState === WebSocket.OPEN) { - console.info("ws.readyState is open"); - this.loading = false; - console.log(this.signatureAddress) - } else { - setTimeout(checkReady, 100); - } - }; - checkReady(); + // 可选:轮询或 watch ready 状态 + const checkReady = () => { + if (webSocketPubSub.ws && webSocketPubSub.ws.readyState === WebSocket.OPEN) { + console.info("ws.readyState is open"); + this.loading = false; + console.log(this.signatureAddress) + } else { + setTimeout(checkReady, 100); + } + }; + checkReady(); + }) } } diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/form/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/form/index.html index 78dfea6..b1ffb8b 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/form/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/form/index.html @@ -130,9 +130,7 @@ layout("/layouts/platform.html"){
- 返回 - 暂存 - 提交申请 + 提交申请
@@ -145,6 +143,7 @@ layout("/layouts/platform.html"){ return { loading: false, diseaseTypes: [], + isFundMember: false, apiBase: "${base!}/platform/medicalMutualAid/apply/form", minePath: "${base!}/platform/medicalMutualAid/apply/mine", formRules: { @@ -175,6 +174,10 @@ layout("/layouts/platform.html"){ this.$axios.post(this.apiBase + "/initApplyData").then((resp) => { if (resp.code === 0) { this.diseaseTypes = resp.data.diseaseTypes || [] + this.isFundMember = resp.data.isFundMember === true + if (!this.isFundMember) { + this.$message.warning("本次补助申请仅面向基金会员开放,您目前还不是会员!") + } } }).finally(() => { this.loading = false @@ -231,6 +234,10 @@ layout("/layouts/platform.html"){ }, // 提交申请,状态仍为未审核,等待互助会审核。 submitApply() { + if (!this.isFundMember) { + this.$message.warning("本次补助申请仅面向基金会员开放,您目前还不是会员!") + return + } this.$refs.form.validate((valid) => { if (valid) { this.$axios.post(this.apiBase + "/submitApply", this.formData).then((resp) => { diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/mine/form.html b/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/mine/form.html index d9e2dea..4e69775 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/mine/form.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/apply/mine/form.html @@ -131,7 +131,7 @@ layout("/layouts/platform.html"){
- +
diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/config/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/config/index.html index 2bc4a69..37fb806 100644 --- a/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/config/index.html +++ b/src/main/resources/views/platform/zhgh/staffbenefit/medicalMutualAid/config/index.html @@ -167,9 +167,7 @@ layout("/layouts/platform.html"){
- - - + @@ -235,9 +233,7 @@ layout("/layouts/platform.html"){ - - - + @@ -385,7 +381,6 @@ layout("/layouts/platform.html"){ loading: false, dialogLoading: false, dialogSaving: false, - yearOptions: [], searchForm: { year: null, configName: "" @@ -424,19 +419,12 @@ layout("/layouts/platform.html"){ } }, methods: { - // 初始化年度选项,列表查询和弹窗年度录入共用同一组选项。 - initYearOptions() { - const currentYear = new Date().getFullYear() - const years = [] - for (let year = currentYear - 5; year <= currentYear + 2; year++) { - years.push(year) - } - this.yearOptions = years.reverse() - }, // 查询年度配置列表,每年一条配置,供页面主列表展示和检索。 loadConfigList() { this.loading = true - this.$axios.post(loc() + "/listConfigs", this.searchForm).then((resp) => { + const params = this.copy(this.searchForm) + params.year = this.toYearNumber(params.year) + this.$axios.post(loc() + "/listConfigs", params).then((resp) => { if (resp.code === 0) { this.configList = resp.data || [] this.pageNumber = 1 @@ -470,6 +458,7 @@ layout("/layouts/platform.html"){ this.$axios.post(loc() + "/configData", { year: year }).then((resp) => { if (resp.code === 0) { this.configForm = resp.data.config || this.defaultConfig(year) + this.configForm.year = this.toYearString(this.configForm.year) this.memberForm = resp.data.memberConfig || this.defaultMemberConfig() this.ratioList = resp.data.ratios || [] this.bonusList = resp.data.bonuses || [] @@ -533,7 +522,7 @@ layout("/layouts/platform.html"){ // 先保存基础配置拿到主键,再保存会员缴费、比例和奖励明细。 saveDialogData() { this.dialogSaving = true - this.$axios.post(loc() + "/saveConfig", this.configForm).then((resp) => { + this.$axios.post(loc() + "/saveConfig", this.buildConfigPayload()).then((resp) => { if (resp.code !== 0) { return Promise.reject(resp) } @@ -628,11 +617,31 @@ layout("/layouts/platform.html"){ // 新增弹窗默认基础配置,仅设置用户要求保留默认值的基础字段。 defaultConfig(year) { return { - year: year, + year: this.toYearString(year), configName: year + "年医疗互助补助配置", status: 1 } }, + // 年度选择器使用字符串回显,提交接口前再转为数字,避免影响后端年度字段类型。 + toYearString(year) { + if (year === null || year === undefined || year === "") { + return null + } + return String(year) + }, + // 后端年度字段为整型,查询和保存时统一在此处转换。 + toYearNumber(year) { + if (year === null || year === undefined || year === "") { + return null + } + return Number(year) + }, + // 基础配置保存前清理年度类型,保持接口参数和实体字段一致。 + buildConfigPayload() { + const payload = this.copy(this.configForm) + payload.year = this.toYearNumber(payload.year) + return payload + }, // 会员缴费配置为全局单条配置,未配置时给出可编辑默认值。 defaultMemberConfig() { return { @@ -672,7 +681,6 @@ layout("/layouts/platform.html"){ } }, created() { - this.initYearOptions() this.loadConfigList() }, mounted() {