From 6380842b34c21517dcf2a9cdef6d1c994e12bd97 Mon Sep 17 00:00:00 2001
From: zhouhefeng
Date: Fri, 3 Jul 2026 17:10:35 +0800
Subject: [PATCH] commit
---
.../sys/services/impl/SysUserServiceImpl.java | 6 +-
.../OutlayManageUnionAllocateService.java | 59 +-
.../OutlayManageUnionAllocateServiceImpl.java | 171 ++-
.../OutlayManageUnionAllocateController.java | 41 +-
...layManageUnionIncomeExpenseController.java | 142 ++
.../OutlayManageUnionUseDetailController.java | 2 +-
.../union/model/OutLayAllocateUnion.java | 2 +-
.../union/vo/OutlayUnionAllocateImportVo.java | 10 +-
.../union/vo/OutlayUnionIncomeExpenseVO.java | 34 +
.../UnionReimburseCollectController.java | 58 +-
.../unionReimburse/model/UnionReimburse.java | 5 +
.../impl/UnionReimburseServiceImpl.java | 28 +-
.../vo/UnionReimburseCollectExcelVO.java | 13 +-
.../outlayManage/union/allocate/index.html | 170 ++-
.../union/incomeExpense/index.html | 163 +++
.../useDetail/quarterlyOutlayAllocate.js | 4 +-
.../unionReimburse/apply/index.html | 1240 ++++++++++-------
.../unionReimburse/collect/index.html | 4 +-
.../zhgh/dayofficework/unionReimburse/info.js | 106 +-
.../unionReimburse/apply/index.html | 849 +++++++++--
.../dayofficework/unionReimburse/info.js | 736 ++++++++--
21 files changed, 2925 insertions(+), 918 deletions(-)
create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionIncomeExpenseController.java
create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionIncomeExpenseVO.java
create mode 100644 src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html
diff --git a/src/main/java/com/budwk/app/sys/services/impl/SysUserServiceImpl.java b/src/main/java/com/budwk/app/sys/services/impl/SysUserServiceImpl.java
index 4ffba70d..63a91406 100644
--- a/src/main/java/com/budwk/app/sys/services/impl/SysUserServiceImpl.java
+++ b/src/main/java/com/budwk/app/sys/services/impl/SysUserServiceImpl.java
@@ -309,9 +309,9 @@ public class SysUserServiceImpl extends BaseServiceImpl implements Sys
String decodePwd = Base64Decoder.decodeStr(passowrd);
String hashedPassword = PwdUtil.getPassword(decodePwd, user.getSalt());
if (!Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
-// if (Globals.sso) {
- throw new BaseException("用户名或者密码不正确");
-// }
+ if (Globals.sso) {
+ throw new BaseException("用户名或者密码不正确");
+ }
}
user = this.fetchLinks(user, "unit");
if (Lang.isNotEmpty(user.getUnit()) && StrUtil.isNotBlank(user.getUnit().getUnionId())) {
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/OutlayManageUnionAllocateService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/OutlayManageUnionAllocateService.java
index 986186d8..a146ca91 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/OutlayManageUnionAllocateService.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/OutlayManageUnionAllocateService.java
@@ -11,41 +11,41 @@ import java.math.BigDecimal;
import java.util.List;
/**
- * 分工会季度额度分配服务。
+ * 分工会分配项目额度分配服务。
*
- * 该服务统一处理季度额度的分配、批量分配和重置回滚,
- * 保证季度记录与年度预算表金额始终同步。
+ * 该服务统一处理会费、评优奖励等分配项目的额度分配、批量分配和重置回滚,
+ * 保证分配项目记录与年度预算表金额始终同步。
*
* @author zhf
*/
public interface OutlayManageUnionAllocateService extends BaseService {
/**
- * 修改单个分工会的季度分配金额。
+ * 修改单个分工会的分配项目金额。
*
- * @param id outlay_allocate_union 表主键,用于定位当前编辑的季度分配记录
- * @param allocateMoney 本次要设置的季度分配金额,传入的是最终金额,不是增量金额
+ * @param id outlay_allocate_union 表主键,用于定位当前编辑的分配项目记录
+ * @param allocateMoney 本次要设置的分配项目金额,传入的是最终金额,不是增量金额
* @return Result 成功时返回 success;失败时返回错误信息,前端据此提示用户
*/
Result doEdit(String id, BigDecimal allocateMoney);
/**
- * 批量设置某一季度所有分工会的分配金额。
+ * 批量设置某一分配项目所有分工会的分配金额。
*
- * @param allocateMoney 本次批量设置的季度分配金额,所有命中的分工会都会写入该金额
- * @param quarterly 要操作的季度,例如 1/2/3/4
- * @param year 要操作的年份,用于筛选对应季度的有效分配记录
+ * @param allocateMoney 本次批量设置的分配项目金额,所有命中的分工会都会写入该金额
+ * @param quarterly 要操作的分配项目编码,复用 OUTLAY_QUARTERLY 字典
+ * @param year 要操作的年份,用于筛选对应分配项目的有效记录
* @return Result 成功时返回 success;失败时返回错误信息
*/
Result doBatchAllocate(BigDecimal allocateMoney, Integer quarterly, Integer year);
/**
- * 判断某年某季度是否已经做过额度分配。
+ * 判断某年某分配项目是否已经做过额度分配。
*
- * 只要当前季度记录中存在分配额度大于 0 的有效记录,
- * 就认为该季度已经分配过额度,前端据此决定是否提示再次分配。
+ * 只要当前分配项目记录中存在分配额度大于 0 的有效记录,
+ * 就认为该分配项目已经分配过额度,前端据此决定是否提示再次分配。
*
- * @param quarterly 要检查的季度,例如 1/2/3/4
+ * @param quarterly 要检查的分配项目编码,取值由 OUTLAY_QUARTERLY 字典维护
* @param year 要检查的年份
* @return true 已分配过;false 未分配
*/
@@ -60,15 +60,28 @@ public interface OutlayManageUnionAllocateService extends BaseService readImportExcel(TempFile file);
/**
- * 根据导入数据按分工会逐条分配季度额度。
+ * 根据导入数据按分工会逐条分配项目额度。
*
* @param importList 导入预览数据
- * @param quarterly 当前季度
+ * @param quarterly 当前分配项目编码
* @param year 当前年度
* @return 导入分配结果
*/
Result doImportAllocate(List importList, Integer quarterly, Integer year);
+ /**
+ * 给指定分工会新增评优奖励分配记录。
+ *
+ * 评优奖励属于 OUTLAY_QUARTERLY 字典中的独立分配项目,只针对单个分工会新增;
+ * 新增后同步累加年度预算表总额度,分工会经费分配详情会按分配项目展示该记录。
+ *
+ * @param year 当前预算年度
+ * @param unionId 要新增评优奖励的分工会 ID
+ * @param allocateMoney 本次新增的评优奖励金额
+ * @return Result 成功时返回 success;失败时返回校验原因
+ */
+ Result doAddAwardAllocate(Integer year, String unionId, BigDecimal allocateMoney);
+
/**
* 导出分工会额度导入模板。
*
@@ -77,24 +90,24 @@ public interface OutlayManageUnionAllocateService extends BaseService页面支持切换年度和季度,所以重置动作必须严格使用前端当前选择值,
- * 不能再按系统当前自然季度处理,否则会出现页面筛选季度和实际重置季度不一致的问题。
+ * 页面支持切换年度和分配项目,所以重置动作必须严格使用前端当前选择值,
+ * 不能再按系统当前默认项目处理,否则会出现页面筛选项目和实际重置项目不一致的问题。
*
- * @param quarterly 要重置的季度,例如 1/2/3/4
+ * @param quarterly 要重置的分配项目编码
* @param year 要重置的年份
* @return Result 成功时返回 success;失败时返回错误信息
*/
Result deleteAllocateRecord(Integer quarterly, Integer year);
/**
- * 按指定年度季度生成分工会预算记录。
+ * 按指定年度分配项目生成分工会预算记录。
*
- * 生成前会先校验该年度季度是否已存在有效记录;
+ *
生成前会先校验该年度分配项目是否已存在有效记录;
* 若已存在,则直接提示前端需要先重置后再重新生成。
*
- * @param quarterly 要生成的季度,例如 1/2/3/4
+ * @param quarterly 要生成的分配项目编码
* @param year 要生成的年份
* @return Result 成功时返回 success;失败时返回错误信息
*/
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/impl/OutlayManageUnionAllocateServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/impl/OutlayManageUnionAllocateServiceImpl.java
index ae2a70b1..f20a3895 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/impl/OutlayManageUnionAllocateServiceImpl.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/service/impl/OutlayManageUnionAllocateServiceImpl.java
@@ -33,13 +33,15 @@ import java.util.Map;
import java.util.Set;
/**
- * 分工会季度额度分配实现。
+ * 分工会分配项目额度分配实现。
*
* @author zhf
*/
@IocBean(args = {"refer:dao"})
public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl implements OutlayManageUnionAllocateService {
+ private static final int AWARD_PROJECT_CODE = 4;
+
public OutlayManageUnionAllocateServiceImpl(Dao dao) {
super(dao);
}
@@ -50,9 +52,9 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl importList, Integer quarterly, Integer year) {
- Result validateResult = validateCurrentQuarterOperation(quarterly);
+ Result validateResult = validateCurrentPeriodOperation(quarterly);
if (validateResult != null) {
return validateResult;
}
@@ -155,7 +157,7 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl unionList = dao().query(Sys_union.class, Cnd.NEW());
Map unionMap = new HashMap<>();
@@ -190,7 +192,7 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl 0) {
+ return Result.error("该分工会本年度已存在评优奖励记录,请直接编辑已有记录!");
+ }
+
+ OutLayAllocateUnion allocateUnion = new OutLayAllocateUnion();
+ allocateUnion.setYear(year);
+ allocateUnion.setUnionId(unionId);
+ allocateUnion.setQuarterly(AWARD_PROJECT_CODE);
+ allocateUnion.setAllocateHeadMoney(getCurrentYearSurplusMoney(year, unionId));
+ allocateUnion.setAllocateMoney(BigDecimal.ZERO);
+ insert(allocateUnion);
+ // 新增评优奖励后复用统一金额同步规则,确保分配项目记录和年度预算表 totalQuota 同步。
+ applyAllocateMoney(allocateUnion, allocateMoney);
+ return Result.success();
+ }
+
@Override
public Workbook exportImportTemplate() {
List entityList = new ArrayList<>();
+ entityList.add(new ExcelExportEntity("工会名称", "unionName", 20));
entityList.add(new ExcelExportEntity("工会编码", "unionCode", 20));
entityList.add(new ExcelExportEntity("分配额度", "allocateMoney", 20));
+ List unionList = dao().query(Sys_union.class, Cnd.NEW().asc("unionCode"));
+ List templateList = new ArrayList<>();
+ for (Sys_union union : unionList) {
+ OutlayUnionAllocateImportVo item = new OutlayUnionAllocateImportVo();
+ item.setUnionName(union.getName());
+ item.setUnionCode(union.getUnionCode());
+ templateList.add(item);
+ }
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
- return ExcelExportUtil.exportExcel(exportParams, entityList, new ArrayList<>());
+ return ExcelExportUtil.exportExcel(exportParams, entityList, templateList);
}
@Override
@@ -220,7 +264,7 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl 0) {
- return Result.error("当前季度已分配,如需重新分配请点击重置分配记录!");
+ return Result.error("当前分配项目已分配,如需重新分配请点击重置分配记录!");
}
- // 第一季度需要承接上一年度剩余额度,其余季度承接当年预算额度,确保生成记录时的分配前额度准确。
+ // 第一个会费项目需要承接上一年度剩余额度,其余项目承接当年预算额度,确保生成记录时的分配前额度准确。
Integer sourceYear = quarterly == 1 ? year - 1 : year;
List outlayManageUnionList = dao().query(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getYear, "=", sourceYear));
@@ -270,10 +314,10 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl allocateUnionList = dao().query(OutLayAllocateUnion.class,
+ Cnd.where(OutLayAllocateUnion::getUnionId, "=", allocateUnion.getUnionId())
+ .and(OutLayAllocateUnion::getYear, "=", allocateUnion.getYear())
+ .and(OutLayAllocateUnion::getDelFlag, "=", false));
+ BigDecimal allocatedTotalMoney = allocateUnionList.stream()
+ .map(OutLayAllocateUnion::getAllocateMoney)
+ .map(this::defaultValue)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+ BigDecimal nonAllocateMoney = defaultValue(manageUnion.getTotalQuota()).subtract(allocatedTotalMoney);
+ if (nonAllocateMoney.compareTo(BigDecimal.ZERO) == 0) {
+ return headMoney;
+ }
+ return BigDecimal.ZERO;
+ }
+
/**
* 当前年份预算表不存在时,按“分配前额度 + 本次分配额度”创建年度预算记录。
*
- * @param allocateUnion 当前季度分配记录,allocateHeadMoney 表示生成记录时的剩余额度快照
- * @param allocateMoney 本次要设置的季度分配额度
+ * @param allocateUnion 当前分配项目记录,allocateHeadMoney 表示生成记录时的剩余额度快照
+ * @param allocateMoney 本次要设置的分配项目额度
* @return OutlayManageUnion 新建的年度预算实体
*/
private OutlayManageUnion buildManageUnion(OutLayAllocateUnion allocateUnion, BigDecimal allocateMoney) {
@@ -347,38 +427,55 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl 待插入的季度分配记录
+ * @return List 待插入的分配项目记录
*/
private List buildAllocateUnionList(List outlayManageUnionList, Integer quarterly, Integer year) {
List unionList = dao().query(Sys_union.class, Cnd.NEW());
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionAllocateController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionAllocateController.java
index 7ffa4b90..9f0c9ffa 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionAllocateController.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionAllocateController.java
@@ -38,13 +38,13 @@ import java.util.List;
/**
* @author zhf
* @date 2026/2/3 11:12
- * @description 分工会经费分配
+ * @description 分工会经费分配项目管理
*/
@IocBean
@At("/platform/outlay/outlayManage/unionAllocate")
@Ok("json:full")
@Slf4j
-@Api(tags = "分工会经费分配")
+@Api(tags = "分工会经费分配项目管理")
public class OutlayManageUnionAllocateController {
@Inject
@@ -100,11 +100,13 @@ public class OutlayManageUnionAllocateController {
@At
@ApiOperation("一键批量分配所有工会额度")
@Aop(TransAop.READ_COMMITTED)
- @SLog(tag = "分工会预算-季度预算分配", msg = "一键批量分配所有工会额度")
+ @SLog(tag = "分工会预算-分配项目预算分配", msg = "一键批量分配所有工会额度")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result doBatchAllocate(@Param("allocateMoney") BigDecimal allocateMoney,
@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
+ // 参数说明:allocateMoney 为本次写入的分配额度;quarterly 承载 OUTLAY_QUARTERLY 字典编码,对应会费、评优奖励等分配项目;year 为预算年度。
+ // 返回 Result,成功时前端刷新列表,失败时 msg 字段用于页面提示。
if (allocateMoney == null || quarterly == null || year == null) {
return Result.error("参数错误!");
}
@@ -112,7 +114,7 @@ public class OutlayManageUnionAllocateController {
}
@At
- @ApiOperation("校验当前季度是否已分配额度")
+ @ApiOperation("校验当前分配项目是否已分配额度")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result hasAllocated(@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
@@ -139,11 +141,13 @@ public class OutlayManageUnionAllocateController {
@At
@ApiOperation("导入分配分工会额度")
@Aop(TransAop.READ_COMMITTED)
- @SLog(tag = "分工会预算-季度预算分配", msg = "导入分配分工会额度")
+ @SLog(tag = "分工会预算-分配项目预算分配", msg = "导入分配分工会额度")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result doImportAllocate(String data,
@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
+ // 参数说明:data 为导入预览行 JSON;quarterly 为分配项目字典编码;year 为预算年度。
+ // 返回 Result,成功表示导入额度已同步到分配项目记录和年度预算表,失败时 msg 字段返回具体校验原因。
if (StrUtil.isBlank(data) || quarterly == null || year == null) {
return Result.error("参数错误!");
}
@@ -151,6 +155,22 @@ public class OutlayManageUnionAllocateController {
return outlayManageUnionAllocateService.doImportAllocate(importList, quarterly, year);
}
+ @At
+ @ApiOperation("新增单个分工会评优奖励")
+ @Aop(TransAop.READ_COMMITTED)
+ @SLog(tag = "分工会预算-分配项目预算分配", msg = "新增单个分工会评优奖励")
+ @SaCheckPermission("outlay.outlayManage.union.allocate")
+ public Result doAddAwardAllocate(@Param("year") Integer year,
+ @Param("unionId") String unionId,
+ @Param("allocateMoney") BigDecimal allocateMoney) {
+ // 参数说明:year 为预算年度;unionId 为分工会 ID;allocateMoney 为本次新增的评优奖励金额。
+ // 返回 Result,成功后前端刷新分配列表;失败时 msg 字段返回参数或重复新增等校验原因。
+ if (year == null || StrUtil.isBlank(unionId) || allocateMoney == null) {
+ return Result.error("参数错误!");
+ }
+ return outlayManageUnionAllocateService.doAddAwardAllocate(year, unionId, allocateMoney);
+ }
+
@At
@Ok("void")
@ApiOperation("下载导入分配模板")
@@ -166,12 +186,13 @@ public class OutlayManageUnionAllocateController {
@At
- @ApiOperation("重置预算季度记录")
+ @ApiOperation("重置预算分配记录")
@Aop(TransAop.READ_COMMITTED)
- @SLog(tag = "分工会预算-季度预算分配", msg = "重置预算季度记录")
+ @SLog(tag = "分工会预算-分配项目预算分配", msg = "重置预算分配记录")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result deleteAllocateRecord(@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
+ // 参数说明:quarterly 为当前要重置的分配项目编码,year 为预算年度;返回 Result 用于提示重置是否成功。
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
@@ -179,11 +200,13 @@ public class OutlayManageUnionAllocateController {
}
@At
- @ApiOperation("预算季度记录生成")
- @SLog(tag = "分工会预算-季度预算分配", msg = "生成了预算分配记录")
+ @ApiOperation("预算分配记录生成")
+ @Aop(TransAop.READ_COMMITTED)
+ @SLog(tag = "分工会预算-分配项目预算分配", msg = "生成了预算分配记录")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result doAllocateRecord(@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
+ // 参数说明:quarterly 为本次生成记录的分配项目编码,year 为预算年度;返回 Result 用于前端提示生成结果。
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionIncomeExpenseController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionIncomeExpenseController.java
new file mode 100644
index 00000000..53e6b90f
--- /dev/null
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionIncomeExpenseController.java
@@ -0,0 +1,142 @@
+package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.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.hutool.core.date.DateUtil;
+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.service.BaseService;
+import com.budwk.app.base.utils.CommonDownloadUtil;
+import com.budwk.app.web.commons.auth.utils.AuthUtil;
+import com.budwk.app.web.commons.auth.utils.SecurityUtil;
+import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo.OutlayUnionIncomeExpenseVO;
+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.dao.Cnd;
+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.Strings;
+import org.nutz.mvc.annotation.At;
+import org.nutz.mvc.annotation.Ok;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 二级分工会经费收支使用情况表。
+ */
+@IocBean
+@At("/platform/outlay/outlayManage/unionIncomeExpense")
+@Ok("json:full")
+@Slf4j
+@Api(tags = "二级分工会经费收支使用情况表")
+public class OutlayManageUnionIncomeExpenseController {
+
+ @Inject
+ private BaseService baseService;
+
+ @At("")
+ @Ok("beetl:/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html")
+ @SaCheckPermission("outlay.outlayManage.union.incomeExpense")
+ public void index() {
+ }
+
+ @At
+ @ApiOperation("分页查询")
+ @SaCheckPermission("outlay.outlayManage.union.incomeExpense")
+ public Result pageData(PageForm pageForm, Integer year, String unionId) {
+ Sql sql = buildIncomeExpenseSql(year, unionId);
+ Pagination pagination = baseService.listPageVO(pageForm, sql, OutlayUnionIncomeExpenseVO.class);
+ return Result.success(pagination);
+ }
+
+ @At
+ @Ok("void")
+ @ApiOperation("导出")
+ @SaCheckPermission("outlay.outlayManage.union.incomeExpense")
+ public void doExport(Integer year, String unionId, HttpServletResponse response) {
+ Integer queryYear = getQueryYear(year);
+ Sql sql = buildIncomeExpenseSql(queryYear, unionId);
+ List list = baseService.listVO(sql, OutlayUnionIncomeExpenseVO.class);
+
+ ArrayList entities = new ArrayList<>();
+ entities.add(new ExcelExportEntity("单位", "unionName", 25));
+ entities.add(new ExcelExportEntity("年初数", "beginMoney", 20));
+ entities.add(new ExcelExportEntity("1-4月会费", "feeJanApr", 20));
+ entities.add(new ExcelExportEntity("5-8月会费", "feeMayAug", 20));
+ entities.add(new ExcelExportEntity("9-12月会费", "feeSepDec", 20));
+ entities.add(new ExcelExportEntity("评优奖励", "awardMoney", 20));
+ entities.add(new ExcelExportEntity("1-12月支出", "usedMoney", 20));
+ entities.add(new ExcelExportEntity("经费余额", "remainMoney", 20));
+
+ ExportParams exportParams = new ExportParams();
+ exportParams.setType(ExcelType.XSSF);
+ Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, list);
+ CommonDownloadUtil.download(queryYear + "年二级分工会经费收支使用情况表.xlsx", workbook, response);
+ }
+
+ /**
+ * 统计参数说明:
+ * year 为统计年度,未传时默认当前年份;unionId 为二级分工会主键,管理员可为空查询全部。
+ * 返回 VO 中 beginMoney 是年初数,feeJanApr/feeMayAug/feeSepDec 是三个会费收入段,
+ * awardMoney 是评优奖励,usedMoney 是年度支出,remainMoney 是当前经费余额。
+ */
+ private Sql buildIncomeExpenseSql(Integer year, String unionId) {
+ Sql sql = Sqls.create("""
+ SELECT
+ mu.year AS year,
+ mu.unionId AS unionId,
+ COALESCE(mu.unionName, su.name) AS unionName,
+ COALESCE(mu.unionCode, su.unionCode) AS unionCode,
+ COALESCE(SUM(CASE WHEN au.quarterly = 1 THEN au.allocateHeadMoney ELSE 0 END), 0) AS beginMoney,
+ COALESCE(SUM(CASE WHEN au.quarterly = 1 THEN au.allocateMoney ELSE 0 END), 0) AS feeJanApr,
+ COALESCE(SUM(CASE WHEN au.quarterly = 2 THEN au.allocateMoney ELSE 0 END), 0) AS feeMayAug,
+ COALESCE(SUM(CASE WHEN au.quarterly = 3 THEN au.allocateMoney ELSE 0 END), 0) AS feeSepDec,
+ COALESCE(SUM(CASE WHEN au.quarterly = 4 THEN au.allocateMoney ELSE 0 END), 0) AS awardMoney,
+ COALESCE(mu.usedQuota, 0) AS usedMoney,
+ COALESCE(mu.totalQuota, 0) - COALESCE(mu.usedQuota, 0) AS remainMoney
+ FROM outlay_manage_union mu
+ LEFT JOIN sys_union su ON su.id = mu.unionId
+ LEFT JOIN outlay_allocate_union au ON au.year = mu.year
+ AND au.unionId = mu.unionId
+ AND au.delFlag = 0
+ $condition
+ """);
+ Cnd cnd = Cnd.NEW();
+ cnd.and("mu.delFlag", "=", false);
+ cnd.and("mu.year", "=", getQueryYear(year));
+ cnd.and("mu.totalQuota", "IS NOT", null);
+ cnd.andEX("mu.unionId", "=", unionId);
+ if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
+ cnd.and("mu.unionId", "=", SecurityUtil.getUnionId());
+ }
+ cnd.groupBy("mu.year");
+ cnd.groupBy("mu.unionId");
+ cnd.groupBy("mu.unionName");
+ cnd.groupBy("mu.unionCode");
+ cnd.groupBy("su.name");
+ cnd.groupBy("su.unionCode");
+ cnd.groupBy("mu.usedQuota");
+ cnd.groupBy("mu.totalQuota");
+ cnd.asc("mu.unionCode");
+ sql.setCondition(cnd);
+ return sql;
+ }
+
+ private Integer getQueryYear(Integer year) {
+ if (year != null) {
+ return year;
+ }
+ return DateUtil.thisYear();
+ }
+}
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionUseDetailController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionUseDetailController.java
index f5f0d912..c4948be5 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionUseDetailController.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/controller/OutlayManageUnionUseDetailController.java
@@ -116,7 +116,7 @@ public class OutlayManageUnionUseDetailController {
}
@At
- @ApiOperation("查询分工会今年每个季度的分配情况")
+ @ApiOperation("查询分工会今年每个分配项目的分配情况")
@SaCheckPermission("outlay.outlayManage.union.useDetail")
public Result queryQuarterlyList(Integer year, String unionId){
Sql sql = Sqls.create("""
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/model/OutLayAllocateUnion.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/model/OutLayAllocateUnion.java
index 532995ad..fcce0286 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/model/OutLayAllocateUnion.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/model/OutLayAllocateUnion.java
@@ -37,7 +37,7 @@ public class OutLayAllocateUnion extends BaseModel implements Serializable {
private String unionId;
@Column
- @Comment("季度")
+ @Comment("分配项目")
@ColDefine(type = ColType.INT)
private Integer quarterly;
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionAllocateImportVo.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionAllocateImportVo.java
index 0390f0f6..7c2297ee 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionAllocateImportVo.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionAllocateImportVo.java
@@ -6,22 +6,20 @@ import lombok.Data;
import java.math.BigDecimal;
/**
- * 分工会季度额度导入行数据。
+ * 分工会分配项目额度导入行数据。
*/
@Data
public class OutlayUnionAllocateImportVo {
+ @Excel(name = "工会名称")
+ private String unionName;
+
@Excel(name = "工会编码")
private String unionCode;
@Excel(name = "分配额度")
private BigDecimal allocateMoney;
- /**
- * 预览时展示匹配到的工会名称。
- */
- private String unionName;
-
/**
* 预览时展示当前行错误信息。
*/
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionIncomeExpenseVO.java b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionIncomeExpenseVO.java
new file mode 100644
index 00000000..f4abf90a
--- /dev/null
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/outlay/outlayManage/union/vo/OutlayUnionIncomeExpenseVO.java
@@ -0,0 +1,34 @@
+package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 二级分工会经费收支使用情况表数据。
+ */
+@Data
+public class OutlayUnionIncomeExpenseVO {
+
+ private Integer year;
+
+ private String unionId;
+
+ private String unionName;
+
+ private String unionCode;
+
+ private BigDecimal beginMoney;
+
+ private BigDecimal feeJanApr;
+
+ private BigDecimal feeMayAug;
+
+ private BigDecimal feeSepDec;
+
+ private BigDecimal awardMoney;
+
+ private BigDecimal usedMoney;
+
+ private BigDecimal remainMoney;
+}
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/controller/UnionReimburseCollectController.java b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/controller/UnionReimburseCollectController.java
index 766f6aff..ae499ab4 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/controller/UnionReimburseCollectController.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/controller/UnionReimburseCollectController.java
@@ -111,8 +111,6 @@ public class UnionReimburseCollectController {
cnd.and(seg);
}
- cnd.and("info.stateId", "in", List.of(3, 2));
-
applyListSort(cnd, pageForm);
sql.setCondition(cnd);
Pagination pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
@@ -185,29 +183,26 @@ public class UnionReimburseCollectController {
@Ok("void")
@SaCheckPermission(value = {"unionReimburse.collect", "h5.unionReimburse.collect"}, mode = SaMode.OR)
@ApiOperation("导出报销汇总表")
- public void onExport(@Param(value = "year") Integer year,
+ public void onExport(PageForm pageForm,
+ @Param(value = "year") Integer year,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId,
@Param(value = "reimburseProject") String reimburseProject,
- @Param(value = "userName") String userName,
+ @Param(value = "searchKeyword") String searchKeyword,
HttpServletResponse response) {
- //查询审核通过的数据
+ // 导出复用收集列表筛选口径,保证下载结果与页面当前查询条件一致。
Sql sql = Sqls.create("""
SELECT
- t1.*,
- ins.state instanceState
+ info.*
FROM
- union_reimburse t1
- LEFT JOIN `wf_process_instance` ins ON ins.businessNo = t1.id
+ union_reimburse info
$condition
""");
- Cnd cnd = buildCondition(year, unionId, unitId, reimburseProject, userName, "t1.");
- // 只查询流程实例状态为20的数据(已完成状态)
- cnd.and("ins.state", "=", 20);
+ Cnd cnd = buildCondition(year, unionId, unitId, reimburseProject, searchKeyword, "info.");
if (!isAdmin()) {
- cnd.andEX("t1.unionId", "=", SecurityUtil.getUnionId());
+ cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
}
- cnd.desc("t1.createTime");
+ applyListSort(cnd, pageForm);
sql.setCondition(cnd);
List list = unionReimburseService.listVO(sql,UnionReimburseCollectExcelVO.class);
@@ -242,11 +237,13 @@ public class UnionReimburseCollectController {
item.setCreateTime(DateUtil.format(DateUtil.parse(item.getCreateTime()), "yyyy-MM-dd HH:mm:ss"));
}
- // 拼接备注字段(仿照系统代码逻辑,使用activityName和condolenceName字段)
+ item.setStateName(formatStateName(item.getStateId()));
+
+ // 备注字段与页面表格保持一致:慰问显示被慰问人,其他项目显示活动名称。
if (cn.hutool.core.util.StrUtil.isNotBlank(item.getActivityName())) {
item.setRemark("活动名称:" + item.getActivityName());
- } else if (cn.hutool.core.util.StrUtil.isNotBlank(item.getCondolenceName())) {
- item.setRemark("慰问对象:" + item.getCondolenceName());
+ } else if (cn.hutool.core.util.StrUtil.isNotBlank(item.getCondolenceUserName())) {
+ item.setRemark("被慰问人:" + item.getCondolenceUserName());
}
});
@@ -263,12 +260,12 @@ public class UnionReimburseCollectController {
* @param unionId 工会ID
* @param unitId 单位ID
* @param reimburseProject 报销项目
- * @param userName 经办人姓名
+ * @param searchKeyword 经办人姓名或工号
* @param prefix 表前缀
* @return 查询条件
*/
private Cnd buildCondition(Integer year, String unionId, String unitId,
- String reimburseProject, String userName, String prefix) {
+ String reimburseProject, String searchKeyword, String prefix) {
Cnd cnd = Cnd.NEW();
// 年度查询条件
@@ -281,9 +278,12 @@ public class UnionReimburseCollectController {
// 报销项目查询条件
cnd.andEX(prefix + "reimburseProject", "=", reimburseProject);
- // 经办人姓名查询条件
- if (StrUtil.isNotBlank(userName)) {
- cnd.and(prefix + "userName", "like", "%" + userName + "%");
+ // 经办人姓名或工号查询条件
+ if (StrUtil.isNotBlank(searchKeyword)) {
+ SqlExpressionGroup seg = new SqlExpressionGroup();
+ seg.orLike(prefix + "userName", searchKeyword);
+ seg.orLike(prefix + "loginName", searchKeyword);
+ cnd.and(seg);
}
return cnd;
@@ -318,4 +318,18 @@ public class UnionReimburseCollectController {
default -> null;
};
}
+
+ private String formatStateName(Integer stateId) {
+ if (stateId == null) {
+ return "";
+ }
+ return switch (stateId) {
+ case 1 -> "待提交";
+ case 2 -> "待审核确认";
+ case 3 -> "报销成功";
+ case 4 -> "拒绝";
+ case 5 -> "退回";
+ default -> String.valueOf(stateId);
+ };
+ }
}
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/model/UnionReimburse.java b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/model/UnionReimburse.java
index d4235db4..665ee424 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/model/UnionReimburse.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/model/UnionReimburse.java
@@ -175,6 +175,11 @@ public class UnionReimburse extends BaseModel {
@ColDefine(type = ColType.VARCHAR, width = 100)
private String bankOfDeposit;
+ @Column
+ @Comment("支付明细")
+ @ColDefine(type = ColType.MYSQL_JSON)
+ private List paymentDetails;
+
/**
* 慰问
*/
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/service/impl/UnionReimburseServiceImpl.java b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/service/impl/UnionReimburseServiceImpl.java
index ea0718ae..dfa08007 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/service/impl/UnionReimburseServiceImpl.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/service/impl/UnionReimburseServiceImpl.java
@@ -369,13 +369,15 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl i
if (Integer.valueOf(3).equals(dbRecord.getStateId())) {
return Result.success();
}
- Result validateResult = validateFundSourceBeforeSubmit(dbRecord);
- if (validateResult != null) {
- return validateResult;
- }
- Result deductResult = deductBudgetAndSaveUseDetail(dbRecord);
- if (deductResult != null && deductResult.getCode() != 0) {
- return deductResult;
+ if (!skipBudgetDeduct(dbRecord)) {
+ Result validateResult = validateFundSourceBeforeSubmit(dbRecord);
+ if (validateResult != null) {
+ return validateResult;
+ }
+ Result deductResult = deductBudgetAndSaveUseDetail(dbRecord);
+ if (deductResult != null && deductResult.getCode() != 0) {
+ return deductResult;
+ }
}
}
dbRecord.setReviewTime(new Date());
@@ -422,7 +424,7 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl i
if (dbRecord == null) {
return Result.error("未找到对应的报销记录");
}
- if (Integer.valueOf(3).equals(dbRecord.getStateId())) {
+ if (Integer.valueOf(3).equals(dbRecord.getStateId()) && !skipBudgetDeduct(dbRecord)) {
OutlayUseDetail oldDetail = dao().fetch(OutlayUseDetail.class, Cnd.where("outlayReimburseId", "=", dbRecord.getId()));
BigDecimal oldMoney = oldDetail != null && oldDetail.getAdjustMoney() != null
? oldDetail.getAdjustMoney()
@@ -652,6 +654,16 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl i
return Result.error("不支持的经费来源");
}
+ /**
+ * 慰问和专项活动费用不占用经费预算,审核通过及后续调整实际金额时都不写预算台账。
+ */
+ private boolean skipBudgetDeduct(UnionReimburse unionReimburse) {
+ return unionReimburse != null && Set.of(
+ "UNION_REIMBURSE_PROJECT_1",
+ "UNION_REIMBURSE_PROJECT_4"
+ ).contains(unionReimburse.getReimburseProject());
+ }
+
/**
* 已通过报销单修改实际金额时,用差额同步预算主表和使用明细,避免重复全量扣减。
*/
diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/vo/UnionReimburseCollectExcelVO.java b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/vo/UnionReimburseCollectExcelVO.java
index 83400096..5030099b 100644
--- a/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/vo/UnionReimburseCollectExcelVO.java
+++ b/src/main/java/com/budwk/app/zhgh/dayofficework/unionReimburse/vo/UnionReimburseCollectExcelVO.java
@@ -22,23 +22,30 @@ public class UnionReimburseCollectExcelVO implements Serializable {
@Excel(name = "所属单位", width = 20)
private String unitName;
+ @Excel(name = "申请时间", width = 30)
+ private String createTime;
+
@Excel(name = "报销项目", width = 20)
private String reimburseProject;
@Excel(name = "备注", width = 20)
private String remark;
- @Excel(name = "金额", width = 20)
+ @Excel(name = "申请状态", width = 20)
+ private String stateName;
+
private Double money;
- @Excel(name = "申请时间", width = 30)
- private String createTime;
+ private Integer stateId;
private String reimburseFundSource;
//活动名称
private String activityName;
+ //被慰问人姓名
+ private String condolenceUserName;
+
//被慰问人
private String condolenceName;
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/allocate/index.html b/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/allocate/index.html
index 9ea27294..8bb2ec53 100644
--- a/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/allocate/index.html
+++ b/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/allocate/index.html
@@ -18,9 +18,9 @@ layout("/layouts/platform.html"){
value-format="yyyy">
-
+
@@ -42,10 +42,13 @@ layout("/layouts/platform.html"){
一键分配
- 季度记录生成
+
+ 新增评优奖励
+
+ 分配记录生成
- 重置季度记录
+ 重置分配记录
-
- 将Excel文件拖到此处,或点击上传
+ :file-list="importFileList">
+ 点击上传
@@ -152,6 +153,41 @@ layout("/layouts/platform.html"){
确 定
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -170,48 +206,62 @@ layout("/layouts/platform.html"){
unionList: [],
tableColumns: [
{prop: 'year', label: '年度'},
- {prop: 'quarterly', label: '季度'},
+ {prop: 'quarterly', label: '分配项目'},
{prop: 'unionName', label: '工会名称'},
{prop: 'allocateHeadMoney', label: '分配前额度'},
{prop: 'allocateMoney', label: '分配额度'},
],
- quarterlyList: [],
+ periodList: [],
batchAllocateDialogVisible: false,
batchAllocateForm: {
allocateMode: "uniform",
allocateMoney: 0,
importPreviewList: []
},
- importFileList: []
+ importFileList: [],
+ awardAllocateDialogVisible: false,
+ awardAllocateForm: {
+ year: this.$moment().format("YYYY"),
+ unionId: "",
+ allocateMoney: 0
+ }
}
},
methods: {
/**
- * 确认提示文案优先展示页面当前筛选季度。
- * 未选择季度时再回退到系统当前自然季度,避免提示文案与用户当前查看条件不一致。
+ * 确认提示文案优先展示页面当前筛选的分配项目名称。
+ * 未选择分配项目时再回退到当前会费项目,避免提示文案与用户当前查看条件不一致。
*/
- getPromptQuarter() {
- return this.pageForm.quarterly || this.$moment().quarter()
+ getPromptProjectName() {
+ return this.getProjectName(this.pageForm.quarterly || this.getCurrentFeeProject())
},
/**
- * 季度记录生成、重置记录都要按页面当前筛选的年度和季度执行。
- * 这里统一封装请求参数,避免前后端再次出现“提示季度”和“实际执行季度”不一致的问题。
+ * 分配记录生成、重置记录都要按页面当前筛选的年度和分配项目执行。
+ * quarterly 参数承载 OUTLAY_QUARTERLY 字典编码,例如 1-4月会费、5-8月会费、9-12月会费、评优奖励。
*/
- getCurrentQuarterParams() {
+ getCurrentProjectParams() {
return {
- quarterly: this.pageForm.quarterly || this.$moment().quarter(),
+ quarterly: this.pageForm.quarterly || this.getCurrentFeeProject(),
year: this.pageForm.year
}
},
/**
- * 生成、重置、一键分配都只允许操作当前自然季度。
- * 这里统一做前端入口校验,避免同类判断分散在多个按钮方法里难维护。
+ * 生成、重置、一键分配都只允许操作当前会费项目。
+ * 当前会费项目按月份划分:1-4月会费、5-8月会费、9-12月会费。
*/
- validateCurrentQuarterAction(actionName) {
- const currentQuarter = this.$moment().quarter()
- const selectedQuarter = Number(this.getCurrentQuarterParams().quarterly)
- if (selectedQuarter !== currentQuarter) {
- this.$message.warning('当前仅允许操作第' + currentQuarter + '季度' + actionName + ',请切换后再操作')
+ getCurrentFeeProject() {
+ return Math.floor(this.$moment().month() / 4) + 1
+ },
+ getProjectName(code) {
+ const options = this.dict.type.OUTLAY_QUARTERLY || []
+ const project = options.find((item) => String(item.code || item.value || item.dictValue) === String(code))
+ return project ? (project.label || project.name || project.dictLabel || code) : code
+ },
+ validateCurrentProjectAction(actionName) {
+ const currentProject = this.getCurrentFeeProject()
+ const selectedProject = Number(this.getCurrentProjectParams().quarterly)
+ if (selectedProject !== currentProject) {
+ this.$message.warning('当前仅允许操作【' + this.getProjectName(currentProject) + '】' + actionName + ',请切换后再操作')
return false
}
return true
@@ -237,7 +287,7 @@ layout("/layouts/platform.html"){
})
},
deleteAllocateRecord() {
- if (!this.validateCurrentQuarterAction('记录重置')) {
+ if (!this.validateCurrentProjectAction('记录重置')) {
return
}
// 重置动作以当前列表是否已有记录为前置条件,避免用户在空列表场景下误操作。
@@ -245,13 +295,13 @@ layout("/layouts/platform.html"){
this.$message.warning('当前列表无可重置记录')
return
}
- this.$confirm('确定要重置【第' + this.getPromptQuarter() + '季度】的预算记录吗?', '提示', {
+ this.$confirm('确定要重置【' + this.getPromptProjectName() + '】的预算记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.formLoading = true
- this.$axios.post("/platform/outlay/outlayManage/unionAllocate/deleteAllocateRecord", this.getCurrentQuarterParams()).then((resp) => {
+ this.$axios.post("/platform/outlay/outlayManage/unionAllocate/deleteAllocateRecord", this.getCurrentProjectParams()).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
@@ -262,16 +312,16 @@ layout("/layouts/platform.html"){
})
},
doAllocateRecord() {
- if (!this.validateCurrentQuarterAction('记录生成')) {
+ if (!this.validateCurrentProjectAction('记录生成')) {
return
}
- this.$confirm('确定要生成【第' + this.getPromptQuarter() + '季度】的预算记录吗?', '提示', {
+ this.$confirm('确定要生成【' + this.getPromptProjectName() + '】的预算记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.formLoading = true
- this.$axios.post("/platform/outlay/outlayManage/unionAllocate/doAllocateRecord", this.getCurrentQuarterParams()).then((resp) => {
+ this.$axios.post("/platform/outlay/outlayManage/unionAllocate/doAllocateRecord", this.getCurrentProjectParams()).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
@@ -282,14 +332,14 @@ layout("/layouts/platform.html"){
})
},
showBatchAllocateDialog() {
- if (!this.validateCurrentQuarterAction('一键分配')) {
+ if (!this.validateCurrentProjectAction('一键分配')) {
return
}
if (this.tableData.length === 0) {
- this.$message.warning('当前没有可分配的工会记录,请先生成季度记录')
+ this.$message.warning('当前没有可分配的工会记录,请先生成分配记录')
return
}
- const currentParams = this.getCurrentQuarterParams()
+ const currentParams = this.getCurrentProjectParams()
const openDialog = () => {
this.resetBatchAllocateForm()
this.batchAllocateDialogVisible = true
@@ -302,7 +352,7 @@ layout("/layouts/platform.html"){
return
}
if (resp.data) {
- this.$confirm('温馨提示:当前季度已分配过额度,再次分配将覆盖本季度原有分配结果,是否继续?', '温馨提示', {
+ this.$confirm('温馨提示:当前分配项目已分配过额度,再次分配将覆盖本项目原有分配结果,是否继续?', '温馨提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning'
@@ -323,6 +373,46 @@ layout("/layouts/platform.html"){
}
this.importFileList = []
},
+ showAwardAllocateDialog() {
+ this.$set(this.awardAllocateForm, "year", this.pageForm.year)
+ this.$set(this.awardAllocateForm, "unionId", this.pageForm.unionId || "")
+ this.$set(this.awardAllocateForm, "allocateMoney", 0)
+ this.$set(this, "awardAllocateDialogVisible", true)
+ },
+ closeAwardAllocateDialog() {
+ this.$set(this, "awardAllocateDialogVisible", false)
+ },
+ doAddAwardAllocate() {
+ if (!this.awardAllocateForm.year) {
+ this.$message.warning("请选择年度")
+ return
+ }
+ if (!this.awardAllocateForm.unionId) {
+ this.$message.warning("请选择所属工会")
+ return
+ }
+ if (!this.awardAllocateForm.allocateMoney || this.awardAllocateForm.allocateMoney <= 0) {
+ this.$message.warning("请输入有效的评优奖励金额")
+ return
+ }
+ this.formLoading = true
+ this.$axios.post("/platform/outlay/outlayManage/unionAllocate/doAddAwardAllocate", {
+ year: this.awardAllocateForm.year,
+ unionId: this.awardAllocateForm.unionId,
+ allocateMoney: this.awardAllocateForm.allocateMoney
+ }).then((resp) => {
+ if (resp.code === 0) {
+ this.$message.success(resp.msg)
+ this.closeAwardAllocateDialog()
+ this.$set(this.pageForm, "year", this.awardAllocateForm.year)
+ this.$set(this.pageForm, "quarterly", "4")
+ this.$set(this.pageForm, "unionId", this.awardAllocateForm.unionId)
+ this.doSearch()
+ }
+ }).finally(() => {
+ this.formLoading = false
+ })
+ },
downloadImportTemplate() {
this.$downLoad("/platform/outlay/outlayManage/unionAllocate/downloadImportTemplate")
},
@@ -349,7 +439,7 @@ layout("/layouts/platform.html"){
this.$set(this.batchAllocateForm, "importPreviewList", [])
},
doBatchAllocate() {
- const currentParams = this.getCurrentQuarterParams()
+ const currentParams = this.getCurrentProjectParams()
if (this.batchAllocateForm.allocateMode === "uniform") {
if (!this.batchAllocateForm.allocateMoney || this.batchAllocateForm.allocateMoney <= 0) {
this.$message.warning('请输入有效的分配额度')
@@ -401,8 +491,8 @@ layout("/layouts/platform.html"){
this.unionList = data
})
this.$businessTool.getDictOptions("OUTLAY_QUARTERLY").then((data) => {
- let quarter = this.$moment().quarter();
- this.$set(this.pageForm, "quarterly", data[quarter - 1].code)
+ let project = this.getCurrentFeeProject();
+ this.$set(this.pageForm, "quarterly", data[project - 1].code)
this.pageData()
})
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html b/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html
new file mode 100644
index 00000000..11cd4393
--- /dev/null
+++ b/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/incomeExpense/index.html
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/useDetail/quarterlyOutlayAllocate.js b/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/useDetail/quarterlyOutlayAllocate.js
index 98a5a2ac..4d5d5226 100644
--- a/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/useDetail/quarterlyOutlayAllocate.js
+++ b/src/main/resources/views/platform/zhgh/dayofficework/outlay/outlayManage/union/useDetail/quarterlyOutlayAllocate.js
@@ -4,10 +4,10 @@ let OUTLAY_MANAGE_UNION_QUARTERLY_ALLOCATE = {
`
-
+
-
+
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/apply/index.html b/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/apply/index.html
index f8e372bb..8f78dde1 100644
--- a/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/apply/index.html
+++ b/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/apply/index.html
@@ -43,472 +43,557 @@ layout("/layouts/platform.html"){
line-height: 22px;
margin-bottom: 6px;
}
+
+ .payment-info-table .el-form-item {
+ margin-bottom: 0;
+ }
- 慰问申请
- 文体活动申请
- 日常活动申请
- 专项活动申请
+
+ 慰问申请
+
+ 文体活动申请
+
+ 日常活动申请
+
+ 专项活动申请
-
-
+
+
-
- 校工会经费
- 分工会经费
- 协会经费
-
-
+
+ 校工会经费
+
+ 分工会经费
+
+ 协会经费
+
+
+
-
+
-
+
{{item.name}}
-
-
-
-
- {{item.name}}
-
-
+ {{formData.userName}}({{formData.loginName}})
+
+
+
+
+
+
+
- {{formData.loginName}}
- {{formData.userName}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ 新增支付信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 无需填写
+
+
+
+
+
+
+
+
+
+
+ 无需填写
+
+
+
+
+
+
+
+
+
+
+ 无需填写
+
+
+
+
+
+
+
+
+
+
+ 无需填写
+
+
+
+
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 附件
-
-
-
-
-
-
- {{ formData.condolenceFilesNotes || getFileDescByProject(formData.reimburseProject) || '需要提供购买的慰问品发票,慰问照片' }}
-
-
-
- {{ getFileDescByProject(formData.reimburseProject) || '请上传活动照片、参加人员名单、付款凭证等相关材料' }}
-
-
-
-
-
-
-
-
+
+
+ 附件
+
+
+
+
+
+
+ {{ formData.condolenceFilesNotes || getFileDescByProject(formData.reimburseProject)
+ || '需要提供购买的慰问品发票,慰问照片' }}
+
+
+
+
+ {{ getFileDescByProject(formData.reimburseProject) || '请上传活动照片、参加人员名单、付款凭证等相关材料'
+ }}
+
+
+
+
+
+
+
+
@@ -523,7 +608,8 @@ layout("/layouts/platform.html"){
发票张数
-
+
@@ -548,7 +634,9 @@ layout("/layouts/platform.html"){
active-text="自动校验"
inactive-text="手工录入">
- 新增发票
+ 新增发票
+
@@ -564,13 +652,16 @@ layout("/layouts/platform.html"){
-
-
+
+
-
+
编辑
@@ -586,7 +677,9 @@ layout("/layouts/platform.html"){
保存
- 下一步
+
+ 下一步
+
提交
提交
@@ -671,7 +764,8 @@ layout("/layouts/platform.html"){
formData: {
reimburseType: "",
hospitalizationTimeRange: [],
- reimburseProject:'',
+ reimburseProject: '',
+ paymentDetails: [],
invoiceDetails: [],
invoiceVerifyEnabled: true
},
@@ -746,6 +840,18 @@ layout("/layouts/platform.html"){
sellerName: [{required: true, message: "请输入销售方信息名称", trigger: ["change", "blur"]}],
itemName: [{required: true, message: "请输入项目名称", trigger: ["change", "blur"]}]
},
+ paymentDetailRules: {
+ paymentWay: [{required: true, message: "请选择支付方式", trigger: ["change", "blur"]}],
+ money: [{required: true, message: "请填写金额", trigger: ["change", "blur"]}],
+ payer: [{required: true, message: "请选择付款人", trigger: ["change", "blur"]}],
+ bankUserName: [{required: true, message: "请填写户名", trigger: ["change", "blur"]}],
+ bankCardNumber: [{
+ required: true,
+ message: "请填写银行卡号",
+ trigger: ["change", "blur"]
+ }, {pattern: /^([1-9]{1})(\d{15}|\d{18})$/, message: "请输入正确的银行卡号", trigger: "blur"}],
+ bankOfDeposit: [{required: true, message: "请填写开户行", trigger: ["change", "blur"]}]
+ },
chooseType: {},
userOptions: [],
typeOptions: [],
@@ -762,6 +868,9 @@ layout("/layouts/platform.html"){
showInvoiceTab() {
return !!this.formData.reimburseProject
},
+ paymentInfoRows() {
+ return this.formData.paymentDetails || []
+ },
bankHistoryUserNames() {
const userNameMap = {}
return (this.historyData || []).reduce((result, item) => {
@@ -825,6 +934,21 @@ layout("/layouts/platform.html"){
invoiceCheckCode: ""
}
},
+ buildDefaultPaymentDetail(detail) {
+ const currentDetail = detail || {}
+ return {
+ paymentWay: currentDetail.paymentWay || "",
+ money: currentDetail.money || "",
+ payer: currentDetail.payer || null,
+ payerName: currentDetail.payerName || null,
+ payerLoginname: currentDetail.payerLoginname || null,
+ bankUserName: currentDetail.bankUserName || null,
+ bankCardNumber: currentDetail.bankCardNumber || null,
+ bankOfDeposit: currentDetail.bankOfDeposit || null,
+ payerOptions: Array.isArray(currentDetail.payerOptions) ? currentDetail.payerOptions : [],
+ historyData: Array.isArray(currentDetail.historyData) ? currentDetail.historyData : []
+ }
+ },
ensureFormData(formData) {
const nextFormData = formData || {}
if (!Array.isArray(nextFormData.invoiceDetails)) {
@@ -836,10 +960,55 @@ layout("/layouts/platform.html"){
if (typeof nextFormData.invoiceVerifyEnabled !== "boolean") {
this.$set(nextFormData, "invoiceVerifyEnabled", true)
}
+ const hasLegacyPayment = nextFormData.paymentWay || nextFormData.payer || nextFormData.bankUserName || nextFormData.bankCardNumber || nextFormData.bankOfDeposit
+ if (Array.isArray(nextFormData.paymentDetails) && nextFormData.paymentDetails.length > 0) {
+ this.$set(nextFormData, "paymentDetails", nextFormData.paymentDetails.map(item => this.buildDefaultPaymentDetail(item)))
+ } else {
+ this.$set(nextFormData, "paymentDetails", hasLegacyPayment ? [this.buildDefaultPaymentDetail({
+ paymentWay: nextFormData.paymentWay,
+ money: nextFormData.money,
+ payer: nextFormData.payer,
+ payerName: nextFormData.payerName,
+ payerLoginname: nextFormData.payerLoginname,
+ bankUserName: nextFormData.bankUserName,
+ bankCardNumber: nextFormData.bankCardNumber,
+ bankOfDeposit: nextFormData.bankOfDeposit
+ })] : [])
+ }
return nextFormData
},
- createRemoteMethodForPayer(keyword) {
- this.selectQueryUserForPayer(keyword, this.payerOptions)
+ // 判断当前支付方式是否为对私支付;对私支付才需要填写付款人和银行卡信息。
+ isPrivatePayment(row) {
+ return row && row.paymentWay === "UNION_REIMBURSE_PAYMENT_WAY_2"
+ },
+ // 切换为对公支付时清空当前行的对私支付字段,避免历史付款人和银行卡信息随申请一并提交。
+ handlePaymentWayChange(row) {
+ if (!this.isPrivatePayment(row)) {
+ this.resetPayerInfo(row)
+ this.$nextTick(() => {
+ if (this.$refs.formRef) {
+ this.$refs.formRef.clearValidate()
+ }
+ })
+ }
+ },
+ // 新增一条支付明细;每条明细保存支付方式、金额以及对私支付所需的收款信息。
+ addPaymentInfo() {
+ this.formData.paymentDetails.push(this.buildDefaultPaymentDetail())
+ },
+ // 删除指定行支付明细,保存时只提交剩余支付明细。
+ deletePaymentInfo(index) {
+ this.formData.paymentDetails.splice(index, 1)
+ this.$nextTick(() => {
+ if (this.$refs.formRef) {
+ this.$refs.formRef.clearValidate()
+ }
+ })
+ },
+ createRemoteMethodForPayer(row) {
+ return (keyword) => {
+ this.selectQueryUserForPayer(keyword, row.payerOptions)
+ }
},
selectQueryUserForPayer(keyword, options) {
options.length = 0
@@ -857,30 +1026,41 @@ layout("/layouts/platform.html"){
}
})
},
- resetPayerInfo() {
+ resetPayerInfo(row) {
+ const rows = row ? [row] : (this.formData.paymentDetails || [])
+ rows.forEach(item => {
+ this.$set(item, "payer", null)
+ this.$set(item, "payerName", null)
+ this.$set(item, "payerLoginname", null)
+ this.$set(item, "bankUserName", null)
+ this.$set(item, "bankCardNumber", null)
+ this.$set(item, "bankOfDeposit", null)
+ this.$set(item, "historyData", [])
+ this.$set(item, "payerOptions", [])
+ })
this.$set(this.formData, "payer", null)
this.$set(this.formData, "payerName", null)
this.$set(this.formData, "payerLoginname", null)
this.$set(this.formData, "bankUserName", null)
this.$set(this.formData, "bankCardNumber", null)
this.$set(this.formData, "bankOfDeposit", null)
- this.$set(this, "historyData", [])
- this.$set(this, "payerOptions", [])
},
appendCurrentPayerOption() {
- if (!this.formData.payer) {
- return
- }
- const exists = this.payerOptions.some((item) => item.id === this.formData.payer)
- if (exists) {
- return
- }
- // 远程下拉编辑回显时需要先补齐当前付款人选项,否则 el-select 只能显示已保存的 id。
- this.payerOptions.push({
- id: this.formData.payer,
- userName: this.formData.payerName || "",
- loginName: this.formData.payerLoginname || "",
- unitName: this.formData.unitName || "暂无"
+ (this.formData.paymentDetails || []).forEach(row => {
+ if (!row.payer) {
+ return
+ }
+ const exists = row.payerOptions.some((item) => item.id === row.payer)
+ if (exists) {
+ return
+ }
+ // 远程下拉编辑回显时需要先补齐当前付款人选项,否则 el-select 只能显示已保存的 id。
+ row.payerOptions.push({
+ id: row.payer,
+ userName: row.payerName || "",
+ loginName: row.payerLoginname || "",
+ unitName: this.formData.unitName || "暂无"
+ })
})
},
createRemoteMethod(options) {
@@ -897,49 +1077,59 @@ layout("/layouts/platform.html"){
})
},
// 获取用户历史银行卡信息
- getUserBankHistory() {
- if (!this.formData.payer) {
- this.historyData = [];
+ getUserBankHistory(row) {
+ if (!row.payer) {
+ this.$set(row, "historyData", [])
return;
}
this.$axios.get("/platform/unionReimburse/apply/findUserBankHistory", {
- params: { payer: this.formData.payer }
+ params: {payer: row.payer}
}).then((res) => {
if (res.code === 0) {
- this.historyData = Array.isArray(res.data) ? res.data : [];
+ this.$set(row, "historyData", Array.isArray(res.data) ? res.data : [])
} else {
console.warn("获取历史银行卡信息失败:", res);
- this.historyData = [];
+ this.$set(row, "historyData", [])
}
})
},
- fillBankInfoFromHistory() {
- const matchItem = this.historyData.find((item) => {
- if (this.formData.bankUserName && item.bankUserName !== this.formData.bankUserName) {
+ fillBankInfoFromHistory(row) {
+ const matchItem = (row.historyData || []).find((item) => {
+ if (row.bankUserName && item.bankUserName !== row.bankUserName) {
return false
}
- if (this.formData.bankCardNumber && item.bankCardNumber !== this.formData.bankCardNumber) {
+ if (row.bankCardNumber && item.bankCardNumber !== row.bankCardNumber) {
return false
}
- if (this.formData.bankOfDeposit && item.bankOfDeposit !== this.formData.bankOfDeposit) {
+ if (row.bankOfDeposit && item.bankOfDeposit !== row.bankOfDeposit) {
return false
}
return true
})
if (matchItem) {
- this.$set(this.formData, "bankUserName", matchItem.bankUserName)
- this.$set(this.formData, "bankCardNumber", matchItem.bankCardNumber)
- this.$set(this.formData, "bankOfDeposit", matchItem.bankOfDeposit)
+ this.$set(row, "bankUserName", matchItem.bankUserName)
+ this.$set(row, "bankCardNumber", matchItem.bankCardNumber)
+ this.$set(row, "bankOfDeposit", matchItem.bankOfDeposit)
}
},
- handleBankUserNameChange(value) {
- const matchItem = this.historyData.find((item) => item.bankUserName === value)
+ handleBankUserNameChange(row) {
+ const matchItem = (row.historyData || []).find((item) => item.bankUserName === row.bankUserName)
if (matchItem) {
- this.$set(this.formData, "bankCardNumber", matchItem.bankCardNumber)
- this.$set(this.formData, "bankOfDeposit", matchItem.bankOfDeposit)
+ this.$set(row, "bankCardNumber", matchItem.bankCardNumber)
+ this.$set(row, "bankOfDeposit", matchItem.bankOfDeposit)
}
},
+ getBankHistoryUserNames(row) {
+ const userNameMap = {}
+ return (row.historyData || []).reduce((result, item) => {
+ if (item.bankUserName && !userNameMap[item.bankUserName]) {
+ userNameMap[item.bankUserName] = true
+ result.push(item.bankUserName)
+ }
+ return result
+ }, [])
+ },
handleVerifySwitchChange(value) {
this.$set(this.formData, "invoiceVerifyEnabled", !!value)
if (value && this.invoiceDialogVisible) {
@@ -947,22 +1137,22 @@ layout("/layouts/platform.html"){
}
},
- async payerUserChange(){
- if (this.formData.payer) {
- await this.getUserBankHistory();
+ async payerUserChange(row) {
+ if (row.payer) {
+ await this.getUserBankHistory(row);
} else {
- this.$set(this, "historyData", [])
- this.$set(this.formData, "payerName", null)
- this.$set(this.formData, "payerLoginname", null)
- this.$set(this.formData, "bankUserName", null)
- this.$set(this.formData, "bankCardNumber", null)
- this.$set(this.formData, "bankOfDeposit", null)
+ this.$set(row, "historyData", [])
+ this.$set(row, "payerName", null)
+ this.$set(row, "payerLoginname", null)
+ this.$set(row, "bankUserName", null)
+ this.$set(row, "bankCardNumber", null)
+ this.$set(row, "bankOfDeposit", null)
}
- const user = this.payerOptions.find(o => o.id === this.formData.payer)
+ const user = row.payerOptions.find(o => o.id === row.payer)
if (user) {
const {userName, loginName,} = user
- this.$set(this.formData, "payerName", userName);
- this.$set(this.formData, "payerLoginname", loginName);
+ this.$set(row, "payerName", userName);
+ this.$set(row, "payerLoginname", loginName);
}
},
async userChange(val) {
@@ -997,7 +1187,7 @@ layout("/layouts/platform.html"){
typeChange(val) {
const type = this.typeOptions.find(o => o.id === val)
if (type) {
- const {id, way, money, uploadFileDesc,name} = type
+ const {id, way, money, uploadFileDesc, name} = type
this.$set(this.formData, "condolenceTypeId", id)
this.$set(this.formData, "way", way)
this.$set(this.formData, "condolenceMoney", parseFloat(money).toFixed(2))
@@ -1257,6 +1447,79 @@ layout("/layouts/platform.html"){
}
return true
},
+ getCleanPaymentDetails() {
+ return (this.formData.paymentDetails || []).map(item => {
+ return {
+ paymentWay: item.paymentWay || null,
+ money: item.money || null,
+ payer: item.payer || null,
+ payerName: item.payerName || null,
+ payerLoginname: item.payerLoginname || null,
+ bankUserName: item.bankUserName || null,
+ bankCardNumber: item.bankCardNumber || null,
+ bankOfDeposit: item.bankOfDeposit || null
+ }
+ })
+ },
+ syncLegacyPaymentFields(paymentDetails, targetData) {
+ const data = targetData || this.formData
+ const firstPayment = paymentDetails && paymentDetails.length ? paymentDetails[0] : {}
+ data.paymentWay = firstPayment.paymentWay || null
+ data.payer = firstPayment.payer || null
+ data.payerName = firstPayment.payerName || null
+ data.payerLoginname = firstPayment.payerLoginname || null
+ data.bankUserName = firstPayment.bankUserName || null
+ data.bankCardNumber = firstPayment.bankCardNumber || null
+ data.bankOfDeposit = firstPayment.bankOfDeposit || null
+ },
+ // 保存前只保留支付明细业务字段,并同步第一条到旧字段,兼容现有打印、导出等旧逻辑。
+ preparePaymentDetailsForSubmit() {
+ const paymentDetails = this.getCleanPaymentDetails()
+ this.syncLegacyPaymentFields(paymentDetails)
+ return paymentDetails
+ },
+ buildSubmitFormData(paymentDetails) {
+ const submitData = JSON.parse(JSON.stringify(this.formData))
+ submitData.paymentDetails = paymentDetails || this.getCleanPaymentDetails()
+ this.syncLegacyPaymentFields(submitData.paymentDetails, submitData)
+ return submitData
+ },
+ validatePaymentDetailsBeforeSubmit(paymentDetails) {
+ if (!paymentDetails.length) {
+ this.$message.warning("请至少维护一条支付信息")
+ return false
+ }
+ for (let i = 0; i < paymentDetails.length; i++) {
+ const currentDetail = paymentDetails[i]
+ if (!currentDetail.paymentWay) {
+ this.$message.warning("第" + (i + 1) + "条支付信息请选择支付方式")
+ return false
+ }
+ if (!currentDetail.money || Number(currentDetail.money) <= 0) {
+ this.$message.warning("第" + (i + 1) + "条支付信息请填写正确的金额")
+ return false
+ }
+ if (currentDetail.paymentWay === "UNION_REIMBURSE_PAYMENT_WAY_2") {
+ if (!currentDetail.payer) {
+ this.$message.warning("第" + (i + 1) + "条支付信息请选择付款人")
+ return false
+ }
+ if (!currentDetail.bankUserName) {
+ this.$message.warning("第" + (i + 1) + "条支付信息请填写户名")
+ return false
+ }
+ if (!currentDetail.bankOfDeposit) {
+ this.$message.warning("第" + (i + 1) + "条支付信息请填写开户行")
+ return false
+ }
+ if (!currentDetail.bankCardNumber || !/^([1-9]{1})(\d{15}|\d{18})$/.test(currentDetail.bankCardNumber)) {
+ this.$message.warning("第" + (i + 1) + "条支付信息请填写正确的银行卡号")
+ return false
+ }
+ }
+ }
+ return true
+ },
//
// typeChange(id) {
// this.chooseType = this.typeOptions.find(o => o.id === id)
@@ -1273,12 +1536,13 @@ layout("/layouts/platform.html"){
onSave() {
this.rebuildInvoiceSummary()
this.normalizeFundBalance()
+ const paymentDetails = this.preparePaymentDetailsForSubmit()
this.$confirm("您确定保存吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
- this.$axios.post("/platform/unionReimburse/apply/save", {data: JSON.stringify(this.formData)}).then(res => {
+ this.$axios.post("/platform/unionReimburse/apply/save", {data: JSON.stringify(this.buildSubmitFormData(paymentDetails))}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
commonUtil.pjaxPush("/platform/unionReimburse/mine/index")
@@ -1296,8 +1560,14 @@ layout("/layouts/platform.html"){
validateBeforeSubmit() {
return new Promise((resolve) => {
this.rebuildInvoiceSummary()
+ const paymentDetails = this.preparePaymentDetailsForSubmit()
this.$refs.formRef.validate((valid) => {
if (valid) {
+ if (!this.validatePaymentDetailsBeforeSubmit(paymentDetails)) {
+ this.$set(this, "activeTabName", "basic")
+ resolve(false)
+ return
+ }
if (this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3" && !this.formData.clubId) {
this.$message.warning("请选择协会")
resolve(false)
@@ -1328,7 +1598,7 @@ layout("/layouts/platform.html"){
type: "warning"
}).then(() => {
this.$axios.post("/platform/unionReimburse/apply/submit", {
- data: JSON.stringify(this.formData)
+ data: JSON.stringify(this.buildSubmitFormData())
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
@@ -1348,7 +1618,7 @@ layout("/layouts/platform.html"){
type: "warning"
}).then(() => {
this.$axios.post("/platform/unionReimburse/apply/submitAgain", {
- data: JSON.stringify(this.formData),
+ data: JSON.stringify(this.buildSubmitFormData()),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
@@ -1380,6 +1650,19 @@ layout("/layouts/platform.html"){
const project = this.descOptions.find(item => item.reimburseProject === projectCode);
return project ? project.fileDesc : '';
},
+ // 新建申请默认优先选择分工会经费;若当前用户没有对应权限,则按页面可见权限回退到其它经费来源。
+ getDefaultFundSource() {
+ if (this.$auth.hasPermission("unionReimburse.fgh")) {
+ return "UNION_REIMBURSE_FUND_SOURCE_2"
+ }
+ if (this.$auth.hasPermission("unionReimburse.xgh")) {
+ return "UNION_REIMBURSE_FUND_SOURCE_1"
+ }
+ if (this.$auth.hasPermission("unionReimburse.club")) {
+ return "UNION_REIMBURSE_FUND_SOURCE_3"
+ }
+ return ""
+ },
selectFundSource(code) {
this.$set(this.formData, "reimburseFundSource", code)
if (code !== "UNION_REIMBURSE_FUND_SOURCE_3") {
@@ -1494,7 +1777,11 @@ layout("/layouts/platform.html"){
if (res.code === 0) {
this.formData = this.ensureFormData(res.data)
this.appendCurrentPayerOption()
- this.getUserBankHistory()
+ this.formData.paymentDetails.forEach(row => {
+ if (row.payer) {
+ this.getUserBankHistory(row)
+ }
+ })
this.reimburseFundSourceChange()
await this.selectQueryUser(this.formData.certifierLoginName, this.userOptions)
this.rebuildInvoiceSummary()
@@ -1512,10 +1799,17 @@ layout("/layouts/platform.html"){
unionName: union?.name,
// reimburseType: "UNION_REIMBURSE_TYPE_1",
reimburseProject: 'UNION_REIMBURSE_PROJECT_1',
+ reimburseFundSource: this.getDefaultFundSource(),
paymentWay: 'UNION_REIMBURSE_PAYMENT_WAY_2',
+ paymentDetails: [this.buildDefaultPaymentDetail({
+ paymentWay: 'UNION_REIMBURSE_PAYMENT_WAY_2'
+ })],
mobile: mobile,
userId: id,
})
+ if (this.formData.reimburseFundSource) {
+ this.reimburseFundSourceChange()
+ }
}
}
},
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/collect/index.html b/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/collect/index.html
index 38082ee3..5160160d 100644
--- a/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/collect/index.html
+++ b/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/collect/index.html
@@ -47,7 +47,7 @@ layout("/layouts/platform.html"){
导出收款人名册
-
+ 导出表格
@@ -89,7 +89,7 @@ layout("/layouts/platform.html"){
查看
- 实际金额
+ 实际金额
打印
删除
diff --git a/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/info.js b/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/info.js
index 77520c51..ab413cb2 100644
--- a/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/info.js
+++ b/src/main/resources/views/platform/zhgh/dayofficework/unionReimburse/info.js
@@ -8,25 +8,19 @@ const unionReimburseInfo = {
-
-
+
+
-
+
-
-
-
-
-
{{viewData.loginName}}
{{viewData.userName}}
{{viewData.unitName}}
@@ -44,20 +38,45 @@ const unionReimburseInfo = {
{{ viewData.mobile }}
-
- {{ viewData.payerName }}
-
-
-
- {{ viewData.bankUserName }}
-
-
-
- {{ viewData.bankOfDeposit }}
-
-
-
- {{ viewData.bankCardNumber }}
+
+
+
+
+
+
+
+
+
+
+ {{ formatMoney(scope.row.money) }}
+
+
+
+
+ {{ scope.row.payerName }}
+ 无需填写
+
+
+
+
+ {{ scope.row.bankUserName }}
+ 无需填写
+
+
+
+
+ {{ scope.row.bankOfDeposit }}
+ 无需填写
+
+
+
+
+ {{ scope.row.bankCardNumber }}
+ 无需填写
+
+
+
@@ -159,20 +178,20 @@ const unionReimburseInfo = {
{{ viewData.condolenceRelationship }}
-
{{ viewData.participants }}
-
+
{{ viewData.paymentNotes }}
-
+
{{ viewData.notes }}
-
+
@@ -285,7 +304,8 @@ const unionReimburseInfo = {
visible: false,
viewData: {
files: [],
- invoiceDetails: []
+ invoiceDetails: [],
+ paymentDetails: []
},
typeName: '',
row: null
@@ -294,6 +314,9 @@ const unionReimburseInfo = {
computed: {
showInvoiceTab() {
return !!this.viewData.reimburseProject
+ },
+ paymentInfoRows() {
+ return this.viewData.paymentDetails || []
}
},
methods: {
@@ -317,7 +340,8 @@ const unionReimburseInfo = {
buildViewData(data) {
const viewData = Object.assign({
files: [],
- invoiceDetails: []
+ invoiceDetails: [],
+ paymentDetails: []
}, data || {})
if (!Array.isArray(viewData.files)) {
viewData.files = []
@@ -325,8 +349,32 @@ const unionReimburseInfo = {
if (!Array.isArray(viewData.invoiceDetails)) {
viewData.invoiceDetails = []
}
+ const hasLegacyPayment = viewData.paymentWay || viewData.payer || viewData.bankUserName || viewData.bankCardNumber || viewData.bankOfDeposit
+ if (Array.isArray(viewData.paymentDetails) && viewData.paymentDetails.length > 0) {
+ viewData.paymentDetails = viewData.paymentDetails.map(item => this.buildPaymentDetail(item))
+ } else {
+ viewData.paymentDetails = hasLegacyPayment ? [this.buildPaymentDetail({
+ paymentWay: viewData.paymentWay,
+ money: viewData.money,
+ payerName: viewData.payerName,
+ bankUserName: viewData.bankUserName,
+ bankOfDeposit: viewData.bankOfDeposit,
+ bankCardNumber: viewData.bankCardNumber
+ })] : []
+ }
return viewData
},
+ buildPaymentDetail(detail) {
+ const currentDetail = detail || {}
+ return {
+ paymentWay: currentDetail.paymentWay || "",
+ money: currentDetail.money || "",
+ payerName: currentDetail.payerName || "",
+ bankUserName: currentDetail.bankUserName || "",
+ bankOfDeposit: currentDetail.bankOfDeposit || "",
+ bankCardNumber: currentDetail.bankCardNumber || ""
+ }
+ },
// 查看页金额统一保留两位小数,和申请页展示口径保持一致。
formatMoney(value) {
if (value === null || value === undefined || value === "") {
diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/apply/index.html b/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/apply/index.html
index 2e42bddf..c1217264 100644
--- a/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/apply/index.html
+++ b/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/apply/index.html
@@ -3,8 +3,117 @@ layout("/layouts/platform_h5.html"){
#-->
-
-
-
-
-
-
-->
-
-
-
-
-
-
-
- {{item.userName}}({{item.loginName}})
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ 支付信息
+ 新增
+
+
请至少维护一条支付信息。
+
+
+
+
+
+ 支付信息{{index + 1}}
+ {{index + 1}} / {{paymentInfoRows.length}}
+
+
{{item.paymentWayName}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.userName}}({{item.loginName}})
+
+
+
+
+
+
+
+
+ 发票识别中...
+
@@ -713,6 +1078,7 @@ layout("/layouts/platform_h5.html"){
bankUserName: "",
bankCardNumber: "",
bankOfDeposit: "",
+ paymentDetails: [],
condolenceName: "",
condolenceId: "",
condolenceUserId: "",
@@ -838,11 +1204,16 @@ layout("/layouts/platform_h5.html"){
payerSearchKeyword: "",
payerOptions: [],
historyData: [],
+ currentPaymentDetail: null,
+ currentPaymentIndex: -1,
searchKeyword: "",
userOptions: []
}
},
computed: {
+ paymentInfoRows() {
+ return this.formData.paymentDetails || []
+ },
bankHistoryUserNames() {
const userNameMap = {}
return (this.historyData || []).reduce((result, item) => {
@@ -868,7 +1239,7 @@ layout("/layouts/platform_h5.html"){
if (currentFileId === this.lastRecognizedFileId) {
return
}
- this.recognizeCurrentInvoice(false)
+ this.recognizeCurrentInvoice(true)
},
deep: true
},
@@ -999,6 +1370,23 @@ layout("/layouts/platform_h5.html"){
invoiceCheckCode: ""
}
},
+ buildDefaultPaymentDetail(detail) {
+ const currentDetail = detail || {}
+ const paymentWayName = currentDetail.paymentWayName || this.getPaymentWayName(currentDetail.paymentWay)
+ return {
+ paymentWay: currentDetail.paymentWay || "",
+ paymentWayName: paymentWayName || "",
+ money: currentDetail.money || "",
+ payer: currentDetail.payer || "",
+ payerName: currentDetail.payerName || "",
+ payerLoginname: currentDetail.payerLoginname || "",
+ bankUserName: currentDetail.bankUserName || "",
+ bankCardNumber: currentDetail.bankCardNumber || "",
+ bankOfDeposit: currentDetail.bankOfDeposit || "",
+ payerOptions: Array.isArray(currentDetail.payerOptions) ? currentDetail.payerOptions : [],
+ historyData: Array.isArray(currentDetail.historyData) ? currentDetail.historyData : []
+ }
+ },
ensureFormData(formData) {
const nextFormData = formData || {}
if (!Array.isArray(nextFormData.invoiceDetails)) {
@@ -1010,8 +1398,114 @@ layout("/layouts/platform_h5.html"){
if (typeof nextFormData.invoiceVerifyEnabled !== "boolean") {
this.$set(nextFormData, "invoiceVerifyEnabled", true)
}
+ const hasLegacyPayment = nextFormData.paymentWay || nextFormData.payer || nextFormData.bankUserName || nextFormData.bankCardNumber || nextFormData.bankOfDeposit
+ if (Array.isArray(nextFormData.paymentDetails) && nextFormData.paymentDetails.length > 0) {
+ this.$set(nextFormData, "paymentDetails", nextFormData.paymentDetails.map(item => this.buildDefaultPaymentDetail(item)))
+ } else {
+ this.$set(nextFormData, "paymentDetails", hasLegacyPayment ? [this.buildDefaultPaymentDetail({
+ paymentWay: nextFormData.paymentWay,
+ paymentWayName: nextFormData.paymentWayName,
+ money: nextFormData.money,
+ payer: nextFormData.payer,
+ payerName: nextFormData.payerName,
+ payerLoginname: nextFormData.payerLoginname,
+ bankUserName: nextFormData.bankUserName,
+ bankCardNumber: nextFormData.bankCardNumber,
+ bankOfDeposit: nextFormData.bankOfDeposit
+ })] : [])
+ }
return nextFormData
},
+ getPaymentWayName(paymentWay) {
+ const matchedPaymentWay = this.paymentWayColumns.find(item => item.value === paymentWay)
+ return matchedPaymentWay ? matchedPaymentWay.text : ""
+ },
+ // 判断当前支付明细是否为对私支付;对私支付需要继续维护付款人和银行卡信息。
+ isPrivatePayment(row) {
+ return row && row.paymentWay === "UNION_REIMBURSE_PAYMENT_WAY_2"
+ },
+ openPaymentWayPicker(row, index) {
+ this.$set(this, "currentPaymentDetail", row)
+ this.$set(this, "currentPaymentIndex", index)
+ this.openPopup("showPaymentWayPicker")
+ },
+ handlePaymentSwipeChange(index) {
+ this.$set(this, "currentPaymentIndex", index)
+ },
+ swipeToPayment(index) {
+ if (!this.paymentInfoRows.length) {
+ this.$set(this, "currentPaymentIndex", 0)
+ return
+ }
+ const targetIndex = Math.max(0, Math.min(index, this.paymentInfoRows.length - 1))
+ this.$set(this, "currentPaymentIndex", targetIndex)
+ this.$nextTick(() => {
+ if (this.$refs.paymentSwipe && this.$refs.paymentSwipe.swipeTo) {
+ this.$refs.paymentSwipe.swipeTo(targetIndex)
+ }
+ })
+ },
+ showPrevPayment() {
+ if (this.currentPaymentIndex <= 0) {
+ return
+ }
+ this.swipeToPayment(this.currentPaymentIndex - 1)
+ },
+ showNextPayment() {
+ if (this.currentPaymentIndex >= this.paymentInfoRows.length - 1) {
+ return
+ }
+ this.swipeToPayment(this.currentPaymentIndex + 1)
+ },
+ // 新增支付明细默认选择对私支付,与 PC 端新建申请默认值保持一致。
+ addPaymentInfo() {
+ this.formData.paymentDetails.push(this.buildDefaultPaymentDetail({
+ paymentWay: "UNION_REIMBURSE_PAYMENT_WAY_2"
+ }))
+ this.swipeToPayment(this.formData.paymentDetails.length - 1)
+ },
+ deletePaymentInfo(index) {
+ this.formData.paymentDetails.splice(index, 1)
+ this.swipeToPayment(index > 0 ? index - 1 : 0)
+ },
+ // 切换经费来源或协会时需要清空所有付款人和银行卡,避免旧收款信息带到新范围。
+ clearPaymentBankInfo(row) {
+ const rows = row ? [row] : (this.formData.paymentDetails || [])
+ rows.forEach(item => {
+ this.$set(item, "payer", "")
+ this.$set(item, "payerName", "")
+ this.$set(item, "payerLoginname", "")
+ this.$set(item, "bankUserName", "")
+ this.$set(item, "bankCardNumber", "")
+ this.$set(item, "bankOfDeposit", "")
+ this.$set(item, "payerOptions", [])
+ this.$set(item, "historyData", [])
+ })
+ this.$set(this.formData, "payer", "")
+ this.$set(this.formData, "payerName", "")
+ this.$set(this.formData, "payerLoginname", "")
+ this.$set(this.formData, "bankUserName", "")
+ this.$set(this.formData, "bankCardNumber", "")
+ this.$set(this.formData, "bankOfDeposit", "")
+ this.$set(this, "historyData", [])
+ },
+ appendCurrentPayerOption() {
+ (this.formData.paymentDetails || []).forEach(row => {
+ if (!row.payer) {
+ return
+ }
+ const exists = row.payerOptions.some(item => item.id === row.payer)
+ if (exists) {
+ return
+ }
+ row.payerOptions.push({
+ id: row.payer,
+ userName: row.payerName || "",
+ loginName: row.payerLoginname || "",
+ unitName: this.formData.unitName || "暂无"
+ })
+ })
+ },
handleReimburseProjectChange(value) {
if (value === "UNION_REIMBURSE_PROJECT_1") {
this.$set(this.formData, "money", "")
@@ -1327,7 +1821,9 @@ layout("/layouts/platform_h5.html"){
return res.data
})
},
- openPayerSelect() {
+ openPayerSelect(row, index) {
+ this.$set(this, "currentPaymentDetail", row)
+ this.$set(this, "currentPaymentIndex", index)
this.$set(this, "payerSelectShow", true)
if (this.payerSearchKeyword) {
this.payerRemoteMethod(this.payerSearchKeyword)
@@ -1344,47 +1840,123 @@ layout("/layouts/platform_h5.html"){
this.$set(this, "payerOptions", [])
return
}
- this.$axios.post("/platform/unionReimburse/apply/listUser", {keyword: keyword}).then((res) => {
+ if (this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3" && !this.formData.clubId) {
+ this.$toast.fail("请先选择所属协会")
+ this.$set(this, "payerOptions", [])
+ return
+ }
+ this.$axios.post("/platform/unionReimburse/apply/listPayerUser", {
+ keyword: keyword,
+ reimburseFundSource: this.formData.reimburseFundSource,
+ clubId: this.formData.clubId
+ }).then((res) => {
this.$set(this, "payerOptions", res && res.data ? res.data : [])
})
},
payerUserChange(user) {
- if (!user) {
+ const row = this.currentPaymentDetail
+ if (!user || !row) {
return
}
- this.$set(this.formData, "payer", user.id)
- this.$set(this.formData, "payerName", user.userName)
- this.$set(this.formData, "payerLoginname", user.loginName)
+ this.$set(row, "payer", user.id)
+ this.$set(row, "payerName", user.userName)
+ this.$set(row, "payerLoginname", user.loginName)
this.$set(this, "payerSelectShow", false)
this.$set(this, "payerSearchKeyword", "")
this.$set(this, "payerOptions", [])
- this.getUserBankHistory()
+ this.getUserBankHistory(row)
},
- getUserBankHistory() {
- if (!this.formData.payer) {
- this.$set(this, "historyData", [])
+ getUserBankHistory(row) {
+ if (!row || !row.payer) {
+ if (row) {
+ this.$set(row, "historyData", [])
+ }
return
}
this.$axios.get("/platform/unionReimburse/apply/findUserBankHistory", {
- params: {payer: this.formData.payer}
+ params: {payer: row.payer}
}).then((res) => {
const historyData = res && res.code === 0 && Array.isArray(res.data) ? res.data : []
- this.$set(this, "historyData", historyData)
+ this.$set(row, "historyData", historyData)
if (historyData.length === 1) {
- this.$set(this.formData, "bankUserName", historyData[0].bankUserName)
- this.$set(this.formData, "bankCardNumber", historyData[0].bankCardNumber)
- this.$set(this.formData, "bankOfDeposit", historyData[0].bankOfDeposit)
+ this.$set(row, "bankUserName", historyData[0].bankUserName)
+ this.$set(row, "bankCardNumber", historyData[0].bankCardNumber)
+ this.$set(row, "bankOfDeposit", historyData[0].bankOfDeposit)
}
})
},
- clearPaymentBankInfo() {
- this.$set(this.formData, "payer", "")
- this.$set(this.formData, "payerName", "")
- this.$set(this.formData, "payerLoginname", "")
- this.$set(this.formData, "bankUserName", "")
- this.$set(this.formData, "bankCardNumber", "")
- this.$set(this.formData, "bankOfDeposit", "")
- this.$set(this, "historyData", [])
+ getCleanPaymentDetails() {
+ return (this.formData.paymentDetails || []).map(item => {
+ return {
+ paymentWay: item.paymentWay || null,
+ money: item.money || null,
+ payer: item.payer || null,
+ payerName: item.payerName || null,
+ payerLoginname: item.payerLoginname || null,
+ bankUserName: item.bankUserName || null,
+ bankCardNumber: item.bankCardNumber || null,
+ bankOfDeposit: item.bankOfDeposit || null
+ }
+ })
+ },
+ syncLegacyPaymentFields(paymentDetails, targetData) {
+ const data = targetData || this.formData
+ const firstPayment = paymentDetails && paymentDetails.length ? paymentDetails[0] : {}
+ data.paymentWay = firstPayment.paymentWay || null
+ data.payer = firstPayment.payer || null
+ data.payerName = firstPayment.payerName || null
+ data.payerLoginname = firstPayment.payerLoginname || null
+ data.bankUserName = firstPayment.bankUserName || null
+ data.bankCardNumber = firstPayment.bankCardNumber || null
+ data.bankOfDeposit = firstPayment.bankOfDeposit || null
+ },
+ // 保存和提交时只提交支付明细业务字段,并同步第一条到旧字段兼容现有打印、导出。
+ preparePaymentDetailsForSubmit() {
+ const paymentDetails = this.getCleanPaymentDetails()
+ this.syncLegacyPaymentFields(paymentDetails)
+ return paymentDetails
+ },
+ buildSubmitFormData(paymentDetails) {
+ const submitData = JSON.parse(JSON.stringify(this.formData))
+ submitData.paymentDetails = paymentDetails || this.getCleanPaymentDetails()
+ this.syncLegacyPaymentFields(submitData.paymentDetails, submitData)
+ return submitData
+ },
+ validatePaymentDetailsBeforeSubmit(paymentDetails) {
+ if (!paymentDetails.length) {
+ this.$toast.fail("请至少维护一条支付信息")
+ return false
+ }
+ for (let i = 0; i < paymentDetails.length; i++) {
+ const currentDetail = paymentDetails[i]
+ if (!currentDetail.paymentWay) {
+ this.$toast.fail("第" + (i + 1) + "条支付信息请选择支付方式")
+ return false
+ }
+ if (!currentDetail.money || Number(currentDetail.money) <= 0) {
+ this.$toast.fail("第" + (i + 1) + "条支付信息请填写正确的金额")
+ return false
+ }
+ if (currentDetail.paymentWay === "UNION_REIMBURSE_PAYMENT_WAY_2") {
+ if (!currentDetail.payer) {
+ this.$toast.fail("第" + (i + 1) + "条支付信息请选择付款人")
+ return false
+ }
+ if (!currentDetail.bankUserName) {
+ this.$toast.fail("第" + (i + 1) + "条支付信息请填写户名")
+ return false
+ }
+ if (!currentDetail.bankOfDeposit) {
+ this.$toast.fail("第" + (i + 1) + "条支付信息请填写开户行")
+ return false
+ }
+ if (!currentDetail.bankCardNumber || !/^([1-9]{1})(\d{15}|\d{18})$/.test(currentDetail.bankCardNumber)) {
+ this.$toast.fail("第" + (i + 1) + "条支付信息请填写正确的银行卡号")
+ return false
+ }
+ }
+ }
+ return true
},
normalizeLoadedFormData(originalData) {
const sourceData = originalData || {}
@@ -1406,15 +1978,19 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "hospitalizationEndTime", this.normalizeDateText(sourceData.hospitalizationTimeRange[1]))
}
this.normalizeCondolenceDateFields()
- if (this.formData.paymentWay === "UNION_REIMBURSE_PAYMENT_WAY_2" && this.formData.payer) {
- this.getUserBankHistory()
- }
+ this.appendCurrentPayerOption()
+ this.formData.paymentDetails.forEach(row => {
+ if (row.payer) {
+ this.getUserBankHistory(row)
+ }
+ })
},
async onSave() {
this.normalizeContactFields()
this.normalizeCondolenceDateFields()
this.rebuildInvoiceSummary()
- this.$axios.post("/platform/unionReimburse/apply/save", { data: JSON.stringify(this.formData) })
+ const paymentDetails = this.preparePaymentDetailsForSubmit()
+ this.$axios.post("/platform/unionReimburse/apply/save", { data: JSON.stringify(this.buildSubmitFormData(paymentDetails)) })
.then((res) => {
this.$toast.clear()
if (res.code === 0) {
@@ -1435,11 +2011,15 @@ layout("/layouts/platform_h5.html"){
this.normalizeContactFields()
this.normalizeCondolenceDateFields()
this.rebuildInvoiceSummary()
+ const paymentDetails = this.preparePaymentDetailsForSubmit()
this.$refs.formRef.validate().then(() => {
// if (!this.formData.userSign) {
// this.$toast.fail("请签名")
// return
// }
+ if (!this.validatePaymentDetailsBeforeSubmit(paymentDetails)) {
+ return
+ }
if (!this.validateInvoiceDetailsBeforeSubmit()) {
return
}
@@ -1447,7 +2027,7 @@ layout("/layouts/platform_h5.html"){
title: "温馨提示",
message: "您确定要提交吗?"
}).then(() => {
- this.$axios.post("/platform/unionReimburse/apply/submit", { data: JSON.stringify(this.formData) })
+ this.$axios.post("/platform/unionReimburse/apply/submit", { data: JSON.stringify(this.buildSubmitFormData(paymentDetails)) })
.then(res => {
this.$toast.clear()
if (res.code === 0) {
@@ -1470,11 +2050,15 @@ layout("/layouts/platform_h5.html"){
this.normalizeContactFields()
this.normalizeCondolenceDateFields()
this.rebuildInvoiceSummary()
+ const paymentDetails = this.preparePaymentDetailsForSubmit()
this.$refs.formRef.validate().then(() => {
if (!this.formData.userSign) {
this.$toast.fail("请签名")
return
}
+ if (!this.validatePaymentDetailsBeforeSubmit(paymentDetails)) {
+ return
+ }
if (!this.validateInvoiceDetailsBeforeSubmit()) {
return
}
@@ -1483,7 +2067,7 @@ layout("/layouts/platform_h5.html"){
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/platform/unionReimburse/apply/submitAgain", {
- data: JSON.stringify(this.formData),
+ data: JSON.stringify(this.buildSubmitFormData(paymentDetails)),
taskId: GetQueryString("taskId")
}).then(res => {
this.$toast.clear()
@@ -1508,10 +2092,15 @@ layout("/layouts/platform_h5.html"){
this.closePopup("showReimburseTypePicker")
},
onPaymentWayConfirm(o) {
- this.$set(this.formData, "paymentWayName", o.text) // 显示名称
- this.$set(this.formData, "paymentWay", o.value) // 字典值
+ const row = this.currentPaymentDetail
+ if (!row) {
+ this.closePopup("showPaymentWayPicker")
+ return
+ }
+ this.$set(row, "paymentWayName", o.text)
+ this.$set(row, "paymentWay", o.value)
if (o.value !== "UNION_REIMBURSE_PAYMENT_WAY_2") {
- this.clearPaymentBankInfo()
+ this.clearPaymentBankInfo(row)
}
this.closePopup("showPaymentWayPicker")
},
@@ -1526,15 +2115,18 @@ layout("/layouts/platform_h5.html"){
if (o.value !== "UNION_REIMBURSE_FUND_SOURCE_3") {
this.$set(this.formData, "clubId", "")
this.$set(this.formData, "clubName", "")
+ this.clearPaymentBankInfo()
this.queryFundBalance()
} else if (this.clubColumns.length === 1) {
this.$set(this.formData, "clubId", this.clubColumns[0].value)
this.$set(this.formData, "clubName", this.clubColumns[0].text)
+ this.clearPaymentBankInfo()
this.queryFundBalance()
} else {
this.$set(this.formData, "clubId", "")
this.$set(this.formData, "clubName", "")
this.$set(this.formData, "fundBalance", "")
+ this.clearPaymentBankInfo()
}
this.closePopup("showReimburseFundSourcePicker")
},
@@ -1542,6 +2134,7 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "clubName", o.text)
this.$set(this.formData, "clubId", o.value)
this.closePopup("showClubPicker")
+ this.clearPaymentBankInfo()
// 选择社团后查询经费余额
this.queryFundBalance()
},
@@ -1585,6 +2178,23 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "activityType", o.value)
this.closePopup("showActivityTypePicker")
},
+ // 新建申请默认优先选择分工会经费;若当前用户没有对应权限,则按页面可见权限回退到其它经费来源。
+ getDefaultFundSource() {
+ if (this.$auth.hasPermission("unionReimburse.fgh")) {
+ return "UNION_REIMBURSE_FUND_SOURCE_2"
+ }
+ if (this.$auth.hasPermission("unionReimburse.xgh")) {
+ return "UNION_REIMBURSE_FUND_SOURCE_1"
+ }
+ if (this.$auth.hasPermission("unionReimburse.club")) {
+ return "UNION_REIMBURSE_FUND_SOURCE_3"
+ }
+ return ""
+ },
+ getReimburseFundSourceName(code) {
+ const matchedFundSource = this.reimburseFundSourceColumns.find(item => item.value === code)
+ return matchedFundSource ? matchedFundSource.text : ""
+ },
async initDictOptions() {
// 报销类别
const reimburseTypeData = await this.$businessTool.getDictOptions("UNION_REIMBURSE_TYPE")
@@ -1800,8 +2410,8 @@ layout("/layouts/platform_h5.html"){
// })
// }
- // 手机端经费来源权限必须使用 h5. 前缀,和 PC 端经费来源项保持一一对应
- if (this.$auth.hasPermission("h5.unionReimburse.xgh")) {
+ // 经费来源子权限和 PC 端保持一致,避免手机端因 h5 前缀过滤为空。
+ if (this.$auth.hasPermission("unionReimburse.xgh")) {
this.reimburseFundSourceColumns.forEach(item => {
if (item.value === "UNION_REIMBURSE_FUND_SOURCE_1") {
filteredSources.push(item)
@@ -1809,7 +2419,7 @@ layout("/layouts/platform_h5.html"){
})
}
- if (this.$auth.hasPermission("h5.unionReimburse.fgh")) {
+ if (this.$auth.hasPermission("unionReimburse.fgh")) {
this.reimburseFundSourceColumns.forEach(item => {
if (item.value === "UNION_REIMBURSE_FUND_SOURCE_2") {
filteredSources.push(item)
@@ -1817,7 +2427,7 @@ layout("/layouts/platform_h5.html"){
})
}
- if (this.$auth.hasPermission("h5.unionReimburse.club")) {
+ if (this.$auth.hasPermission("unionReimburse.club")) {
this.reimburseFundSourceColumns.forEach(item => {
if (item.value === "UNION_REIMBURSE_FUND_SOURCE_3") {
filteredSources.push(item)
@@ -1933,6 +2543,15 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "unitName", user.unit.name)
this.$set(this.formData, "unionId", user.union.id)
this.$set(this.formData, "unionName", user.union.name)
+ const defaultFundSource = this.getDefaultFundSource()
+ this.$set(this.formData, "reimburseFundSource", defaultFundSource)
+ this.$set(this.formData, "reimburseFundSourceName", this.getReimburseFundSourceName(defaultFundSource))
+ this.$set(this.formData, "paymentDetails", [this.buildDefaultPaymentDetail({
+ paymentWay: "UNION_REIMBURSE_PAYMENT_WAY_2"
+ })])
+ if (this.formData.reimburseFundSource) {
+ this.queryFundBalance()
+ }
}
}
},
diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/info.js b/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/info.js
index e8434aa8..e2dc4636 100644
--- a/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/info.js
+++ b/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/info.js
@@ -2,118 +2,263 @@ const UNION_REIMBURSE_INFO = {
template:
/*language=HTML*/
`
-
+
+
-
- {{ viewData.loginName }}
- {{ viewData.userName }}
- {{ viewData.mobile }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ viewData.clubName }}
-
- {{ formatMoney(viewData.fundBalance) }}
+
@@ -178,13 +330,35 @@ const UNION_REIMBURSE_INFO = {
visible: false,
viewData: {},
doneTasks: [],
- row: null
+ row: null,
+ currentPaymentIndex: 0
}
},
+ computed: {
+ paymentInfoRows() {
+ return this.viewData.paymentDetails || []
+ }
+ },
+ mounted() {
+ this.injectInfoStyle()
+ },
methods: {
+ injectInfoStyle() {
+ // 当前组件是普通 JS 对象注册,Vue 不会自动注入 style 字段,这里只为本详情弹窗注入一次样式。
+ const styleId = "union-reimburse-info-style"
+ if (document.getElementById(styleId) || !this.$options.style) {
+ return
+ }
+ const styleNode = document.createElement("style")
+ styleNode.id = styleId
+ styleNode.type = "text/css"
+ styleNode.appendChild(document.createTextNode(this.$options.style))
+ document.head.appendChild(styleNode)
+ },
onOpen(row) {
this.row = row
this.visible = true
+ this.currentPaymentIndex = 0
this.getInfo()
this.getDoneTasks()
},
@@ -208,11 +382,82 @@ const UNION_REIMBURSE_INFO = {
isCondolenceType(typeId) {
return this.viewData.condolenceTypeId === typeId || this.viewData.condolenceType === typeId
},
+ getPaymentWayText(paymentWay) {
+ const matchedPaymentWay = this.dict.type.UNION_REIMBURSE_PAYMENT_WAY.find(item => item.code === paymentWay)
+ return matchedPaymentWay ? matchedPaymentWay.name : ""
+ },
+ buildViewData(data) {
+ const viewData = Object.assign({
+ files: [],
+ invoiceDetails: [],
+ paymentDetails: []
+ }, data || {})
+ if (!Array.isArray(viewData.files)) {
+ viewData.files = []
+ }
+ if (!Array.isArray(viewData.invoiceDetails)) {
+ viewData.invoiceDetails = []
+ }
+ const hasLegacyPayment = viewData.paymentWay || viewData.payer || viewData.bankUserName || viewData.bankCardNumber || viewData.bankOfDeposit
+ if (Array.isArray(viewData.paymentDetails) && viewData.paymentDetails.length > 0) {
+ viewData.paymentDetails = viewData.paymentDetails.map(item => this.buildPaymentDetail(item))
+ } else {
+ viewData.paymentDetails = hasLegacyPayment ? [this.buildPaymentDetail({
+ paymentWay: viewData.paymentWay,
+ money: viewData.money,
+ payerName: viewData.payerName,
+ bankUserName: viewData.bankUserName,
+ bankOfDeposit: viewData.bankOfDeposit,
+ bankCardNumber: viewData.bankCardNumber
+ })] : []
+ }
+ return viewData
+ },
+ buildPaymentDetail(detail) {
+ const currentDetail = detail || {}
+ return {
+ paymentWay: currentDetail.paymentWay || "",
+ money: currentDetail.money || "",
+ payerName: currentDetail.payerName || "",
+ bankUserName: currentDetail.bankUserName || "",
+ bankOfDeposit: currentDetail.bankOfDeposit || "",
+ bankCardNumber: currentDetail.bankCardNumber || ""
+ }
+ },
+ handlePaymentSwipeChange(index) {
+ this.currentPaymentIndex = index
+ },
+ swipeToPayment(index) {
+ if (!this.paymentInfoRows.length) {
+ this.currentPaymentIndex = 0
+ return
+ }
+ const targetIndex = Math.max(0, Math.min(index, this.paymentInfoRows.length - 1))
+ this.currentPaymentIndex = targetIndex
+ this.$nextTick(() => {
+ if (this.$refs.paymentInfoSwipe && this.$refs.paymentInfoSwipe.swipeTo) {
+ this.$refs.paymentInfoSwipe.swipeTo(targetIndex)
+ }
+ })
+ },
+ showPrevPayment() {
+ if (this.currentPaymentIndex <= 0) {
+ return
+ }
+ this.swipeToPayment(this.currentPaymentIndex - 1)
+ },
+ showNextPayment() {
+ if (this.currentPaymentIndex >= this.paymentInfoRows.length - 1) {
+ return
+ }
+ this.swipeToPayment(this.currentPaymentIndex + 1)
+ },
// 获取申请信息
getInfo() {
this.$axios.post("/platform/unionReimburse/apply/info", { id: this.row.id }).then((res) => {
if (res.code === 0) {
- this.viewData = res.data
+ this.viewData = this.buildViewData(res.data)
+ this.currentPaymentIndex = 0
}
})
},
@@ -230,6 +475,209 @@ const UNION_REIMBURSE_INFO = {
}
})
}
- }
+ },
+ style: /*language=CSS*/ `
+ .union-reimburse-info-sheet {
+ height: 92vh;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+ .union-reimburse-info-sheet .van-action-sheet__content {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .union-info-header {
+ flex: 0 0 auto;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 56px;
+ padding: 0 20px;
+ background: #fff;
+ border-top: 4px solid #1677ff;
+ border-bottom: 1px solid #e7ebf0;
+ }
+
+ .union-info-header-title {
+ color: #111827;
+ font-size: 16px;
+ font-weight: 700;
+ }
+
+ .union-info-close {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 28px;
+ height: 28px;
+ color: #8b95a3;
+ font-size: 20px;
+ }
+
+ .detail-container {
+ flex: 1;
+ overflow: hidden;
+ background: #f2f4f7;
+ }
+
+ .union-info-scroll {
+ height: 100%;
+ overflow-y: auto;
+ padding-bottom: 16px;
+ }
+
+ .union-info-section {
+ background: #fff;
+ margin-bottom: 10px;
+ }
+
+ .union-info-section-title {
+ display: flex;
+ align-items: center;
+ height: 44px;
+ padding: 0 16px;
+ color: #1f2937;
+ font-size: 14px;
+ font-weight: 700;
+ background: #f5f7fa;
+ border-bottom: 1px solid #e7ebf0;
+ }
+
+ .union-info-section-title::before {
+ content: "";
+ width: 4px;
+ height: 16px;
+ margin-right: 8px;
+ border-radius: 2px;
+ background: #1677ff;
+ }
+
+ .union-info-row {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ min-height: 44px;
+ padding: 12px 20px;
+ border-bottom: 1px solid #edf0f4;
+ box-sizing: border-box;
+ }
+
+ .union-info-row:last-child {
+ border-bottom: 0;
+ }
+
+ .union-info-label {
+ flex: 0 0 96px;
+ color: #8a94a6;
+ font-size: 14px;
+ line-height: 20px;
+ }
+
+ .union-info-value {
+ flex: 1;
+ min-width: 0;
+ color: #1f2937;
+ font-size: 14px;
+ line-height: 20px;
+ text-align: right;
+ word-break: break-all;
+ white-space: pre-line;
+ }
+
+ .union-info-link {
+ color: #1677ff;
+ }
+
+ .union-payment-tabs {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ padding: 12px 20px 4px;
+ background: #fff;
+ }
+
+ .union-payment-tab {
+ height: 30px;
+ padding: 0 13px;
+ border-radius: 999px;
+ color: #8a94a6;
+ background: #f0f2f5;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 30px;
+ }
+
+ .union-payment-tab.active {
+ color: #fff;
+ background: #1677ff;
+ }
+
+ .union-empty-text {
+ padding: 14px 20px;
+ color: #9aa3af;
+ font-size: 13px;
+ }
+
+ .union-file-preview {
+ padding: 12px 20px 16px;
+ }
+
+ .union-invoice-subtitle {
+ display: flex;
+ align-items: center;
+ height: 40px;
+ padding: 0 20px;
+ color: #6b7280;
+ font-size: 13px;
+ background: #f5f7fa;
+ border-top: 1px solid #edf0f4;
+ border-bottom: 1px solid #edf0f4;
+ }
+
+ .union-invoice-card-list {
+ padding: 12px 16px 4px;
+ }
+
+ .union-invoice-card {
+ margin-bottom: 12px;
+ padding: 14px 14px 12px;
+ border-radius: 12px;
+ border: 1px solid #e6ebf2;
+ background: #fff;
+ box-shadow: 0 1px 3px rgba(31, 35, 41, 0.05);
+ }
+
+ .union-invoice-card-title {
+ margin-bottom: 8px;
+ color: #1677ff;
+ font-size: 13px;
+ font-weight: 700;
+ }
+
+ .union-invoice-file-preview {
+ padding: 12px 0 0;
+ }
+
+ .process-title {
+ display: flex;
+ align-items: center;
+ height: 40px;
+ padding: 0 20px;
+ color: #1f2937;
+ font-size: 14px;
+ font-weight: 700;
+ background: #f5f7fa;
+ }
+
+ .signature-image {
+ width: 100%;
+ height: 120px;
+ object-fit: contain;
+ }
+ `
}