feat:工会报销:1、报销申请增加协会报销,增加社团活动;2、协会报销关联经费管理-社团预算;3、文体活动、日常活动报销,去除附件必填校验;4、活动增加报销金额,报销金额小于发票金额;5、报销审核、汇总,表格中增加流水号字段,所属单位隐藏
This commit is contained in:
+11
@@ -313,4 +313,15 @@ public class UnionReimburseApplyController {
|
|||||||
public Result getBudgetBalance(String reimburseFundSource, String clubId) {
|
public Result getBudgetBalance(String reimburseFundSource, String clubId) {
|
||||||
return unionReimburseService.getBudgetBalance(reimburseFundSource, clubId, null);
|
return unionReimburseService.getBudgetBalance(reimburseFundSource, clubId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询可申请社团经费报销的社团。
|
||||||
|
*
|
||||||
|
* @return 全部未解散社团列表
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||||
|
public Result listReimburseClubs() {
|
||||||
|
return Result.success(unionReimburseService.listReimburseClubs());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -121,6 +121,16 @@ public class UnionReimburseCollectController {
|
|||||||
applyListSort(cnd, pageForm);
|
applyListSort(cnd, pageForm);
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
// 复用打印流水号,按当日全部申请排序,避免分页或筛选改变编号。
|
||||||
|
for (NutMap row : pagination.getList()) {
|
||||||
|
UnionReimburse form = new UnionReimburse();
|
||||||
|
form.setId(row.getString("id"));
|
||||||
|
// SQL映射可能返回日期字符串,兼容日期对象后再参与流水号计算。
|
||||||
|
Object createTime = row.get("createTime");
|
||||||
|
form.setCreateTime(createTime instanceof java.util.Date ? (java.util.Date) createTime
|
||||||
|
: (createTime == null ? null : DateUtil.parse(createTime.toString())));
|
||||||
|
row.put("serialNo", unionReimburseExportService.buildPrintSerialNo(form));
|
||||||
|
}
|
||||||
return Result.success(pagination);
|
return Result.success(pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +176,7 @@ public class UnionReimburseCollectController {
|
|||||||
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_2' THEN '文体活动'
|
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_2' THEN '文体活动'
|
||||||
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_3' THEN '日常活动'
|
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_3' THEN '日常活动'
|
||||||
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_4' THEN '专项活动'
|
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_4' THEN '专项活动'
|
||||||
|
WHEN rei.reimburseProject = 'UNION_REIMBURSE_PROJECT_5' THEN '社团活动'
|
||||||
ELSE rei.reimburseProject
|
ELSE rei.reimburseProject
|
||||||
END as reimbursementItemName,
|
END as reimbursementItemName,
|
||||||
u.mobile
|
u.mobile
|
||||||
@@ -249,6 +260,8 @@ public class UnionReimburseCollectController {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (projectDict != null) {
|
if (projectDict != null) {
|
||||||
item.setReimburseProject(projectDict.getName());
|
item.setReimburseProject(projectDict.getName());
|
||||||
|
} else if ("UNION_REIMBURSE_PROJECT_5".equals(item.getReimburseProject())) {
|
||||||
|
item.setReimburseProject("社团活动");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 转换报销经费来源
|
// 转换报销经费来源
|
||||||
|
|||||||
+15
@@ -2,6 +2,7 @@ package com.budwk.app.zhgh.dayofficework.unionReimburse.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.dev33.satoken.annotation.SaMode;
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.annotation.SLog;
|
import com.budwk.app.base.annotation.SLog;
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
@@ -10,6 +11,7 @@ import com.budwk.app.base.result.Result;
|
|||||||
import com.budwk.app.base.utils.PageUtil;
|
import com.budwk.app.base.utils.PageUtil;
|
||||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||||
|
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseExportService;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
@@ -36,6 +38,9 @@ public class UnionReimburseReviewController {
|
|||||||
@Inject
|
@Inject
|
||||||
private UnionReimburseService unionReimburseService;
|
private UnionReimburseService unionReimburseService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private UnionReimburseExportService unionReimburseExportService;
|
||||||
|
|
||||||
@At("/index")
|
@At("/index")
|
||||||
@Ok("beetl:/platform/zhgh/dayofficework/unionReimburse/review/index.html")
|
@Ok("beetl:/platform/zhgh/dayofficework/unionReimburse/review/index.html")
|
||||||
@SaCheckPermission("unionReimburse.review")
|
@SaCheckPermission("unionReimburse.review")
|
||||||
@@ -88,6 +93,16 @@ public class UnionReimburseReviewController {
|
|||||||
cnd.desc("info.createdAt");
|
cnd.desc("info.createdAt");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
// 复用打印流水号,按当日全部申请排序,避免分页或筛选改变编号。
|
||||||
|
for (NutMap row : pagination.getList()) {
|
||||||
|
UnionReimburse form = new UnionReimburse();
|
||||||
|
form.setId(row.getString("id"));
|
||||||
|
// SQL映射可能返回日期字符串,兼容日期对象后再参与流水号计算。
|
||||||
|
Object createTime = row.get("createTime");
|
||||||
|
form.setCreateTime(createTime instanceof java.util.Date ? (java.util.Date) createTime
|
||||||
|
: (createTime == null ? null : DateUtil.parse(createTime.toString())));
|
||||||
|
row.put("serialNo", unionReimburseExportService.buildPrintSerialNo(form));
|
||||||
|
}
|
||||||
return Result.success(pagination);
|
return Result.success(pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
@@ -24,4 +24,11 @@ public interface UnionReimburseExportService {
|
|||||||
* @return 活动及慰问模板通用的平铺字段及 payments、invoices 循环行
|
* @return 活动及慰问模板通用的平铺字段及 payments、invoices 循环行
|
||||||
*/
|
*/
|
||||||
Map<String, Object> buildExportData(UnionReimburse form);
|
Map<String, Object> buildExportData(UnionReimburse form);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表与打印共用按申请日期及当日申请时间排序的流水号,历史申请参与相同排序。
|
||||||
|
* @param form 报销申请,必须包含申请时间和单据ID
|
||||||
|
* @return 年月日加至少三位当日序号,例如20261009001;缺少必要字段或申请不存在时抛出业务异常
|
||||||
|
*/
|
||||||
|
String buildPrintSerialNo(UnionReimburse form);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -58,10 +58,17 @@ public interface UnionReimburseService extends BaseService<UnionReimburse> {
|
|||||||
Result recognizeInvoice(String fileId, Boolean verifySwitch);
|
Result recognizeInvoice(String fileId, Boolean verifySwitch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询报销可用经费余额,同时校验是否已分配以及协会归属权限。
|
* 查询报销可用经费余额,同时校验是否已分配、经费来源权限及社团有效性。
|
||||||
*/
|
*/
|
||||||
Result getBudgetBalance(String reimburseFundSource, String clubId, String unionId);
|
Result getBudgetBalance(String reimburseFundSource, String clubId, String unionId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询未解散社团,供社团经费报销选择。
|
||||||
|
*
|
||||||
|
* @return 全部未解散社团的ID、名称和编码列表
|
||||||
|
*/
|
||||||
|
List<NutMap> listReimburseClubs();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 审核报销,审核通过时扣减对应预算并新增预算使用详情。
|
* 审核报销,审核通过时扣减对应预算并新增预算使用详情。
|
||||||
*/
|
*/
|
||||||
|
|||||||
+8
-2
@@ -185,7 +185,8 @@ public class UnionReimburseExportServiceImpl implements UnionReimburseExportServ
|
|||||||
* @param form 已通过导出权限校验的报销申请
|
* @param form 已通过导出权限校验的报销申请
|
||||||
* @return 年月日加至少三位当日序号,例如 20261009001
|
* @return 年月日加至少三位当日序号,例如 20261009001
|
||||||
*/
|
*/
|
||||||
private String buildPrintSerialNo(UnionReimburse form) {
|
@Override
|
||||||
|
public String buildPrintSerialNo(UnionReimburse form) {
|
||||||
if (form.getCreateTime() == null || StrUtil.isBlank(form.getId())) {
|
if (form.getCreateTime() == null || StrUtil.isBlank(form.getId())) {
|
||||||
throw new BaseException("报销申请时间或单据ID为空,无法生成打印流水号");
|
throw new BaseException("报销申请时间或单据ID为空,无法生成打印流水号");
|
||||||
}
|
}
|
||||||
@@ -220,7 +221,9 @@ public class UnionReimburseExportServiceImpl implements UnionReimburseExportServ
|
|||||||
data.put("no", text(form.getDocumentNo()));
|
data.put("no", text(form.getDocumentNo()));
|
||||||
data.put("serialNo", buildPrintSerialNo(form));
|
data.put("serialNo", buildPrintSerialNo(form));
|
||||||
String unit = text(form.getUnitName());
|
String unit = text(form.getUnitName());
|
||||||
data.put("union", text(form.getUnionName()) + (unit.isEmpty() ? "" : "(" + unit + ")"));
|
data.put("union", "UNION_REIMBURSE_FUND_SOURCE_3".equals(form.getReimburseFundSource())
|
||||||
|
? text(form.getClubName())
|
||||||
|
: text(form.getUnionName()) + (unit.isEmpty() ? "" : "(" + unit + ")"));
|
||||||
data.put("handler", text(form.getUserName()));
|
data.put("handler", text(form.getUserName()));
|
||||||
data.put("login", text(form.getLoginName()));
|
data.put("login", text(form.getLoginName()));
|
||||||
data.put("phone", text(form.getMobile()));
|
data.put("phone", text(form.getMobile()));
|
||||||
@@ -229,6 +232,9 @@ public class UnionReimburseExportServiceImpl implements UnionReimburseExportServ
|
|||||||
+ ("UNION_REIMBURSE_PROJECT_1".equals(project) ? "√" : "□") + "慰问 "
|
+ ("UNION_REIMBURSE_PROJECT_1".equals(project) ? "√" : "□") + "慰问 "
|
||||||
+ ("UNION_REIMBURSE_PROJECT_3".equals(project) ? "√" : "□") + "日常活动 "
|
+ ("UNION_REIMBURSE_PROJECT_3".equals(project) ? "√" : "□") + "日常活动 "
|
||||||
+ ("UNION_REIMBURSE_PROJECT_4".equals(project) ? "√" : "□") + "专项活动");
|
+ ("UNION_REIMBURSE_PROJECT_4".equals(project) ? "√" : "□") + "专项活动");
|
||||||
|
if ("UNION_REIMBURSE_PROJECT_5".equals(project)) {
|
||||||
|
data.put("project", "√社团活动");
|
||||||
|
}
|
||||||
data.put("activity", text(form.getActivityName()));
|
data.put("activity", text(form.getActivityName()));
|
||||||
data.put("reason", text(form.getPaymentNotes()));
|
data.put("reason", text(form.getPaymentNotes()));
|
||||||
data.put("notes", text(form.getNotes()));
|
data.put("notes", text(form.getNotes()));
|
||||||
|
|||||||
+160
-22
@@ -11,7 +11,6 @@ import com.budwk.app.base.service.impl.BaseServiceImpl;
|
|||||||
import com.budwk.app.sys.models.Sys_file;
|
import com.budwk.app.sys.models.Sys_file;
|
||||||
import com.budwk.app.sys.views.View_user;
|
import com.budwk.app.sys.views.View_user;
|
||||||
import com.budwk.app.sys.services.SysFileService;
|
import com.budwk.app.sys.services.SysFileService;
|
||||||
import com.budwk.app.zhgh.club.model.ClubUser;
|
|
||||||
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.club.model.OutlayManageClub;
|
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.club.model.OutlayManageClub;
|
||||||
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.model.OutlayUseDetail;
|
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.model.OutlayUseDetail;
|
||||||
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.school.model.OutlayManageSchool;
|
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.school.model.OutlayManageSchool;
|
||||||
@@ -148,6 +147,10 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (amountResult != null) {
|
if (amountResult != null) {
|
||||||
return amountResult;
|
return amountResult;
|
||||||
}
|
}
|
||||||
|
Result activityAmountResult = validateActivityApplyMoney(unionReimburse);
|
||||||
|
if (activityAmountResult != null) {
|
||||||
|
return activityAmountResult;
|
||||||
|
}
|
||||||
UnionReimburse oldRecord = null;
|
UnionReimburse oldRecord = null;
|
||||||
if (StrUtil.isNotBlank(unionReimburse.getId())) {
|
if (StrUtil.isNotBlank(unionReimburse.getId())) {
|
||||||
oldRecord = this.fetch(unionReimburse.getId());
|
oldRecord = this.fetch(unionReimburse.getId());
|
||||||
@@ -159,6 +162,18 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result sourceResult = validateApplicantFundSource(unionReimburse);
|
||||||
|
if (sourceResult != null) {
|
||||||
|
return sourceResult;
|
||||||
|
}
|
||||||
|
if (oldRecord != null
|
||||||
|
&& ("UNION_REIMBURSE_FUND_SOURCE_3".equals(oldRecord.getReimburseFundSource())
|
||||||
|
|| "UNION_REIMBURSE_FUND_SOURCE_3".equals(unionReimburse.getReimburseFundSource()))
|
||||||
|
&& !Integer.valueOf(1).equals(oldRecord.getStateId())
|
||||||
|
&& !Integer.valueOf(5).equals(oldRecord.getStateId())) {
|
||||||
|
return Result.error("社团报销仅允许修改草稿或退回的申请");
|
||||||
|
}
|
||||||
|
|
||||||
// 人员身份和敏感资料由服务端补齐,避免前端删减字段导致丢失或被篡改。
|
// 人员身份和敏感资料由服务端补齐,避免前端删减字段导致丢失或被篡改。
|
||||||
if (oldRecord == null) {
|
if (oldRecord == null) {
|
||||||
View_user handler = dao().fetch(View_user.class, Cnd.where("id", "=", SecurityUtil.getUserId()));
|
View_user handler = dao().fetch(View_user.class, Cnd.where("id", "=", SecurityUtil.getUserId()));
|
||||||
@@ -491,6 +506,18 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Result getBudgetBalance(String reimburseFundSource, String clubId, String unionId) {
|
public Result getBudgetBalance(String reimburseFundSource, String clubId, String unionId) {
|
||||||
|
if (!canApplyFundSource(reimburseFundSource)) {
|
||||||
|
return Result.error("当前角色无权使用该经费来源");
|
||||||
|
}
|
||||||
|
if ("UNION_REIMBURSE_FUND_SOURCE_3".equals(reimburseFundSource)
|
||||||
|
&& listReimburseClubs().stream().noneMatch(club -> Objects.equals(clubId, club.getString("id")))) {
|
||||||
|
return Result.error("请选择有效的社团");
|
||||||
|
}
|
||||||
|
return queryBudgetBalance(reimburseFundSource, clubId, unionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审核人按申请单的经费归属校验预算,不要求审核人同时是该社团负责人。
|
||||||
|
private Result queryBudgetBalance(String reimburseFundSource, String clubId, String unionId) {
|
||||||
if (StrUtil.isBlank(reimburseFundSource)) {
|
if (StrUtil.isBlank(reimburseFundSource)) {
|
||||||
return Result.error("请选择经费来源");
|
return Result.error("请选择经费来源");
|
||||||
}
|
}
|
||||||
@@ -515,16 +542,13 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (StrUtil.isBlank(clubId)) {
|
if (StrUtil.isBlank(clubId)) {
|
||||||
return Result.error("请选择协会");
|
return Result.error("请选择协会");
|
||||||
}
|
}
|
||||||
List<String> myClubIds = getCurrentUserClubIds();
|
|
||||||
if (!isAdmin() && !myClubIds.contains(clubId)) {
|
|
||||||
return Result.error("当前用户无权使用该协会经费");
|
|
||||||
}
|
|
||||||
OutlayManageClub outlayManageClub = dao().fetch(OutlayManageClub.class,
|
OutlayManageClub outlayManageClub = dao().fetch(OutlayManageClub.class,
|
||||||
Cnd.where("clubId", "=", clubId).and("year", "=", DateUtil.thisYear()));
|
Cnd.where("clubId", "=", clubId).and("year", "=", DateUtil.thisYear()));
|
||||||
if (outlayManageClub == null) {
|
if (outlayManageClub == null) {
|
||||||
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
|
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
|
||||||
}
|
}
|
||||||
return Result.success(formatMoney(outlayManageClub.getTotalQuota().subtract(outlayManageClub.getUsedQuota())));
|
return Result.success(formatMoney(safeMoney(outlayManageClub.getTotalQuota()).subtract(safeMoney(outlayManageClub.getUsedQuota()))));
|
||||||
}
|
}
|
||||||
return Result.error("不支持的经费来源");
|
return Result.error("不支持的经费来源");
|
||||||
}
|
}
|
||||||
@@ -533,6 +557,7 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
* 审核通过时统一校验余额、扣减预算并写入预算使用详情,避免控制器分散业务逻辑。
|
* 审核通过时统一校验余额、扣减预算并写入预算使用详情,避免控制器分散业务逻辑。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Result reviewApply(String reimburseId, String reviewOpinion, int submitType) {
|
public Result reviewApply(String reimburseId, String reviewOpinion, int submitType) {
|
||||||
if (!List.of(3, 4, 5).contains(submitType)) {
|
if (!List.of(3, 4, 5).contains(submitType)) {
|
||||||
return Result.error("无效的审核操作类型");
|
return Result.error("无效的审核操作类型");
|
||||||
@@ -541,6 +566,25 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (dbRecord == null) {
|
if (dbRecord == null) {
|
||||||
return Result.error("记录不存在");
|
return Result.error("记录不存在");
|
||||||
}
|
}
|
||||||
|
if ("UNION_REIMBURSE_FUND_SOURCE_3".equals(dbRecord.getReimburseFundSource())) {
|
||||||
|
// 同一申请审核串行处理,避免重复点击导致社团已使用额度累计两次。
|
||||||
|
Sql lockSql = Sqls.create("SELECT * FROM union_reimburse WHERE id=@id FOR UPDATE");
|
||||||
|
lockSql.setParam("id", reimburseId);
|
||||||
|
lockSql.setEntity(dao().getEntity(UnionReimburse.class));
|
||||||
|
lockSql.setCallback(Sqls.callback.entities());
|
||||||
|
dao().execute(lockSql);
|
||||||
|
List<UnionReimburse> records = lockSql.getList(UnionReimburse.class);
|
||||||
|
if (records.isEmpty()) {
|
||||||
|
return Result.error("记录不存在");
|
||||||
|
}
|
||||||
|
dbRecord = records.get(0);
|
||||||
|
if (submitType == 3 && Integer.valueOf(3).equals(dbRecord.getStateId())) {
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
if (!Integer.valueOf(2).equals(dbRecord.getStateId())) {
|
||||||
|
return Result.error("仅可审核待审核确认的社团报销");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (submitType == 3) {
|
if (submitType == 3) {
|
||||||
// 已通过的单据再次触发通过时直接返回,避免重复扣减预算。
|
// 已通过的单据再次触发通过时直接返回,避免重复扣减预算。
|
||||||
if (Integer.valueOf(3).equals(dbRecord.getStateId())) {
|
if (Integer.valueOf(3).equals(dbRecord.getStateId())) {
|
||||||
@@ -668,8 +712,43 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
unionReimburse.setInvoiceDetails(invoiceDetails);
|
unionReimburse.setInvoiceDetails(invoiceDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isManualReimburseAmount(UnionReimburse form) {
|
||||||
|
return "UNION_REIMBURSE_PROJECT_2".equals(form.getReimburseProject())
|
||||||
|
|| "UNION_REIMBURSE_PROJECT_3".equals(form.getReimburseProject())
|
||||||
|
|| "UNION_REIMBURSE_PROJECT_4".equals(form.getReimburseProject());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 有发票时汇总票面金额和张数;无发票时按已校验的支付明细汇总金额,张数为零。
|
* 文体、日常、专项活动保留手填报销金额,有发票时限制票面总额,无发票不设此上限。
|
||||||
|
* @param form 已通过发票和支付信息校验的申请
|
||||||
|
* @return 金额必填、精度或上限校验不通过时返回错误,通过返回null
|
||||||
|
*/
|
||||||
|
private Result validateActivityApplyMoney(UnionReimburse form) {
|
||||||
|
if (!isManualReimburseAmount(form)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Double money = form.getMoney();
|
||||||
|
if (money == null) {
|
||||||
|
return Result.error("请填写报销金额");
|
||||||
|
}
|
||||||
|
if (!Double.isFinite(money) || money <= 0
|
||||||
|
|| BigDecimal.valueOf(money).stripTrailingZeros().scale() > 2) {
|
||||||
|
return Result.error("报销金额必须为正数,且最多两位小数");
|
||||||
|
}
|
||||||
|
if (Lang.isNotEmpty(form.getInvoiceDetails())) {
|
||||||
|
BigDecimal invoiceTotal = BigDecimal.ZERO;
|
||||||
|
for (UnionReimburseInvoiceDetail detail : form.getInvoiceDetails()) {
|
||||||
|
invoiceTotal = invoiceTotal.add(BigDecimal.valueOf(detail.getInvoiceAmount()).setScale(2, RoundingMode.HALF_UP));
|
||||||
|
}
|
||||||
|
if (BigDecimal.valueOf(money).compareTo(invoiceTotal) > 0) {
|
||||||
|
return Result.error("报销金额不能超过发票总额(" + invoiceTotal.toPlainString() + "元)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 汇总票面金额和张数;三类活动保留手填金额,其余项目无发票时按支付明细汇总。
|
||||||
*/
|
*/
|
||||||
private void fillInvoiceSummary(UnionReimburse unionReimburse) {
|
private void fillInvoiceSummary(UnionReimburse unionReimburse) {
|
||||||
double totalMoney = 0D;
|
double totalMoney = 0D;
|
||||||
@@ -692,7 +771,10 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
}
|
}
|
||||||
totalMoney = paymentTotal.setScale(2, RoundingMode.HALF_UP).doubleValue();
|
totalMoney = paymentTotal.setScale(2, RoundingMode.HALF_UP).doubleValue();
|
||||||
}
|
}
|
||||||
|
// 三类活动使用已校验的手填申请金额,不能被发票或支付合计覆盖。
|
||||||
|
if (!isManualReimburseAmount(unionReimburse)) {
|
||||||
unionReimburse.setMoney(BigDecimal.valueOf(totalMoney).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
unionReimburse.setMoney(BigDecimal.valueOf(totalMoney).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
||||||
|
}
|
||||||
unionReimburse.setInvoiceNumber(String.valueOf(invoiceFileCount));
|
unionReimburse.setInvoiceNumber(String.valueOf(invoiceFileCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,7 +908,11 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (unionReimburse.getActivityTime() == null) {
|
if (unionReimburse.getActivityTime() == null) {
|
||||||
return Result.error("请选择活动时间");
|
return Result.error("请选择活动时间");
|
||||||
}
|
}
|
||||||
if (Lang.isEmpty(unionReimburse.getFiles())) {
|
// 文体、日常和社团活动附件选填,其他活动保留附件必填校验。
|
||||||
|
if (!"UNION_REIMBURSE_PROJECT_2".equals(unionReimburse.getReimburseProject())
|
||||||
|
&& !"UNION_REIMBURSE_PROJECT_3".equals(unionReimburse.getReimburseProject())
|
||||||
|
&& !"UNION_REIMBURSE_PROJECT_5".equals(unionReimburse.getReimburseProject())
|
||||||
|
&& Lang.isEmpty(unionReimburse.getFiles())) {
|
||||||
return Result.error("请上传附件");
|
return Result.error("请上传附件");
|
||||||
}
|
}
|
||||||
return validateInvoiceDetails(unionReimburse);
|
return validateInvoiceDetails(unionReimburse);
|
||||||
@@ -929,7 +1015,7 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
* 提交和审核前统一校验预算是否已分配、余额是否充足。
|
* 提交和审核前统一校验预算是否已分配、余额是否充足。
|
||||||
*/
|
*/
|
||||||
private Result validateFundSourceBeforeSubmit(UnionReimburse unionReimburse) {
|
private Result validateFundSourceBeforeSubmit(UnionReimburse unionReimburse) {
|
||||||
Result balanceResult = getBudgetBalance(unionReimburse.getReimburseFundSource(), unionReimburse.getClubId(), unionReimburse.getUnionId());
|
Result balanceResult = queryBudgetBalance(unionReimburse.getReimburseFundSource(), unionReimburse.getClubId(), unionReimburse.getUnionId());
|
||||||
if (balanceResult == null || balanceResult.getCode() != 0) {
|
if (balanceResult == null || balanceResult.getCode() != 0) {
|
||||||
return balanceResult == null ? Result.error("经费余额校验失败") : balanceResult;
|
return balanceResult == null ? Result.error("经费余额校验失败") : balanceResult;
|
||||||
}
|
}
|
||||||
@@ -985,11 +1071,19 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if (outlayManageClub == null) {
|
if (outlayManageClub == null) {
|
||||||
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
|
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
|
||||||
}
|
}
|
||||||
if (outlayManageClub.getTotalQuota().subtract(outlayManageClub.getUsedQuota()).compareTo(applyMoney) < 0) {
|
// 本年度分配总额度保持不变,审批金额原子累加至已使用额度,余额由两者相减得到。
|
||||||
return Result.error("协会经费余额不足");
|
Sql deductSql = Sqls.create("""
|
||||||
|
UPDATE outlay_manage_club
|
||||||
|
SET usedQuota = COALESCE(usedQuota, 0) + @amount
|
||||||
|
WHERE id = @id
|
||||||
|
AND COALESCE(totalQuota, 0) - COALESCE(usedQuota, 0) >= @amount
|
||||||
|
""");
|
||||||
|
deductSql.setParam("id", outlayManageClub.getId());
|
||||||
|
deductSql.setParam("amount", applyMoney);
|
||||||
|
dao().execute(deductSql);
|
||||||
|
if (deductSql.getUpdateCount() != 1) {
|
||||||
|
return Result.error("社团经费余额不足");
|
||||||
}
|
}
|
||||||
outlayManageClub.setUsedQuota(outlayManageClub.getUsedQuota().add(applyMoney));
|
|
||||||
dao().updateIgnoreNull(outlayManageClub);
|
|
||||||
insertUseDetail(unionReimburse, outlayManageClub.getId(), applyMoney);
|
insertUseDetail(unionReimburse, outlayManageClub.getId(), applyMoney);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
@@ -1201,6 +1295,9 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
if ("UNION_REIMBURSE_PROJECT_4".equals(reimburseProject)) {
|
if ("UNION_REIMBURSE_PROJECT_4".equals(reimburseProject)) {
|
||||||
return "专项活动申请";
|
return "专项活动申请";
|
||||||
}
|
}
|
||||||
|
if ("UNION_REIMBURSE_PROJECT_5".equals(reimburseProject)) {
|
||||||
|
return "社团活动申请";
|
||||||
|
}
|
||||||
return "报销申请";
|
return "报销申请";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,16 +1305,57 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
|
|||||||
return money == null ? 0D : money.setScale(2, RoundingMode.HALF_UP).doubleValue();
|
return money == null ? 0D : money.setScale(2, RoundingMode.HALF_UP).doubleValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getCurrentUserClubIds() {
|
/**
|
||||||
if (isAdmin()) {
|
* 查询未解散社团,社团选择和余额查询不按负责人归属过滤。
|
||||||
return new ArrayList<>();
|
*
|
||||||
|
* @return 全部未解散社团的ID、名称和编码
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<NutMap> listReimburseClubs() {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT c.id, c.clubName, c.clubCode
|
||||||
|
FROM sys_club c
|
||||||
|
WHERE c.dismiss = 0
|
||||||
|
ORDER BY c.clubCode, c.id
|
||||||
|
""");
|
||||||
|
return listMap(sql);
|
||||||
}
|
}
|
||||||
List<ClubUser> clubUsers = dao().query(ClubUser.class, Cnd.where("userId", "=", SecurityUtil.getUserId()));
|
|
||||||
return clubUsers.stream()
|
// 社团经费按菜单权限授权,其他经费保留原申请角色判断。
|
||||||
.map(ClubUser::getClubId)
|
private boolean canApplyFundSource(String source) {
|
||||||
.filter(StrUtil::isNotBlank)
|
if (StrUtil.isBlank(source)) {
|
||||||
.distinct()
|
return false;
|
||||||
.collect(Collectors.toList());
|
}
|
||||||
|
boolean branchRole = AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_CHAIRMAN.name(), RoleConstant.BRANCH_UNION_ADMIN.name());
|
||||||
|
boolean clubRole = AuthUtil.hasRoleOr(RoleConstant.CLUB_MANAGER.name(), RoleConstant.CLUB_PRESIDENT.name());
|
||||||
|
return switch (source) {
|
||||||
|
case "UNION_REIMBURSE_FUND_SOURCE_1" -> isAdmin()
|
||||||
|
|| (!branchRole && !clubRole && AuthUtil.hasRoleOr(RoleConstant.SCHOOL_OUTLAY_ADMIN.name()));
|
||||||
|
case "UNION_REIMBURSE_FUND_SOURCE_2" -> isAdmin() || branchRole;
|
||||||
|
case "UNION_REIMBURSE_FUND_SOURCE_3" -> AuthUtil.hasPermission("unionReimburse.club");
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result validateApplicantFundSource(UnionReimburse form) {
|
||||||
|
if (!canApplyFundSource(form.getReimburseFundSource())) {
|
||||||
|
return Result.error("当前角色无权使用该经费来源");
|
||||||
|
}
|
||||||
|
if ("UNION_REIMBURSE_FUND_SOURCE_3".equals(form.getReimburseFundSource())) {
|
||||||
|
if (!"UNION_REIMBURSE_PROJECT_5".equals(form.getReimburseProject())) {
|
||||||
|
return Result.error("社团经费请选择社团活动");
|
||||||
|
}
|
||||||
|
NutMap club = listReimburseClubs().stream()
|
||||||
|
.filter(item -> Objects.equals(form.getClubId(), item.getString("id")))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
if (club == null) {
|
||||||
|
return Result.error("请选择有效的社团");
|
||||||
|
}
|
||||||
|
form.setClubName(club.getString("clubName"));
|
||||||
|
} else if ("UNION_REIMBURSE_PROJECT_5".equals(form.getReimburseProject())) {
|
||||||
|
return Result.error("社团活动只能使用社团经费");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result validateInvoiceDuplicate(UnionReimburse unionReimburse) {
|
private Result validateInvoiceDuplicate(UnionReimburse unionReimburse) {
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
-- 社团活动属于报销项目的正式字典配置,两端沿用现有字典接口读取。
|
||||||
|
-- 仅补充缺失记录;已有记录(包括已禁用记录)不覆盖,不在查询接口中添加兜底项。
|
||||||
|
INSERT INTO sys_dict (
|
||||||
|
id, parentId, path, name, remark, code, disabled, location, hasChildren,
|
||||||
|
createdBy, createdAt, updatedBy, updatedAt, delFlag
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
REPLACE(UUID(), '-', ''),
|
||||||
|
parent.id,
|
||||||
|
CONCAT(parent.path, LPAD(IFNULL((
|
||||||
|
SELECT MAX(CAST(RIGHT(child.path, 4) AS UNSIGNED))
|
||||||
|
FROM sys_dict child
|
||||||
|
WHERE child.path LIKE CONCAT(parent.path, '____')
|
||||||
|
), 0) + 1, 4, '0')),
|
||||||
|
'社团活动',
|
||||||
|
'',
|
||||||
|
'UNION_REIMBURSE_PROJECT_5',
|
||||||
|
0,
|
||||||
|
IFNULL((SELECT MAX(child.location) FROM sys_dict child WHERE child.parentId = parent.id), 0) + 1,
|
||||||
|
0,
|
||||||
|
'', UNIX_TIMESTAMP(NOW()) * 1000,
|
||||||
|
'', UNIX_TIMESTAMP(NOW()) * 1000,
|
||||||
|
0
|
||||||
|
FROM sys_dict parent
|
||||||
|
WHERE parent.code = 'UNION_REIMBURSE_PROJECT'
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM (SELECT code FROM sys_dict WHERE code = 'UNION_REIMBURSE_PROJECT_5') existing_item
|
||||||
|
);
|
||||||
|
|
||||||
|
UPDATE sys_dict parent
|
||||||
|
SET parent.hasChildren = 1
|
||||||
|
WHERE parent.code = 'UNION_REIMBURSE_PROJECT'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM (SELECT parentId FROM sys_dict WHERE code = 'UNION_REIMBURSE_PROJECT_5') club_activity
|
||||||
|
WHERE club_activity.parentId = parent.id
|
||||||
|
);
|
||||||
+4
-2
@@ -57,8 +57,10 @@ layout("/layouts/platform.html"){
|
|||||||
min-width="50"
|
min-width="50"
|
||||||
>
|
>
|
||||||
<template v-slot="{row}" v-if="column.prop=='surplusQuota'">
|
<template v-slot="{row}" v-if="column.prop=='surplusQuota'">
|
||||||
<span v-if="!row.totalQuota">{{row.totalQuota}}元</span>
|
<span>{{(Number(row.totalQuota || 0) - Number(row.usedQuota || 0)).toFixed(2)}}</span>
|
||||||
<span v-else>{{(row.totalQuota-row.usedQuota).toFixed(2)}}</span>
|
</template>
|
||||||
|
<template v-slot="{row}" v-else-if="column.prop=='usedQuota'">
|
||||||
|
<span>{{Number(row.usedQuota || 0).toFixed(2)}}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
+134
-59
@@ -7,6 +7,11 @@ layout("/layouts/platform.html"){
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 社团表单改为两组字段后,左侧标签仍保持原三组字段表单的六分之一宽度。 */
|
||||||
|
.club-reimbursement-form .el-descriptions-item__label:first-child {
|
||||||
|
width: calc(100% / 6);
|
||||||
|
}
|
||||||
|
|
||||||
.invoice-toolbar {
|
.invoice-toolbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -60,17 +65,21 @@ layout("/layouts/platform.html"){
|
|||||||
日常活动申请</h3>
|
日常活动申请</h3>
|
||||||
<h3 style="color: rgb(24, 103, 176);" v-else-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_4'">
|
<h3 style="color: rgb(24, 103, 176);" v-else-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_4'">
|
||||||
专项活动申请</h3>
|
专项活动申请</h3>
|
||||||
|
<h3 style="color: rgb(24, 103, 176);" v-else-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_5'">
|
||||||
|
社团活动申请</h3>
|
||||||
</template>
|
</template>
|
||||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||||
class="flow-task-form">
|
class="flow-task-form">
|
||||||
<el-tabs class="reimbursement-tabs" v-model="activeTabName">
|
<el-tabs class="reimbursement-tabs" v-model="activeTabName">
|
||||||
<el-tab-pane label="申请基本信息" name="basic">
|
<el-tab-pane label="申请基本信息" name="basic">
|
||||||
<el-descriptions :column="3" border>
|
<!-- 来源或项目切换时重建表单项,避免动态布局复用旧字段的校验状态。 -->
|
||||||
<el-descriptions-item label="经费来源" span="3">
|
<el-descriptions :column="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3' ? 2 : 3" :class="{'club-reimbursement-form': formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3'}" border :key="formData.reimburseFundSource + ':' + formData.reimburseProject">
|
||||||
|
<el-descriptions-item label="经费来源" :span="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3' ? 2 : 3">
|
||||||
<el-form-item label="经费来源" prop="reimburseFundSource">
|
<el-form-item label="经费来源" prop="reimburseFundSource">
|
||||||
|
|
||||||
|
<!-- 在表单重建前同步切换报销项目,避免延迟的 change 事件丢失。 -->
|
||||||
<el-radio-group v-model="formData.reimburseFundSource" size="medium"
|
<el-radio-group v-model="formData.reimburseFundSource" size="medium"
|
||||||
@change="selectFundSource">
|
@input="selectFundSource">
|
||||||
<el-radio v-if="$auth.hasPermission('unionReimburse.xgh')"
|
<el-radio v-if="$auth.hasPermission('unionReimburse.xgh')"
|
||||||
label="UNION_REIMBURSE_FUND_SOURCE_1"
|
label="UNION_REIMBURSE_FUND_SOURCE_1"
|
||||||
border>校工会经费
|
border>校工会经费
|
||||||
@@ -88,11 +97,11 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="报销项目" :span="3">
|
<el-descriptions-item label="报销项目" :span="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3' ? 2 : 3">
|
||||||
<el-form-item label="报销项目" prop="reimburseProject">
|
<el-form-item label="报销项目" prop="reimburseProject">
|
||||||
<el-radio-group v-model="formData.reimburseProject" size="medium"
|
<el-radio-group v-model="formData.reimburseProject" size="medium"
|
||||||
@change="handleReimburseProjectChange">
|
@change="handleReimburseProjectChange">
|
||||||
<el-radio :label="item.code" border v-for="item in reimburseProjectList">
|
<el-radio :label="item.code" border v-for="item in availableReimburseProjects" :key="item.code">
|
||||||
{{item.name}}
|
{{item.name}}
|
||||||
</el-radio>
|
</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
@@ -104,24 +113,6 @@ layout("/layouts/platform.html"){
|
|||||||
<el-descriptions-item label="经办人">{{formData.userName}}({{formData.loginName}})
|
<el-descriptions-item label="经办人">{{formData.userName}}({{formData.loginName}})
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="所属协会"
|
|
||||||
v-if="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3'">
|
|
||||||
<el-form-item label="所属协会" prop="clubId">
|
|
||||||
<el-select clearable
|
|
||||||
placeholder="请选择协会"
|
|
||||||
style="width: 100%;"
|
|
||||||
v-model="formData.clubId"
|
|
||||||
@change="clubChange">
|
|
||||||
<el-option
|
|
||||||
:key="item.id"
|
|
||||||
:label="item.clubName"
|
|
||||||
:value="item.id"
|
|
||||||
v-for="item in clubOptions">
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-descriptions-item>
|
|
||||||
|
|
||||||
<!-- <el-descriptions-item label="报销类别">-->
|
<!-- <el-descriptions-item label="报销类别">-->
|
||||||
<!-- <el-form-item label="报销类别" prop="reimburseType">-->
|
<!-- <el-form-item label="报销类别" prop="reimburseType">-->
|
||||||
<!-- <el-radio-group v-model="formData.reimburseType" size="medium">-->
|
<!-- <el-radio-group v-model="formData.reimburseType" size="medium">-->
|
||||||
@@ -149,7 +140,7 @@ layout("/layouts/platform.html"){
|
|||||||
placeholder="请输入联系方式"></el-input>
|
placeholder="请输入联系方式"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="余额" v-if="formData.reimburseFundSource">
|
<el-descriptions-item label="余额" v-if="formData.reimburseFundSource && formData.reimburseFundSource !== 'UNION_REIMBURSE_FUND_SOURCE_3'">
|
||||||
<el-form-item label="余额">
|
<el-form-item label="余额">
|
||||||
<el-input :value="canViewFundBalance ? fundBalanceText : '******'" readonly></el-input>
|
<el-input :value="canViewFundBalance ? fundBalanceText : '******'" readonly></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -273,7 +264,34 @@ layout("/layouts/platform.html"){
|
|||||||
</el-date-picker>
|
</el-date-picker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="" :span="2"
|
<el-descriptions-item label="报销金额" v-if="isManualReimburseAmount">
|
||||||
|
<el-form-item label="报销金额" prop="money">
|
||||||
|
<el-input v-model="formData.money" placeholder="请输入报销金额,最多两位小数"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="所属协会"
|
||||||
|
v-if="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3'">
|
||||||
|
<el-form-item label="所属协会" prop="clubId">
|
||||||
|
<el-select clearable
|
||||||
|
placeholder="请选择协会"
|
||||||
|
style="width: 100%;"
|
||||||
|
v-model="formData.clubId"
|
||||||
|
@change="clubChange">
|
||||||
|
<el-option
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.clubName"
|
||||||
|
:value="item.id"
|
||||||
|
v-for="item in clubOptions">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="余额" v-if="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3'">
|
||||||
|
<el-form-item label="余额">
|
||||||
|
<el-input :value="canViewFundBalance ? fundBalanceText : '******'" readonly></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="" :span="isManualReimburseAmount ? 1 : 2"
|
||||||
v-if="formData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1' && formData.reimburseFundSource !== 'UNION_REIMBURSE_FUND_SOURCE_3'">
|
v-if="formData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1' && formData.reimburseFundSource !== 'UNION_REIMBURSE_FUND_SOURCE_3'">
|
||||||
|
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@@ -399,7 +417,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item :span="3">
|
<el-descriptions-item :span="formData.reimburseFundSource === 'UNION_REIMBURSE_FUND_SOURCE_3' ? 2 : 3">
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
附件
|
附件
|
||||||
</template>
|
</template>
|
||||||
@@ -438,7 +456,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="报销金额" prop="money">
|
<el-form-item label="报销金额" prop="money">
|
||||||
<div class="invoice-field-title">报销金额</div>
|
<div class="invoice-field-title">报销金额</div>
|
||||||
<el-input v-model="formData.money" placeholder="有发票按发票汇总,无发票按支付信息汇总" readonly></el-input>
|
<el-input v-model="formData.money" :placeholder="isManualReimburseAmount ? '请在申请基本信息填写报销金额' : '有发票按发票汇总,无发票按支付信息汇总'" readonly></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@@ -587,7 +605,7 @@ layout("/layouts/platform.html"){
|
|||||||
<div>
|
<div>
|
||||||
<div class="invoice-toolbar-title">发票明细列表</div>
|
<div class="invoice-toolbar-title">发票明细列表</div>
|
||||||
<div class="invoice-summary-tip">
|
<div class="invoice-summary-tip">
|
||||||
发票选填;无发票时按支付信息汇总报销金额。上传后须通过验真,每条明细对应一张发票图片或单页 PDF。
|
{{ isManualReimburseAmount ? '发票选填;有发票时报销金额不得超过发票总额,无发票仍可提交。' : '发票选填;无发票时按支付信息汇总报销金额。' }}上传后须通过验真,每条明细对应一张发票图片或单页 PDF。
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -821,7 +839,13 @@ layout("/layouts/platform.html"){
|
|||||||
// invoiceNumber: [{required: true, message: "请填写发票张数", trigger: ["change", "blur"]}],
|
// invoiceNumber: [{required: true, message: "请填写发票张数", trigger: ["change", "blur"]}],
|
||||||
// invoice: [{required: true, message: "请填写发票号码", trigger: ["change", "blur"]}],
|
// invoice: [{required: true, message: "请填写发票号码", trigger: ["change", "blur"]}],
|
||||||
activityName: [{required: true, message: "请填写活动名称", trigger: ["change", "blur"]}],
|
activityName: [{required: true, message: "请填写活动名称", trigger: ["change", "blur"]}],
|
||||||
money: [{required: true, message: "请填写报销金额", trigger: ["change", "blur"]}],
|
money: [{required: true, message: "请填写报销金额", trigger: ["change", "blur"]}, {
|
||||||
|
validator: (rule, value, callback) => {
|
||||||
|
const message = this.getReimburseAmountMessage()
|
||||||
|
callback(message ? new Error(message) : undefined)
|
||||||
|
},
|
||||||
|
trigger: ["change", "blur"]
|
||||||
|
}],
|
||||||
condolenceRelationship: [{required: true, message: "与被慰问人关系", trigger: ["change", "blur"]}],
|
condolenceRelationship: [{required: true, message: "与被慰问人关系", trigger: ["change", "blur"]}],
|
||||||
marryTime: [{required: true, message: "结婚时间", trigger: ["change", "blur"]}],
|
marryTime: [{required: true, message: "结婚时间", trigger: ["change", "blur"]}],
|
||||||
fertilityTime: [{required: true, message: "生育时间", trigger: ["change", "blur"]}],
|
fertilityTime: [{required: true, message: "生育时间", trigger: ["change", "blur"]}],
|
||||||
@@ -835,8 +859,8 @@ layout("/layouts/platform.html"){
|
|||||||
],
|
],
|
||||||
files: [{
|
files: [{
|
||||||
validator: (rule, value, callback) => {
|
validator: (rule, value, callback) => {
|
||||||
// 慰问项目不展示附件上传,提交时无需校验附件。
|
// 慰问项目无需校验附件,文体、日常和社团活动附件选填。
|
||||||
if (this.formData.reimburseProject === "UNION_REIMBURSE_PROJECT_1") {
|
if (["UNION_REIMBURSE_PROJECT_1", "UNION_REIMBURSE_PROJECT_2", "UNION_REIMBURSE_PROJECT_3", "UNION_REIMBURSE_PROJECT_5"].includes(this.formData.reimburseProject)) {
|
||||||
callback()
|
callback()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -910,6 +934,16 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
isManualReimburseAmount() {
|
||||||
|
return ["UNION_REIMBURSE_PROJECT_2", "UNION_REIMBURSE_PROJECT_3", "UNION_REIMBURSE_PROJECT_4"]
|
||||||
|
.includes(this.formData.reimburseProject)
|
||||||
|
},
|
||||||
|
// 社团经费固定对应社团活动,复用文体活动的基本信息和发票表单。
|
||||||
|
availableReimburseProjects() {
|
||||||
|
const clubFund = this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
return this.reimburseProjectList.filter(item =>
|
||||||
|
clubFund ? item.code === "UNION_REIMBURSE_PROJECT_5" : item.code !== "UNION_REIMBURSE_PROJECT_5")
|
||||||
|
},
|
||||||
// 按选中类型的业务编码控制字段,类型列表异步加载及旧申请回显后自动重新计算。
|
// 按选中类型的业务编码控制字段,类型列表异步加载及旧申请回显后自动重新计算。
|
||||||
condolenceTypeCode() {
|
condolenceTypeCode() {
|
||||||
if (this.formData.reimburseProject !== "UNION_REIMBURSE_PROJECT_1") return ""
|
if (this.formData.reimburseProject !== "UNION_REIMBURSE_PROJECT_1") return ""
|
||||||
@@ -917,9 +951,11 @@ layout("/layouts/platform.html"){
|
|||||||
const selectedType = this.typeOptions.find(item => item.id === typeId)
|
const selectedType = this.typeOptions.find(item => item.id === typeId)
|
||||||
return selectedType ? selectedType.code : ""
|
return selectedType ? selectedType.code : ""
|
||||||
},
|
},
|
||||||
// 仅系统管理员和校工会管理员可查看真实余额,其他账号统一显示余额遮罩。
|
// 社团经费按菜单授权查看年度剩余额度,其他经费沿用原余额可见范围。
|
||||||
canViewFundBalance() {
|
canViewFundBalance() {
|
||||||
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||||
|
|| (this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
&& this.$auth.hasPermission("unionReimburse.club"))
|
||||||
},
|
},
|
||||||
showInvoiceTab() {
|
showInvoiceTab() {
|
||||||
return !!this.formData.reimburseProject
|
return !!this.formData.reimburseProject
|
||||||
@@ -1549,6 +1585,27 @@ layout("/layouts/platform.html"){
|
|||||||
this.rebuildInvoiceSummary()
|
this.rebuildInvoiceSummary()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
// 手填金额按分比较票面总额;未上传发票时仍允许申请。
|
||||||
|
getReimburseAmountMessage() {
|
||||||
|
if (!this.isManualReimburseAmount) return ""
|
||||||
|
const value = String(this.formData.money == null ? "" : this.formData.money)
|
||||||
|
if (!value) return "请填写报销金额"
|
||||||
|
const cents = this.moneyToCents(value)
|
||||||
|
if (!/^\d+(\.\d{1,2})?$/.test(value) || cents === null || cents <= 0) {
|
||||||
|
return "报销金额必须为正数,且最多两位小数"
|
||||||
|
}
|
||||||
|
const invoices = this.formData.invoiceDetails || []
|
||||||
|
let invoiceCents = 0
|
||||||
|
for (let i = 0; i < invoices.length; i++) {
|
||||||
|
const amount = this.moneyToCents(invoices[i] && invoices[i].invoiceAmount)
|
||||||
|
if (amount === null || amount <= 0) return "请填写正确的发票金额"
|
||||||
|
invoiceCents += amount
|
||||||
|
}
|
||||||
|
if (invoices.length && cents > invoiceCents) {
|
||||||
|
return "报销金额不能超过发票总额(" + (invoiceCents / 100).toFixed(2) + "元)"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
},
|
||||||
rebuildInvoiceSummary() {
|
rebuildInvoiceSummary() {
|
||||||
let totalMoney = 0
|
let totalMoney = 0
|
||||||
let fileCount = 0
|
let fileCount = 0
|
||||||
@@ -1573,10 +1630,18 @@ layout("/layouts/platform.html"){
|
|||||||
})
|
})
|
||||||
totalMoney = paymentCents / 100
|
totalMoney = paymentCents / 100
|
||||||
}
|
}
|
||||||
|
// 三类活动保留手填申请金额,发票及支付明细变化只更新张数。
|
||||||
|
if (!this.isManualReimburseAmount) {
|
||||||
this.$set(this.formData, "money", totalMoney ? totalMoney.toFixed(2) : "0.00")
|
this.$set(this.formData, "money", totalMoney ? totalMoney.toFixed(2) : "0.00")
|
||||||
|
}
|
||||||
this.$set(this.formData, "invoiceNumber", String(fileCount))
|
this.$set(this.formData, "invoiceNumber", String(fileCount))
|
||||||
},
|
},
|
||||||
validateInvoiceDetailsBeforeSubmit() {
|
validateInvoiceDetailsBeforeSubmit() {
|
||||||
|
const amountMessage = this.getReimburseAmountMessage()
|
||||||
|
if (amountMessage) {
|
||||||
|
this.$message.warning(amountMessage)
|
||||||
|
return false
|
||||||
|
}
|
||||||
const invoiceDetails = this.formData.invoiceDetails || []
|
const invoiceDetails = this.formData.invoiceDetails || []
|
||||||
// 发票可不上传;已经添加的发票仍须填写完整并沿用验真流程。
|
// 发票可不上传;已经添加的发票仍须填写完整并沿用验真流程。
|
||||||
for (let i = 0; i < invoiceDetails.length; i++) {
|
for (let i = 0; i < invoiceDetails.length; i++) {
|
||||||
@@ -1904,6 +1969,7 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
// 根据报销项目获取对应的附件说明
|
// 根据报销项目获取对应的附件说明
|
||||||
getFileDescByProject(projectCode) {
|
getFileDescByProject(projectCode) {
|
||||||
|
if (projectCode === "UNION_REIMBURSE_PROJECT_5") return "社团活动附件说明"
|
||||||
if (!this.descOptions || !Array.isArray(this.descOptions)) {
|
if (!this.descOptions || !Array.isArray(this.descOptions)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -1912,27 +1978,27 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
// 根据当前选择的报销项目获取管理端配置的提示内容。
|
// 根据当前选择的报销项目获取管理端配置的提示内容。
|
||||||
getProjectTipByProject(projectCode) {
|
getProjectTipByProject(projectCode) {
|
||||||
|
if (projectCode === "UNION_REIMBURSE_PROJECT_5") projectCode = "UNION_REIMBURSE_PROJECT_2"
|
||||||
if (!this.descOptions || !Array.isArray(this.descOptions)) {
|
if (!this.descOptions || !Array.isArray(this.descOptions)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
const project = this.descOptions.find(item => item.reimburseProject === projectCode);
|
const project = this.descOptions.find(item => item.reimburseProject === projectCode);
|
||||||
return project ? project.projectTip : '';
|
return project ? project.projectTip : '';
|
||||||
},
|
},
|
||||||
// 新建申请默认优先选择分工会经费;若当前用户没有对应权限,则按页面可见权限回退到其它经费来源。
|
// 默认来源与角色允许的按钮一致,社团负责人默认进入社团活动申请。
|
||||||
getDefaultFundSource() {
|
getDefaultFundSource() {
|
||||||
if (this.$auth.hasPermission("unionReimburse.fgh")) {
|
const option = this.budgetTypeOption.find(item => item.code === "UNION_REIMBURSE_FUND_SOURCE_2")
|
||||||
return "UNION_REIMBURSE_FUND_SOURCE_2"
|
|| this.budgetTypeOption.find(item => item.code === "UNION_REIMBURSE_FUND_SOURCE_3")
|
||||||
}
|
|| (this.$auth.hasPermission("unionReimburse.xgh") && this.budgetTypeOption[0])
|
||||||
if (this.$auth.hasPermission("unionReimburse.xgh")) {
|
return option ? option.code : ""
|
||||||
return "UNION_REIMBURSE_FUND_SOURCE_1"
|
|
||||||
}
|
|
||||||
if (this.$auth.hasPermission("unionReimburse.club")) {
|
|
||||||
return "UNION_REIMBURSE_FUND_SOURCE_3"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
},
|
},
|
||||||
selectFundSource(code) {
|
selectFundSource(code) {
|
||||||
this.$set(this.formData, "reimburseFundSource", code)
|
this.$set(this.formData, "reimburseFundSource", code)
|
||||||
|
if (code === "UNION_REIMBURSE_FUND_SOURCE_3") {
|
||||||
|
this.$set(this.formData, "reimburseProject", "UNION_REIMBURSE_PROJECT_5")
|
||||||
|
} else if (this.formData.reimburseProject === "UNION_REIMBURSE_PROJECT_5") {
|
||||||
|
this.$set(this.formData, "reimburseProject", "UNION_REIMBURSE_PROJECT_2")
|
||||||
|
}
|
||||||
if (code !== "UNION_REIMBURSE_FUND_SOURCE_3") {
|
if (code !== "UNION_REIMBURSE_FUND_SOURCE_3") {
|
||||||
this.$set(this.formData, "clubId", null)
|
this.$set(this.formData, "clubId", null)
|
||||||
this.$set(this.formData, "clubName", null)
|
this.$set(this.formData, "clubName", null)
|
||||||
@@ -1986,9 +2052,13 @@ layout("/layouts/platform.html"){
|
|||||||
this.fundBalanceText = "查询中..."
|
this.fundBalanceText = "查询中..."
|
||||||
this.$axios.post("/platform/unionReimburse/apply/getBudgetBalance", params)
|
this.$axios.post("/platform/unionReimburse/apply/getBudgetBalance", params)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
// 切换社团后忽略旧请求,避免显示上一社团的余额。
|
||||||
|
if (fundSource !== this.formData.reimburseFundSource
|
||||||
|
|| (params.clubId && params.clubId !== this.formData.clubId)) return
|
||||||
if (response.code === 0) {
|
if (response.code === 0) {
|
||||||
this.$set(this.formData, "fundBalance", response.data || 0)
|
this.$set(this.formData, "fundBalance", response.data || 0)
|
||||||
this.fundBalanceText = (response.data || 0).toString()
|
this.fundBalanceText = fundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
? Number(response.data || 0).toFixed(2) : (response.data || 0).toString()
|
||||||
} else {
|
} else {
|
||||||
this.$set(this.formData, "fundBalance", null)
|
this.$set(this.formData, "fundBalance", null)
|
||||||
this.fundBalanceText = response.msg || "查询失败"
|
this.fundBalanceText = response.msg || "查询失败"
|
||||||
@@ -1996,6 +2066,8 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
if (fundSource !== this.formData.reimburseFundSource
|
||||||
|
|| (params.clubId && params.clubId !== this.formData.clubId)) return
|
||||||
console.error("经费余额查询失败:", error)
|
console.error("经费余额查询失败:", error)
|
||||||
this.$set(this.formData, "fundBalance", null)
|
this.$set(this.formData, "fundBalance", null)
|
||||||
this.fundBalanceText = "查询失败"
|
this.fundBalanceText = "查询失败"
|
||||||
@@ -2016,7 +2088,8 @@ layout("/layouts/platform.html"){
|
|||||||
this.formData.hospitalizationEndTime
|
this.formData.hospitalizationEndTime
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if (this.$auth.hasRoleOr(["SCHOOL_OUTLAY_ADMIN", "SCHOOL_UNION_ADMIN"])) {
|
if (this.$auth.hasRoleOr(["SCHOOL_OUTLAY_ADMIN", "SCHOOL_UNION_ADMIN"])
|
||||||
|
&& !this.$auth.hasRoleOr(["BRANCH_UNION_CHAIRMAN", "BRANCH_UNION_ADMIN", "CLUB_MANAGER", "CLUB_PRESIDENT"])) {
|
||||||
this.budgetTypeOption.map(v => {
|
this.budgetTypeOption.map(v => {
|
||||||
if (["UNION_REIMBURSE_FUND_SOURCE_1"].includes(v.code)) {
|
if (["UNION_REIMBURSE_FUND_SOURCE_1"].includes(v.code)) {
|
||||||
budgetTypeOption.push(v)
|
budgetTypeOption.push(v)
|
||||||
@@ -2030,7 +2103,7 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (this.$auth.hasRoleOr(["CLUB_MANAGER", "CLUB_PRESIDENT"])) {
|
if (this.$auth.hasPermission("unionReimburse.club")) {
|
||||||
this.budgetTypeOption.map(v => {
|
this.budgetTypeOption.map(v => {
|
||||||
if (["UNION_REIMBURSE_FUND_SOURCE_3"].includes(v.code)) {
|
if (["UNION_REIMBURSE_FUND_SOURCE_3"].includes(v.code)) {
|
||||||
budgetTypeOption.push(v)
|
budgetTypeOption.push(v)
|
||||||
@@ -2039,11 +2112,22 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
this.budgetTypeOption = budgetTypeOption
|
this.budgetTypeOption = budgetTypeOption
|
||||||
}
|
}
|
||||||
|
// 社团经费按菜单权限过滤,默认来源与按钮可见范围保持一致。
|
||||||
|
this.budgetTypeOption = this.budgetTypeOption.filter(item =>
|
||||||
|
item.code !== "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
|| this.$auth.hasPermission("unionReimburse.club"))
|
||||||
this.reimburseProjectList = await this.$businessTool.getDictOptions("UNION_REIMBURSE_PROJECT")
|
this.reimburseProjectList = await this.$businessTool.getDictOptions("UNION_REIMBURSE_PROJECT")
|
||||||
|
if (this.budgetTypeOption.some(item => item.code === "UNION_REIMBURSE_FUND_SOURCE_3")) {
|
||||||
|
const clubs = await this.$axios.post("/platform/unionReimburse/apply/listReimburseClubs")
|
||||||
|
this.clubOptions = clubs.data || []
|
||||||
|
}
|
||||||
if (this.bizId) {
|
if (this.bizId) {
|
||||||
this.$axios.post("/platform/unionReimburse/apply/info", {id: this.bizId}).then(async (res) => {
|
this.$axios.post("/platform/unionReimburse/apply/info", {id: this.bizId}).then(async (res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.formData = this.ensureFormData(res.data)
|
this.formData = this.ensureFormData(res.data)
|
||||||
|
if (this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3") {
|
||||||
|
this.$set(this.formData, "reimburseProject", "UNION_REIMBURSE_PROJECT_5")
|
||||||
|
}
|
||||||
this.appendCurrentPayerOption()
|
this.appendCurrentPayerOption()
|
||||||
this.formData.paymentDetails.forEach(row => {
|
this.formData.paymentDetails.forEach(row => {
|
||||||
if (row.payer) {
|
if (row.payer) {
|
||||||
@@ -2066,7 +2150,8 @@ layout("/layouts/platform.html"){
|
|||||||
unionId: union?.id,
|
unionId: union?.id,
|
||||||
unionName: union?.name,
|
unionName: union?.name,
|
||||||
// reimburseType: "UNION_REIMBURSE_TYPE_1",
|
// reimburseType: "UNION_REIMBURSE_TYPE_1",
|
||||||
reimburseProject: 'UNION_REIMBURSE_PROJECT_1',
|
reimburseProject: this.getDefaultFundSource() === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
? "UNION_REIMBURSE_PROJECT_5" : "UNION_REIMBURSE_PROJECT_1",
|
||||||
reimburseFundSource: this.getDefaultFundSource(),
|
reimburseFundSource: this.getDefaultFundSource(),
|
||||||
paymentWay: 'UNION_REIMBURSE_PAYMENT_WAY_2',
|
paymentWay: 'UNION_REIMBURSE_PAYMENT_WAY_2',
|
||||||
paymentDetails: [this.buildDefaultPaymentDetail({
|
paymentDetails: [this.buildDefaultPaymentDetail({
|
||||||
@@ -2076,7 +2161,7 @@ layout("/layouts/platform.html"){
|
|||||||
userId: id,
|
userId: id,
|
||||||
})
|
})
|
||||||
if (this.formData.reimburseFundSource) {
|
if (this.formData.reimburseFundSource) {
|
||||||
this.reimburseFundSourceChange()
|
this.selectFundSource(this.formData.reimburseFundSource)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2085,17 +2170,7 @@ layout("/layouts/platform.html"){
|
|||||||
this.init()
|
this.init()
|
||||||
this.queryFileDesc()
|
this.queryFileDesc()
|
||||||
this.queryCondolenceType()
|
this.queryCondolenceType()
|
||||||
//社团查询
|
|
||||||
this.$businessTool.listClubByRole().then((res) => {
|
|
||||||
this.$set(this, "clubOptions", res || [])
|
|
||||||
if (res && res.length === 1 && !this.formData.clubId) {
|
|
||||||
this.$set(this.formData, "clubId", res[0].id)
|
|
||||||
this.$set(this.formData, "clubName", res[0].clubName)
|
|
||||||
}
|
|
||||||
if (this.formData.reimburseFundSource) {
|
|
||||||
this.reimburseFundSourceChange()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+2
-2
@@ -51,10 +51,10 @@ layout("/layouts/platform.html"){
|
|||||||
</table-tool>
|
</table-tool>
|
||||||
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
|
||||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||||
|
<el-table-column prop="serialNo" label="流水号" width="120"></el-table-column>
|
||||||
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
|
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="userName" label="姓名"></el-table-column>
|
<el-table-column prop="userName" label="姓名"></el-table-column>
|
||||||
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
|
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="unitName" label="所属单位" sortable="custom"></el-table-column>
|
|
||||||
<el-table-column prop="createTime" label="申请时间" sortable="custom">
|
<el-table-column prop="createTime" label="申请时间" sortable="custom">
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="{row}">
|
||||||
{{ formatCreateTime(row.createTime) }}
|
{{ formatCreateTime(row.createTime) }}
|
||||||
@@ -62,7 +62,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
|
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="{row}">
|
||||||
<el-select v-if="isAdmin && row.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'"
|
<el-select v-if="isAdmin && row.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1' && row.reimburseFundSource !== 'UNION_REIMBURSE_FUND_SOURCE_3'"
|
||||||
:value="row.reimburseProject"
|
:value="row.reimburseProject"
|
||||||
size="mini"
|
size="mini"
|
||||||
style="width: 120px"
|
style="width: 120px"
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const unionReimburseInfo = {
|
|||||||
<el-descriptions-item label="联系方式">
|
<el-descriptions-item label="联系方式">
|
||||||
<span>{{ viewData.mobile }}</span>
|
<span>{{ viewData.mobile }}</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item></el-descriptions-item>
|
<el-descriptions-item v-if="viewData.reimburseFundSource !== 'UNION_REIMBURSE_FUND_SOURCE_3'"></el-descriptions-item>
|
||||||
<el-descriptions-item v-if="!viewData.reimburseFundSource"></el-descriptions-item>
|
<el-descriptions-item v-if="!viewData.reimburseFundSource"></el-descriptions-item>
|
||||||
<el-descriptions-item label="支付信息" :span="3">
|
<el-descriptions-item label="支付信息" :span="3">
|
||||||
<el-table :data="paymentInfoRows" border empty-text="暂无支付信息" style="width: 100%">
|
<el-table :data="paymentInfoRows" border empty-text="暂无支付信息" style="width: 100%">
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ layout("/layouts/platform.html"){
|
|||||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
|
||||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_3'">日常活动</span>
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_3'">日常活动</span>
|
||||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_4'">专项活动</span>
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_4'">专项活动</span>
|
||||||
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_5'">社团活动</span>
|
||||||
<span v-else>{{ row.reimburseProject }}</span>
|
<span v-else>{{ row.reimburseProject }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
+2
-1
@@ -58,10 +58,10 @@ layout("/layouts/platform.html"){
|
|||||||
<el-table-column v-if="!pageForm.approval" type="selection" width="55"
|
<el-table-column v-if="!pageForm.approval" type="selection" width="55"
|
||||||
:reserve-selection="true" :selectable="(row) => row.stateId == 2"></el-table-column>
|
:reserve-selection="true" :selectable="(row) => row.stateId == 2"></el-table-column>
|
||||||
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
|
||||||
|
<el-table-column prop="serialNo" label="流水号" width="120"></el-table-column>
|
||||||
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
|
<el-table-column prop="loginName" label="经办人工号" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="userName" label="姓名"></el-table-column>
|
<el-table-column prop="userName" label="姓名"></el-table-column>
|
||||||
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
|
<el-table-column prop="unionName" label="所属工会" sortable="custom"></el-table-column>
|
||||||
<el-table-column prop="unitName" label="所属单位" sortable="custom"></el-table-column>
|
|
||||||
<el-table-column prop="createTime" label="申请时间" sortable="custom">
|
<el-table-column prop="createTime" label="申请时间" sortable="custom">
|
||||||
<template slot-scope="{row}">
|
<template slot-scope="{row}">
|
||||||
{{ formatCreateTime(row.createTime) }}
|
{{ formatCreateTime(row.createTime) }}
|
||||||
@@ -73,6 +73,7 @@ layout("/layouts/platform.html"){
|
|||||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
|
||||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_3'">日常活动</span>
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_3'">日常活动</span>
|
||||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_4'">专项活动</span>
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_4'">专项活动</span>
|
||||||
|
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_5'">社团活动</span>
|
||||||
<span v-else>{{ row.reimburseProject }}</span>
|
<span v-else>{{ row.reimburseProject }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|||||||
+96
-25
@@ -337,7 +337,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</template>
|
</template>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-popup position="bottom" round :close-on-click-overlay="true" v-model:show="showReimburseProjectPicker" class="union-half-popup">
|
<van-popup position="bottom" round :close-on-click-overlay="true" v-model:show="showReimburseProjectPicker" class="union-half-popup">
|
||||||
<van-picker :columns="reimburseProjectColumns" @cancel="closePopup('showReimburseProjectPicker')"
|
<van-picker :columns="availableReimburseProjectColumns" @cancel="closePopup('showReimburseProjectPicker')"
|
||||||
@confirm="onReimburseProjectConfirm" show-toolbar></van-picker>
|
@confirm="onReimburseProjectConfirm" show-toolbar></van-picker>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
<van-field
|
<van-field
|
||||||
@@ -680,6 +680,12 @@ layout("/layouts/platform_h5.html"){
|
|||||||
required
|
required
|
||||||
is-link
|
is-link
|
||||||
></van-field>
|
></van-field>
|
||||||
|
<van-field v-if="isManualReimburseAmount"
|
||||||
|
label="报销金额" name="money"
|
||||||
|
v-model="formData.money"
|
||||||
|
placeholder="请输入报销金额,最多两位小数"
|
||||||
|
:rules="[{ required: true, message: '请填写报销金额' }, { validator: () => !getReimburseAmountMessage(), message: getReimburseAmountMessage }]"
|
||||||
|
required></van-field>
|
||||||
<van-popup position="bottom" round :close-on-click-overlay="true" v-model:show="showActivityTimePicker" class="union-half-popup">
|
<van-popup position="bottom" round :close-on-click-overlay="true" v-model:show="showActivityTimePicker" class="union-half-popup">
|
||||||
<van-datetime-picker type="date" title="选择活动时间" :min-date="minDate" :max-date="maxDate"
|
<van-datetime-picker type="date" title="选择活动时间" :min-date="minDate" :max-date="maxDate"
|
||||||
@cancel="closePopup('showActivityTimePicker')"
|
@cancel="closePopup('showActivityTimePicker')"
|
||||||
@@ -692,8 +698,9 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<section class="form-section">
|
<section class="form-section">
|
||||||
<h2 class="form-section__title">附件信息</h2>
|
<h2 class="form-section__title">附件信息</h2>
|
||||||
<van-cell-group :border="false">
|
<van-cell-group :border="false">
|
||||||
<van-field class="more-text reimburse-upload-field" name="files" required
|
<van-field class="more-text reimburse-upload-field" name="files"
|
||||||
label="" :rules="[{ required: true, message: '请上传附件' }]">
|
:required="!['UNION_REIMBURSE_PROJECT_2', 'UNION_REIMBURSE_PROJECT_3', 'UNION_REIMBURSE_PROJECT_5'].includes(formData.reimburseProject)"
|
||||||
|
label="" :rules="['UNION_REIMBURSE_PROJECT_2', 'UNION_REIMBURSE_PROJECT_3', 'UNION_REIMBURSE_PROJECT_5'].includes(formData.reimburseProject) ? [] : [{ required: true, message: '请上传附件' }]">
|
||||||
<template #input>
|
<template #input>
|
||||||
<h5-file-upload
|
<h5-file-upload
|
||||||
slot="input"
|
slot="input"
|
||||||
@@ -706,6 +713,11 @@ layout("/layouts/platform_h5.html"){
|
|||||||
></h5-file-upload>
|
></h5-file-upload>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
|
<van-cell v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_5'">
|
||||||
|
<template #title>
|
||||||
|
<span style="color: #ee0a24;">社团活动附件说明</span>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
</section>
|
</section>
|
||||||
<van-cell-group class="form-section">
|
<van-cell-group class="form-section">
|
||||||
@@ -762,10 +774,10 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
<van-cell-group class="form-section" v-if="formData.reimburseProject">
|
<van-cell-group class="form-section" v-if="formData.reimburseProject">
|
||||||
<div class="form-section__title">电子发票(选填)</div>
|
<div class="form-section__title">电子发票(选填)</div>
|
||||||
<div class="invoice-tip">无发票时按支付信息汇总报销金额;上传的发票仍须通过验真。</div>
|
<div class="invoice-tip">{{ isManualReimburseAmount ? '有发票时报销金额不得超过发票总额,无发票仍可提交;上传的发票仍须通过验真。' : '无发票时按支付信息汇总报销金额;上传的发票仍须通过验真。' }}</div>
|
||||||
<van-field label="报销金额"
|
<van-field label="报销金额"
|
||||||
v-model="formData.money"
|
v-model="formData.money"
|
||||||
placeholder="有发票按发票汇总,无发票按支付信息汇总"
|
:placeholder="isManualReimburseAmount ? '请在报销信息填写报销金额' : '有发票按发票汇总,无发票按支付信息汇总'"
|
||||||
readonly></van-field>
|
readonly></van-field>
|
||||||
<van-field label="发票张数"
|
<van-field label="发票张数"
|
||||||
v-model="formData.invoiceNumber"
|
v-model="formData.invoiceNumber"
|
||||||
@@ -847,6 +859,11 @@ layout("/layouts/platform_h5.html"){
|
|||||||
></h5-file-upload>
|
></h5-file-upload>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
|
<van-cell v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_5'">
|
||||||
|
<template #title>
|
||||||
|
<span style="color: #ee0a24;">社团活动附件说明</span>
|
||||||
|
</template>
|
||||||
|
</van-cell>
|
||||||
<van-field label="发票号码"
|
<van-field label="发票号码"
|
||||||
v-model="detailForm.invoiceNo" readonly
|
v-model="detailForm.invoiceNo" readonly
|
||||||
placeholder="请输入发票号码"
|
placeholder="请输入发票号码"
|
||||||
@@ -1136,6 +1153,10 @@ layout("/layouts/platform_h5.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
isManualReimburseAmount() {
|
||||||
|
return ["UNION_REIMBURSE_PROJECT_2", "UNION_REIMBURSE_PROJECT_3", "UNION_REIMBURSE_PROJECT_4"]
|
||||||
|
.includes(this.formData.reimburseProject)
|
||||||
|
},
|
||||||
// 发票或支付明细变化时同步展示超额提示。
|
// 发票或支付明细变化时同步展示超额提示。
|
||||||
paymentAmountLimitMessage() {
|
paymentAmountLimitMessage() {
|
||||||
return this.getPaymentAmountLimitMessage(this.formData.paymentDetails || [])
|
return this.getPaymentAmountLimitMessage(this.formData.paymentDetails || [])
|
||||||
@@ -1147,9 +1168,17 @@ layout("/layouts/platform_h5.html"){
|
|||||||
const selectedType = this.typeOptions.find(item => item.id === typeId)
|
const selectedType = this.typeOptions.find(item => item.id === typeId)
|
||||||
return selectedType ? selectedType.code : ""
|
return selectedType ? selectedType.code : ""
|
||||||
},
|
},
|
||||||
// 仅系统管理员和校工会管理员可查看真实余额,其他账号统一显示余额遮罩。
|
// 社团经费按菜单授权查看年度剩余额度,其他经费沿用原余额可见范围。
|
||||||
canViewFundBalance() {
|
canViewFundBalance() {
|
||||||
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||||
|
|| (this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
&& this.$auth.hasPermission("unionReimburse.club"))
|
||||||
|
},
|
||||||
|
// 社团经费仅可选择社团活动,其他经费不展示社团活动。
|
||||||
|
availableReimburseProjectColumns() {
|
||||||
|
const clubFund = this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
return this.reimburseProjectColumns.filter(item =>
|
||||||
|
clubFund ? item.value === "UNION_REIMBURSE_PROJECT_5" : item.value !== "UNION_REIMBURSE_PROJECT_5")
|
||||||
},
|
},
|
||||||
paymentInfoRows() {
|
paymentInfoRows() {
|
||||||
return this.formData.paymentDetails || []
|
return this.formData.paymentDetails || []
|
||||||
@@ -1233,6 +1262,9 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
"formData.reimburseProject"(newVal) {
|
"formData.reimburseProject"(newVal) {
|
||||||
this.handleReimburseProjectChange(newVal)
|
this.handleReimburseProjectChange(newVal)
|
||||||
|
},
|
||||||
|
"formData.reimburseFundSource"() {
|
||||||
|
this.syncReimburseProject()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1852,6 +1884,27 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.rebuildInvoiceSummary()
|
this.rebuildInvoiceSummary()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
// 手填金额按分比较票面总额;未上传发票时仍允许申请。
|
||||||
|
getReimburseAmountMessage() {
|
||||||
|
if (!this.isManualReimburseAmount) return ""
|
||||||
|
const value = String(this.formData.money == null ? "" : this.formData.money)
|
||||||
|
if (!value) return "请填写报销金额"
|
||||||
|
const cents = this.moneyToCents(value)
|
||||||
|
if (!/^\d+(\.\d{1,2})?$/.test(value) || cents === null || cents <= 0) {
|
||||||
|
return "报销金额必须为正数,且最多两位小数"
|
||||||
|
}
|
||||||
|
const invoices = this.formData.invoiceDetails || []
|
||||||
|
let invoiceCents = 0
|
||||||
|
for (let i = 0; i < invoices.length; i++) {
|
||||||
|
const amount = this.moneyToCents(invoices[i] && invoices[i].invoiceAmount)
|
||||||
|
if (amount === null || amount <= 0) return "请填写正确的发票金额"
|
||||||
|
invoiceCents += amount
|
||||||
|
}
|
||||||
|
if (invoices.length && cents > invoiceCents) {
|
||||||
|
return "报销金额不能超过发票总额(" + (invoiceCents / 100).toFixed(2) + "元)"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
},
|
||||||
rebuildInvoiceSummary() {
|
rebuildInvoiceSummary() {
|
||||||
let totalMoney = 0
|
let totalMoney = 0
|
||||||
let fileCount = 0
|
let fileCount = 0
|
||||||
@@ -1876,10 +1929,18 @@ layout("/layouts/platform_h5.html"){
|
|||||||
})
|
})
|
||||||
totalMoney = paymentCents / 100
|
totalMoney = paymentCents / 100
|
||||||
}
|
}
|
||||||
|
// 三类活动保留手填申请金额,发票及支付明细变化只更新张数。
|
||||||
|
if (!this.isManualReimburseAmount) {
|
||||||
this.$set(this.formData, "money", totalMoney ? totalMoney.toFixed(2) : "0.00")
|
this.$set(this.formData, "money", totalMoney ? totalMoney.toFixed(2) : "0.00")
|
||||||
|
}
|
||||||
this.$set(this.formData, "invoiceNumber", String(fileCount))
|
this.$set(this.formData, "invoiceNumber", String(fileCount))
|
||||||
},
|
},
|
||||||
validateInvoiceDetailsBeforeSubmit() {
|
validateInvoiceDetailsBeforeSubmit() {
|
||||||
|
const amountMessage = this.getReimburseAmountMessage()
|
||||||
|
if (amountMessage) {
|
||||||
|
this.$toast.fail(amountMessage)
|
||||||
|
return false
|
||||||
|
}
|
||||||
const invoiceDetails = this.formData.invoiceDetails || []
|
const invoiceDetails = this.formData.invoiceDetails || []
|
||||||
// 发票可不上传;已经添加的发票仍须填写完整并沿用验真流程。
|
// 发票可不上传;已经添加的发票仍须填写完整并沿用验真流程。
|
||||||
for (let i = 0; i < invoiceDetails.length; i++) {
|
for (let i = 0; i < invoiceDetails.length; i++) {
|
||||||
@@ -2366,6 +2427,15 @@ layout("/layouts/platform_h5.html"){
|
|||||||
}
|
}
|
||||||
this.closePopup("showPaymentWayPicker")
|
this.closePopup("showPaymentWayPicker")
|
||||||
},
|
},
|
||||||
|
// 新建、切换来源及编辑回显都保持社团经费与社团活动一致。
|
||||||
|
syncReimburseProject() {
|
||||||
|
const clubFund = this.formData.reimburseFundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
if (!clubFund && this.formData.reimburseProject !== "UNION_REIMBURSE_PROJECT_5") return
|
||||||
|
const projectCode = clubFund ? "UNION_REIMBURSE_PROJECT_5" : "UNION_REIMBURSE_PROJECT_2"
|
||||||
|
const project = this.reimburseProjectColumns.find(item => item.value === projectCode)
|
||||||
|
this.$set(this.formData, "reimburseProject", project ? project.value : "")
|
||||||
|
this.$set(this.formData, "reimburseProjectName", project ? project.text : "")
|
||||||
|
},
|
||||||
onReimburseProjectConfirm(o) {
|
onReimburseProjectConfirm(o) {
|
||||||
this.$set(this.formData, "reimburseProjectName", o.text) // 显示名称
|
this.$set(this.formData, "reimburseProjectName", o.text) // 显示名称
|
||||||
this.$set(this.formData, "reimburseProject", o.value) // 字典值
|
this.$set(this.formData, "reimburseProject", o.value) // 字典值
|
||||||
@@ -2441,16 +2511,10 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
// 新建申请默认优先选择分工会经费;若当前用户没有对应权限,则按页面可见权限回退到其它经费来源。
|
// 新建申请默认优先选择分工会经费;若当前用户没有对应权限,则按页面可见权限回退到其它经费来源。
|
||||||
getDefaultFundSource() {
|
getDefaultFundSource() {
|
||||||
if (this.$auth.hasPermission("unionReimburse.fgh")) {
|
const option = this.reimburseFundSourceColumns.find(item => item.value === "UNION_REIMBURSE_FUND_SOURCE_2")
|
||||||
return "UNION_REIMBURSE_FUND_SOURCE_2"
|
|| this.reimburseFundSourceColumns.find(item => item.value === "UNION_REIMBURSE_FUND_SOURCE_3")
|
||||||
}
|
|| this.reimburseFundSourceColumns[0]
|
||||||
if (this.$auth.hasPermission("unionReimburse.xgh")) {
|
return option ? option.value : ""
|
||||||
return "UNION_REIMBURSE_FUND_SOURCE_1"
|
|
||||||
}
|
|
||||||
if (this.$auth.hasPermission("unionReimburse.club")) {
|
|
||||||
return "UNION_REIMBURSE_FUND_SOURCE_3"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
},
|
},
|
||||||
getReimburseFundSourceName(code) {
|
getReimburseFundSourceName(code) {
|
||||||
const matchedFundSource = this.reimburseFundSourceColumns.find(item => item.value === code)
|
const matchedFundSource = this.reimburseFundSourceColumns.find(item => item.value === code)
|
||||||
@@ -2467,6 +2531,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
// 根据当前选择的报销项目获取管理端配置的提示内容。
|
// 根据当前选择的报销项目获取管理端配置的提示内容。
|
||||||
getProjectTipByProject(projectCode) {
|
getProjectTipByProject(projectCode) {
|
||||||
|
if (projectCode === "UNION_REIMBURSE_PROJECT_5") projectCode = "UNION_REIMBURSE_PROJECT_2"
|
||||||
if (!this.descOptions || !Array.isArray(this.descOptions)) {
|
if (!this.descOptions || !Array.isArray(this.descOptions)) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -2485,7 +2550,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.$set(this, "reimburseProjectList", reimburseProjectData)
|
this.$set(this, "reimburseProjectList", reimburseProjectData)
|
||||||
return this.$businessTool.getDictOptions("UNION_REIMBURSE_FUND_SOURCE")
|
return this.$businessTool.getDictOptions("UNION_REIMBURSE_FUND_SOURCE")
|
||||||
}).then((reimburseFundSourceData) => {
|
}).then((reimburseFundSourceData) => {
|
||||||
this.$set(this, "reimburseFundSourceColumns", reimburseFundSourceData.map(item => ({value: item.code, text: item.name})))
|
this.$set(this, "reimburseFundSourceColumns", reimburseFundSourceData.map(item => ({value: item.code, text: item.code === "UNION_REIMBURSE_FUND_SOURCE_3" ? "协会经费" : item.name})))
|
||||||
this.filterReimburseFundSources()
|
this.filterReimburseFundSources()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -2567,7 +2632,8 @@ layout("/layouts/platform_h5.html"){
|
|||||||
|
|
||||||
// 查询社团
|
// 查询社团
|
||||||
queryClubs() {
|
queryClubs() {
|
||||||
return this.$businessTool.listClubByRole().then((res) => {
|
return this.$axios.post("/platform/unionReimburse/apply/listReimburseClubs").then((response) => {
|
||||||
|
const res = response.data || []
|
||||||
this.$set(this, "clubOptions", res)
|
this.$set(this, "clubOptions", res)
|
||||||
this.$set(this, "clubColumns", res.map(item => {
|
this.$set(this, "clubColumns", res.map(item => {
|
||||||
return { text: item.clubName, value: item.id }
|
return { text: item.clubName, value: item.id }
|
||||||
@@ -2601,7 +2667,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
url: "/platform/unionReimburse/apply/getUnionBalance"
|
url: "/platform/unionReimburse/apply/getUnionBalance"
|
||||||
},
|
},
|
||||||
"UNION_REIMBURSE_FUND_SOURCE_3": {
|
"UNION_REIMBURSE_FUND_SOURCE_3": {
|
||||||
url: "/platform/unionReimburse/apply/getClubBudget"
|
url: "/platform/unionReimburse/apply/getBudgetBalance"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2630,14 +2696,20 @@ layout("/layouts/platform_h5.html"){
|
|||||||
// 发送请求
|
// 发送请求
|
||||||
this.$axios.post(apiInfo.url, params)
|
this.$axios.post(apiInfo.url, params)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
// 切换来源或社团后,旧请求不得覆盖当前余额。
|
||||||
|
if (fundSource !== this.formData.reimburseFundSource
|
||||||
|
|| (params.clubId && params.clubId !== this.formData.clubId)) return
|
||||||
if (response.code === 0) {
|
if (response.code === 0) {
|
||||||
// 显示经费余额(只显示数字,不显示"元")
|
// 显示经费余额(只显示数字,不显示"元")
|
||||||
this.$set(this.formData, "fundBalance", response.data || "0.00")
|
this.$set(this.formData, "fundBalance", fundSource === "UNION_REIMBURSE_FUND_SOURCE_3"
|
||||||
|
? Number(response.data || 0).toFixed(2) : (response.data || "0.00"))
|
||||||
} else {
|
} else {
|
||||||
this.$set(this.formData, "fundBalance", "查询失败")
|
this.$set(this.formData, "fundBalance", "查询失败")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
if (fundSource !== this.formData.reimburseFundSource
|
||||||
|
|| (params.clubId && params.clubId !== this.formData.clubId)) return
|
||||||
console.error("经费余额查询失败:", error)
|
console.error("经费余额查询失败:", error)
|
||||||
this.$set(this.formData, "fundBalance", "查询失败")
|
this.$set(this.formData, "fundBalance", "查询失败")
|
||||||
this.$toast.fail("经费余额查询失败")
|
this.$toast.fail("经费余额查询失败")
|
||||||
@@ -2807,12 +2879,11 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.$set(this.formData, "unionId", user.union.id)
|
this.$set(this.formData, "unionId", user.union.id)
|
||||||
this.$set(this.formData, "unionName", user.union.name)
|
this.$set(this.formData, "unionName", user.union.name)
|
||||||
const defaultFundSource = this.getDefaultFundSource()
|
const defaultFundSource = this.getDefaultFundSource()
|
||||||
this.$set(this.formData, "reimburseFundSource", defaultFundSource)
|
|
||||||
this.$set(this.formData, "reimburseFundSourceName", this.getReimburseFundSourceName(defaultFundSource))
|
|
||||||
this.$set(this.formData, "paymentDetails", [])
|
this.$set(this.formData, "paymentDetails", [])
|
||||||
if (this.formData.reimburseFundSource) {
|
this.onReimburseFundSourceConfirm({
|
||||||
this.queryFundBalance()
|
value: defaultFundSource,
|
||||||
}
|
text: this.getReimburseFundSourceName(defaultFundSource)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user