Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -285,21 +285,28 @@ public class SysUnitController {
|
||||
@SaCheckLogin
|
||||
public Object tree(@Param("pid") String pid, HttpServletRequest req) {
|
||||
try {
|
||||
String rootId = StrUtil.blankToDefault(pid, "0");
|
||||
String virtualRootId = "root";
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("id", "=", pid);
|
||||
cnd.asc("unitcode");
|
||||
List<Sys_unit> list = sysUnitService.query(cnd);
|
||||
|
||||
List<TreeNode<String>> nodeList = CollUtil.newArrayList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
nodeList.add(new TreeNode<>(list.get(i).getId(), list.get(i).getParentId(), list.get(i).getName(), i)
|
||||
Sys_unit unit = list.get(i);
|
||||
/*
|
||||
* 单位根节点存在 id 与 parentId 都为 0 的自引用数据。
|
||||
* 构建树时把当前查询根挂到虚拟根下,避免“中国地质大学”和 parentId=0 的学院被构造成同级。
|
||||
*/
|
||||
String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId();
|
||||
nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i)
|
||||
.setExtra(
|
||||
Map.of(
|
||||
"unitTypeCode", list.get(i).getUnitTypeCode()
|
||||
"unitTypeCode", unit.getUnitTypeCode()
|
||||
)
|
||||
));
|
||||
}
|
||||
List<Tree<String>> treeList = TreeUtil.build(nodeList, StrUtil.blankToDefault(pid, "0"));
|
||||
List<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId);
|
||||
return Result.success(treeList);
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
|
||||
+1
-3
@@ -15,7 +15,6 @@ import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.culture.models.ActivityTissue;
|
||||
@@ -151,8 +150,7 @@ public class ActivityCultureApplyActivityController {
|
||||
return Result.success();
|
||||
}
|
||||
if (tissue.getIsEnrollSystem()) {
|
||||
Sys_home_activity sysHomeActivity = tissue.covertToSysHomeActivity();
|
||||
activityCultureService.insertOrUpdate(sysHomeActivity);
|
||||
activityCultureService.syncHomeActivity(tissue);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
+1
-3
@@ -9,7 +9,6 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.culture.models.ActivityTissue;
|
||||
import com.budwk.app.zhgh.activity.culture.service.ActivityCultureService;
|
||||
@@ -144,8 +143,7 @@ public class ActivityCultureAuditActivityController {
|
||||
tissue.setIsUnseal(true);
|
||||
activityCultureService.update(tissue);
|
||||
if (args.getInt("submitType") == 1) {
|
||||
Sys_home_activity sysHomeActivity = tissue.covertToSysHomeActivity();
|
||||
activityCultureService.insertOrUpdate(sysHomeActivity);
|
||||
activityCultureService.syncHomeActivity(tissue);
|
||||
}
|
||||
flowCommonService.executeTask(args);
|
||||
return Result.success();
|
||||
|
||||
+9
-3
@@ -74,9 +74,15 @@ public class ActivityCultureInfoManageController {
|
||||
@SaCheckPermission(value = {"activity.culture.infoManage.school", "activity.culture.infoManage.union", "activity.culture.infoManage.club"}, mode = SaMode.OR)
|
||||
public Result activityStatusChange(@Valid String id, @Valid Boolean isUnseal) {
|
||||
activityCultureService.update(Chain.make("isUnseal", isUnseal), Cnd.where("id", "=", id));
|
||||
activityCultureService.dao().update(Sys_home_activity.class,
|
||||
Chain.make("enable", isUnseal),
|
||||
Cnd.where("id", "=", id));
|
||||
ActivityTissue tissue = activityCultureService.fetch(id);
|
||||
tissue.setIsUnseal(isUnseal);
|
||||
if (Boolean.TRUE.equals(isUnseal)) {
|
||||
activityCultureService.syncHomeActivity(tissue);
|
||||
} else {
|
||||
activityCultureService.dao().update(Sys_home_activity.class,
|
||||
Chain.make("enable", false),
|
||||
Cnd.where("id", "=", id));
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,4 +24,14 @@ public interface ActivityCultureService extends BaseService<ActivityTissue> {
|
||||
Object pageData(PageForm page, String year, String name, String unionId, Integer activity_type);
|
||||
|
||||
NutMap findOne(String id);
|
||||
|
||||
/**
|
||||
* 同步文化活动到首页活动表。
|
||||
* 1. 非报名类活动不推送首页,直接清理首页记录。
|
||||
* 2. 校工会活动没有审核流,提交后默认可推首页。
|
||||
* 3. 分工会、协会活动仅在已审核通过或已存在首页记录时更新首页信息。
|
||||
*
|
||||
* @param tissue 文化活动
|
||||
*/
|
||||
void syncHomeActivity(ActivityTissue tissue);
|
||||
}
|
||||
|
||||
+37
@@ -5,6 +5,7 @@ import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.model.Audit;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
@@ -80,6 +81,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
@Override
|
||||
public void doEditActivity(ActivityTissue tissue) {
|
||||
update(tissue);
|
||||
syncHomeActivity(tissue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,6 +125,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
cnd.andEX("tissue.projectTypeCode", "!=", "50004");
|
||||
cnd.andEX("tissue.unionId", "=", unionId);
|
||||
cnd.andEX("tissue.activity_type", "=", activity_type);
|
||||
cnd.groupBy("tissue.id");
|
||||
|
||||
if (Strings.isNotBlank(name)) {
|
||||
cnd.where().andLike("tissue.name", name);
|
||||
@@ -188,4 +191,38 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
|
||||
return nutMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncHomeActivity(ActivityTissue tissue) {
|
||||
if (tissue == null || Strings.isBlank(tissue.getId())) {
|
||||
return;
|
||||
}
|
||||
// 非报名活动不需要出现在首页,编辑成活动管理模式时同步移除首页记录。
|
||||
if (!Boolean.TRUE.equals(tissue.getIsEnrollSystem())) {
|
||||
dao().delete(Sys_home_activity.class, tissue.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_home_activity oldHomeActivity = dao().fetch(Sys_home_activity.class, tissue.getId());
|
||||
boolean canCreateHomeActivity = (tissue.getActivity_type() != null
|
||||
&& tissue.getActivity_type() == 40001)
|
||||
|| Boolean.TRUE.equals(tissue.getIsUnseal())
|
||||
|| oldHomeActivity != null;
|
||||
if (!canCreateHomeActivity) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_home_activity sysHomeActivity = tissue.covertToSysHomeActivity();
|
||||
// 校工会文化活动没有审核环节,前端未回传启用状态时默认直接上首页。
|
||||
if (tissue.getActivity_type() != null && tissue.getActivity_type() == 40001 && tissue.getIsUnseal() == null) {
|
||||
sysHomeActivity.setEnable(true);
|
||||
}
|
||||
// 保留首页管理中手工设置的置顶、大图和排序,避免活动编辑时被覆盖。
|
||||
if (oldHomeActivity != null) {
|
||||
sysHomeActivity.setTop(oldHomeActivity.getTop());
|
||||
sysHomeActivity.setPush(oldHomeActivity.getPush());
|
||||
sysHomeActivity.setSortNo(oldHomeActivity.getSortNo());
|
||||
}
|
||||
dao().insertOrUpdate(sysHomeActivity);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -60,6 +60,7 @@ public class H5ActivityWorksUploadCollectionController {
|
||||
awc.*
|
||||
FROM
|
||||
`activity_works_collection` awc
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("YEAR(awc.startDateTime)", "=", year);
|
||||
@@ -68,9 +69,9 @@ public class H5ActivityWorksUploadCollectionController {
|
||||
cnd.and(new Static("now() > awc.startDateTime and now() < awc.endDateTime"));
|
||||
}//查询已结束的
|
||||
else if (activityType == 3) {
|
||||
cnd.and(new Static("now() > awc.startDateTime"));
|
||||
cnd.and(new Static("now() >= awc.endDateTime"));
|
||||
} else if (activityType == 4) {
|
||||
cnd.and(new Static("now() < awc.endDateTime"));
|
||||
cnd.and(new Static("now() < awc.startDateTime"));
|
||||
}
|
||||
cnd.and("awc.enable", "=", 1);
|
||||
cnd.and("awc.type", "=", 1);
|
||||
|
||||
+19
-8
@@ -28,6 +28,7 @@ import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.web.controllers.open.commons.service.CommonService;
|
||||
import com.budwk.app.zhgh.club.model.ClubUser;
|
||||
import com.budwk.app.zhgh.club.model.ClubUserApply;
|
||||
import com.budwk.app.zhgh.club.service.ClubUserJoinService;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -64,6 +65,8 @@ public class ClubUserJoinApplyController {
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private ClubUserJoinService clubUserJoinService;
|
||||
|
||||
@At("/")
|
||||
@SaCheckPermission("club.join.apply")
|
||||
@@ -112,6 +115,8 @@ public class ClubUserJoinApplyController {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setMode(true);
|
||||
clubUserApply.setApplyDate(new Date());
|
||||
clubUserApply.setJoinTime(clubUserJoinService.resolveJoinTime(clubUserApply.getClubId(), clubUserApply.getUserId()));
|
||||
clubUserApply.setExitTime(null);
|
||||
dao.insertOrUpdate(clubUserApply);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -124,12 +129,10 @@ public class ClubUserJoinApplyController {
|
||||
public Result submit(@Param("data") ClubUserApply clubUserApply,
|
||||
@Param("mode") Boolean mode) {
|
||||
if(mode == false) {
|
||||
clubUserApply = dao.fetch(
|
||||
ClubUserApply.class,
|
||||
Cnd.where("userId", "=", SecurityUtil.getUserId())
|
||||
.and("clubId", "=", clubUserApply.getClubId())
|
||||
.desc("applyDate")
|
||||
);
|
||||
clubUserApply = clubUserJoinService.buildExitApply(clubUserApply.getClubId(), SecurityUtil.getUserId());
|
||||
if (ObjectUtil.isEmpty(clubUserApply)) {
|
||||
return Result.error("当前不是该社团成员,无法申请退出!");
|
||||
}
|
||||
}
|
||||
ClubUserApply userApply = dao.fetch(ClubUserApply.class, Cnd.where("userId", "=", clubUserApply.getUserId()).and("clubId", "=", clubUserApply.getClubId()).and("mode", "=", mode).desc(ClubUserApply::getApplyDate));
|
||||
if (ObjectUtil.isNotEmpty(userApply) && StrUtil.isNotBlank(userApply.getId())) {
|
||||
@@ -142,9 +145,17 @@ public class ClubUserJoinApplyController {
|
||||
if(!mode) {
|
||||
clubUserApply.setId(null);
|
||||
}
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setMode(mode);
|
||||
clubUserApply.setApplyDate(new Date());
|
||||
Date applyDate = new Date();
|
||||
clubUserApply.setApplyDate(applyDate);
|
||||
if (mode) {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setJoinTime(clubUserJoinService.resolveJoinTime(clubUserApply.getClubId(), clubUserApply.getUserId()));
|
||||
clubUserApply.setExitTime(null);
|
||||
} else {
|
||||
clubUserApply.setJoinTime(clubUserJoinService.resolveJoinTime(clubUserApply.getClubId(), clubUserApply.getUserId()));
|
||||
clubUserApply.setExitTime(applyDate);
|
||||
}
|
||||
dao.insertOrUpdate(clubUserApply);
|
||||
|
||||
// 开启流程实例
|
||||
|
||||
+3
-1
@@ -133,6 +133,9 @@ public class ClubExamineApplyController {
|
||||
.and("year", "=", year)
|
||||
.desc("year")
|
||||
);
|
||||
if (club == null) {
|
||||
return Result.success(0f);
|
||||
}
|
||||
Number number = ObjectUtil.defaultIfNull(club.getTotalQuota(), 0);
|
||||
return Result.success(number.floatValue());
|
||||
}
|
||||
@@ -154,7 +157,6 @@ public class ClubExamineApplyController {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("club.examine")
|
||||
public Result info(String id) {
|
||||
if(StrUtil.isBlank(id)) {
|
||||
return Result.error("id信息为空,请核查");
|
||||
|
||||
+57
@@ -1,17 +1,29 @@
|
||||
package com.budwk.app.zhgh.club.controller.examine;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
|
||||
import com.budwk.app.zhgh.club.service.SysClubExamineService;
|
||||
import com.budwk.app.zhgh.club.vo.ClubExamineVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubExaminePageVo;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @ClassName ClubExamineSchoolLeaderAuditController
|
||||
@@ -39,4 +51,49 @@ public class ClubExamineSchoolLeaderAuditController {
|
||||
Pagination<ClubExaminePageVo> pagination = sysClubExamineService.schoolLeaderAuditPageData(pageForm);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("club.examine.schoolLeaderAudit")
|
||||
public void doExportPlan(String id, HttpServletResponse response) {
|
||||
ClubExamineVo examineVo = sysClubExamineService.findOne(id);
|
||||
if (Lang.isEmpty(examineVo)) {
|
||||
return;
|
||||
}
|
||||
// 导出下一年度活动计划,字段顺序与查看页列表保持一致。
|
||||
List<NutMap> exportData = sysClubExamineService.getPlanExportData(id);
|
||||
List<ExcelExportEntity> entityList = new ArrayList<>();
|
||||
entityList.add(new ExcelExportEntity("活动主题/赛事名称", "activityName", 40));
|
||||
entityList.add(new ExcelExportEntity("活动/赛事主办单位", "activityUnit", 40));
|
||||
entityList.add(new ExcelExportEntity("活动地点", "activityAddress", 40));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, exportData);
|
||||
CommonDownloadUtil.download(examineVo.getClubName() + "下一年度活动计划.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@SaCheckPermission("club.examine.schoolLeaderAudit")
|
||||
public void doExportActivity(String id, HttpServletResponse response) {
|
||||
ClubExamineVo examineVo = sysClubExamineService.findOne(id);
|
||||
if (Lang.isEmpty(examineVo)) {
|
||||
return;
|
||||
}
|
||||
// 导出本年度活动开展情况,字段与年审填报表格列保持一致。
|
||||
List<NutMap> exportData = sysClubExamineService.getYearActivityExportData(id);
|
||||
List<ExcelExportEntity> entityList = new ArrayList<>();
|
||||
entityList.add(new ExcelExportEntity("活动时间", "activityTime", 20));
|
||||
entityList.add(new ExcelExportEntity("活动主题/赛事名称", "activityName", 40));
|
||||
entityList.add(new ExcelExportEntity("活动/赛事主办单位", "activityUnit", 40));
|
||||
entityList.add(new ExcelExportEntity("活动地点", "activityAddress", 40));
|
||||
entityList.add(new ExcelExportEntity("参加人数", "joinNum", 20));
|
||||
entityList.add(new ExcelExportEntity("获奖情况", "prize", 30));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, exportData);
|
||||
CommonDownloadUtil.download(examineVo.getClubName() + "本年度活动开展情况.xlsx", workbook, response);
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -22,6 +22,7 @@ import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.*;
|
||||
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
|
||||
import com.budwk.app.zhgh.club.service.SysClubInfoManageService;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.club.service.impl.SysClubUserServiceImpl;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
@@ -64,6 +65,8 @@ public class ClubChangeManagerController {
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private SysClubInfoManageService infoManageService;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/change/index.html")
|
||||
@@ -102,7 +105,10 @@ public class ClubChangeManagerController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
cnd.and("info.clubId", "in", clubIdList);
|
||||
}
|
||||
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
|
||||
if (StrUtil.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "LIKE", "%" + pageForm.getClubName() + "%");
|
||||
@@ -112,6 +118,7 @@ public class ClubChangeManagerController {
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = infoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
@@ -130,6 +137,17 @@ public class ClubChangeManagerController {
|
||||
@SaCheckPermission("club.infoManage.change")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "提交变更理事机构")
|
||||
public Object submit(@Param("data") SysClubManager clubManager) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubManager::getClubId, "=", clubManager.getClubId());
|
||||
if (StrUtil.isNotBlank(clubManager.getId())) {
|
||||
cnd.and(SysClubManager::getId, "!=", clubManager.getId());
|
||||
}
|
||||
List<SysClubManager> managerList = dao.query(SysClubManager.class, cnd);
|
||||
List<String> pendingProcessIds = managerList.stream().map(SysClubManager::getId).toList();
|
||||
int pendingCount = dao.count(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", pendingProcessIds).and(ProcessInstance::getState, "not in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (pendingCount > 0) {
|
||||
return Result.error("您有该社团的申请记录尚未完成,请核对!");
|
||||
}
|
||||
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
String errMsg = "校工会审核" + clubManager.getPeriod() + "的换届报告通过后才能变更理事成员";
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.budwk.app.zhgh.club.controller.infoManage;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
|
||||
import com.budwk.app.zhgh.club.service.SysClubInfoManageService;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserJoinVo;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@Ok("json")
|
||||
@At("/platform/club/infoManage/exitManage")
|
||||
public class ClubExitManageController {
|
||||
|
||||
@Inject
|
||||
private SysClubInfoManageService clubInfoManageService;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/exitManage/index.html")
|
||||
@SaCheckPermission("club.infoManage.exitManage")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("club.infoManage.exitManage")
|
||||
public Result pageData(@Valid ClubUserPageForm pageForm) {
|
||||
Pagination<ClubUserCommonPageVo> pagination = clubInfoManageService.exitManagePageData(pageForm);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("club.infoManage.exitManage")
|
||||
public Result info(@Valid String id) {
|
||||
ClubUserJoinVo clubUserJoinVo = clubInfoManageService.exitManageInfo(id);
|
||||
return Result.success(clubUserJoinVo);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("club.infoManage.exitManage")
|
||||
public Result getClubList() {
|
||||
List<SysClub> clubList;
|
||||
if (AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
clubList = sysClubService.getMyManageClub();
|
||||
} else {
|
||||
clubList = sysClubService.getMyManageClub();
|
||||
}
|
||||
return Result.success(clubList);
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
@@ -15,6 +16,7 @@ import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.model.SysClubRefresh;
|
||||
@@ -58,6 +60,8 @@ public class ClubRefreshReportController {
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/refreshReport/index.html")
|
||||
@@ -96,7 +100,10 @@ public class ClubRefreshReportController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
cnd.and("info.clubId", "in", clubIdList);
|
||||
}
|
||||
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
|
||||
if (StrUtil.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "LIKE", "%" + pageForm.getClubName() + "%");
|
||||
@@ -119,6 +126,7 @@ public class ClubRefreshReportController {
|
||||
public Object submit(@Param("data") SysClubRefresh clubRefresh) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubRefresh::getClubId, "=", clubRefresh.getClubId());
|
||||
if(StrUtil.isNotBlank(clubRefresh.getId())) {
|
||||
cnd.and(SysClubRefresh::getId, "!=", clubRefresh.getId());
|
||||
}
|
||||
|
||||
+9
-1
@@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
@@ -15,6 +16,7 @@ import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.model.SysClubRefresh;
|
||||
@@ -59,6 +61,8 @@ public class ClubRuleUpdateController {
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/ruleUpdate/index.html")
|
||||
@@ -97,7 +101,10 @@ public class ClubRuleUpdateController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
cnd.and("info.clubId", "in", clubIdList);
|
||||
}
|
||||
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
|
||||
if (StrUtil.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "LIKE", "%" + pageForm.getClubName() + "%");
|
||||
@@ -120,6 +127,7 @@ public class ClubRuleUpdateController {
|
||||
public Object submit(@Param("data")SysClubRule clubRule) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubRule::getClubId, "=", clubRule.getClubId());
|
||||
if(StrUtil.isNotBlank(clubRule.getId())) {
|
||||
cnd.and(SysClubRule::getId, "!=", clubRule.getId());
|
||||
}
|
||||
|
||||
@@ -85,4 +85,14 @@ public class ClubUserApply extends BaseModel {
|
||||
@Comment("申请时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date applyDate;
|
||||
|
||||
@Column
|
||||
@Comment("入会时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date joinTime;
|
||||
|
||||
@Column
|
||||
@Comment("退会时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date exitTime;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class SysClubExamineRegister extends BaseModel {
|
||||
|
||||
@Column
|
||||
@Comment("社团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@ColDefine(type = ColType.VARCHAR)
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -4,4 +4,25 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.club.model.ClubUserApply;
|
||||
|
||||
public interface ClubUserJoinService extends BaseService<ClubUserApply> {
|
||||
|
||||
/**
|
||||
* 构造退会申请数据。
|
||||
* 当用户没有历史入会申请记录时,使用当前社团成员关系和人员基础信息兜底生成一份退会申请,
|
||||
* 以保证会长等通过社团注册直接入会的人员也能正常发起退会流程。
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 退会申请对象,不存在当前成员关系时返回null
|
||||
*/
|
||||
ClubUserApply buildExitApply(String clubId, String userId);
|
||||
|
||||
/**
|
||||
* 获取社团成员的入会时间,优先取历史有效入会申请记录,
|
||||
* 没有时兜底为社团创办时间。
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 入会时间
|
||||
*/
|
||||
java.util.Date resolveJoinTime(String clubId, String userId);
|
||||
}
|
||||
|
||||
@@ -30,4 +30,20 @@ public interface SysClubExamineService extends BaseService<SysClubExamineRegiste
|
||||
Pagination<ClubExaminePageVo> schoolLeaderAuditPageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
ClubExamineVo findOne(@Valid String id);
|
||||
|
||||
/**
|
||||
* 查询本年度活动开展情况导出数据。
|
||||
*
|
||||
* @param id 年审主键
|
||||
* @return 导出行数据
|
||||
*/
|
||||
List<NutMap> getYearActivityExportData(@Valid String id);
|
||||
|
||||
/**
|
||||
* 查询下一年度活动计划导出数据。
|
||||
*
|
||||
* @param id 年审主键
|
||||
* @return 导出行数据
|
||||
*/
|
||||
List<NutMap> getPlanExportData(@Valid String id);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
|
||||
import com.budwk.app.zhgh.club.vo.ClubCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserJoinVo;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -23,8 +24,12 @@ public interface SysClubInfoManageService extends BaseService<ClubCommonPageVo>
|
||||
|
||||
Pagination<ClubUserCommonPageVo> infoManageUserPageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
Pagination<ClubUserCommonPageVo> exitManagePageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
Pagination<ClubUserCommonPageVo> clubManagePersonAuditPageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
ClubUserJoinVo exitManageInfo(String id);
|
||||
|
||||
List<NutMap> getClubTreeData();
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,94 @@
|
||||
package com.budwk.app.zhgh.club.service.impl;
|
||||
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.zhgh.club.model.ClubUser;
|
||||
import com.budwk.app.zhgh.club.model.ClubUserApply;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.service.ClubUserJoinService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ClubUserJoinServiceImpl extends BaseServiceImpl<ClubUserApply> implements ClubUserJoinService {
|
||||
public ClubUserJoinServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClubUserApply buildExitApply(String clubId, String userId) {
|
||||
// 优先复用最近一次申请记录中的补充信息,避免用户重复填写基础资料。
|
||||
ClubUserApply latestApply = fetch(
|
||||
Cnd.where("userId", "=", userId)
|
||||
.and("clubId", "=", clubId)
|
||||
.desc(ClubUserApply::getApplyDate)
|
||||
);
|
||||
if (latestApply != null) {
|
||||
latestApply.setId(null);
|
||||
return latestApply;
|
||||
}
|
||||
|
||||
// 对于会长等注册社团时直接入会的人员,没有申请记录时从当前成员信息兜底生成退会申请。
|
||||
ClubUser clubUser = dao().fetch(ClubUser.class, Cnd.where("clubId", "=", clubId).and("userId", "=", userId));
|
||||
if (clubUser == null) {
|
||||
return null;
|
||||
}
|
||||
View_user viewUser = dao().fetch(View_user.class, Cnd.where("id", "=", userId));
|
||||
|
||||
ClubUserApply clubUserApply = new ClubUserApply();
|
||||
clubUserApply.setClubId(clubId);
|
||||
clubUserApply.setUserId(userId);
|
||||
clubUserApply.setClubPosition(clubUser.getClubPosition());
|
||||
clubUserApply.setEmail(clubUser.getEmail());
|
||||
clubUserApply.setAvatar(clubUser.getAvatar());
|
||||
clubUserApply.setSameTimeJoinOtherClubSituation(clubUser.getSameTimeJoinOtherClubSituation());
|
||||
clubUserApply.setAwardsExperience(clubUser.getAwardsExperience());
|
||||
clubUserApply.setJoinTime(resolveJoinTime(clubId, userId));
|
||||
|
||||
List<String> roleCodes = clubUser.getRoleCode();
|
||||
if (roleCodes != null && !roleCodes.isEmpty()) {
|
||||
String exitRoleCode = roleCodes.stream()
|
||||
.filter(roleCode -> !RoleConstant.CLUB_MEMBER.name().equals(roleCode))
|
||||
.findFirst()
|
||||
.orElse(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setRoleCode(exitRoleCode);
|
||||
} else {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
}
|
||||
|
||||
if (viewUser != null) {
|
||||
clubUserApply.setBirthday(viewUser.getBirthday());
|
||||
clubUserApply.setMobile(viewUser.getMobile());
|
||||
if (clubUserApply.getEmail() == null) {
|
||||
clubUserApply.setEmail(viewUser.getEmail());
|
||||
}
|
||||
if (clubUserApply.getAvatar() == null) {
|
||||
clubUserApply.setAvatar(viewUser.getAvatar());
|
||||
}
|
||||
}
|
||||
return clubUserApply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date resolveJoinTime(String clubId, String userId) {
|
||||
ClubUserApply latestJoinApply = fetch(
|
||||
Cnd.where("userId", "=", userId)
|
||||
.and("clubId", "=", clubId)
|
||||
.and("mode", "=", true)
|
||||
.desc(ClubUserApply::getApplyDate)
|
||||
);
|
||||
if (latestJoinApply != null && latestJoinApply.getJoinTime() != null) {
|
||||
return latestJoinApply.getJoinTime();
|
||||
}
|
||||
|
||||
SysClub club = dao().fetch(SysClub.class, clubId);
|
||||
if (club != null && club.getFoundTime() != null) {
|
||||
return DateUtil.parse(club.getFoundTime());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.budwk.app.zhgh.club.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
@@ -308,7 +309,7 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
|
||||
""");
|
||||
// 构建基础分页查询条件
|
||||
buildPageBaseCondition(cnd, pageForm, "info");
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
// cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
cnd.groupBy("info.id");
|
||||
// cnd.desc("registerDate");
|
||||
cnd.asc("sc.foundTime");
|
||||
@@ -367,6 +368,41 @@ public class SysClubExamineServiceImpl extends BaseServiceImpl<SysClubExamineReg
|
||||
return clubExamineVo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> getYearActivityExportData(String id) {
|
||||
ClubExamineVo examineVo = this.findOne(id);
|
||||
if (Lang.isEmpty(examineVo) || Lang.isEmpty(examineVo.getYearActivityList())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 导出字段与前端表格字段保持一致,避免控制层再做字段转换。
|
||||
return examineVo.getYearActivityList().stream()
|
||||
.map(item -> Dict.create()
|
||||
.set("activityTime", item.getStr("activityTime"))
|
||||
.set("activityName", item.getStr("activityName"))
|
||||
.set("activityUnit", item.getStr("activityUnit"))
|
||||
.set("activityAddress", item.getStr("activityAddress"))
|
||||
.set("joinNum", item.getStr("joinNum"))
|
||||
.set("prize", item.getStr("prize")))
|
||||
.map(NutMap::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> getPlanExportData(String id) {
|
||||
ClubExamineVo examineVo = this.findOne(id);
|
||||
if (Lang.isEmpty(examineVo) || Lang.isEmpty(examineVo.getPlans())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 下年度活动计划导出只保留页面已有的三个业务字段。
|
||||
return examineVo.getPlans().stream()
|
||||
.map(item -> Dict.create()
|
||||
.set("activityName", item.getStr("activityName"))
|
||||
.set("activityUnit", item.getStr("activityUnit"))
|
||||
.set("activityAddress", item.getStr("activityAddress")))
|
||||
.map(NutMap::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成审核分页通用SQL
|
||||
* @param pageForm 分页查询参数
|
||||
|
||||
+108
-1
@@ -20,6 +20,7 @@ import com.budwk.app.zhgh.club.service.SysClubInfoManageService;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.club.vo.ClubCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserJoinVo;
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||
@@ -139,11 +140,27 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
u.unitid as unitId,
|
||||
u.mobile,
|
||||
club.clubName,
|
||||
u.unitname as unitName
|
||||
u.unitname as unitName,
|
||||
DATE_FORMAT(IFNULL(joinInfo.joinTime, club.foundTime), '%Y-%m-%d %H:%i:%s') as joinTime
|
||||
FROM
|
||||
club_user scu
|
||||
LEFT JOIN sys_club club ON scu.clubId = club.id
|
||||
RIGHT JOIN `vw_user` u ON scu.userId = u.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
joinApply.userId,
|
||||
joinApply.clubId,
|
||||
MAX(joinApply.joinTime) AS joinTime
|
||||
FROM
|
||||
club_user_apply joinApply
|
||||
LEFT JOIN wf_process_instance joinIns ON joinIns.businessNo = joinApply.id
|
||||
WHERE
|
||||
joinApply.mode = true
|
||||
AND joinIns.state = 20
|
||||
GROUP BY
|
||||
joinApply.userId,
|
||||
joinApply.clubId
|
||||
) joinInfo ON joinInfo.userId = scu.userId AND joinInfo.clubId = scu.clubId
|
||||
$condition
|
||||
$order
|
||||
""");
|
||||
@@ -206,6 +223,96 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
return listPageVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<ClubUserCommonPageVo> exitManagePageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.clubId,
|
||||
info.userId,
|
||||
info.roleCode AS applyRoleCode,
|
||||
info.clubPosition,
|
||||
info.email,
|
||||
info.mobile,
|
||||
info.birthday,
|
||||
info.avatar,
|
||||
info.sameTimeJoinOtherClubSituation,
|
||||
info.awardsExperience,
|
||||
info.signature,
|
||||
info.applyDate,
|
||||
u.username AS userName,
|
||||
u.loginname AS loginName,
|
||||
u.sex,
|
||||
u.personType,
|
||||
u.userState,
|
||||
club.clubName,
|
||||
u.unitname AS unitName,
|
||||
DATE_FORMAT(IFNULL(info.joinTime, club.foundTime), '%Y-%m-%d %H:%i:%s') AS joinTime,
|
||||
DATE_FORMAT(info.exitTime, '%Y-%m-%d %H:%i:%s') AS exitTime,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId
|
||||
FROM
|
||||
club_user_apply info
|
||||
LEFT JOIN sys_club club ON club.id = info.clubId
|
||||
LEFT JOIN vw_user u ON u.id = info.userId
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.mode", "=", false);
|
||||
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
cnd.andEX("info.clubId", "=", pageForm.getClubId());
|
||||
cnd.andEX("u.personType", "=", pageForm.getPersonType());
|
||||
cnd.andEX("u.userState", "=", pageForm.getUserState());
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
cnd.and(Cnd.exps("u.loginname", "like", "%" + pageForm.getSearchKeyword() + "%").or("u.username", "like", "%" + pageForm.getSearchKeyword() + "%"));
|
||||
}
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = commonService.findUserRoleByRoleCode(List.of(RoleConstant.CLUB_PRESIDENT.name(), RoleConstant.CLUB_VICE_PRESIDENT.name(), RoleConstant.CLUB_SECRETARY.name(), RoleConstant.CLUB_VICE_SECRETARY.name(), RoleConstant.CLUB_OPERATOR.name()));
|
||||
List<Sys_user_role> clubList = dao().query(Sys_user_role.class, Cnd.where("roleId", "in", clubIdList).and("userId", "=", SecurityUtil.getUserId()).and("clubId", "is not", null));
|
||||
cnd.and("info.clubId", "in", clubList.stream().map(Sys_user_role::getClubId).toList());
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
cnd.desc("info.applyDate");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<ClubUserCommonPageVo> pagination = listPageVO(pageForm, sql, ClubUserCommonPageVo.class);
|
||||
List<ClubUserCommonPageVo> list = pagination.getList(ClubUserCommonPageVo.class);
|
||||
for (ClubUserCommonPageVo vo : list) {
|
||||
vo.setRoleName(SysClubUserServiceImpl.convertRoleName(List.of(vo.getApplyRoleCode())));
|
||||
}
|
||||
pagination.setList(list);
|
||||
return pagination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClubUserJoinVo exitManageInfo(String id) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
cua.*,
|
||||
club.clubName,
|
||||
u.loginname AS loginName,
|
||||
u.username AS userName,
|
||||
u.sex,
|
||||
u.mobile,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
u.technicalTitle,
|
||||
u.education,
|
||||
u.academicDegree,
|
||||
u.position
|
||||
FROM
|
||||
club_user_apply cua
|
||||
LEFT JOIN vw_user u ON u.id = cua.userId
|
||||
LEFT JOIN sys_club club ON club.id = cua.clubId
|
||||
WHERE cua.id = @id
|
||||
""");
|
||||
sql.setParam("id", id);
|
||||
return fetchVO(sql, ClubUserJoinVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<ClubUserCommonPageVo> clubManagePersonAuditPageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
@@ -29,6 +29,9 @@ public class ClubUserCommonPageVo extends ClubUser {
|
||||
private String unionName;
|
||||
private String birthday;
|
||||
private String unionId;
|
||||
private String joinTime;
|
||||
private String exitTime;
|
||||
private String applyRoleCode;
|
||||
|
||||
private String roleName;
|
||||
}
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ public class ActivityBudget extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("举办单位")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String helpUnitName;
|
||||
|
||||
@Column
|
||||
|
||||
+3
-1
@@ -80,7 +80,9 @@ public class OutlayManageClubQueryController {
|
||||
SELECT * FROM `outlay_manage_club` $condition
|
||||
""");
|
||||
cnd.andEX("year", "=", year);
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
// if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
// 现逻辑:系统管理员、校工会社团管理员可查看全部社团分页数据,会长仅查看自己负责的社团。
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> roleIds = sysRoleService.getRoleIdsByCode(List.of(RoleConstant.CLUB_PRESIDENT, RoleConstant.CLUB_SECRETARY));
|
||||
List<Sys_user_role> userRoles = clubQueryService.dao().query(Sys_user_role.class,
|
||||
Cnd.where("userId", "=", SecurityUtil.getUserId())
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class OutlayManageClub extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("社团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@ColDefine(type = ColType.VARCHAR)
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
|
||||
+25
-79
@@ -27,6 +27,7 @@ import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceTypeService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.CondolenceType;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.vo.UnionReimburseBankHistoryVO;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -85,19 +86,7 @@ public class UnionReimburseApplyController {
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
@SLog(type = "unionReimburse", tag = "工会报销-报销申请", msg = "保存报销申请")
|
||||
public Result save(@Param("data") UnionReimburse unionReimburse) {
|
||||
if (StrUtil.isBlank(unionReimburse.getId())) {
|
||||
unionReimburse.setCreateTime(new Date());
|
||||
String documentNo = generateDocumentNo();
|
||||
unionReimburse.setDocumentNo(documentNo);
|
||||
}
|
||||
unionReimburse.setStateId(1);//待提交
|
||||
if (("UNION_REIMBURSE_PROJECT_1").equals(unionReimburse.getReimburseProject())){
|
||||
unionReimburse.setRealMoney(unionReimburse.getCondolenceMoney());
|
||||
}else {
|
||||
unionReimburse.setRealMoney(unionReimburse.getMoney());
|
||||
}
|
||||
dao.insertOrUpdate(unionReimburse);
|
||||
return Result.success();
|
||||
return unionReimburseService.saveApply(unionReimburse, 1);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -105,18 +94,10 @@ public class UnionReimburseApplyController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result submit(@Param("data") UnionReimburse unionReimburse) {
|
||||
if (StrUtil.isBlank(unionReimburse.getId())) {
|
||||
unionReimburse.setCreateTime(new Date());
|
||||
String documentNo = generateDocumentNo();
|
||||
unionReimburse.setDocumentNo(documentNo);
|
||||
Result result = unionReimburseService.saveApply(unionReimburse, 2);
|
||||
if (result.getCode() != 0) {
|
||||
return result;
|
||||
}
|
||||
unionReimburse.setStateId(2);//待审核
|
||||
if (("UNION_REIMBURSE_PROJECT_1").equals(unionReimburse.getReimburseProject())){
|
||||
unionReimburse.setRealMoney(unionReimburse.getCondolenceMoney());
|
||||
}else {
|
||||
unionReimburse.setRealMoney(unionReimburse.getMoney());
|
||||
}
|
||||
dao.insertOrUpdate(unionReimburse);
|
||||
// // 开启流程实例
|
||||
// Dict args = Dict.create();
|
||||
// args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
@@ -153,7 +134,7 @@ public class UnionReimburseApplyController {
|
||||
@SaCheckLogin
|
||||
@ApiOperation("获取当前登录人的申请信息")
|
||||
public Result info(@Param("id") String id) {
|
||||
UnionReimburse unionReimburse = dao.fetch(UnionReimburse.class, id);
|
||||
UnionReimburse unionReimburse = unionReimburseService.getApplyForm(id);
|
||||
return Result.success(unionReimburse);
|
||||
}
|
||||
|
||||
@@ -190,14 +171,9 @@ public class UnionReimburseApplyController {
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.and(View_user::getId, "!=", SecurityUtil.getUserId());
|
||||
/*if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
if (AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_ADMIN.name(), RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
|
||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||
} else {
|
||||
cnd.and(View_user::getId, "=", SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
}*/
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = unionReimburseService.listPageMap(1, 50, sql);
|
||||
return Result.success(pagination.getList());
|
||||
@@ -215,20 +191,25 @@ public class UnionReimburseApplyController {
|
||||
@ApiOperation("查询厉害账号信息")
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result findUserBankHistory(String payer) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
bankCardNumber,
|
||||
bankOfDeposit
|
||||
FROM union_reimburse
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("payer", "=", payer);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> result = unionReimburseService.listMap(sql);
|
||||
List<UnionReimburseBankHistoryVO> result = unionReimburseService.getUserBankHistory(payer);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("校验发票号码是否重复")
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result checkInvoiceDuplicate(String invoiceNo, String reimburseId) {
|
||||
Result result = unionReimburseService.checkInvoiceDuplicate(invoiceNo, reimburseId);
|
||||
return result == null ? Result.success() : result;
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("自动识别发票信息")
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result recognizeInvoice(String fileId, @Param("verifySwitch") Boolean verifySwitch) {
|
||||
return unionReimburseService.recognizeInvoice(fileId, verifySwitch);
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("查询校工会经费余额")
|
||||
@@ -281,39 +262,4 @@ public class UnionReimburseApplyController {
|
||||
// 如果没有找到该社团的经费记录,返回0
|
||||
return Result.success(0.0);
|
||||
}
|
||||
@At
|
||||
@ApiOperation("生成文件编号")
|
||||
private String generateDocumentNo() {
|
||||
int currentYear = DateUtil.thisYear();
|
||||
String yearPrefix = String.valueOf(currentYear);
|
||||
|
||||
org.nutz.dao.Cnd cnd = org.nutz.dao.Cnd.where("documentNo", "LIKE", yearPrefix + "%");
|
||||
cnd.desc("documentNo");
|
||||
cnd.limit(1);
|
||||
|
||||
List<UnionReimburse> list = dao.query(UnionReimburse.class, cnd);
|
||||
|
||||
int nextSeq = 1; // 默认从01开始
|
||||
if (!list.isEmpty()) {
|
||||
String maxNo = list.get(0).getDocumentNo();
|
||||
if (maxNo != null && maxNo.startsWith(yearPrefix)) {
|
||||
// 提取序号部分(去掉年份前缀)
|
||||
String seqPart = maxNo.substring(yearPrefix.length());
|
||||
try {
|
||||
int currentMaxSeq = Integer.parseInt(seqPart);
|
||||
nextSeq = currentMaxSeq + 1;
|
||||
} catch (NumberFormatException e) {
|
||||
// 如果解析失败,使用默认值1
|
||||
nextSeq = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化序号为两位数
|
||||
String seqStr = String.format("%02d", nextSeq);
|
||||
return yearPrefix + seqStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+25
-2
@@ -3,11 +3,13 @@ package com.budwk.app.zhgh.dayofficework.unionReimburse.controller;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -105,6 +107,9 @@ public class UnionReimburseCertifierUserSignController {
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
@@ -116,10 +121,11 @@ public class UnionReimburseCertifierUserSignController {
|
||||
seg.orLike("info.loginName",pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
String orderField = normalizeSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isAllBlank(orderField, pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
cnd.orderBy(orderField, PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
@@ -128,4 +134,21 @@ public class UnionReimburseCertifierUserSignController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
private String normalizeSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "loginName" -> "info.loginName";
|
||||
case "unionName" -> "info.unionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "createTime" -> "info.createTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+43
-4
@@ -12,6 +12,7 @@ import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.sys.models.Sys_dict;
|
||||
@@ -93,6 +94,9 @@ public class UnionReimburseCollectController {
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
@@ -106,7 +110,7 @@ public class UnionReimburseCollectController {
|
||||
|
||||
cnd.and("info.stateId", "in", List.of(3, 2));
|
||||
|
||||
cnd.desc("info.createTime");
|
||||
applyListSort(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
@@ -149,7 +153,7 @@ public class UnionReimburseCollectController {
|
||||
cnd.andEX("YEAR(rei.createTime)", "=", year);
|
||||
cnd.andEX("u.unitid", "=", unitId);
|
||||
cnd.andEX("u.unionid", "=", unionId);
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("u.unionid", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
cnd.desc("rei.createTime");
|
||||
@@ -166,8 +170,10 @@ public class UnionReimburseCollectController {
|
||||
|
||||
try{
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("收款人名册.xls").getBytes("utf-8"), "ISO8859-1"));
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), excelExportEntities, list);
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("收款人名册.xlsx").getBytes("utf-8"), "ISO8859-1"));
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, excelExportEntities, list);
|
||||
workbook.write(response.getOutputStream());
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
@@ -197,6 +203,9 @@ public class UnionReimburseCollectController {
|
||||
Cnd cnd = buildCondition(year, unionId, unitId, reimburseProject, userName, "t1.");
|
||||
// 只查询流程实例状态为20的数据(已完成状态)
|
||||
cnd.and("ins.state", "=", 20);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("t1.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
cnd.desc("t1.createTime");
|
||||
|
||||
sql.setCondition(cnd);
|
||||
@@ -275,4 +284,34 @@ public class UnionReimburseCollectController {
|
||||
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集页列表只允许固定字段排序,前端传入原序时回退到默认申请时间倒序。
|
||||
*/
|
||||
private void applyListSort(Cnd cnd, PageForm pageForm) {
|
||||
String orderField = normalizeSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isAllBlank(orderField, pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
return;
|
||||
}
|
||||
cnd.orderBy(orderField, PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
|
||||
private String normalizeSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "loginName" -> "info.loginName";
|
||||
case "unionName" -> "info.unionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "createTime" -> "info.createTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -84,7 +84,6 @@ public class UnionReimburseDescController {
|
||||
|
||||
@At
|
||||
@ApiOperation("查询附件说明")
|
||||
@SaCheckPermission(value = {"unionReimburse.desc", "h5.unionReimburse.desc"}, mode = SaMode.OR)
|
||||
public Result queryFileDesc() {
|
||||
List<UnionReimburseDesc> list = unionReimburseDesc.query(Cnd.NEW().desc(UnionReimburseDesc::getCode));
|
||||
return Result.success(list);
|
||||
|
||||
+34
-1
@@ -9,14 +9,17 @@ import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.model.Audit;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.MoneyUtil;
|
||||
import com.budwk.app.base.utils.OfficePlusUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
@@ -133,6 +136,9 @@ public class UnionReimburseMineController {
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
@@ -143,13 +149,40 @@ public class UnionReimburseMineController {
|
||||
seg.orLike("info.loginName", "%" + searchKeyword + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.desc("info.createTime");
|
||||
applyListSort(cnd, pageForm);
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
private void applyListSort(Cnd cnd, PageForm pageForm) {
|
||||
String orderField = normalizeSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isAllBlank(orderField, pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
return;
|
||||
}
|
||||
cnd.orderBy(orderField, PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
|
||||
private String normalizeSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "loginName" -> "info.loginName";
|
||||
case "unionName" -> "info.unionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "createTime" -> "info.createTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
|
||||
+8
-31
@@ -1,7 +1,5 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.controller;
|
||||
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -10,15 +8,12 @@ import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -35,8 +30,6 @@ import org.nutz.mvc.annotation.Param;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.openjdk.nashorn.internal.runtime.regexp.joni.Config.log;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/unionReimburse/review")
|
||||
@Ok("json:full")
|
||||
@@ -49,12 +42,12 @@ public class UnionReimburseReviewController {
|
||||
@Inject
|
||||
private UnionReimburseService unionReimburseService;
|
||||
|
||||
|
||||
@At("/index")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/unionReimburse/review/index.html")
|
||||
@SaCheckPermission("unionReimburse.review")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/unionReimburse/review/index.html")
|
||||
@SaCheckPermission("h5.unionReimburse.review")
|
||||
@@ -71,37 +64,26 @@ public class UnionReimburseReviewController {
|
||||
String unitId,
|
||||
String reimburseProject) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
SELECT
|
||||
info.*
|
||||
FROM
|
||||
union_reimburse info
|
||||
$condition
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
|
||||
if (approval) {
|
||||
// 已审核:查询 stateId 为 3(报销成功)、4(拒绝)、5(退回)的记录
|
||||
cnd.and("info.stateId", "in", List.of(3, 4, 5));
|
||||
} else {
|
||||
// 未审核:只查询 stateId 为 2(待审核确认)的记录
|
||||
cnd.and("info.stateId", "=", 2);
|
||||
}
|
||||
// 年度查询条件
|
||||
cnd.andEX("year(info.createTime)", "=", year);
|
||||
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
|
||||
|
||||
// 姓名和工号查询条件
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orLike("info.userName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.loginName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.userName", pageForm.getSearchKeyword());
|
||||
seg.orLike("info.loginName", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
@@ -119,21 +101,18 @@ public class UnionReimburseReviewController {
|
||||
@ApiOperation("审核")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"unionReimburse.review", "h5.unionReimburse.review"}, mode = SaMode.OR)
|
||||
@SLog( tag = "审核工会报销", msg = "审核工会报销")
|
||||
public Result reviewTask(@Param("data") UnionReimburse unionReimburse,String submitType) {
|
||||
@SLog(tag = "审核工会报销", msg = "审核工会报销")
|
||||
public Result reviewTask(@Param("data") UnionReimburse unionReimburse, String submitType) {
|
||||
if (submitType == null || !List.of("3", "4", "5").contains(submitType)) {
|
||||
return Result.error("无效的审核操作类型");
|
||||
}
|
||||
|
||||
UnionReimburse dbRecord = dao.fetch(UnionReimburse.class, unionReimburse.getId());
|
||||
if (dbRecord == null) {
|
||||
return Result.error("记录不存在");
|
||||
}
|
||||
|
||||
dbRecord.setReviewTime(new Date());
|
||||
dbRecord.setStateId(Integer.parseInt(submitType));
|
||||
dbRecord.setReviewOpinion(unionReimburse.getReviewOpinion());
|
||||
|
||||
dao.update(dbRecord);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -142,7 +121,7 @@ public class UnionReimburseReviewController {
|
||||
@ApiOperation("一键审核")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"unionReimburse.review", "h5.unionReimburse.review"}, mode = SaMode.OR)
|
||||
@SLog( tag = "一键审核", msg = "一键审核")
|
||||
@SLog(tag = "一键审核", msg = "一键审核")
|
||||
public Result allReview() {
|
||||
try {
|
||||
List<UnionReimburse> reimbursements = unionReimburseService.query(Cnd.where("stateId", "=", 2));
|
||||
@@ -158,6 +137,4 @@ public class UnionReimburseReviewController {
|
||||
return Result.error("一键审核失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -6,11 +6,14 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.param.UnionReimbursePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -93,6 +96,8 @@ public class UnionReimburseStatisticsController {
|
||||
}
|
||||
if (Strings.isNotBlank(unionId)) {
|
||||
sql.setVar("unionIdCnd", String.format("AND us.unionId = '%s' ", unionId));
|
||||
} else if (!isAdmin()) {
|
||||
sql.setVar("unionIdCnd", String.format("AND us.unionId = '%s' ", SecurityUtil.getUnionId()));
|
||||
}
|
||||
if (Strings.isNotBlank(condolenceTypeId)) {
|
||||
sql.setVar("typeCnd", String.format("AND con.condolenceTypeId = '%s' ", condolenceTypeId));
|
||||
@@ -150,4 +155,7 @@ public class UnionReimburseStatisticsController {
|
||||
}
|
||||
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -415,4 +415,9 @@ public class UnionReimburse extends BaseModel {
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 发票明细列表仅用于申请页表单回显和提交,不直接映射主表字段。
|
||||
*/
|
||||
private List<UnionReimburseInvoiceDetail> invoiceDetails;
|
||||
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.model;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 工会报销发票明细。
|
||||
* 每条明细对应一张发票文件,保存发票号码、金额和销售方等信息。
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("union_reimburse_invoice_detail")
|
||||
public class UnionReimburseInvoiceDetail extends BaseModel {
|
||||
|
||||
@Name
|
||||
@Comment("ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@PrevInsert(uu32 = true)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("报销主表ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String reimburseId;
|
||||
|
||||
@Column
|
||||
@Comment("发票文件")
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
private List<JSONObject> invoiceFiles;
|
||||
|
||||
@Column
|
||||
@Comment("发票号码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
private String invoiceNo;
|
||||
|
||||
@Column
|
||||
@Comment("发票金额")
|
||||
@ColDefine(type = ColType.FLOAT, width = 10, precision = 2)
|
||||
private Double invoiceAmount;
|
||||
|
||||
@Column
|
||||
@Comment("销售方信息名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 200)
|
||||
private String sellerName;
|
||||
|
||||
@Column
|
||||
@Comment("项目名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String itemName;
|
||||
|
||||
@Column
|
||||
@Comment("备注")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String remark;
|
||||
}
|
||||
+30
@@ -1,11 +1,41 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.param.UnionReimbursePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.vo.UnionReimburseBankHistoryVO;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface UnionReimburseService extends BaseService<UnionReimburse> {
|
||||
|
||||
Sql getSql(UnionReimbursePageForm pageForm);
|
||||
|
||||
/**
|
||||
* 保存或提交报销申请,并同步保存发票明细。
|
||||
*/
|
||||
Result saveApply(UnionReimburse unionReimburse, int stateId);
|
||||
|
||||
/**
|
||||
* 查询申请表单详情,补齐发票明细回显数据。
|
||||
*/
|
||||
UnionReimburse getApplyForm(String id);
|
||||
|
||||
/**
|
||||
* 查询付款人的历史收款信息。
|
||||
*/
|
||||
List<UnionReimburseBankHistoryVO> getUserBankHistory(String payer);
|
||||
|
||||
/**
|
||||
* 校验发票号码是否与历史报销记录重复。
|
||||
*/
|
||||
Result checkInvoiceDuplicate(String invoiceNo, String reimburseId);
|
||||
|
||||
/**
|
||||
* 识别单张发票文件,并在需要时调用腾讯云验真接口补齐票面信息。
|
||||
*/
|
||||
Result recognizeInvoice(String fileId, Boolean verifySwitch);
|
||||
|
||||
}
|
||||
|
||||
+638
-14
@@ -1,24 +1,69 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.service.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_file;
|
||||
import com.budwk.app.sys.services.SysFileService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburseInvoiceDetail;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.param.UnionReimbursePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.vo.UnionReimburseBankHistoryVO;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import com.tencentcloudapi.common.Credential;
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
import com.tencentcloudapi.common.profile.ClientProfile;
|
||||
import com.tencentcloudapi.common.profile.HttpProfile;
|
||||
import com.tencentcloudapi.ocr.v20181119.OcrClient;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.TextVatInvoice;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoice;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceItem;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceOCRRequest;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceOCRResponse;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceVerifyRequest;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceVerifyResponse;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> implements UnionReimburseService {
|
||||
public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> implements UnionReimburseService {
|
||||
@Inject
|
||||
private SysFileService sysFileService;
|
||||
@Inject
|
||||
private PropertiesProxy conf;
|
||||
public UnionReimburseServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
@@ -35,30 +80,609 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse>
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
// 年度查询条件
|
||||
cnd.andEX("year(info.createTime)", "=", pageForm.getYear());
|
||||
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.condolenceUnionId", "=", pageForm.getUnionId());
|
||||
cnd.andEX("info.unitId", "=", pageForm.getUnitId());
|
||||
|
||||
cnd.andEX("info.condolenceTypeId", "=", pageForm.getCondolenceTypeId());
|
||||
cnd.andEX("info.way", "=", pageForm.getWay());
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", pageForm.getReimburseProject());
|
||||
// 姓名和工号查询条件
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.condolenceUnionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orLike("info.condolenceUserName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.condolenceLoginName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.condolenceUserName", pageForm.getSearchKeyword());
|
||||
seg.orLike("info.condolenceLoginName", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
|
||||
cnd.and("info.stateId", "in", List.of(3, 2));
|
||||
|
||||
cnd.desc("info.createTime");
|
||||
applyStatisticsSort(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result saveApply(UnionReimburse unionReimburse, int stateId) {
|
||||
if (unionReimburse == null) {
|
||||
return Result.error("报销数据不能为空");
|
||||
}
|
||||
UnionReimburse oldRecord = null;
|
||||
if (StrUtil.isNotBlank(unionReimburse.getId())) {
|
||||
oldRecord = this.fetch(unionReimburse.getId());
|
||||
if (oldRecord == null) {
|
||||
return Result.error("未找到对应的报销记录");
|
||||
}
|
||||
}
|
||||
|
||||
normalizeInvoiceDetails(unionReimburse);
|
||||
if (needInvoiceDetails(unionReimburse)) {
|
||||
fillInvoiceSummary(unionReimburse);
|
||||
}
|
||||
if (stateId == 2) {
|
||||
Result validateResult = validateBeforeSubmit(unionReimburse);
|
||||
if (validateResult != null) {
|
||||
return validateResult;
|
||||
}
|
||||
Result duplicateResult = validateInvoiceDuplicate(unionReimburse);
|
||||
if (duplicateResult != null) {
|
||||
return duplicateResult;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldRecord == null) {
|
||||
unionReimburse.setCreateTime(DateUtil.date());
|
||||
unionReimburse.setDocumentNo(generateDocumentNo());
|
||||
} else {
|
||||
unionReimburse.setCreateTime(oldRecord.getCreateTime());
|
||||
unionReimburse.setDocumentNo(oldRecord.getDocumentNo());
|
||||
}
|
||||
unionReimburse.setStateId(stateId);
|
||||
if ("UNION_REIMBURSE_PROJECT_1".equals(unionReimburse.getReimburseProject())) {
|
||||
unionReimburse.setRealMoney(unionReimburse.getCondolenceMoney());
|
||||
} else {
|
||||
unionReimburse.setRealMoney(unionReimburse.getMoney());
|
||||
}
|
||||
this.dao().insertOrUpdate(unionReimburse);
|
||||
saveInvoiceDetails(unionReimburse.getId(), unionReimburse.getInvoiceDetails());
|
||||
return Result.success(stateId == 2 ? "提交成功" : "保存成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnionReimburse getApplyForm(String id) {
|
||||
UnionReimburse unionReimburse = this.fetch(id);
|
||||
if (unionReimburse == null) {
|
||||
return null;
|
||||
}
|
||||
List<UnionReimburseInvoiceDetail> invoiceDetails = this.dao().query(
|
||||
UnionReimburseInvoiceDetail.class,
|
||||
Cnd.where("reimburseId", "=", id).asc("createdAt")
|
||||
);
|
||||
unionReimburse.setInvoiceDetails(invoiceDetails == null ? new ArrayList<>() : invoiceDetails);
|
||||
return unionReimburse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UnionReimburseBankHistoryVO> getUserBankHistory(String payer) {
|
||||
if (StrUtil.isBlank(payer)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
bankUserName,
|
||||
bankCardNumber,
|
||||
bankOfDeposit
|
||||
FROM
|
||||
union_reimburse
|
||||
$condition
|
||||
GROUP BY
|
||||
bankUserName,
|
||||
bankCardNumber,
|
||||
bankOfDeposit
|
||||
ORDER BY
|
||||
MAX(createTime) DESC
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("payer", "=", payer);
|
||||
cnd.and("bankUserName", "is not", null);
|
||||
cnd.and("bankCardNumber", "is not", null);
|
||||
cnd.and("bankOfDeposit", "is not", null);
|
||||
sql.setCondition(cnd);
|
||||
return this.listVO(sql, UnionReimburseBankHistoryVO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result checkInvoiceDuplicate(String invoiceNo, String reimburseId) {
|
||||
String currentInvoiceNo = StrUtil.blankToDefault(StrUtil.trim(invoiceNo), "");
|
||||
if (StrUtil.isBlank(currentInvoiceNo)) {
|
||||
return Result.error("发票号码不能为空");
|
||||
}
|
||||
return queryHistoryInvoiceDuplicate(currentInvoiceNo, reimburseId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result recognizeInvoice(String fileId, Boolean verifySwitch) {
|
||||
if (StrUtil.isBlank(fileId)) {
|
||||
return Result.error("请先上传发票文件");
|
||||
}
|
||||
Sys_file sysFile = sysFileService.fetch(fileId);
|
||||
if (sysFile == null) {
|
||||
return Result.error("发票文件不存在");
|
||||
}
|
||||
Credential credential = getInvoiceCredential();
|
||||
if (credential == null) {
|
||||
return Result.error("未配置腾讯云发票识别密钥,请先在 application-dev.yaml 中配置 invoice.tencent.secret-id 和 invoice.tencent.secret-key");
|
||||
}
|
||||
try {
|
||||
byte[] fileBytes = sysFileService.download(fileId);
|
||||
VatInvoiceOCRResponse response = executeOcr(credential, sysFile, fileBytes);
|
||||
NutMap result = buildOcrResult(response);
|
||||
String msg = "发票识别成功";
|
||||
if (Boolean.TRUE.equals(verifySwitch)) {
|
||||
String verifyMsg = enrichByVerify(credential, result);
|
||||
msg = StrUtil.isBlank(verifyMsg) ? "发票识别并校验成功" : verifyMsg;
|
||||
}
|
||||
return Result.success(msg, result);
|
||||
} catch (TencentCloudSDKException e) {
|
||||
log.error("腾讯云发票识别失败,fileId:{}", fileId, e);
|
||||
return Result.error("腾讯云发票识别失败:" + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("发票识别失败,fileId:{}", fileId, e);
|
||||
return Result.error("发票识别失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一规整发票明细中的文本和金额,避免空格、空数组等脏数据进入库表。
|
||||
*/
|
||||
private void normalizeInvoiceDetails(UnionReimburse unionReimburse) {
|
||||
if (unionReimburse.getInvoiceDetails() == null) {
|
||||
unionReimburse.setInvoiceDetails(new ArrayList<>());
|
||||
return;
|
||||
}
|
||||
List<UnionReimburseInvoiceDetail> invoiceDetails = unionReimburse.getInvoiceDetails().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
invoiceDetails.forEach(detail -> {
|
||||
detail.setInvoiceNo(StrUtil.trim(detail.getInvoiceNo()));
|
||||
detail.setSellerName(StrUtil.trim(detail.getSellerName()));
|
||||
detail.setItemName(StrUtil.trim(detail.getItemName()));
|
||||
detail.setRemark(StrUtil.trim(detail.getRemark()));
|
||||
if (detail.getInvoiceFiles() == null) {
|
||||
detail.setInvoiceFiles(new ArrayList<>());
|
||||
}
|
||||
if (detail.getInvoiceAmount() != null) {
|
||||
detail.setInvoiceAmount(BigDecimal.valueOf(detail.getInvoiceAmount())
|
||||
.setScale(2, RoundingMode.HALF_UP)
|
||||
.doubleValue());
|
||||
}
|
||||
});
|
||||
unionReimburse.setInvoiceDetails(invoiceDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动类报销由发票明细自动汇总金额和发票张数,减少手工输入出错。
|
||||
*/
|
||||
private void fillInvoiceSummary(UnionReimburse unionReimburse) {
|
||||
double totalMoney = 0D;
|
||||
int invoiceFileCount = 0;
|
||||
for (UnionReimburseInvoiceDetail detail : unionReimburse.getInvoiceDetails()) {
|
||||
if (detail.getInvoiceAmount() != null) {
|
||||
totalMoney = BigDecimal.valueOf(totalMoney)
|
||||
.add(BigDecimal.valueOf(detail.getInvoiceAmount()))
|
||||
.doubleValue();
|
||||
}
|
||||
if (Lang.isNotEmpty(detail.getInvoiceFiles())) {
|
||||
invoiceFileCount++;
|
||||
}
|
||||
}
|
||||
unionReimburse.setMoney(BigDecimal.valueOf(totalMoney).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
||||
unionReimburse.setInvoiceNumber(String.valueOf(invoiceFileCount));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交前补一层后端校验,防止前端绕过校验直接提交。
|
||||
*/
|
||||
private Result validateBeforeSubmit(UnionReimburse unionReimburse) {
|
||||
if (StrUtil.isBlank(unionReimburse.getMobile())) {
|
||||
return Result.error("请填写联系方式");
|
||||
}
|
||||
if (!isValidContact(unionReimburse.getMobile())) {
|
||||
return Result.error("请输入正确的联系方式");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getBankUserName())) {
|
||||
return Result.error("请填写户名");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getBankCardNumber())) {
|
||||
return Result.error("请填写银行账号");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getBankOfDeposit())) {
|
||||
return Result.error("请填写开户行");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getPaymentNotes())) {
|
||||
return Result.error("请填写支付内容");
|
||||
}
|
||||
if (!needInvoiceDetails(unionReimburse)) {
|
||||
return null;
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getActivityName())) {
|
||||
return Result.error("请填写活动名称");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getActivityPlace())) {
|
||||
return Result.error("请填写活动地点");
|
||||
}
|
||||
if (unionReimburse.getActivityTime() == null) {
|
||||
return Result.error("请选择活动时间");
|
||||
}
|
||||
if (Lang.isEmpty(unionReimburse.getFiles())) {
|
||||
return Result.error("请上传附件");
|
||||
}
|
||||
if (Lang.isEmpty(unionReimburse.getInvoiceDetails())) {
|
||||
return Result.error("请至少维护一条发票明细");
|
||||
}
|
||||
for (int i = 0; i < unionReimburse.getInvoiceDetails().size(); i++) {
|
||||
UnionReimburseInvoiceDetail detail = unionReimburse.getInvoiceDetails().get(i);
|
||||
int rowIndex = i + 1;
|
||||
if (Lang.isEmpty(detail.getInvoiceFiles())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请上传发票文件");
|
||||
}
|
||||
if (StrUtil.isBlank(detail.getInvoiceNo())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写发票号码");
|
||||
}
|
||||
if (detail.getInvoiceAmount() == null || detail.getInvoiceAmount() <= 0) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写正确的发票金额");
|
||||
}
|
||||
if (StrUtil.isBlank(detail.getSellerName())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写销售方信息名称");
|
||||
}
|
||||
if (StrUtil.isBlank(detail.getItemName())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写项目名称");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同次提交和历史记录都要拦截重复发票,避免重复报销。
|
||||
*/
|
||||
private Result validateInvoiceDuplicate(UnionReimburse unionReimburse) {
|
||||
Map<String, List<Integer>> currentInvoiceMap = new LinkedHashMap<>();
|
||||
List<UnionReimburseInvoiceDetail> details = unionReimburse.getInvoiceDetails();
|
||||
for (int i = 0; i < details.size(); i++) {
|
||||
String invoiceNo = StrUtil.trim(details.get(i).getInvoiceNo());
|
||||
if (StrUtil.isBlank(invoiceNo)) {
|
||||
continue;
|
||||
}
|
||||
currentInvoiceMap.computeIfAbsent(invoiceNo, key -> new ArrayList<>()).add(i + 1);
|
||||
}
|
||||
for (Map.Entry<String, List<Integer>> entry : currentInvoiceMap.entrySet()) {
|
||||
if (entry.getValue().size() > 1) {
|
||||
String rowText = entry.getValue().stream().map(String::valueOf).collect(Collectors.joining("、"));
|
||||
return Result.error("发票号码【" + entry.getKey() + "】与本次提交的第" + rowText + "条发票重复,不能提交");
|
||||
}
|
||||
}
|
||||
for (String invoiceNo : currentInvoiceMap.keySet()) {
|
||||
Result duplicateResult = queryHistoryInvoiceDuplicate(invoiceNo, unionReimburse.getId());
|
||||
if (duplicateResult != null) {
|
||||
return duplicateResult;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史重复校验会排除当前单据自身,避免编辑回显时误判。
|
||||
*/
|
||||
private Result queryHistoryInvoiceDuplicate(String invoiceNo, String reimburseId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
d.invoiceNo,
|
||||
r.activityName
|
||||
FROM
|
||||
union_reimburse_invoice_detail d
|
||||
LEFT JOIN union_reimburse r ON r.id = d.reimburseId
|
||||
WHERE
|
||||
d.invoiceNo = @invoiceNo
|
||||
AND (@reimburseId = '' OR d.reimburseId <> @reimburseId)
|
||||
LIMIT 1
|
||||
""");
|
||||
sql.params().set("invoiceNo", invoiceNo);
|
||||
sql.params().set("reimburseId", StrUtil.blankToDefault(StrUtil.trim(reimburseId), ""));
|
||||
List<NutMap> repeatList = this.listMap(sql);
|
||||
if (Lang.isEmpty(repeatList)) {
|
||||
return null;
|
||||
}
|
||||
String activityName = repeatList.get(0).getString("activityName");
|
||||
if (StrUtil.isBlank(activityName)) {
|
||||
activityName = "历史报销记录";
|
||||
}
|
||||
return Result.error("发票号码【" + invoiceNo + "】与以往活动名称【" + activityName + "】中提交的发票重复,不能提交");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次按当前表单全量覆盖明细,避免旧明细残留。
|
||||
*/
|
||||
/**
|
||||
* 发票识别优先读取当前项目配置的 SecretId/SecretKey,没有时再回退读取用户提供的 csv 文件。
|
||||
*/
|
||||
private Credential getInvoiceCredential() {
|
||||
String secretId = StrUtil.trim(conf.get("invoice.tencent.secret-id"));
|
||||
String secretKey = StrUtil.trim(conf.get("invoice.tencent.secret-key"));
|
||||
if (StrUtil.isNotBlank(secretId) && StrUtil.isNotBlank(secretKey)) {
|
||||
return new Credential(secretId, secretKey);
|
||||
}
|
||||
return loadCredentialFromSecretFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容腾讯云控制台下载的密钥 csv,便于本地开发时不把明文密钥直接写进配置文件。
|
||||
*/
|
||||
private Credential loadCredentialFromSecretFile() {
|
||||
String secretFile = StrUtil.trim(conf.get("invoice.tencent.secret-file"));
|
||||
if (StrUtil.isBlank(secretFile)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Path path = Paths.get(secretFile);
|
||||
if (!Files.exists(path)) {
|
||||
return null;
|
||||
}
|
||||
List<String> lines = Files.readAllLines(path);
|
||||
if (lines.size() < 2) {
|
||||
return null;
|
||||
}
|
||||
String[] values = lines.get(1).split(",", -1);
|
||||
if (values.length < 2) {
|
||||
return null;
|
||||
}
|
||||
String secretId = StrUtil.trim(values[0]);
|
||||
String secretKey = StrUtil.trim(values[1]);
|
||||
if (StrUtil.isBlank(secretId) || StrUtil.isBlank(secretKey)) {
|
||||
return null;
|
||||
}
|
||||
return new Credential(secretId, secretKey);
|
||||
} catch (Exception e) {
|
||||
log.warn("读取腾讯云发票识别密钥文件失败,file:{}", secretFile, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一创建腾讯云 OCR 客户端,避免控制器直接依赖第三方 SDK。
|
||||
*/
|
||||
private OcrClient createOcrClient(Credential credential) {
|
||||
HttpProfile httpProfile = new HttpProfile();
|
||||
httpProfile.setEndpoint("ocr.tencentcloudapi.com");
|
||||
ClientProfile clientProfile = new ClientProfile();
|
||||
clientProfile.setHttpProfile(httpProfile);
|
||||
return new OcrClient(credential, "", clientProfile);
|
||||
}
|
||||
|
||||
private VatInvoiceOCRResponse executeOcr(Credential credential, Sys_file sysFile, byte[] fileBytes) throws TencentCloudSDKException {
|
||||
OcrClient client = createOcrClient(credential);
|
||||
VatInvoiceOCRRequest request = new VatInvoiceOCRRequest();
|
||||
request.setImageBase64(Base64.getEncoder().encodeToString(fileBytes));
|
||||
String fileName = StrUtil.blankToDefault(sysFile.getName(), "").toLowerCase();
|
||||
if (fileName.endsWith(".pdf")) {
|
||||
request.setIsPdf(true);
|
||||
request.setPdfPageNumber(1L);
|
||||
}
|
||||
return client.VatInvoiceOCR(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将腾讯云 OCR 返回的票面字段规整成页面可直接回填的键值结构。
|
||||
*/
|
||||
private NutMap buildOcrResult(VatInvoiceOCRResponse response) {
|
||||
NutMap result = NutMap.NEW();
|
||||
TextVatInvoice[] infos = response.getVatInvoiceInfos();
|
||||
VatInvoiceItem[] items = response.getItems();
|
||||
result.setv("invoiceNo", pickValue(infos, "发票号码", "号码", "No"));
|
||||
result.setv("invoiceCode", pickValue(infos, "发票代码", "代码", "Code"));
|
||||
result.setv("invoiceDate", normalizeDate(pickValue(infos, "开票日期", "日期", "Date")));
|
||||
result.setv("invoiceCheckCode", pickValue(infos, "校验码", "校验码后6位", "CheckCode"));
|
||||
result.setv("invoiceAmount", parseMoney(pickValue(infos, "小写金额", "价税合计(小写)", "价税合计", "合计金额", "AmountWithTax")));
|
||||
result.setv("sellerName", pickValue(infos, "销售方名称", "销售方信息名称", "销售方", "SellerName"));
|
||||
result.setv("itemName", joinItemNames(items));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动校验需要票面关键信息,缺字段时只提示人工核对,不阻塞用户继续录入。
|
||||
*/
|
||||
private String enrichByVerify(Credential credential, NutMap result) {
|
||||
String invoiceCode = result.getString("invoiceCode");
|
||||
String invoiceNo = result.getString("invoiceNo");
|
||||
String invoiceDate = result.getString("invoiceDate");
|
||||
String checkCode = lastDigits(result.getString("invoiceCheckCode"), 6);
|
||||
if (StrUtil.isBlank(checkCode)) {
|
||||
checkCode = moneyToVerifyValue(result.get("invoiceAmount"));
|
||||
}
|
||||
if (StrUtil.hasBlank(invoiceCode, invoiceNo, invoiceDate, checkCode)) {
|
||||
return "发票识别成功,但自动校验信息不完整,请人工核对后提交";
|
||||
}
|
||||
try {
|
||||
OcrClient client = createOcrClient(credential);
|
||||
VatInvoiceVerifyRequest request = new VatInvoiceVerifyRequest();
|
||||
request.setInvoiceCode(invoiceCode);
|
||||
request.setInvoiceNo(invoiceNo);
|
||||
request.setInvoiceDate(invoiceDate.replace("-", ""));
|
||||
request.setAdditional(checkCode);
|
||||
VatInvoiceVerifyResponse response = client.VatInvoiceVerify(request);
|
||||
VatInvoice invoice = response.getInvoice();
|
||||
if (invoice == null) {
|
||||
return "发票识别成功,但自动校验未返回有效结果,请人工核对后提交";
|
||||
}
|
||||
result.setv("invoiceCode", invoice.getCode());
|
||||
result.setv("invoiceNo", invoice.getNumber());
|
||||
result.setv("invoiceDate", normalizeDate(invoice.getDate()));
|
||||
result.setv("invoiceCheckCode", invoice.getCheckCode());
|
||||
result.setv("sellerName", invoice.getSellerName());
|
||||
result.setv("invoiceAmount", parseMoney(invoice.getAmountWithTax()));
|
||||
result.setv("itemName", joinItemNames(invoice.getItems()));
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.warn("腾讯云发票验真失败,invoiceNo:{}", invoiceNo, e);
|
||||
return "发票识别成功,但自动校验失败,请人工核对后提交";
|
||||
}
|
||||
}
|
||||
|
||||
private String pickValue(TextVatInvoice[] infos, String... aliases) {
|
||||
if (infos == null || aliases == null) {
|
||||
return "";
|
||||
}
|
||||
Set<String> aliasSet = new LinkedHashSet<>();
|
||||
for (String alias : aliases) {
|
||||
aliasSet.add(normalizeFieldName(alias));
|
||||
}
|
||||
for (TextVatInvoice info : infos) {
|
||||
if (info == null) {
|
||||
continue;
|
||||
}
|
||||
if (aliasSet.contains(normalizeFieldName(info.getName()))) {
|
||||
return StrUtil.blankToDefault(StrUtil.trim(info.getValue()), "");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String normalizeFieldName(String name) {
|
||||
return StrUtil.blankToDefault(name, "")
|
||||
.replace(":", "")
|
||||
.replace(":", "")
|
||||
.replace(" ", "")
|
||||
.replace("\u00A0", "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
private String normalizeDate(String dateText) {
|
||||
String date = StrUtil.blankToDefault(StrUtil.trim(dateText), "");
|
||||
if (StrUtil.isBlank(date)) {
|
||||
return "";
|
||||
}
|
||||
String digits = date.replaceAll("[^0-9]", "");
|
||||
if (digits.length() == 8) {
|
||||
return digits.substring(0, 4) + "-" + digits.substring(4, 6) + "-" + digits.substring(6);
|
||||
}
|
||||
return date.replace("年", "-").replace("月", "-").replace("日", "");
|
||||
}
|
||||
|
||||
private Double parseMoney(Object moneyObj) {
|
||||
String moneyText = StrUtil.blankToDefault(StrUtil.trim(ObjectUtil.defaultIfNull(moneyObj, "").toString()), "");
|
||||
if (StrUtil.isBlank(moneyText)) {
|
||||
return null;
|
||||
}
|
||||
moneyText = moneyText.replace(",", "").replace("¥", "").replace("¥", "");
|
||||
try {
|
||||
return BigDecimal.valueOf(Double.parseDouble(moneyText)).setScale(2, RoundingMode.HALF_UP).doubleValue();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String joinItemNames(VatInvoiceItem[] items) {
|
||||
if (items == null || items.length == 0) {
|
||||
return "";
|
||||
}
|
||||
return Arrays.stream(items)
|
||||
.map(VatInvoiceItem::getName)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
private String lastDigits(String text, int length) {
|
||||
String digits = StrUtil.blankToDefault(text, "").replaceAll("[^0-9]", "");
|
||||
if (digits.length() <= length) {
|
||||
return digits;
|
||||
}
|
||||
return digits.substring(digits.length() - length);
|
||||
}
|
||||
|
||||
private String moneyToVerifyValue(Object moneyObj) {
|
||||
Double money = parseMoney(moneyObj);
|
||||
if (money == null) {
|
||||
return "";
|
||||
}
|
||||
return BigDecimal.valueOf(money).setScale(2, RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
private void saveInvoiceDetails(String reimburseId, List<UnionReimburseInvoiceDetail> invoiceDetails) {
|
||||
this.dao().clear(UnionReimburseInvoiceDetail.class, Cnd.where("reimburseId", "=", reimburseId));
|
||||
if (Lang.isEmpty(invoiceDetails)) {
|
||||
return;
|
||||
}
|
||||
invoiceDetails.forEach(detail -> {
|
||||
detail.setId(null);
|
||||
detail.setReimburseId(reimburseId);
|
||||
this.dao().insert(detail);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前仅活动类报销维护发票明细,慰问类仍按原有逻辑处理金额。
|
||||
*/
|
||||
private boolean needInvoiceDetails(UnionReimburse unionReimburse) {
|
||||
return unionReimburse != null && !"UNION_REIMBURSE_PROJECT_1".equals(unionReimburse.getReimburseProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成年度流水号,保持与现有单据编号规则一致。
|
||||
*/
|
||||
private String generateDocumentNo() {
|
||||
int currentYear = DateUtil.thisYear();
|
||||
String yearPrefix = String.valueOf(currentYear);
|
||||
Cnd cnd = Cnd.where("documentNo", "like", yearPrefix + "%");
|
||||
cnd.desc("documentNo");
|
||||
cnd.limit(1);
|
||||
List<UnionReimburse> list = this.query(cnd);
|
||||
int nextSeq = 1;
|
||||
if (Lang.isNotEmpty(list) && StrUtil.isNotBlank(list.get(0).getDocumentNo())) {
|
||||
String maxNo = list.get(0).getDocumentNo();
|
||||
if (maxNo.startsWith(yearPrefix)) {
|
||||
String seqPart = maxNo.substring(yearPrefix.length());
|
||||
if (StrUtil.isNumeric(seqPart)) {
|
||||
nextSeq = Integer.parseInt(seqPart) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return yearPrefix + String.format("%02d", nextSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计页排序字段仅允许白名单列,避免传入非法字段。
|
||||
*/
|
||||
private void applyStatisticsSort(Cnd cnd, UnionReimbursePageForm pageForm) {
|
||||
String orderField = normalizeStatisticsSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isBlank(orderField) || StrUtil.isBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
return;
|
||||
}
|
||||
cnd.orderBy(orderField, "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
}
|
||||
|
||||
private String normalizeStatisticsSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "condolenceLoginName" -> "info.condolenceLoginName";
|
||||
case "condolenceUnionName" -> "info.condolenceUnionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "newCreateTime", "createTime" -> "info.createTime";
|
||||
case "newCondolenceTime" -> "info.condolenceTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 联系方式支持手机号和座机,和前端规则保持一致。
|
||||
*/
|
||||
private boolean isValidContact(String mobile) {
|
||||
return mobile.matches("^(1[3-9]\\d{9}|0\\d{2,3}-?\\d{7,8})$");
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 付款人历史银行卡信息。
|
||||
* 用于申请页下次填写时快速回填户名、银行卡号和开户行。
|
||||
*/
|
||||
@Data
|
||||
public class UnionReimburseBankHistoryVO {
|
||||
private String bankUserName;
|
||||
private String bankCardNumber;
|
||||
private String bankOfDeposit;
|
||||
}
|
||||
+46
-24
@@ -54,29 +54,41 @@ public class ProposalQueryAnalysisController {
|
||||
@At
|
||||
@ApiOperation("统计数据")
|
||||
@SaCheckPermission("proposal.query.analysis")
|
||||
public Result statisticsData(String sessionId) {
|
||||
public Result statisticsData(String sessionId, String dimension) {
|
||||
/*
|
||||
* 查询参数说明:
|
||||
* sessionId:教代会届次ID,用于限定统计提案范围;
|
||||
* dimension:统计维度,可传“提案人单位、提案类型、代表团、立案结果、满意度”,为空时返回全部维度。
|
||||
* 返回值:Result.data 为统计行列表,包含 dimension、itemName、count、rate。
|
||||
*/
|
||||
if (StrUtil.isBlank(sessionId)) {
|
||||
return Result.error("请先选择教代会届次");
|
||||
}
|
||||
return Result.success(buildStatisticsRows(sessionId));
|
||||
return Result.success(buildStatisticsRows(sessionId, dimension));
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("分析数据")
|
||||
@SaCheckPermission("proposal.query.analysis")
|
||||
public Result analysisData(String sessionId) {
|
||||
public Result analysisData(String sessionId, String dimension) {
|
||||
/*
|
||||
* 查询参数说明:
|
||||
* sessionId:教代会届次ID,用于限定分析提案范围;
|
||||
* dimension:统计维度,可传“提案人单位、提案类型、代表团、立案结果、满意度”,为空时返回全部维度。
|
||||
* 返回值:Result.data 为分析行列表,包含 dimension、total、categoryCount、topItem、topCount、topRate、analysis。
|
||||
*/
|
||||
if (StrUtil.isBlank(sessionId)) {
|
||||
return Result.error("请先选择教代会届次");
|
||||
}
|
||||
return Result.success(buildAnalysisRows(sessionId));
|
||||
return Result.success(buildAnalysisRows(sessionId, dimension));
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("void")
|
||||
@ApiOperation("导出统计数据")
|
||||
@SaCheckPermission("proposal.query.analysis")
|
||||
public void exportStatisticsData(String sessionId, HttpServletResponse response) {
|
||||
List<NutMap> list = buildStatisticsRows(sessionId);
|
||||
public void exportStatisticsData(String sessionId, String dimension, HttpServletResponse response) {
|
||||
List<NutMap> list = buildStatisticsRows(sessionId, dimension);
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("统计维度", "dimension", 20));
|
||||
entities.add(new ExcelExportEntity("分类项", "itemName", 30));
|
||||
@@ -92,8 +104,8 @@ public class ProposalQueryAnalysisController {
|
||||
@Ok("void")
|
||||
@ApiOperation("导出分析数据")
|
||||
@SaCheckPermission("proposal.query.analysis")
|
||||
public void exportAnalysisData(String sessionId, HttpServletResponse response) {
|
||||
List<NutMap> list = buildAnalysisRows(sessionId);
|
||||
public void exportAnalysisData(String sessionId, String dimension, HttpServletResponse response) {
|
||||
List<NutMap> list = buildAnalysisRows(sessionId, dimension);
|
||||
List<ExcelExportEntity> entities = new ArrayList<>();
|
||||
entities.add(new ExcelExportEntity("统计维度", "dimension", 20));
|
||||
entities.add(new ExcelExportEntity("总量", "total", 12));
|
||||
@@ -108,15 +120,15 @@ public class ProposalQueryAnalysisController {
|
||||
CommonDownloadUtil.download("提案分析数据.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
private List<NutMap> buildStatisticsRows(String sessionId) {
|
||||
Map<String, List<NutMap>> dataMap = loadDimensionData(sessionId);
|
||||
private List<NutMap> buildStatisticsRows(String sessionId, String dimension) {
|
||||
Map<String, List<NutMap>> dataMap = loadDimensionData(sessionId, dimension);
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
dataMap.forEach((dimension, items) -> {
|
||||
dataMap.forEach((dimensionName, items) -> {
|
||||
long total = items.stream().mapToLong(v -> v.getLong("count", 0L)).sum();
|
||||
for (NutMap item : items) {
|
||||
long count = item.getLong("count", 0L);
|
||||
result.add(NutMap.NEW()
|
||||
.addv("dimension", dimension)
|
||||
.addv("dimension", dimensionName)
|
||||
.addv("itemName", item.getString("itemName", "未维护"))
|
||||
.addv("count", count)
|
||||
.addv("rate", formatPercent(count, total)));
|
||||
@@ -125,13 +137,13 @@ public class ProposalQueryAnalysisController {
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<NutMap> buildAnalysisRows(String sessionId) {
|
||||
Map<String, List<NutMap>> dataMap = loadDimensionData(sessionId);
|
||||
private List<NutMap> buildAnalysisRows(String sessionId, String dimension) {
|
||||
Map<String, List<NutMap>> dataMap = loadDimensionData(sessionId, dimension);
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
dataMap.forEach((dimension, items) -> {
|
||||
dataMap.forEach((dimensionName, items) -> {
|
||||
if (items.isEmpty()) {
|
||||
result.add(NutMap.NEW()
|
||||
.addv("dimension", dimension)
|
||||
.addv("dimension", dimensionName)
|
||||
.addv("total", 0)
|
||||
.addv("categoryCount", 0)
|
||||
.addv("topItem", "-")
|
||||
@@ -150,10 +162,10 @@ public class ProposalQueryAnalysisController {
|
||||
long topCount = top.getLong("count", 0L);
|
||||
String topItem = top.getString("itemName", "未维护");
|
||||
String topRate = formatPercent(topCount, total);
|
||||
String analysis = String.format("%s主要集中在【%s】,数量为%d,占比%s。", dimension, topItem, topCount, topRate);
|
||||
String analysis = String.format("%s主要集中在【%s】,数量为%d,占比%s。", dimensionName, topItem, topCount, topRate);
|
||||
|
||||
result.add(NutMap.NEW()
|
||||
.addv("dimension", dimension)
|
||||
.addv("dimension", dimensionName)
|
||||
.addv("total", total)
|
||||
.addv("categoryCount", sorted.size())
|
||||
.addv("topItem", topItem)
|
||||
@@ -164,13 +176,23 @@ public class ProposalQueryAnalysisController {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, List<NutMap>> loadDimensionData(String sessionId) {
|
||||
private Map<String, List<NutMap>> loadDimensionData(String sessionId, String dimension) {
|
||||
Map<String, List<NutMap>> map = new LinkedHashMap<>();
|
||||
map.put("提案人单位", queryUnitStat(sessionId));
|
||||
map.put("提案类型", queryTypeStat(sessionId));
|
||||
map.put("代表团", queryDelegationStat(sessionId));
|
||||
map.put("立案结果", queryCaseFilingResultStat(sessionId));
|
||||
map.put("满意度", querySatisfactionStat(sessionId));
|
||||
if (StrUtil.isBlank(dimension) || "提案人单位".equals(dimension)) {
|
||||
map.put("提案人单位", queryUnitStat(sessionId));
|
||||
}
|
||||
if (StrUtil.isBlank(dimension) || "提案类型".equals(dimension)) {
|
||||
map.put("提案类型", queryTypeStat(sessionId));
|
||||
}
|
||||
if (StrUtil.isBlank(dimension) || "代表团".equals(dimension)) {
|
||||
map.put("代表团", queryDelegationStat(sessionId));
|
||||
}
|
||||
if (StrUtil.isBlank(dimension) || "立案结果".equals(dimension)) {
|
||||
map.put("立案结果", queryCaseFilingResultStat(sessionId));
|
||||
}
|
||||
if (StrUtil.isBlank(dimension) || "满意度".equals(dimension)) {
|
||||
map.put("满意度", querySatisfactionStat(sessionId));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -73,9 +73,10 @@ public class ProposalQueryComprehensiveController {
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
||||
LEFT JOIN wf_process_task replyTask on replyTask.processInstanceId = ins.id AND replyTask.taskState = 20 AND replyTask.taskName in ('master_reply','slave_reply','opinion_master_reply')
|
||||
LEFT JOIN wf_process_task replyTask on replyTask.processInstanceId = ins.id
|
||||
$condition
|
||||
""");
|
||||
// AND replyTask.taskState = 20 AND replyTask.taskName in ('master_reply','slave_reply','opinion_master_reply')
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (ArrayUtil.isNotEmpty(pageForm.getOrigins()) && StrUtil.isNotBlank(pageForm.getCommonKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
|
||||
+16
-6
@@ -6,6 +6,7 @@ import com.budwk.app.flow.engine.util.FlowUtil;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -44,16 +45,25 @@ public class ProposalQueryUnitReplyController {
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.query.unitReply")
|
||||
public Result data(String sessionId, String undertakeUnitId) {
|
||||
public Result data(String sessionId, String undertakeUnitId, String caseFilingResult) {
|
||||
/*
|
||||
* 查询参数说明:
|
||||
* sessionId:教代会届次ID,用于限定统计的提案范围;
|
||||
* undertakeUnitId:承办单位ID,用于只统计某个承办单位,为空时统计全部承办单位;
|
||||
* caseFilingResult:立案结果字典值,对应 proposal_info.caseFilingResult,为空时不限制立案结果。
|
||||
* 返回值:Result.data 中包含 tableData 统计行列表,以及 slaveNeedReply 协办单位是否需要答复配置。
|
||||
*/
|
||||
// 提案配置 协办是否需要答复
|
||||
ProposalConfig proposalConfig = dao.fetch(ProposalConfig.class, Cnd.NEW());
|
||||
boolean slaveNeedReply = proposalConfig.getSlaveUnitNeedReply();
|
||||
|
||||
// 当前届次所有的提案ID
|
||||
Sql sql = Sqls.create("select id from proposal_info where sessionId = @sessionId").setParam("sessionId", sessionId);
|
||||
sql.setCallback(Sqls.callback.strList());
|
||||
dao.execute(sql);
|
||||
List<String> proposalIds = sql.getList(String.class);
|
||||
Cnd proposalCnd = Cnd.where(ProposalInfo::getSessionId, "=", sessionId);
|
||||
proposalCnd.andEX(ProposalInfo::getCaseFilingResult, "=", caseFilingResult);
|
||||
List<String> proposalIds = dao.query(ProposalInfo.class, proposalCnd)
|
||||
.stream()
|
||||
.map(ProposalInfo::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if(proposalIds.isEmpty()){
|
||||
return Result.success().addData(Map.of("tableData", Collections.EMPTY_LIST, "slaveNeedReply", slaveNeedReply));
|
||||
@@ -73,7 +83,7 @@ public class ProposalQueryUnitReplyController {
|
||||
List<ProposalReplyUnit> replyUnits = dao.query(ProposalReplyUnit.class, cnd);
|
||||
|
||||
// 承办单位答复记录
|
||||
List<ProcessTask> replyTasks = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "in", instIds).and(ProcessTask::getTaskName, "in", List.of("master_reply", "slave_reply", "opinion_master_reply")).and(ProcessTask::getTaskState, "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.DOING.getCode())));
|
||||
List<ProcessTask> replyTasks = dao.query(ProcessTask.class, Cnd.where(ProcessTask::getProcessInstanceId, "in", instIds).and(ProcessTask::getTaskName, "in", List.of("two_unit_reply","unit_reply","master_reply", "slave_reply", "opinion_master_reply")).and(ProcessTask::getTaskState, "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.DOING.getCode())));
|
||||
|
||||
// 承办单位
|
||||
List<NutMap> tableData = new ArrayList<>();
|
||||
|
||||
+4
-1
@@ -45,7 +45,7 @@ public class ProposalCaseCheckController {
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/proposal/transact/caseCheck/index.html")
|
||||
@SaCheckPermission("proposal.mine")
|
||||
@SaCheckPermission("proposal.caseCheck")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ public class ProposalCaseCheckController {
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN vw_user vu ON vu.id = info.createUserId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
@@ -99,6 +100,8 @@ public class ProposalCaseCheckController {
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
// 工会筛选按提案人所属工会口径处理,来源为 proposal_info.createUserId 关联 vw_user.unionId。
|
||||
cnd.andEX("vu.unionId", "=", pageForm.getUnionId());
|
||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
|
||||
+3
@@ -83,6 +83,7 @@ public class ProposalCommitteeFilingController {
|
||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
||||
LEFT JOIN vw_user vu ON vu.id = info.createUserId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
@@ -97,6 +98,8 @@ public class ProposalCommitteeFilingController {
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
// 工会筛选按提案人所属工会口径处理,来源为 proposal_info.createUserId 关联 vw_user.unionId。
|
||||
cnd.andEX("vu.unionId", "=", pageForm.getUnionId());
|
||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
|
||||
+3
@@ -99,6 +99,7 @@ public class ProposalCommitteeFilingUnitController {
|
||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
||||
LEFT JOIN vw_user vu ON vu.id = info.createUserId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
@@ -113,6 +114,8 @@ public class ProposalCommitteeFilingUnitController {
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
// 工会筛选按提案人所属工会口径处理,来源为 proposal_info.createUserId 关联 vw_user.unionId。
|
||||
cnd.andEX("vu.unionId", "=", pageForm.getUnionId());
|
||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
|
||||
+4
-1
@@ -42,7 +42,7 @@ public class ProposalPreAuditController {
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/proposal/transact/preAudit/index.html")
|
||||
@SaCheckPermission("proposal.mine")
|
||||
@SaCheckPermission("proposal.preAudit")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ public class ProposalPreAuditController {
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN vw_user vu ON vu.id = info.createUserId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
@@ -97,6 +98,8 @@ public class ProposalPreAuditController {
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
// 工会筛选按提案人所属工会口径处理,来源为 proposal_info.createUserId 关联 vw_user.unionId。
|
||||
cnd.andEX("vu.unionId", "=", pageForm.getUnionId());
|
||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
|
||||
+3
@@ -114,6 +114,7 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
||||
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
||||
LEFT JOIN vw_user vu ON vu.id = info.createUserId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
@@ -130,6 +131,8 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
// 工会筛选按提案人所属工会口径处理,来源为 proposal_info.createUserId 关联 vw_user.unionId。
|
||||
cnd.andEX("vu.unionId", "=", pageForm.getUnionId());
|
||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
|
||||
+148
-34
@@ -2,24 +2,25 @@ package com.budwk.app.zhgh.democratic.proposal.controller.transact;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.aspose.slides.internal.og.and;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.bpm.service.BpmService;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.entity.ProcessTaskActor;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalSecondedService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -28,11 +29,12 @@ import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
@@ -55,11 +57,9 @@ public class ProposalSecondedController {
|
||||
@Inject
|
||||
private BaseService baseService;
|
||||
@Inject
|
||||
private ProposalCommonService proposalCommonService;
|
||||
@Inject
|
||||
private BpmService bpmService;
|
||||
@Inject
|
||||
private ProposalSecondedService proposalSecondedService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/proposal/transact/seconded/index.html")
|
||||
@@ -96,6 +96,7 @@ public class ProposalSecondedController {
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
nt.taskName curTaskCode,
|
||||
if(t.taskName = 'second', ta.actorId, ps.seconderId) taskActorUserId,
|
||||
if(t.taskName = 'second', ta.actorName, ps.userName) taskActorName,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
@@ -108,36 +109,40 @@ public class ProposalSecondedController {
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||
LEFT JOIN proposal_second ps ON ps.proposalId = info.id
|
||||
LEFT JOIN proposal_second ps ON ps.proposalId = info.id AND ps.seconderId = @seconderId
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
""");
|
||||
sql.setParam("seconderId", SecurityUtil.getUserId());
|
||||
sql.setParam("seconderId", SecurityUtil.getUserId());
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.taskName", "in", List.of("invite", "second", "delegation", "committee"));
|
||||
cnd.and("ps.isAgree", "is", null);
|
||||
|
||||
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
}
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
|
||||
if (approval) {
|
||||
// 已附议页签只展示当前登录附议人已经处理过的记录。
|
||||
cnd.and("ps.isAgree", "is not", null);
|
||||
cnd.and("t.taskName", "in", List.of("invite", "second", "delegation", "preAudit", "committee"));
|
||||
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
// 未附议页签只展示当前登录附议人尚未处理的记录。
|
||||
cnd.and("ps.isAgree", "is", null);
|
||||
// 待附议列表只展示两类任务:
|
||||
// 1. invite / second 节点任务
|
||||
// 2. delegation / committee 节点,且任务状态必须是已废弃(99)
|
||||
SqlExpressionGroup taskGroup = Cnd.exps("t.taskName", "in", List.of("invite", "second"));
|
||||
SqlExpressionGroup delegationOrCommitteeGroup = Cnd.exps("t.taskName", "in", List.of("delegation", "preAudit", "committee"));
|
||||
delegationOrCommitteeGroup.and("t.taskState", "=", ProcessTaskStateEnum.ABANDON.getCode());
|
||||
taskGroup.or(delegationOrCommitteeGroup);
|
||||
cnd.and(taskGroup);
|
||||
}
|
||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
List<NutMap> list = pagination.getList(NutMap.class);
|
||||
for (NutMap row : list) {
|
||||
// String instanceId = row.getString("instanceId");
|
||||
}
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@@ -146,37 +151,146 @@ public class ProposalSecondedController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("修改提案附议信息")
|
||||
@SLog(tag = "提案管理系统-附议提案", msg = "修改提案附议信息")
|
||||
/**
|
||||
* 仅更新附议结果和附议任务状态,不调用流程引擎推进流程。
|
||||
* 参数说明:
|
||||
* 1. proposalId:提案主键,用于定位 proposal_second 附议记录。
|
||||
* 2. taskId:当前页面点击的任务主键,用于定位本次需要完成的 wf_process_task。
|
||||
* 3. taskActorUserId:附议人用户ID,用于校验附议记录和任务参与人是否匹配。
|
||||
* 4. opinion:附议意见,写入 proposal_second.opinion。
|
||||
* 5. submitType:附议结果,1 表示同意,20 表示不同意。
|
||||
* 返回值:
|
||||
* Result.success() 表示 proposal_second 和 wf_process_task 更新成功;
|
||||
* Result.error(...) 表示参数错误或未找到对应业务数据。
|
||||
*/
|
||||
public Result updateInfo(@Param("proposalId") String proposalId,
|
||||
@Param("taskId") Long taskId,
|
||||
@Param("taskActorUserId") String taskActorUserId,
|
||||
@Param("opinion") String opinion,
|
||||
@Param("submitType") Integer submitType) {
|
||||
// 查询附议信息表
|
||||
if (Strings.isBlank(proposalId) || Strings.isBlank(taskActorUserId) || taskId == null || submitType == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
|
||||
// 先定位 wf_process_task,确保本次请求能准确命中需要完成的附议任务,再更新两张业务表。
|
||||
ProcessTask processTask = this.getSecondTask(taskId, taskActorUserId);
|
||||
if (processTask == null) {
|
||||
return Result.error("未找到附议任务");
|
||||
}
|
||||
|
||||
// 更新 proposal_second,记录当前附议人的最终附议结果、附议意见和附议时间。
|
||||
ProposalSecond proposalSecond = dao.fetch(
|
||||
ProposalSecond.class,
|
||||
Cnd.where(ProposalSecond::getProposalId, "=", proposalId)
|
||||
.and(ProposalSecond::getSeconderId, "=", taskActorUserId)
|
||||
);
|
||||
if (proposalSecond == null) {
|
||||
return Result.error("未找到附议记录");
|
||||
}
|
||||
proposalSecond.setIsAgree(ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.AGREE.getCode()));
|
||||
proposalSecond.setOpinion(opinion);
|
||||
proposalSecond.setIsAgree(submitType == 1);
|
||||
proposalSecond.setSecondedTime(DateUtil.date());
|
||||
dao.update(proposalSecond);
|
||||
|
||||
// 流程实例
|
||||
ProcessInstance processInstance = dao.fetch(ProcessInstance.class,Cnd.where(ProcessInstance::getBusinessNo, "=", proposalId));
|
||||
if(processInstance == null) return Result.success();
|
||||
|
||||
ProcessTask processTask = dao.fetch(ProcessTask.class,Cnd.where(ProcessTask::getProcessInstanceId, "=", processInstance.getId())
|
||||
.and(ProcessTask::getTaskName, "=", "second")
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.ABANDON.getCode())
|
||||
.and(new Static("id in (select processTaskId from wf_process_task_actor where actorId='" + taskActorUserId + "')"))
|
||||
.limit(1,1));
|
||||
if(processTask == null) return Result.success();
|
||||
|
||||
// 仅更新本次附议对应的 wf_process_task,不推动实例、也不创建后续任务。
|
||||
View_user user = dao.fetch(View_user.class, Cnd.where(View_user::getId, "=", taskActorUserId));
|
||||
Dict taskArgs = Json.fromJson(Dict.class, processTask.getVariable());
|
||||
taskArgs.set("u_userId", user.getId());
|
||||
taskArgs.set("initiator", user.getId());
|
||||
taskArgs.set("initiatorName", user.getUsername());
|
||||
taskArgs.set("initiatorAccount", user.getLoginname());
|
||||
taskArgs.set("initiatorUnitId", user.getUnitId());
|
||||
taskArgs.set("initiatorUnitName", user.getUnitName());
|
||||
taskArgs.set("initiatorUnionId", user.getUnionId());
|
||||
taskArgs.set("initiatorUnionName", user.getUnionName());
|
||||
taskArgs.set("tf_loginName", user.getLoginname());
|
||||
taskArgs.set("tf_unionId", user.getUnionId());
|
||||
taskArgs.set("tf_unitId", user.getUnitId());
|
||||
taskArgs.set("tf_unitName", user.getUnitName());
|
||||
taskArgs.set("tf_userId", user.getId());
|
||||
taskArgs.set("tf_userName", user.getUsername());
|
||||
processTask.setVariable(JSONUtil.toJsonStr(taskArgs));
|
||||
processTask.setTaskState(ProcessTaskStateEnum.FINISHED.getCode());
|
||||
processTask.setFinishTime(DateUtil.date());
|
||||
processTask.setOperator(taskActorUserId);
|
||||
dao.update(processTask);
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* second 节点审核专用接口。
|
||||
* 参数说明:
|
||||
* 1. data:前端提交的 JSON 字符串,必须包含 processTaskId、proposalId、taskActorUserId、tf_opinion、submitType。
|
||||
* 2. processTaskId:wf_process_task 主键,公共流程执行服务依赖该参数定位当前审核任务。
|
||||
* 3. proposalId:提案主键,附议业务表 proposal_second 通过该字段定位当前提案记录。
|
||||
* 4. taskActorUserId:附议人用户ID,用于定位当前登录人的附议记录。
|
||||
* 5. tf_opinion:审核意见,会同步写入流程表单变量和附议业务表 opinion 字段。
|
||||
* 6. submitType:审核结果,1 表示同意,20 表示不同意。
|
||||
* 返回值:
|
||||
* Result.success() 表示公共流程任务执行成功且 proposal_second 已同步更新;
|
||||
* Result.error(...) 表示请求参数不完整。
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("proposal.seconded")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("执行附议审核任务")
|
||||
@SLog(tag = "提案管理系统-附议提案", msg = "执行附议审核任务")
|
||||
public Result executeTask(@Param("data") String data) {
|
||||
if (Strings.isBlank(data)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
String proposalId = args.getStr("proposalId");
|
||||
String taskActorUserId = args.getStr("taskActorUserId");
|
||||
String opinion = args.getStr("tf_opinion");
|
||||
Integer submitType = args.getInt("submitType");
|
||||
if (args.getLong("processTaskId") == null || Strings.isBlank(proposalId) || Strings.isBlank(taskActorUserId) || submitType == null) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
flowCommonService.executeTask(args);
|
||||
proposalSecondedService.updateSecondRecord(proposalId, taskActorUserId, opinion, submitType);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据当前点击的任务和附议人,定位实际需要完成的 second 节点任务。
|
||||
* 处理规则:
|
||||
* 1. 如果页面点击的就是 second 节点任务,则直接更新该任务。
|
||||
* 2. 如果页面点击的是 invite、delegation、committee 等关联节点,则回查同实例下当前附议人的 second 任务。
|
||||
*/
|
||||
private ProcessTask getSecondTask(Long taskId, String taskActorUserId) {
|
||||
ProcessTask currentTask = dao.fetch(ProcessTask.class, taskId);
|
||||
if (currentTask == null) {
|
||||
return null;
|
||||
}
|
||||
if ("second".equals(currentTask.getTaskName())
|
||||
&& List.of(ProcessTaskStateEnum.DOING.getCode(), ProcessTaskStateEnum.ABANDON.getCode()).contains(currentTask.getTaskState())
|
||||
&& this.isTaskActorMatched(currentTask.getId(), taskActorUserId)) {
|
||||
return currentTask;
|
||||
}
|
||||
|
||||
List<ProcessTask> secondTaskList = dao.query(ProcessTask.class,
|
||||
Cnd.where(ProcessTask::getProcessInstanceId, "=", currentTask.getProcessInstanceId())
|
||||
.and(ProcessTask::getTaskName, "=", "second")
|
||||
.and(ProcessTask::getTaskState, "in", List.of(ProcessTaskStateEnum.DOING.getCode(), ProcessTaskStateEnum.ABANDON.getCode()))
|
||||
.desc(ProcessTask::getCreatedAt));
|
||||
for (ProcessTask secondTask : secondTaskList) {
|
||||
if (this.isTaskActorMatched(secondTask.getId(), taskActorUserId)) {
|
||||
return secondTask;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验任务参与人是否为当前附议人,避免误更新其他代表的 second 任务。
|
||||
*/
|
||||
private boolean isTaskActorMatched(Long processTaskId, String taskActorUserId) {
|
||||
return dao.count(ProcessTaskActor.class,
|
||||
Cnd.where(ProcessTaskActor::getProcessTaskId, "=", processTaskId)
|
||||
.and(ProcessTaskActor::getActorId, "=", taskActorUserId)) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -83,6 +83,7 @@ public class ProposalWriteController {
|
||||
@ApiOperation("保存提案")
|
||||
@SLog(tag = "提案管理系统-我的提案", msg = "保存提案")
|
||||
public Result save(@Param("info") ProposalInfo proposalInfo) {
|
||||
proposalWriteService.checkCurrentUserDelegate(proposalInfo.getSessionId());
|
||||
if (StrUtil.isBlank(proposalInfo.getCode())) {
|
||||
proposalInfo.setCode(proposalWriteService.generateProposalCode(proposalInfo.getSessionId(), proposalInfo.getDelegationId()));
|
||||
}
|
||||
@@ -98,6 +99,7 @@ public class ProposalWriteController {
|
||||
@ApiOperation("提交提案")
|
||||
@SLog(tag = "提案管理系统-我的提案", msg = "提交提案")
|
||||
public Result submit(@Param("info") ProposalInfo proposalInfo) {
|
||||
proposalWriteService.checkCurrentUserDelegate(proposalInfo.getSessionId());
|
||||
if (StrUtil.isBlank(proposalInfo.getCode())) {
|
||||
proposalInfo.setCode(proposalWriteService.generateProposalCode(proposalInfo.getSessionId(), proposalInfo.getDelegationId()));
|
||||
}
|
||||
|
||||
+2
-28
@@ -1,19 +1,9 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.listenter;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.flow.engine.event.ProcessEvent;
|
||||
import com.budwk.app.flow.engine.event.ProcessEventListener;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
|
||||
import com.budwk.app.flow.service.ProcessInstanceService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalMerge;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
@@ -25,27 +15,11 @@ import org.nutz.lang.Lang;
|
||||
@IocBean
|
||||
public class ProposalCommitteeFilingRevokeEventListener implements ProcessEventListener {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private ProcessInstanceService processInstanceService;
|
||||
|
||||
@Override
|
||||
public void onEvent(ProcessEvent event) {
|
||||
if (event.getEventType() == ProcessEventTypeEnum.PROCESS_TASK_REVOKE) {
|
||||
Long taskId = event.getSourceId();
|
||||
ProcessTask task = dao.fetch(ProcessTask.class, taskId);
|
||||
ProcessInstance processInstance = processInstanceService.getById(task.getProcessInstanceId());
|
||||
|
||||
// 处理并案信息撤回
|
||||
if ("committee".equals(task.getTaskName())) {
|
||||
// 如果有并案,删掉并案数据(傻逼提的需求,nmsl)
|
||||
ProposalMerge proposalMerge = dao.fetch(ProposalMerge.class, Cnd.where("proposalId", "=", processInstance.getBusinessNo()));
|
||||
|
||||
if (Lang.isNotEmpty(proposalMerge)) {
|
||||
dao.clear(ProposalMerge.class, Cnd.where(ProposalMerge::getProposalId, "=", proposalMerge.getProposalId()));
|
||||
}
|
||||
}
|
||||
// proposal_merge 的删除逻辑已统一收口到 ProposalCommitteeFilingServiceImpl.revokeTask,
|
||||
// 这里不再重复处理业务表,避免事件监听和 service 两处口径不一致。
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public class ProposalQueryComprehensiveParam extends PageForm {
|
||||
if (Lang.isNotEmpty(searchParam.getSessionIds())) {
|
||||
cnd.and("info.sessionId", "in", searchParam.getSessionIds());
|
||||
} else {
|
||||
cnd.andEX("info.sessionId", "=", searchParam.getSessionId());
|
||||
// cnd.andEX("info.sessionId", "=", searchParam.getSessionId());
|
||||
}
|
||||
|
||||
//提案名称
|
||||
|
||||
@@ -19,6 +19,7 @@ public class ProposalSearchParam extends PageForm {
|
||||
private String code;
|
||||
private String sessionId;
|
||||
private String delegationId;
|
||||
private String unionId;
|
||||
private String createUserName;
|
||||
private String createUserLoginName;
|
||||
private String createUserKeyword;
|
||||
|
||||
+9
-1
@@ -5,5 +5,13 @@ import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond;
|
||||
|
||||
public interface ProposalSecondedService extends BaseService<ProposalSecond> {
|
||||
|
||||
|
||||
/**
|
||||
* 仅更新附议表 proposal_second 中当前附议人的附议结果。
|
||||
* 参数说明:
|
||||
* 1. proposalId:提案ID,用于定位当前提案的附议记录。
|
||||
* 2. taskActorUserId:附议人用户ID,用于定位当前登录人的附议记录。
|
||||
* 3. opinion:附议意见,写入附议记录的 opinion 字段。
|
||||
* 4. submitType:附议结果,1 表示同意,20 表示不同意。
|
||||
*/
|
||||
void updateSecondRecord(String proposalId, String taskActorUserId, String opinion, Integer submitType);
|
||||
}
|
||||
|
||||
+10
@@ -22,5 +22,15 @@ public interface ProposalWriteService extends BaseService<ProposalInfo> {
|
||||
|
||||
List<Sys_dict> listSourceByCode(@Valid String code);
|
||||
|
||||
/**
|
||||
* 校验当前登录用户在指定教代会届次下是否具备代表身份。
|
||||
* 参数说明:
|
||||
* 1. sessionId:教代会届次ID,保存和提交提案时通过该字段定位当前届次代表信息。
|
||||
* 返回值说明:
|
||||
* 1. 校验通过时无返回值。
|
||||
* 2. 校验不通过时抛出业务异常,由上层统一返回提示信息。
|
||||
*/
|
||||
void checkCurrentUserDelegate(String sessionId);
|
||||
|
||||
ProposalInfo importProposal(Map<String, String> stringStringMap);
|
||||
}
|
||||
|
||||
+22
-22
@@ -234,10 +234,10 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
// 提案附议
|
||||
List<NutMap> secondInfos = new ArrayList<>();
|
||||
List<ProcessTaskVO> secondTaskVos = taskGroups.get("提案附议");
|
||||
if(secondTaskVos != null && secondTaskVos.size() > 0) {
|
||||
if (secondTaskVos != null && secondTaskVos.size() > 0) {
|
||||
for (ProcessTaskVO secondTaskVO : secondTaskVos) {
|
||||
Dict taskFormData = secondTaskVO.getTaskFormData();
|
||||
if(taskFormData == null) {
|
||||
if (taskFormData == null) {
|
||||
continue;
|
||||
}
|
||||
NutMap secondInfo = new NutMap();
|
||||
@@ -248,7 +248,7 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
taskUserSql.setCallback(Sqls.callback.map());
|
||||
execute(taskUserSql);
|
||||
NutMap taskUserMap = (NutMap) taskUserSql.getResult();
|
||||
secondInfo.put("s_mobile", taskUserMap.getString("mobile"));
|
||||
secondInfo.put("s_mobile", Objects.isNull(taskUserMap) ? "" : taskUserMap.getString("mobile"));
|
||||
secondInfos.add(secondInfo);
|
||||
}
|
||||
}
|
||||
@@ -256,10 +256,10 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
// 代表团意见
|
||||
List<NutMap> delegationAuditList = new ArrayList<>();
|
||||
List<ProcessTaskVO> delegationTaskVos = taskGroups.get("团长审核");
|
||||
if(delegationTaskVos != null && delegationTaskVos.size() > 0) {
|
||||
if (delegationTaskVos != null && delegationTaskVos.size() > 0) {
|
||||
for (ProcessTaskVO delegationTaskVO : delegationTaskVos) {
|
||||
Dict taskFormData = delegationTaskVO.getTaskFormData();
|
||||
if(taskFormData == null) {
|
||||
if (taskFormData == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -601,10 +601,10 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
List<NutMap> caseUnitList = listMap(caseUnitSql);
|
||||
for (NutMap v : caseUnitList) {
|
||||
String hostUnitName = v.getString("masterUnitName");
|
||||
if (StrUtil.isNotBlank(hostUnitName)){
|
||||
if (StrUtil.isNotBlank(hostUnitName)) {
|
||||
underTakeNames.add(hostUnitName);
|
||||
}
|
||||
if (StrUtil.isNotBlank(v.getString("slaveUnitNames"))){
|
||||
if (StrUtil.isNotBlank(v.getString("slaveUnitNames"))) {
|
||||
List<String> helpUnitNames = Arrays.asList(v.getString("slaveUnitNames").split("、"));
|
||||
underTakeNames.addAll(helpUnitNames);
|
||||
}
|
||||
@@ -725,73 +725,73 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
String proposalMeasures = MapUtil.getStr(dataMap, "建议措施", "");
|
||||
|
||||
// 工号
|
||||
if(StrUtil.isBlank(loginName)) {
|
||||
if (StrUtil.isBlank(loginName)) {
|
||||
throw new RuntimeException("工号不能为空");
|
||||
}
|
||||
Sys_user user = sysUserService.getByLoginName(loginName);
|
||||
if(user == null){
|
||||
if (user == null) {
|
||||
throw new RuntimeException("工号不存在");
|
||||
}
|
||||
if(StrUtil.isNotBlank(username) && !username.equals(user.getUsername())) {
|
||||
if (StrUtil.isNotBlank(username) && !username.equals(user.getUsername())) {
|
||||
throw new RuntimeException("工号和提案人不一致");
|
||||
}
|
||||
|
||||
// 提案时间
|
||||
if(StrUtil.isBlank(proposalDate)) {
|
||||
if (StrUtil.isBlank(proposalDate)) {
|
||||
throw new RuntimeException("提案时间不能为空");
|
||||
}
|
||||
|
||||
// 提案类型
|
||||
if(StrUtil.isBlank(proposalType)) {
|
||||
if (StrUtil.isBlank(proposalType)) {
|
||||
throw new RuntimeException("提案类型不能为空");
|
||||
}
|
||||
ProposalType proposalTypeObj = dao().fetch(ProposalType.class, Cnd.where(ProposalType::getName, "=", proposalType));
|
||||
if(proposalTypeObj == null) {
|
||||
if (proposalTypeObj == null) {
|
||||
throw new RuntimeException("提案类型不存在");
|
||||
}
|
||||
|
||||
// 提案方式
|
||||
if(StrUtil.isBlank(proposalSource)) {
|
||||
if (StrUtil.isBlank(proposalSource)) {
|
||||
throw new RuntimeException("提案方式不能为空");
|
||||
}
|
||||
Sys_dict dict = sysDictService.fetch(Cnd.where("code", "=", "PROPOSAL_SOURCE"));
|
||||
if(dict == null) {
|
||||
if (dict == null) {
|
||||
throw new RuntimeException("提案方式字典配置不存在");
|
||||
}
|
||||
List<Sys_dict> sysDicts = sysDictService.query(Cnd.where("parentId", "=", Strings.sNull(dict.getId())).asc("location"));
|
||||
if(sysDicts == null || sysDicts.size() == 0) {
|
||||
if (sysDicts == null || sysDicts.size() == 0) {
|
||||
throw new RuntimeException("提案方式字典配置不存在");
|
||||
}
|
||||
Sys_dict proposalSourceDict = sysDicts.stream().filter(v -> v.getName().equals(proposalSource)).findFirst().orElse(null);
|
||||
if(proposalSourceDict == null) {
|
||||
if (proposalSourceDict == null) {
|
||||
throw new RuntimeException("提案方式不存在");
|
||||
}
|
||||
|
||||
// 提案名称
|
||||
if(StrUtil.isBlank(proposalName)) {
|
||||
if (StrUtil.isBlank(proposalName)) {
|
||||
throw new RuntimeException("提案名称不能为空");
|
||||
}
|
||||
|
||||
// 案由
|
||||
if(StrUtil.isBlank(proposalContent)) {
|
||||
if (StrUtil.isBlank(proposalContent)) {
|
||||
throw new RuntimeException("案由不能为空");
|
||||
}
|
||||
|
||||
// 建议措施
|
||||
if(StrUtil.isBlank(proposalMeasures)) {
|
||||
if (StrUtil.isBlank(proposalMeasures)) {
|
||||
throw new RuntimeException("建议措施不能为空");
|
||||
}
|
||||
|
||||
// 判断当前导入用户是否是代表
|
||||
Teacher_congress_delegate delegate = teacherCongressDelegateService.fetch(Cnd.where(Teacher_congress_delegate::getUserId, "=", SecurityUtil.getUserId())
|
||||
.and(Teacher_congress_delegate::getDelFlag, "!=", 1).limit(1));
|
||||
if(delegate == null) {
|
||||
if (delegate == null) {
|
||||
throw new RuntimeException("当前用户不是代表");
|
||||
}
|
||||
|
||||
// 教代会
|
||||
List<Teacher_congress_session> teacherCongressSessions = this.dao().query(Teacher_congress_session.class, Cnd.where("enable", "=", 1).desc("startDate"));
|
||||
if(teacherCongressSessions == null || teacherCongressSessions.size() <= 0) {
|
||||
if (teacherCongressSessions == null || teacherCongressSessions.size() <= 0) {
|
||||
throw new RuntimeException("没有开启的教代会");
|
||||
}
|
||||
Teacher_congress_session teacherCongressSession = teacherCongressSessions.get(0);
|
||||
|
||||
+3
@@ -83,6 +83,9 @@ public class ProposalCommitteeFilingServiceImpl extends BaseServiceImpl<Proposal
|
||||
for (ProcessTask mergeTask : mergeTasks) {
|
||||
flowCommonService.revokeTask(mergeTask.getId());
|
||||
}
|
||||
|
||||
// 并案整组撤回后,需要同步删除 proposal_merge 中整组并案关系,避免列表仍按并案数据展示。
|
||||
dao().clear(ProposalMerge.class, Cnd.where(ProposalMerge::getProposalId, "in", mergeProposalIds));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-5
@@ -1,21 +1,37 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.web.controllers.open.commons.service.CommonService;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalSecond;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalSecondedService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ProposalSecondedServiceImpl extends BaseServiceImpl<ProposalSecond> implements ProposalSecondedService {
|
||||
|
||||
@Inject
|
||||
private CommonService commonService;
|
||||
|
||||
public ProposalSecondedServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSecondRecord(String proposalId, String taskActorUserId, String opinion, Integer submitType) {
|
||||
if (Strings.isBlank(proposalId) || Strings.isBlank(taskActorUserId) || submitType == null) {
|
||||
return;
|
||||
}
|
||||
// 仅更新当前提案、当前附议人的附议结果,不处理流程任务表。
|
||||
ProposalSecond proposalSecond = this.fetch(Cnd.where(ProposalSecond::getProposalId, "=", proposalId)
|
||||
.and(ProposalSecond::getSeconderId, "=", taskActorUserId));
|
||||
if (proposalSecond == null) {
|
||||
return;
|
||||
}
|
||||
proposalSecond.setIsAgree(ObjectUtil.equals(submitType, ProcessSubmitTypeEnum.AGREE.getCode()));
|
||||
proposalSecond.setOpinion(opinion);
|
||||
proposalSecond.setSecondedTime(DateUtil.date());
|
||||
this.update(proposalSecond);
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -121,6 +121,23 @@ public class ProposalWriteServiceImpl extends BaseServiceImpl<ProposalInfo> impl
|
||||
return dict == null ? new ArrayList<>() : sysDictService.query(Cnd.where("parentId", "=", Strings.sNull(dict.getId())).asc("location"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCurrentUserDelegate(String sessionId) {
|
||||
if (StrUtil.isBlank(sessionId)) {
|
||||
throw new RuntimeException("所属教代会不能为空");
|
||||
}
|
||||
// 撰写提案必须绑定当前届次代表身份,避免非代表用户保存或提交提案。
|
||||
Teacher_congress_delegate delegate = teacherCongressDelegateService.fetch(
|
||||
Cnd.where(Teacher_congress_delegate::getSessionId, "=", sessionId)
|
||||
.and(Teacher_congress_delegate::getUserId, "=", SecurityUtil.getUserId())
|
||||
.and(Teacher_congress_delegate::getDelFlag, "!=", 1)
|
||||
.limit(1)
|
||||
);
|
||||
if (delegate == null) {
|
||||
throw new RuntimeException("当前用户不是代表,无法撰写提案");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProposalInfo importProposal(Map<String, String> dataMap) {
|
||||
String loginName = MapUtil.getStr(dataMap, "工号", "");
|
||||
|
||||
+10
-2
@@ -150,7 +150,7 @@ public class TeacherCongressDelegatePushController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tc.delegate.push")
|
||||
// @SLog(tag = "民主管理-教代会代表推选", msg = "获取本分工会下的非代表用户")
|
||||
public Result getUnionUser(String sessionId, String unionId) {
|
||||
public Result getUnionUser(String sessionId, String unionId, String keyword) {
|
||||
// 查询预选中的代表
|
||||
Cnd cndx = Cnd.where("sessionId", "=", sessionId);
|
||||
cndx.andEX("unionId", "=", SecurityUtil.getUnionId());
|
||||
@@ -173,7 +173,7 @@ public class TeacherCongressDelegatePushController {
|
||||
`vw_user` u
|
||||
LEFT JOIN teacher_congress_delegate tcd ON tcd.userId = u.id
|
||||
AND tcd.sessionId = @sessionId
|
||||
LEFT JOIN teacher_congress_delegate_push tcdp ON tcdp.userId = tcdp.id
|
||||
LEFT JOIN teacher_congress_delegate_push tcdp ON tcdp.userId = u.id
|
||||
AND tcdp.sessionId = @sessionId
|
||||
$condition
|
||||
""");
|
||||
@@ -185,6 +185,14 @@ public class TeacherCongressDelegatePushController {
|
||||
cnd.and("tcd.userId", "is", null);
|
||||
cnd.and("tcdp.id", "is", null);
|
||||
cnd.and("u.unionId", "=", SecurityUtil.getUnionId());
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("u.username", keyword);
|
||||
group.orLike("u.loginname", keyword);
|
||||
cnd.and(group);
|
||||
}
|
||||
// 搜索候选人时只返回少量命中数据,避免前端大列表筛选导致严重卡顿
|
||||
cnd.limit(1, 100);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> userList = baseService.listMap(sql);
|
||||
|
||||
|
||||
+6
-4
@@ -129,7 +129,8 @@ public class AidFundApplyController {
|
||||
}
|
||||
//如果有两个工号并且有一个工号已经是会员就不让他申请了
|
||||
if (userList.size() >= 2) {
|
||||
int size = userList.stream().filter(Sys_user::getAidFundMember).toList().size();
|
||||
// 历史用户数据中 aidFundMember 可能为空,这里只统计明确为基金会员的工号,避免空值自动拆箱报错
|
||||
int size = userList.stream().filter(sysUser -> Boolean.TRUE.equals(sysUser.getAidFundMember())).toList().size();
|
||||
if (size > 0) {
|
||||
return Result.success(Map.of("disabled", true, "label", "请用新工号登陆办理申请业务!"));
|
||||
}
|
||||
@@ -149,7 +150,7 @@ public class AidFundApplyController {
|
||||
aidFundMemberChangeRecord.setUserId(SecurityUtil.getUserId());
|
||||
Sys_user user = dao.fetch(Sys_user.class, SecurityUtil.getUserId());
|
||||
if (StrUtil.isBlank(aidFundMemberChangeRecord.getId())) aidFundMemberChangeRecord.setApplyTime(new Date());
|
||||
if (user.getAidFundMember() == AidFundMemberMode.NORMAL.getCode()) {
|
||||
if (Boolean.TRUE.equals(user.getAidFundMember())) {
|
||||
aidFundMemberChangeRecord.setChangeType("AIDFUND_MEMBER_CHANGE_TYPE_FOUR");
|
||||
} else {
|
||||
aidFundMemberChangeRecord.setChangeType("AIDFUND_MEMBER_CHANGE_TYPE_ONE");
|
||||
@@ -159,7 +160,8 @@ public class AidFundApplyController {
|
||||
Dict args = Dict.create();
|
||||
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
args.set(FlowConst.FORM_DATA, aidFundMemberChangeRecord);
|
||||
args.set("aidFundMemberUserType", user.getAidFundMemberUserType());
|
||||
// 流程变量中的基金会员类型以本次申请提交值为准,避免继续使用用户表中的旧值。
|
||||
args.set("aidFundMemberUserType", aidFundMemberChangeRecord.getAidFundMemberUserType());
|
||||
ProcessInstance instance = flowEngine.startProcessInstanceByKey("JJHY", aidFundMemberChangeRecord.getId(), SecurityUtil.getUserId(), args);
|
||||
|
||||
// 自动完成第一个申请任务
|
||||
@@ -194,7 +196,7 @@ public class AidFundApplyController {
|
||||
us.username,
|
||||
us.loginname,
|
||||
us.mobile,
|
||||
us.aidFundMemberUserType,
|
||||
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
|
||||
us.arrivalAtSchoolDate,
|
||||
us.sex,
|
||||
us.unitName,
|
||||
|
||||
+7
-2
@@ -76,14 +76,17 @@ public class AidFundApplyMineController {
|
||||
@Param(value = "year") Integer year) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
info.id,
|
||||
info.userId,
|
||||
info.changeType,
|
||||
info.applyTime,
|
||||
us.arrivalAtSchoolDate,
|
||||
us.mobile,
|
||||
us.loginname loginName,
|
||||
us.username userName,
|
||||
us.unitName,
|
||||
us.unionName,
|
||||
us.aidFundMemberUserType,
|
||||
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
|
||||
us.sex,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
@@ -113,6 +116,8 @@ public class AidFundApplyMineController {
|
||||
|
||||
cnd.andEX("year(info.applyTime)", "=", year);
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
// 管理端代操作产生的记录不属于“我的申请”,历史空值按普通申请处理。
|
||||
cnd.andEX("IFNULL(info.adminOperate, 0)", "=", 0);
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
|
||||
-1
@@ -58,7 +58,6 @@ public class AidFundChangeRecordController {
|
||||
us.mobile,
|
||||
us.unitName,
|
||||
us.unionName,
|
||||
us.aidFundMemberUserType,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
|
||||
+63
-82
@@ -1,24 +1,24 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.controller;
|
||||
|
||||
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
||||
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.AidFundMemberChangeRecordService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -27,6 +27,8 @@ import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -44,8 +46,6 @@ public class AidFundFoundationAuditController {
|
||||
@Inject
|
||||
private AidFundMemberChangeRecordService changeRecordService;
|
||||
|
||||
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/staffbenefit/medicalMutualAid/aidFund/foundationAudit/index.html")
|
||||
@SaCheckPermission("medicalMutualAid.aidFund.foundationAudit")
|
||||
@@ -61,79 +61,8 @@ public class AidFundFoundationAuditController {
|
||||
@At
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
|
||||
public Result pageData(PageForm pageForm,
|
||||
@Param(value = "year") Integer year,
|
||||
@Param(value = "aidFundMemberUserType") String aidFundMemberUserType,
|
||||
@Param(value = "unionId") String unionId,
|
||||
@Param(value = "unitId") String unitId,
|
||||
@Param(value = "changeType") String changeType,
|
||||
@Param(value = "approval") Boolean approval) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
us.arrivalAtSchoolDate,
|
||||
us.mobile,
|
||||
us.loginname loginName,
|
||||
us.username userName,
|
||||
us.unitName,
|
||||
us.unionName,
|
||||
us.aidFundMemberUserType,
|
||||
us.sex,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
t.id taskId,
|
||||
t.taskName AS taskKey,
|
||||
t.displayName taskName,
|
||||
t.taskType,
|
||||
t.performType taskPerformType,
|
||||
t.taskState,
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
|
||||
FROM
|
||||
wf_process_task t
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||
LEFT JOIN aid_fund_member_change_record info ON info.id = ins.businessNo
|
||||
LEFT JOIN vw_user us ON us.id = info.userId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or("us.loginname", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or("us.username", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("YEAR(info.applyTime)", "=", year);
|
||||
cnd.andEX("us.aidFundMemberUserType", "=", aidFundMemberUserType);
|
||||
cnd.andEX("us.unionId", "=", unionId);
|
||||
cnd.andEX("us.unitId", "=", unitId);
|
||||
cnd.andEX("info.changeType", "=", changeType);
|
||||
|
||||
cnd.and("t.taskName", "=", "85c7d148-44f5-4333-b854-ab225357fd3e");
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
|
||||
if (approval) {
|
||||
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.applyTime");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
cnd.groupBy("t.id");
|
||||
sql.setCondition(cnd);
|
||||
public Result pageData(AidFundPageForm pageForm) {
|
||||
Sql sql = changeRecordService.getFoundationAuditSql(pageForm);
|
||||
Pagination<NutMap> pageVO = changeRecordService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
|
||||
List<NutMap> list = pageVO.getList();
|
||||
@@ -144,6 +73,39 @@ public class AidFundFoundationAuditController {
|
||||
return Result.success(pageVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出互管会审核页面申请记录。
|
||||
*
|
||||
* @param pageForm 页面筛选参数,和列表页查询条件保持一致
|
||||
* @param response HTTP 响应对象,用于输出 Excel 文件流
|
||||
*/
|
||||
@At
|
||||
@Ok("void")
|
||||
@ApiOperation("导出申请记录")
|
||||
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
|
||||
public void exportApplyRecord(AidFundPageForm pageForm, HttpServletResponse response) {
|
||||
List<NutMap> listMap = changeRecordService.getFoundationAuditExportList(pageForm);
|
||||
List<ExcelExportEntity> entityList = new ArrayList<>();
|
||||
entityList.add(new ExcelExportEntity("工号", "loginName", 20));
|
||||
entityList.add(new ExcelExportEntity("姓名", "userName", 20));
|
||||
entityList.add(new ExcelExportEntity("性别", "sex", 15));
|
||||
entityList.add(new ExcelExportEntity("电话", "mobile", 20));
|
||||
entityList.add(new ExcelExportEntity("工会", "unionName", 20));
|
||||
entityList.add(new ExcelExportEntity("单位", "unitName", 20));
|
||||
entityList.add(new ExcelExportEntity("入校时间", "arrivalAtSchoolDate", 20));
|
||||
entityList.add(new ExcelExportEntity("基金会员类型", "aidFundMemberUserType", 20));
|
||||
entityList.add(new ExcelExportEntity("缴纳金额", "money", 20));
|
||||
entityList.add(new ExcelExportEntity("变更类型", "changeType", 20));
|
||||
entityList.add(new ExcelExportEntity("申请时间", "applyTime", 20));
|
||||
entityList.add(new ExcelExportEntity("审核状态", "approvalStatus", 20));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, listMap);
|
||||
String fileName = (pageForm.getYear() == null ? "" : pageForm.getYear()) + "基金会员审核记录.xlsx";
|
||||
CommonDownloadUtil.download(fileName, workbook, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("查询需要缴费多少")
|
||||
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
|
||||
@@ -163,4 +125,23 @@ public class AidFundFoundationAuditController {
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核互管会待办记录。
|
||||
*
|
||||
* @param param 统一的审批参数,包含审批意见和审核动作
|
||||
* @param ids 勾选的申请记录 ID 数组
|
||||
* @return 批量审核结果统计
|
||||
*/
|
||||
@At
|
||||
@SLog(tag = "基金会员", msg = "互管会批量审核基金会员记录")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@ApiOperation("批量审核")
|
||||
@SaCheckPermission(value = {"medicalMutualAid.aidFund.foundationAudit", "h5.medicalMutualAid.aidFund.foundationAudit"}, mode = SaMode.OR)
|
||||
public Result batchExecuteTask(@Param("data") String param, @Param("ids") String[] ids) {
|
||||
if (ids == null || ids.length == 0 || StrUtil.isBlank(param)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
return Result.success(changeRecordService.batchExecuteTask(param, ids));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
-86
@@ -10,18 +10,12 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.mode.AidFundMemberMode;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
@@ -35,7 +29,6 @@ import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -79,55 +72,32 @@ public class AidFundManageController {
|
||||
@ApiOperation("分页查询")
|
||||
@SaCheckPermission("medicalMutualAid.aidFund.manage")
|
||||
public Result pageData(AidFundPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
id,
|
||||
loginname,
|
||||
username,
|
||||
sex,
|
||||
arrivalAtSchoolDate,
|
||||
unitName,
|
||||
unionName,
|
||||
aidFundMemberUserType,
|
||||
aidFundMemberJoinTime
|
||||
FROM
|
||||
vw_user
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
|
||||
if (AuthUtil.hasRole(RoleConstant.RETIREMENT_WORKPLACE.name())) {
|
||||
cnd.and(Sys_user::getAidFundMemberUserType, "=", "离退休人员");
|
||||
} else {
|
||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
}
|
||||
|
||||
if (pageForm.getNotPayedCurrentYear()) {
|
||||
cnd.and("id", "in", Sqls.create("SELECT userid FROM `aid_fund_member_pay` where `year` = YEAR(CURDATE()) and isPayed = 0"));
|
||||
}
|
||||
cnd.andEX(Sys_user::getAidFundMemberUserType, "=", pageForm.getAidFundMemberUserType());
|
||||
cnd.andEX(View_user::getUnionId, "=", pageForm.getUnionId());
|
||||
cnd.andEX(View_user::getUnitId, "=", pageForm.getUnitId());
|
||||
sql.setCondition(cnd);
|
||||
cnd.and(Sys_user::getAidFundMember, "=", AidFundMemberMode.NORMAL.getCode());
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orLike("loginname", pageForm.getSearchKeyword());
|
||||
seg.orLike("username", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.desc("unitCode");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = userService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
Sql sql = aidFundMemberService.getManageSql(pageForm);
|
||||
Pagination pagination = aidFundMemberService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("medicalMutualAid.aidFund.manage")
|
||||
@Ok("void")
|
||||
@ApiOperation("导出会员名单")
|
||||
public void exportMemberList(AidFundPageForm pageForm, HttpServletResponse response) {
|
||||
List<NutMap> listMap = aidFundMemberService.listMap(aidFundMemberService.getManageSql(pageForm));
|
||||
|
||||
List<ExcelExportEntity> entityList = new ArrayList<>();
|
||||
entityList.add(new ExcelExportEntity("姓名", "username", 20));
|
||||
entityList.add(new ExcelExportEntity("工号", "loginname", 20));
|
||||
entityList.add(new ExcelExportEntity("性别", "sex", 20));
|
||||
entityList.add(new ExcelExportEntity("会员类型", "aidFundMemberUserType", 20));
|
||||
entityList.add(new ExcelExportEntity("单位", "unitName", 20));
|
||||
entityList.add(new ExcelExportEntity("工会", "unionName", 20));
|
||||
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, listMap);
|
||||
CommonDownloadUtil.download("会员名单.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@SaCheckPermission("medicalMutualAid.aidFund.manage")
|
||||
@@ -198,9 +168,12 @@ public class AidFundManageController {
|
||||
return Result.error("请选择要退会的人员");
|
||||
}
|
||||
List<AidFundMemberChangeRecord> recordArrayList = new ArrayList<>();
|
||||
List<Sys_user> sysUserList = userService.query(Cnd.where("id", "in", ids));
|
||||
for (String id : ids) {
|
||||
Sys_user user = sysUserList.stream().filter(sysUser -> sysUser.getId().equals(id)).findFirst().orElse(null);
|
||||
AidFundMemberChangeRecord record = new AidFundMemberChangeRecord()
|
||||
.setUserId(id)
|
||||
.setAidFundMemberUserType(user.getAidFundMemberUserType())
|
||||
.setApplyTime(new Date())
|
||||
.setChangeType("AIDFUND_MEMBER_CHANGE_TYPE_SEVEN");
|
||||
recordArrayList.add(record);
|
||||
@@ -220,25 +193,7 @@ public class AidFundManageController {
|
||||
if (ObjectUtil.isEmpty(ids) || StrUtil.isBlank(changeType)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
List<AidFundMemberChangeRecord> recordArrayList = new ArrayList<>();
|
||||
for (String id : ids) {
|
||||
AidFundMemberChangeRecord record = new AidFundMemberChangeRecord()
|
||||
.setUserId(id)
|
||||
.setApplyTime(new Date())
|
||||
.setChangeType(changeType);
|
||||
recordArrayList.add(record);
|
||||
}
|
||||
Chain add;
|
||||
if (changeType.equals("AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
|
||||
//会员退休
|
||||
add = Chain.make("aidFundMemberUserType", "离退休人员");
|
||||
} else {
|
||||
add = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
|
||||
.add("aidFundMemberQuitTime", new Date());
|
||||
}
|
||||
|
||||
userService.update(add, Cnd.where("id", "in", ids));
|
||||
userService.insert(recordArrayList);
|
||||
aidFundMemberService.doBatchChangeTypeByAdmin(ids, changeType);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@@ -258,21 +213,10 @@ public class AidFundManageController {
|
||||
@ApiOperation("变更基金会员")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result doEditChangeType(String userId, String changeType) {
|
||||
AidFundMemberChangeRecord record = new AidFundMemberChangeRecord()
|
||||
.setUserId(userId)
|
||||
.setApplyTime(new Date())
|
||||
.setChangeType(changeType);
|
||||
aidFundMemberService.insert(record);
|
||||
Chain add;
|
||||
if (changeType.equals("AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
|
||||
//会员退休
|
||||
add = Chain.make("aidFundMemberUserType", "离退休人员");
|
||||
} else {
|
||||
add = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
|
||||
.add("aidFundMemberQuitTime", new Date());
|
||||
if (StrUtil.isBlank(userId) || StrUtil.isBlank(changeType)) {
|
||||
return Result.error("参数错误");
|
||||
}
|
||||
|
||||
userService.update(add, Cnd.where("id", "=", userId));
|
||||
aidFundMemberService.doEditChangeTypeByAdmin(userId, changeType);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -63,14 +63,17 @@ public class AidFundRetirementAuditController {
|
||||
@Param(value = "approval") Boolean approval) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
info.id,
|
||||
info.userId,
|
||||
info.changeType,
|
||||
info.applyTime,
|
||||
us.arrivalAtSchoolDate,
|
||||
us.mobile,
|
||||
us.loginname loginName,
|
||||
us.username userName,
|
||||
us.unitName,
|
||||
us.unionName,
|
||||
us.aidFundMemberUserType,
|
||||
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
|
||||
us.sex,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
@@ -106,7 +109,7 @@ public class AidFundRetirementAuditController {
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("YEAR(info.applyTime)", "=", year);
|
||||
cnd.andEX("us.aidFundMemberUserType", "=", aidFundMemberUserType);
|
||||
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", aidFundMemberUserType);
|
||||
cnd.andEX("info.changeType", "=", changeType);
|
||||
|
||||
cnd.and("t.taskName", "=", "f756c818-6bb7-4f50-b8fa-24390fc7b0b8");
|
||||
|
||||
+6
-3
@@ -65,14 +65,17 @@ public class AidFundUnionAuditController {
|
||||
@Param(value = "approval") Boolean approval) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
info.id,
|
||||
info.userId,
|
||||
info.changeType,
|
||||
info.applyTime,
|
||||
us.arrivalAtSchoolDate,
|
||||
us.mobile,
|
||||
us.loginname loginName,
|
||||
us.username userName,
|
||||
us.unitName,
|
||||
us.unionName,
|
||||
us.aidFundMemberUserType,
|
||||
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
|
||||
us.sex,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
@@ -108,7 +111,7 @@ public class AidFundUnionAuditController {
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("YEAR(info.applyTime)", "=", year);
|
||||
cnd.andEX("us.aidFundMemberUserType", "=", aidFundMemberUserType);
|
||||
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", aidFundMemberUserType);
|
||||
cnd.andEX("info.changeType", "=", changeType);
|
||||
|
||||
cnd.and("t.taskName", "=", "06ed1d6d-5f96-485f-9150-ed1ef4a082d6");
|
||||
|
||||
+10
@@ -38,10 +38,20 @@ public class AidFundMemberChangeRecord extends BaseModel {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String changeType;
|
||||
|
||||
@Column
|
||||
@Comment("申请时选择的基金会员类型(dict)")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String aidFundMemberUserType;
|
||||
|
||||
@Column
|
||||
@Comment("申请时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date applyTime;
|
||||
|
||||
@Column
|
||||
@Comment("是否系统管理员操作")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
private Boolean adminOperate;
|
||||
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -22,6 +22,9 @@ public class AidFundPageForm extends PageForm {
|
||||
private String changeType;
|
||||
private Integer year;
|
||||
|
||||
//是否已审核
|
||||
private Boolean approval;
|
||||
|
||||
//是否扣款null全部、1已缴费、0未缴费
|
||||
private Integer isPayed;
|
||||
}
|
||||
|
||||
+45
@@ -1,6 +1,8 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberPay;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
@@ -9,10 +11,53 @@ import java.util.List;
|
||||
|
||||
public interface AidFundMemberChangeRecordService extends BaseService<AidFundMemberChangeRecord> {
|
||||
|
||||
/**
|
||||
* 构建互管会审核页面查询 SQL。
|
||||
*
|
||||
* @param pageForm 页面筛选参数,包含年度、姓名/工号、工会、单位、会员类型、变更类型和审核状态
|
||||
* @return 可直接用于分页或导出的查询 SQL
|
||||
*/
|
||||
Sql getFoundationAuditSql(AidFundPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 查询互管会审核页面导出数据。
|
||||
*
|
||||
* @param pageForm 页面筛选参数,和列表页保持一致
|
||||
* @return 导出所需的列表数据,每条记录对应一条基金会员变更申请
|
||||
*/
|
||||
List<NutMap> getFoundationAuditExportList(AidFundPageForm pageForm);
|
||||
|
||||
/**
|
||||
* 执行流程审核动作。
|
||||
*
|
||||
* @param param 流程提交参数 JSON,包含提交流程所需的任务、意见和业务字段
|
||||
* @param id 基金会员变更记录 ID
|
||||
*/
|
||||
void executeTask( String param, String id);
|
||||
|
||||
/**
|
||||
* 批量执行互管会审核任务。
|
||||
*
|
||||
* @param param 流程提交参数 JSON,包含统一的审批意见和提交类型
|
||||
* @param ids 选中的基金会员变更记录 ID 数组
|
||||
* @return 批量审核结果,包含成功数、失败数和失败原因
|
||||
*/
|
||||
NutMap batchExecuteTask(String param, String[] ids);
|
||||
|
||||
/**
|
||||
* 计算基金会员应补缴金额。
|
||||
*
|
||||
* @param arrivalAtSchoolDate 入校时间,格式为 yyyy-MM-dd
|
||||
* @param userId 用户 ID,空值时默认取当前登录人
|
||||
* @return 当前规则下计算出的应缴金额
|
||||
*/
|
||||
int getPayMoney(String arrivalAtSchoolDate,String userId);
|
||||
|
||||
/**
|
||||
* 查询用户历年缴费记录。
|
||||
*
|
||||
* @param userId 用户 ID,空值时默认取当前登录人
|
||||
* @return 用户及其旧工号对应的缴费记录列表
|
||||
*/
|
||||
List<AidFundMemberPay> getUserPayRecordList(String userId);
|
||||
}
|
||||
|
||||
+27
@@ -2,6 +2,8 @@ package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.List;
|
||||
@@ -31,5 +33,30 @@ public interface AidFundMemberService extends BaseService {
|
||||
Double getPayMoney(Sys_user user, Integer year);
|
||||
|
||||
|
||||
/**
|
||||
* 获取基金会员台账列表查询SQL。
|
||||
*
|
||||
* @param pageForm 页面查询条件,包含会员类型、工会、单位、关键字、排序及未缴费筛选参数
|
||||
* @return 与基金会员台账页面一致的查询SQL
|
||||
*/
|
||||
Sql getManageSql(AidFundPageForm pageForm);
|
||||
|
||||
|
||||
List<NutMap> findChangeRecordList(String userId);
|
||||
|
||||
/**
|
||||
* 管理端批量变更基金会员状态,并记录“系统管理员操作”来源。
|
||||
*
|
||||
* @param ids 需要变更的用户ID数组,来自台账页面勾选行
|
||||
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
|
||||
*/
|
||||
void doBatchChangeTypeByAdmin(String[] ids, String changeType);
|
||||
|
||||
/**
|
||||
* 管理端对单个用户执行“变更”操作,并记录“系统管理员操作”来源。
|
||||
*
|
||||
* @param userId 被变更的用户ID
|
||||
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
|
||||
*/
|
||||
void doEditChangeTypeByAdmin(String userId, String changeType);
|
||||
}
|
||||
|
||||
+231
-7
@@ -3,20 +3,34 @@ package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.impl;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.mode.AidFundMemberMode;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberPay;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.AidFundMemberChangeRecordService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
@@ -33,6 +47,9 @@ import java.util.*;
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class AidFundMemberChangeRecordServiceImpl extends BaseServiceImpl<AidFundMemberChangeRecord> implements AidFundMemberChangeRecordService {
|
||||
private static final String FOUNDATION_AUDIT_TASK_NAME = "85c7d148-44f5-4333-b854-ab225357fd3e";
|
||||
private static final String CHANGE_TYPE_JOIN = "AIDFUND_MEMBER_CHANGE_TYPE_ONE";
|
||||
|
||||
public AidFundMemberChangeRecordServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
@@ -41,21 +58,228 @@ public class AidFundMemberChangeRecordServiceImpl extends BaseServiceImpl<AidFun
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
|
||||
@Inject
|
||||
private SysDictService sysDictService;
|
||||
|
||||
@Override
|
||||
public Sql getFoundationAuditSql(AidFundPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.userId,
|
||||
info.changeType,
|
||||
info.applyTime,
|
||||
us.arrivalAtSchoolDate,
|
||||
us.mobile,
|
||||
us.loginname loginName,
|
||||
us.username userName,
|
||||
us.unitName,
|
||||
us.unionName,
|
||||
IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType) aidFundMemberUserType,
|
||||
us.sex,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId,
|
||||
t.id taskId,
|
||||
t.taskName AS taskKey,
|
||||
t.displayName taskName,
|
||||
t.taskType,
|
||||
t.performType taskPerformType,
|
||||
t.taskState,
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
|
||||
FROM
|
||||
wf_process_task t
|
||||
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||
LEFT JOIN aid_fund_member_change_record info ON info.id = ins.businessNo
|
||||
LEFT JOIN vw_user us ON us.id = info.userId
|
||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.or("us.loginname", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
seg.or("us.username", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.andEX("YEAR(info.applyTime)", "=", pageForm.getYear());
|
||||
// 新申请优先按变更表中的基金会员类型筛选,历史数据为空时兜底用户表。
|
||||
cnd.andEX("IFNULL(info.aidFundMemberUserType, us.aidFundMemberUserType)", "=", pageForm.getAidFundMemberUserType());
|
||||
cnd.andEX("us.unionId", "=", pageForm.getUnionId());
|
||||
cnd.andEX("us.unitId", "=", pageForm.getUnitId());
|
||||
cnd.andEX("info.changeType", "=", pageForm.getChangeType());
|
||||
cnd.and("t.taskName", "=", FOUNDATION_AUDIT_TASK_NAME);
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())){
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
}
|
||||
|
||||
if (Boolean.TRUE.equals(pageForm.getApproval())) {
|
||||
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||
} else {
|
||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||
}
|
||||
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.applyTime");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
cnd.groupBy("t.id");
|
||||
sql.setCondition(cnd);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> getFoundationAuditExportList(AidFundPageForm pageForm) {
|
||||
List<NutMap> list = listMap(getFoundationAuditSql(pageForm));
|
||||
Map<String, String> memberTypeMap = getDictNameMap("AIDFUND_MEMBER_USER_TYPE");
|
||||
Map<String, String> changeTypeMap = getDictNameMap("AIDFUND_MEMBER_CHANGE_TYPE");
|
||||
list.forEach(map -> {
|
||||
String arrivalAtSchoolDate = map.getString("arrivalAtSchoolDate");
|
||||
String changeType = map.getString("changeType");
|
||||
map.put("approvalStatus", ObjectUtil.equals(map.getInt("taskState"), ProcessTaskStateEnum.DOING.getCode()) ? "未审核" : "已审核");
|
||||
map.put("aidFundMemberUserType", memberTypeMap.getOrDefault(map.getString("aidFundMemberUserType"), map.getString("aidFundMemberUserType")));
|
||||
map.put("changeType", changeTypeMap.getOrDefault(changeType, changeType));
|
||||
map.put("arrivalAtSchoolDate", StrUtil.isBlank(arrivalAtSchoolDate) ? "" : DateUtil.format(DateUtil.parse(arrivalAtSchoolDate), "yyyy-MM-dd"));
|
||||
map.put("applyTime", map.getTime("applyTime") == null ? "" : DateUtil.formatDateTime(map.getTime("applyTime")));
|
||||
// 仅加入基金时需要计算补缴金额,其他变更类型保持空白,避免误导为固定收费。
|
||||
map.put("money", ObjectUtil.equals(changeType, CHANGE_TYPE_JOIN) && StrUtil.isNotBlank(arrivalAtSchoolDate)
|
||||
? getPayMoney(arrivalAtSchoolDate, map.getString("userId")) : "");
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
private Map<String, String> getDictNameMap(String dictCode) {
|
||||
return sysDictService.getSubListByCode(dictCode).stream().collect(HashMap::new, (map, dict) -> map.put(dict.getCode(), dict.getName()), HashMap::putAll);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void executeTask(String param, String id) {
|
||||
Dict args = Json.fromJson(Dict.class, param);
|
||||
executeTask(args, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public NutMap batchExecuteTask(String param, String[] ids) {
|
||||
NutMap result = NutMap.NEW();
|
||||
if (ArrayUtil.isEmpty(ids)) {
|
||||
return result.setv("successCount", 0).setv("failCount", 0).setv("failMessages", List.of("请选择需要审核的记录"));
|
||||
}
|
||||
Dict baseArgs = Json.fromJson(Dict.class, param);
|
||||
List<ProcessTask> doingTasks = processTaskService.getDoingTaskByBizIdTaskName(Arrays.asList(ids), FOUNDATION_AUDIT_TASK_NAME);
|
||||
Map<String, ProcessTask> taskMap = new HashMap<>();
|
||||
List<Long> instanceIds = doingTasks.stream().map(ProcessTask::getProcessInstanceId).filter(Objects::nonNull).distinct().toList();
|
||||
Map<Long, String> businessNoMap = new HashMap<>();
|
||||
if (CollectionUtil.isNotEmpty(instanceIds)) {
|
||||
List<ProcessInstance> instances = dao().query(ProcessInstance.class, Cnd.where(ProcessInstance::getId, "in", instanceIds));
|
||||
instances.forEach(instance -> businessNoMap.put(instance.getId(), instance.getBusinessNo()));
|
||||
}
|
||||
doingTasks.forEach(task -> {
|
||||
String businessNo = businessNoMap.get(task.getProcessInstanceId());
|
||||
if (StrUtil.isNotBlank(businessNo)) {
|
||||
taskMap.put(businessNo, task);
|
||||
}
|
||||
});
|
||||
List<String> failMessages = new ArrayList<>();
|
||||
int successCount = 0;
|
||||
for (String id : ids) {
|
||||
AidFundMemberChangeRecord changeRecord = fetch(id);
|
||||
if (changeRecord == null) {
|
||||
failMessages.add(id + ":申请记录不存在");
|
||||
continue;
|
||||
}
|
||||
ProcessTask processTask = taskMap.get(id);
|
||||
if (processTask == null) {
|
||||
failMessages.add(resolveRecordName(changeRecord) + ":审核任务不存在或已处理");
|
||||
continue;
|
||||
}
|
||||
if (!processTaskService.isAllowed(processTask, SecurityUtil.getUserId())) {
|
||||
failMessages.add(resolveRecordName(changeRecord) + ":当前账号无权审核该记录");
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Dict args = buildBatchTaskArgs(baseArgs, changeRecord, processTask);
|
||||
executeTask(args, id);
|
||||
successCount++;
|
||||
} catch (Exception e) {
|
||||
failMessages.add(resolveRecordName(changeRecord) + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
result.setv("successCount", successCount);
|
||||
result.setv("failCount", failMessages.size());
|
||||
result.setv("failMessages", failMessages);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量审核沿用单条审核逻辑,但需要为每条记录补齐流程任务 ID 和加入基金时的入校时间。
|
||||
*/
|
||||
private Dict buildBatchTaskArgs(Dict baseArgs, AidFundMemberChangeRecord changeRecord, ProcessTask processTask) {
|
||||
Dict args = baseArgs.clone();
|
||||
args.set(FlowConst.PROCESS_TASK_ID_KEY, processTask.getId());
|
||||
args.set("changeType", changeRecord.getChangeType());
|
||||
if (ObjectUtil.equals(args.getInt("submitType"), 1) && ObjectUtil.equals(changeRecord.getChangeType(), CHANGE_TYPE_JOIN)) {
|
||||
Sys_user user = dao().fetch(Sys_user.class, changeRecord.getUserId());
|
||||
if (user == null || StrUtil.isBlank(user.getArrivalAtSchoolDate())) {
|
||||
throw new IllegalArgumentException("缺少入校时间,无法批量通过");
|
||||
}
|
||||
args.set("arrivalAtSchoolDate", user.getArrivalAtSchoolDate());
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
private String resolveRecordName(AidFundMemberChangeRecord changeRecord) {
|
||||
Sys_user user = dao().fetch(Sys_user.class, changeRecord.getUserId());
|
||||
if (user == null || StrUtil.isBlank(user.getUsername())) {
|
||||
return changeRecord.getId();
|
||||
}
|
||||
return user.getUsername();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一处理互管会审核通过后的用户状态同步,并继续推进流程任务。
|
||||
*/
|
||||
private void executeTask(Dict args, String id) {
|
||||
AidFundMemberChangeRecord changeRecord = fetch(id);
|
||||
if (changeRecord == null) {
|
||||
throw new IllegalArgumentException("申请记录不存在");
|
||||
}
|
||||
if (args.getInt("submitType") == 1) {
|
||||
//如果是通过
|
||||
if (ObjectUtil.equals(args.getStr("changeType"), "AIDFUND_MEMBER_CHANGE_TYPE_ONE")) {
|
||||
//如果是加入基金
|
||||
dao().update(Sys_user.class, Chain.make("arrivalAtSchoolDate", args.getStr("arrivalAtSchoolDate")).add("aidFundMemberJoinTime", new Date())
|
||||
.add("aidFundMember", AidFundMemberMode.NORMAL.getCode()),
|
||||
// 审核通过后需要把本次申请的基金会员类型同步回用户表,历史空值则保留用户原值不覆盖。
|
||||
String aidFundMemberUserType = changeRecord.getAidFundMemberUserType();
|
||||
// 如果是通过,加入基金需要回写入校时间和入会状态,其他类型按退会逻辑处理。
|
||||
if (ObjectUtil.equals(args.getStr("changeType"), CHANGE_TYPE_JOIN)) {
|
||||
if (StrUtil.isBlank(args.getStr("arrivalAtSchoolDate"))) {
|
||||
throw new IllegalArgumentException("缺少入校时间,无法通过审核");
|
||||
}
|
||||
Chain chain = Chain.make("arrivalAtSchoolDate", args.getStr("arrivalAtSchoolDate"))
|
||||
.add("aidFundMemberJoinTime", new Date())
|
||||
.add("aidFundMember", AidFundMemberMode.NORMAL.getCode());
|
||||
if (StrUtil.isNotBlank(aidFundMemberUserType)) {
|
||||
chain.add("aidFundMemberUserType", aidFundMemberUserType);
|
||||
}
|
||||
dao().update(Sys_user.class, chain,
|
||||
Cnd.where(Sys_user::getId, "=", changeRecord.getUserId()));
|
||||
} else {
|
||||
dao().update(Sys_user.class, Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
|
||||
.add("aidFundMemberQuitTime", new Date()),
|
||||
Chain chain = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
|
||||
.add("aidFundMemberQuitTime", new Date());
|
||||
if (StrUtil.isNotBlank(aidFundMemberUserType)) {
|
||||
chain.add("aidFundMemberUserType", aidFundMemberUserType);
|
||||
}
|
||||
dao().update(Sys_user.class, chain,
|
||||
Cnd.where(Sys_user::getId, "=", changeRecord.getUserId()));
|
||||
}
|
||||
}
|
||||
|
||||
+154
@@ -2,18 +2,28 @@ package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.mode.AidFundMemberMode;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberChangeRecord;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberHistory;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.model.AidFundMemberPay;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.service.AidFundMemberService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
@@ -121,6 +131,62 @@ public class AidFundMemberServiceImpl extends BaseServiceImpl implements AidFund
|
||||
return (year + 1 - beforeYear) * money + (year - beforeYear) * money * 0.1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一封装基金会员台账列表查询口径,分页查询和导出都复用这里,避免“所见”和“所得”不一致。
|
||||
*
|
||||
* @param pageForm 页面查询条件,包含会员类型、工会、单位、关键字、排序及未缴费筛选参数
|
||||
* @return 基金会员台账查询SQL
|
||||
*/
|
||||
@Override
|
||||
public Sql getManageSql(AidFundPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
id,
|
||||
loginname,
|
||||
username,
|
||||
sex,
|
||||
arrivalAtSchoolDate,
|
||||
unitName,
|
||||
unionName,
|
||||
aidFundMemberUserType,
|
||||
aidFundMemberJoinTime
|
||||
FROM
|
||||
vw_user
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
// 非系统管理员按现有页面权限口径控制数据范围,确保导出结果与列表展示一致。
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
|
||||
if (AuthUtil.hasRole(RoleConstant.RETIREMENT_WORKPLACE.name())) {
|
||||
cnd.and(Sys_user::getAidFundMemberUserType, "=", "离退休人员");
|
||||
} else {
|
||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
}
|
||||
|
||||
if (pageForm.getNotPayedCurrentYear()) {
|
||||
cnd.and("id", "in", Sqls.create("SELECT userid FROM `aid_fund_member_pay` where `year` = YEAR(CURDATE()) and isPayed = 0"));
|
||||
}
|
||||
cnd.andEX(Sys_user::getAidFundMemberUserType, "=", pageForm.getAidFundMemberUserType());
|
||||
cnd.andEX(View_user::getUnionId, "=", pageForm.getUnionId());
|
||||
cnd.andEX(View_user::getUnitId, "=", pageForm.getUnitId());
|
||||
cnd.and(Sys_user::getAidFundMember, "=", AidFundMemberMode.NORMAL.getCode());
|
||||
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orLike("loginname", pageForm.getSearchKeyword());
|
||||
seg.orLike("username", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.desc("unitCode");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NutMap> findChangeRecordList(String userId) {
|
||||
Sql sql = Sqls.create("""
|
||||
@@ -168,5 +234,93 @@ public class AidFundMemberServiceImpl extends BaseServiceImpl implements AidFund
|
||||
return listMap(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理端批量变更基金会员状态时,统一同步用户表并记录“系统管理员操作”的变更记录。
|
||||
*
|
||||
* @param ids 需要变更的用户ID数组,来自台账页面勾选结果
|
||||
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void doBatchChangeTypeByAdmin(String[] ids, String changeType) {
|
||||
List<Sys_user> sysUserList = dao().query(Sys_user.class, Cnd.where("id", "in", ids));
|
||||
List<AidFundMemberChangeRecord> recordArrayList = new ArrayList<>();
|
||||
for (String id : ids) {
|
||||
Sys_user user = sysUserList.stream().filter(sysUser -> sysUser.getId().equals(id)).findFirst().orElse(null);
|
||||
if (user == null) {
|
||||
continue;
|
||||
}
|
||||
recordArrayList.add(buildAdminChangeRecord(user, changeType));
|
||||
}
|
||||
updateUserChangeType(ids, changeType);
|
||||
if (!recordArrayList.isEmpty()) {
|
||||
dao().insert(recordArrayList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理端单个“变更”操作时,统一同步用户表并记录“系统管理员操作”的变更记录。
|
||||
*
|
||||
* @param userId 被变更的用户ID
|
||||
* @param changeType 变更类型字典值,对应 AIDFUND_MEMBER_CHANGE_TYPE
|
||||
*/
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void doEditChangeTypeByAdmin(String userId, String changeType) {
|
||||
Sys_user user = dao().fetch(Sys_user.class, userId);
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
dao().insert(buildAdminChangeRecord(user, changeType));
|
||||
updateUserChangeType(new String[]{userId}, changeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理端变更落记录时,需要明确标记记录来源,避免被“我的申请”误识别为本人发起。
|
||||
*
|
||||
* @param user 当前被操作的用户
|
||||
* @param changeType 变更类型字典值
|
||||
* @return 已补齐管理员操作标记和会员类型快照的变更记录
|
||||
*/
|
||||
private AidFundMemberChangeRecord buildAdminChangeRecord(Sys_user user, String changeType) {
|
||||
return new AidFundMemberChangeRecord()
|
||||
.setUserId(user.getId())
|
||||
.setAidFundMemberUserType(resolveChangeRecordMemberType(user, changeType))
|
||||
.setApplyTime(new Date())
|
||||
.setChangeType(changeType)
|
||||
.setAdminOperate(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退休变更需要把记录中的会员类型同步成退休类型,其余情况沿用当前用户档案中的会员类型。
|
||||
*
|
||||
* @param user 当前被操作的用户
|
||||
* @param changeType 变更类型字典值
|
||||
* @return 变更记录中应保存的基金会员类型
|
||||
*/
|
||||
private String resolveChangeRecordMemberType(Sys_user user, String changeType) {
|
||||
if (ObjectUtil.equals(changeType, "AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
|
||||
return "离退休人员";
|
||||
}
|
||||
return user.getAidFundMemberUserType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理端“变更”与“批量变更”共用同一套用户表更新规则,确保页面操作口径一致。
|
||||
*
|
||||
* @param ids 需要更新的用户ID数组
|
||||
* @param changeType 变更类型字典值
|
||||
*/
|
||||
private void updateUserChangeType(String[] ids, String changeType) {
|
||||
Chain add;
|
||||
if (ObjectUtil.equals(changeType, "AIDFUND_MEMBER_CHANGE_TYPE_EIGTH")) {
|
||||
add = Chain.make("aidFundMemberUserType", "离退休人员");
|
||||
} else {
|
||||
add = Chain.make("aidFundMember", AidFundMemberMode.NONE.getCode())
|
||||
.add("aidFundMemberQuitTime", new Date());
|
||||
}
|
||||
dao().update(Sys_user.class, add, Cnd.where("id", "in", ids));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+23
@@ -73,6 +73,29 @@ public class MedicalCalculateMoneyController {
|
||||
return Result.success(applyData);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("更新医疗互助补助金额明细")
|
||||
@SaCheckPermission("medicalMutualAid.medical.calculateMoney")
|
||||
public Object setGrantsOrUnionInto(String keys, double value) {
|
||||
//获取申请最新年份
|
||||
Sql yearSql = Sqls.create("SELECT MAX(YEAR(applyTime)) AS currentYear FROM medical_apply");
|
||||
yearSql.setCallback(Sqls.callback.longs());
|
||||
medicalCalculateMoneyService.execute(yearSql);
|
||||
long year = yearSql.getLong();
|
||||
MedicalMoneyDetail moneyDetail = medicalCalculateMoneyService.dao().fetch(MedicalMoneyDetail.class, Cnd.where("year", "=", year));
|
||||
if (Lang.isEmpty(moneyDetail)) {
|
||||
moneyDetail = new MedicalMoneyDetail();
|
||||
moneyDetail.setYear((int) year);
|
||||
}
|
||||
if (keys.equals("grants")) {
|
||||
moneyDetail.setSchoolGrants(new BigDecimal(value));
|
||||
} else if (keys.equals("into")) {
|
||||
moneyDetail.setUnionInto(new BigDecimal(value));
|
||||
}
|
||||
medicalCalculateMoneyService.insertOrUpdate(moneyDetail);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("按比例修改补助金额")
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service.MedicalDashBoardService;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardCategoryStatVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardOverviewVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionResultVO;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助数据看板
|
||||
*/
|
||||
@IocBean
|
||||
@At("/platform/medicalMutualAid/medical/dashboard")
|
||||
@Api("医疗互助数据看板")
|
||||
@Ok("json:full")
|
||||
public class MedicalDashBoardController {
|
||||
|
||||
@Inject
|
||||
private MedicalDashBoardService medicalDashBoardService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/staffbenefit/medicalMutualAid/medical/dashboard/index.html")
|
||||
@SaCheckPermission("medicalMutualAid.medical.dashboard")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询医疗互助总览统计。
|
||||
* 返回值字段说明:
|
||||
* 1. fundMemberCount:当前基金会员总数
|
||||
* 2. currentYearApplyCount:本年度已办结申请数
|
||||
* 3. majorDiseaseApplyCount:重疾已办结申请数
|
||||
* 4. commonDiseaseApplyCount:普通疾病已办结申请数
|
||||
* 5. totalSubsidyMoney:补助金额合计
|
||||
* 6. totalLoveSubsidyMoney:爱心基金金额合计
|
||||
*
|
||||
* @return 医疗互助总览统计 VO
|
||||
*/
|
||||
@At
|
||||
@ApiOperation("查询医疗互助总览统计")
|
||||
@SaCheckPermission("medicalMutualAid.medical.dashboard")
|
||||
public Result overview() {
|
||||
MedicalDashboardOverviewVO vo = medicalDashBoardService.getOverview();
|
||||
return Result.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按工会统计医疗互助已办结申请数据。
|
||||
* 返回值字段说明:
|
||||
* 1. tableData:表格使用的工会统计列表
|
||||
* 2. 列表元素中 applyCount 为已办结申请数,subsidyMoney 为补助金额合计
|
||||
*
|
||||
* @return 工会统计结果 VO
|
||||
*/
|
||||
@At
|
||||
@ApiOperation("按工会统计医疗互助数据")
|
||||
@SaCheckPermission("medicalMutualAid.medical.dashboard")
|
||||
public Result unionStat() {
|
||||
MedicalDashboardUnionResultVO vo = medicalDashBoardService.getUnionStat();
|
||||
return Result.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按在职状态统计医疗互助已办结申请数据。
|
||||
* 返回列表字段说明:
|
||||
* 1. code:在职状态编码
|
||||
* 2. name:在职状态名称
|
||||
* 3. applyCount:该状态下已办结申请数
|
||||
* 4. subsidyMoney:该状态下补助金额合计
|
||||
*
|
||||
* @return 在职状态统计 VO 列表
|
||||
*/
|
||||
@At
|
||||
@ApiOperation("按在职状态统计医疗互助数据")
|
||||
@SaCheckPermission("medicalMutualAid.medical.dashboard")
|
||||
public Result userStateStat() {
|
||||
List<MedicalDashboardCategoryStatVO> list = medicalDashBoardService.getUserStateStat();
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按人员类型统计医疗互助已办结申请数据。
|
||||
* 返回列表字段说明:
|
||||
* 1. code:人员类型编码
|
||||
* 2. name:人员类型名称
|
||||
* 3. applyCount:该类型下已办结申请数
|
||||
* 4. subsidyMoney:该类型下补助金额合计
|
||||
*
|
||||
* @return 人员类型统计 VO 列表
|
||||
*/
|
||||
@At
|
||||
@ApiOperation("按人员类型统计医疗互助数据")
|
||||
@SaCheckPermission("medicalMutualAid.medical.dashboard")
|
||||
public Result personTypeStat() {
|
||||
List<MedicalDashboardCategoryStatVO> list = medicalDashBoardService.getPersonTypeStat();
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按疾病类型统计医疗互助已办结申请数据。
|
||||
* 返回列表字段说明:
|
||||
* 1. code:疾病类型 ID
|
||||
* 2. name:疾病名称
|
||||
* 3. applyCount:该疾病下已办结申请数
|
||||
* 4. subsidyMoney:该疾病下补助金额合计
|
||||
*
|
||||
* @return 疾病类型统计 VO 列表
|
||||
*/
|
||||
@At
|
||||
@ApiOperation("按疾病类型统计医疗互助数据")
|
||||
@SaCheckPermission("medicalMutualAid.medical.dashboard")
|
||||
public Result diseaseTypeStat() {
|
||||
List<MedicalDashboardCategoryStatVO> list = medicalDashBoardService.getDiseaseTypeStat();
|
||||
return Result.success(list);
|
||||
}
|
||||
}
|
||||
+1
@@ -55,6 +55,7 @@ public class MedicalUnionAuditController {
|
||||
@SaCheckPermission("medicalMutualAid.medical.unionAudit")
|
||||
public Result pageData(MedicalPageForm pageForm) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
|
||||
cnd.and("t.taskName", "=", "a9bbf69c-5edf-4161-a364-47996d212472");
|
||||
Sql sql = medicalAuditService.getAuditSql(pageForm, cnd);
|
||||
sql.setCondition(cnd);
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.model.MedicalApply;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardCategoryStatVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardOverviewVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionResultVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助数据看板 service
|
||||
*/
|
||||
public interface MedicalDashBoardService extends BaseService<MedicalApply> {
|
||||
|
||||
/**
|
||||
* 查询医疗互助数据看板总览数据。
|
||||
* 返回值包含:
|
||||
* 1. 已办结申请总数
|
||||
* 2. 本年度已办结申请数
|
||||
* 3. 重疾/普通疾病申请数
|
||||
* 4. 补助金额与爱心基金金额汇总
|
||||
*
|
||||
* @return 医疗互助总览统计 VO
|
||||
*/
|
||||
MedicalDashboardOverviewVO getOverview();
|
||||
|
||||
/**
|
||||
* 按工会统计医疗互助已办结申请数据。
|
||||
* 返回值中的 chartData 与 tableData 当前来源相同,
|
||||
* 便于前端图表和表格按既有字段直接取值。
|
||||
*
|
||||
* @return 工会统计结果 VO
|
||||
*/
|
||||
MedicalDashboardUnionResultVO getUnionStat();
|
||||
|
||||
/**
|
||||
* 按人员在职状态统计医疗互助已办结申请数据。
|
||||
* code 为在职状态编码,name 为字典名称。
|
||||
*
|
||||
* @return 在职状态统计列表
|
||||
*/
|
||||
List<MedicalDashboardCategoryStatVO> getUserStateStat();
|
||||
|
||||
/**
|
||||
* 按人员类型统计医疗互助已办结申请数据。
|
||||
* code 为人员类型编码,name 为字典名称。
|
||||
*
|
||||
* @return 人员类型统计列表
|
||||
*/
|
||||
List<MedicalDashboardCategoryStatVO> getPersonTypeStat();
|
||||
|
||||
/**
|
||||
* 按疾病类型统计医疗互助已办结申请数据。
|
||||
* code 为疾病类型 ID,name 为疾病名称。
|
||||
*
|
||||
* @return 疾病类型统计列表
|
||||
*/
|
||||
List<MedicalDashboardCategoryStatVO> getDiseaseTypeStat();
|
||||
}
|
||||
+2
-1
@@ -186,6 +186,7 @@ public class MedicalApplyServiceImpl extends BaseServiceImpl<MedicalApply> imple
|
||||
|
||||
// 查询申请成功的记录
|
||||
List<NutMap> applyRecords = getApplyRecord(allUserIds);
|
||||
applyRecords.removeIf(item -> applyId.equals(item.getString("id")));
|
||||
|
||||
//是否首次申请 爱心互助基金 重大疾病
|
||||
boolean isFirstApply = applyRecords.stream().filter(v -> v.getBoolean("isMajorDiseases")).toList().isEmpty();
|
||||
@@ -230,7 +231,7 @@ public class MedicalApplyServiceImpl extends BaseServiceImpl<MedicalApply> imple
|
||||
Boolean isBeyondAllMoney = allMoney.compareTo(medicalSetting.getPreviousYearMaxMoney()) > 0;
|
||||
|
||||
|
||||
Sys_user user = dao().fetch(Sys_user.class, SecurityUtil.getUserId());
|
||||
Sys_user user = dao().fetch(Sys_user.class, applyInfo.getString("userId"));
|
||||
|
||||
boolean fullTenYears = DateUtil.thisYear() - Integer.parseInt(user.getAidFundDeductTime()) >= 10;
|
||||
boolean fullFifYears = DateUtil.thisYear() - Integer.parseInt(user.getAidFundDeductTime()) >= 15;
|
||||
|
||||
+3
-1
@@ -72,7 +72,9 @@ public class MedicalAuditServiceImpl extends BaseServiceImpl<MedicalApply> imple
|
||||
seg.orLike("us.username", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
if(!SecurityUtil.getUserLoginname().equals("superadmin")){
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
}
|
||||
cnd.andEX("year(info.applyTime)", "=", pageForm.getYear());
|
||||
cnd.andEX("info.diseaseId", "=", pageForm.getDiseaseId());
|
||||
cnd.andEX("us.unionid", "=", pageForm.getUnionId());
|
||||
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service.impl;
|
||||
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.model.MedicalApply;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.service.MedicalDashBoardService;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardCategoryStatVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardOverviewVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionResultVO;
|
||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo.MedicalDashboardUnionStatVO;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助数据看板 service 实现
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class MedicalDashBoardServiceImpl extends BaseServiceImpl<MedicalApply> implements MedicalDashBoardService {
|
||||
|
||||
public MedicalDashBoardServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MedicalDashboardOverviewVO getOverview() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
(SELECT COUNT(1) FROM sys_user WHERE aidFundMember = 1) AS fundMemberCount,
|
||||
COUNT(DISTINCT CASE WHEN YEAR(info.applyTime) = YEAR(NOW()) THEN info.id END) AS currentYearApplyCount,
|
||||
COUNT(DISTINCT CASE WHEN type.isMajorDiseases = 1 THEN info.id END) AS majorDiseaseApplyCount,
|
||||
COUNT(DISTINCT CASE WHEN type.isMajorDiseases = 0 THEN info.id END) AS commonDiseaseApplyCount,
|
||||
COALESCE(SUM(info.subsidyMoney), 0) AS totalSubsidyMoney,
|
||||
COALESCE(SUM(info.loveSubsidyMoney), 0) AS totalLoveSubsidyMoney
|
||||
FROM
|
||||
medical_apply info
|
||||
INNER JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
LEFT JOIN medical_disease_type type ON type.id = info.diseaseId
|
||||
WHERE
|
||||
ins.state = @state
|
||||
""");
|
||||
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
NutMap data = fetchOne(sql);
|
||||
|
||||
MedicalDashboardOverviewVO vo = new MedicalDashboardOverviewVO();
|
||||
vo.setFundMemberCount(data.getLong("fundMemberCount", 0L));
|
||||
vo.setCurrentYearApplyCount(data.getLong("currentYearApplyCount", 0L));
|
||||
vo.setMajorDiseaseApplyCount(data.getLong("majorDiseaseApplyCount", 0L));
|
||||
vo.setCommonDiseaseApplyCount(data.getLong("commonDiseaseApplyCount", 0L));
|
||||
vo.setTotalSubsidyMoney(getBigDecimalValue(data, "totalSubsidyMoney"));
|
||||
vo.setTotalLoveSubsidyMoney(getBigDecimalValue(data, "totalLoveSubsidyMoney"));
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MedicalDashboardUnionResultVO getUnionStat() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
un.id AS unionId,
|
||||
un.`name` AS unionName,
|
||||
un.unionCode AS unionCode,
|
||||
COUNT(applyInfo.id) AS applyCount,
|
||||
COALESCE(SUM(applyInfo.subsidyMoney), 0) AS subsidyMoney
|
||||
FROM
|
||||
sys_union un
|
||||
LEFT JOIN vw_user us ON us.unionId = un.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
info.id,
|
||||
info.userId,
|
||||
info.subsidyMoney
|
||||
FROM
|
||||
medical_apply info
|
||||
INNER JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
WHERE
|
||||
ins.state = @state
|
||||
) applyInfo ON applyInfo.userId = us.id
|
||||
GROUP BY
|
||||
un.id, un.`name`, un.unionCode
|
||||
ORDER BY
|
||||
un.unionCode
|
||||
""");
|
||||
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
List<MedicalDashboardUnionStatVO> list = toUnionStatList(listMap(sql));
|
||||
|
||||
MedicalDashboardUnionResultVO resultVO = new MedicalDashboardUnionResultVO();
|
||||
resultVO.setTableData(new ArrayList<>(list));
|
||||
return resultVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MedicalDashboardCategoryStatVO> getUserStateStat() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
dict.`code` AS code,
|
||||
dict.`name` AS name,
|
||||
COUNT(info.id) AS applyCount,
|
||||
COALESCE(SUM(info.subsidyMoney), 0) AS subsidyMoney
|
||||
FROM
|
||||
sys_dict dict
|
||||
LEFT JOIN sys_dict parent ON parent.id = dict.parentId
|
||||
LEFT JOIN vw_user us ON us.userState = dict.`code`
|
||||
LEFT JOIN medical_apply info ON info.userId = us.id
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id AND ins.state = @state
|
||||
WHERE
|
||||
parent.`code` = 'USER_STATE'
|
||||
AND ins.id IS NOT NULL
|
||||
GROUP BY
|
||||
dict.`code`, dict.`name`, dict.location
|
||||
ORDER BY
|
||||
dict.location
|
||||
""");
|
||||
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
return toCategoryStatList(listMap(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MedicalDashboardCategoryStatVO> getPersonTypeStat() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
dict.`code` AS code,
|
||||
dict.`name` AS name,
|
||||
COUNT(info.id) AS applyCount,
|
||||
COALESCE(SUM(info.subsidyMoney), 0) AS subsidyMoney
|
||||
FROM
|
||||
sys_dict dict
|
||||
LEFT JOIN sys_dict parent ON parent.id = dict.parentId
|
||||
LEFT JOIN vw_user us ON us.personType = dict.`code`
|
||||
LEFT JOIN medical_apply info ON info.userId = us.id
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id AND ins.state = @state
|
||||
WHERE
|
||||
parent.`code` = 'USER_PERSON_TYPE'
|
||||
AND ins.id IS NOT NULL
|
||||
GROUP BY
|
||||
dict.`code`, dict.`name`, dict.location
|
||||
ORDER BY
|
||||
dict.location
|
||||
""");
|
||||
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
return toCategoryStatList(listMap(sql));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MedicalDashboardCategoryStatVO> getDiseaseTypeStat() {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
type.id AS code,
|
||||
type.diseaseName AS name,
|
||||
COUNT(info.id) AS applyCount,
|
||||
COALESCE(SUM(info.subsidyMoney), 0) AS subsidyMoney
|
||||
FROM
|
||||
medical_disease_type type
|
||||
LEFT JOIN medical_apply info ON info.diseaseId = type.id
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id AND ins.state = @state
|
||||
WHERE
|
||||
ins.id IS NOT NULL
|
||||
GROUP BY
|
||||
type.id, type.diseaseName, type.diseaseCode
|
||||
ORDER BY
|
||||
type.diseaseCode
|
||||
""");
|
||||
sql.setParam("state", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
return toCategoryStatList(listMap(sql));
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行单行统计 SQL。
|
||||
* 该方法用于处理总览类统计,返回结果仅一行。
|
||||
*
|
||||
* @param sql 已设置好查询参数的 SQL 对象
|
||||
* @return 单行统计数据,字段不存在时返回空 NutMap,避免上层空指针
|
||||
*/
|
||||
private NutMap fetchOne(Sql sql) {
|
||||
sql.setCallback(Sqls.callback.map());
|
||||
dao().execute(sql);
|
||||
Object result = sql.getResult();
|
||||
if (result instanceof NutMap) {
|
||||
return (NutMap) result;
|
||||
}
|
||||
return NutMap.NEW();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将工会统计查询结果转换为 VO。
|
||||
*
|
||||
* @param dataList SQL 查询返回的 map 列表,字段需包含 unionId、unionName、unionCode、applyCount、subsidyMoney
|
||||
* @return 工会统计 VO 列表
|
||||
*/
|
||||
private List<MedicalDashboardUnionStatVO> toUnionStatList(List<NutMap> dataList) {
|
||||
List<MedicalDashboardUnionStatVO> list = new ArrayList<>();
|
||||
for (NutMap data : dataList) {
|
||||
MedicalDashboardUnionStatVO vo = new MedicalDashboardUnionStatVO();
|
||||
vo.setUnionId(data.getString("unionId"));
|
||||
vo.setUnionName(data.getString("unionName"));
|
||||
vo.setUnionCode(data.getString("unionCode"));
|
||||
vo.setApplyCount(data.getLong("applyCount", 0L));
|
||||
vo.setSubsidyMoney(getBigDecimalValue(data, "subsidyMoney"));
|
||||
list.add(vo);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将通用分类统计查询结果转换为 VO。
|
||||
*
|
||||
* @param dataList SQL 查询返回的 map 列表,字段需包含 code、name、applyCount、subsidyMoney
|
||||
* @return 分类统计 VO 列表
|
||||
*/
|
||||
private List<MedicalDashboardCategoryStatVO> toCategoryStatList(List<NutMap> dataList) {
|
||||
List<MedicalDashboardCategoryStatVO> list = new ArrayList<>();
|
||||
for (NutMap data : dataList) {
|
||||
MedicalDashboardCategoryStatVO vo = new MedicalDashboardCategoryStatVO();
|
||||
vo.setCode(data.getString("code"));
|
||||
vo.setName(data.getString("name"));
|
||||
vo.setApplyCount(data.getLong("applyCount", 0L));
|
||||
vo.setSubsidyMoney(getBigDecimalValue(data, "subsidyMoney"));
|
||||
list.add(vo);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NutMap 中安全读取金额字段。
|
||||
* SQL 聚合查询返回的金额字段有时会是 BigDecimal、Double、Long 或字符串,
|
||||
* 因此这里统一做一次转换,避免 controller/service 层重复判空和类型判断。
|
||||
*
|
||||
* @param data NutMap 查询结果对象
|
||||
* @param key 金额字段名
|
||||
* @return 对应金额,字段为空时返回 0
|
||||
*/
|
||||
private BigDecimal getBigDecimalValue(NutMap data, String key) {
|
||||
Object value = data.get(key);
|
||||
if (value == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
return new BigDecimal(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助分类统计返回值
|
||||
*/
|
||||
@Data
|
||||
public class MedicalDashboardCategoryStatVO {
|
||||
|
||||
/**
|
||||
* 分类编码。
|
||||
* 不同接口场景下可能表示在职状态编码、人员类型编码、疾病ID 等。
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 分类名称,用于前端直接展示图表/表格标题。
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 当前分类下的已办结申请数
|
||||
*/
|
||||
private Long applyCount;
|
||||
|
||||
/**
|
||||
* 当前分类下的已办结补助金额合计
|
||||
*/
|
||||
private BigDecimal subsidyMoney;
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助数据看板总览统计返回值
|
||||
*/
|
||||
@Data
|
||||
public class MedicalDashboardOverviewVO {
|
||||
|
||||
/**
|
||||
* 当前基金会员总数
|
||||
*/
|
||||
private Long fundMemberCount;
|
||||
|
||||
/**
|
||||
* 本年度已办结申请数
|
||||
*/
|
||||
private Long currentYearApplyCount;
|
||||
|
||||
/**
|
||||
* 已办结重疾申请数
|
||||
*/
|
||||
private Long majorDiseaseApplyCount;
|
||||
|
||||
/**
|
||||
* 已办结普通疾病申请数
|
||||
*/
|
||||
private Long commonDiseaseApplyCount;
|
||||
|
||||
/**
|
||||
* 已办结补助金额合计
|
||||
*/
|
||||
private BigDecimal totalSubsidyMoney;
|
||||
|
||||
/**
|
||||
* 已办结爱心基金金额合计
|
||||
*/
|
||||
private BigDecimal totalLoveSubsidyMoney;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助按工会统计返回值
|
||||
*/
|
||||
@Data
|
||||
public class MedicalDashboardUnionResultVO {
|
||||
|
||||
/**
|
||||
* 表格数据。
|
||||
* 当前页面仅保留工会统计表格,因此只返回表格所需列表。
|
||||
*/
|
||||
private List<MedicalDashboardUnionStatVO> tableData;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.budwk.app.zhgh.staffbenefit.medicalMutualAid.medical.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author Codex
|
||||
* @description 医疗互助按工会统计返回值
|
||||
*/
|
||||
@Data
|
||||
public class MedicalDashboardUnionStatVO {
|
||||
|
||||
/**
|
||||
* 工会ID
|
||||
*/
|
||||
private String unionId;
|
||||
|
||||
/**
|
||||
* 工会名称
|
||||
*/
|
||||
private String unionName;
|
||||
|
||||
/**
|
||||
* 工会编码
|
||||
*/
|
||||
private String unionCode;
|
||||
|
||||
/**
|
||||
* 已办结申请数
|
||||
*/
|
||||
private Long applyCount;
|
||||
|
||||
/**
|
||||
* 已办结补助金额合计
|
||||
*/
|
||||
private BigDecimal subsidyMoney;
|
||||
}
|
||||
@@ -82,6 +82,7 @@ layout("/layouts/platform.html"){
|
||||
:expand-on-click-node="false"
|
||||
:props="{ children: 'children', label: 'name' }"
|
||||
node-key="id"
|
||||
:default-expanded-keys="defaultExpandedKeys"
|
||||
@node-click="treeNodeClick"
|
||||
:filter-node-method="filterNode"
|
||||
highlight-current
|
||||
@@ -156,6 +157,7 @@ layout("/layouts/platform.html"){
|
||||
filterText: null,
|
||||
currentTreeNode: null,
|
||||
currentTreeData: null,
|
||||
defaultExpandedKeys: [],
|
||||
treeData: []
|
||||
}
|
||||
},
|
||||
@@ -175,6 +177,7 @@ layout("/layouts/platform.html"){
|
||||
this.treeData = res.data
|
||||
if (this.treeData) {
|
||||
this.currentTreeData = this.treeData[0]
|
||||
this.defaultExpandedKeys = this.treeData.length > 0 ? [this.treeData[0].id] : []
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
@@ -456,6 +456,8 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
|
||||
complete_result></file-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="40">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="其他" prop="otherFiles">
|
||||
<file-upload :value.sync="formData.otherFiles" accept=".jpg,.jpeg,.png"
|
||||
|
||||
@@ -107,7 +107,7 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
|
||||
:disabled="row.projectTypeCode==50004">
|
||||
编辑
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
<el-dropdown-item u
|
||||
v-if="row.canRevoke" :command="{type:'Revoke',row}">
|
||||
撤回
|
||||
</el-dropdown-item>
|
||||
|
||||
@@ -80,7 +80,7 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
openAnnualLimit() {
|
||||
window.location.href = '/platform/trainSignUp/annualLimit'
|
||||
commonUtil.pjaxPush('/platform/trainSignUp/annualLimit')
|
||||
},
|
||||
openAdd() {
|
||||
this.$refs.guava.edit(() => {
|
||||
|
||||
@@ -22,8 +22,9 @@ layout("/layouts/platform.html"){
|
||||
width: 80px;
|
||||
}
|
||||
/* 财务明细表格高度 */
|
||||
.finance-table {
|
||||
.finance-table >>> .el-table__body-wrapper {
|
||||
max-height: 600px;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
/* 统计表格高度 */
|
||||
.stat-table {
|
||||
@@ -570,6 +571,11 @@ layout("/layouts/platform.html"){
|
||||
{{formatNumber(row.support)}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="其他收入(元)" prop="otherIncome">
|
||||
<template slot-scope="{row}">
|
||||
{{formatNumber(row.otherIncome)}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="年度总支出(元)" prop="totalExpend">
|
||||
<template slot-scope="{row}">
|
||||
{{formatNumber(row.totalExpend)}}
|
||||
@@ -661,7 +667,7 @@ layout("/layouts/platform.html"){
|
||||
// 财务数据
|
||||
financeData: {
|
||||
incomeDetailed: [], // 收支明细
|
||||
incomeCensus: [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, totalExpend: 0, surplus: 0 }] // 收支统计
|
||||
incomeCensus: [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, otherIncome: 0, totalExpend: 0, surplus: 0 }] // 收支统计
|
||||
},
|
||||
|
||||
// 表单校验规则
|
||||
@@ -679,12 +685,13 @@ layout("/layouts/platform.html"){
|
||||
{ label: "校工会拨款", value: "校工会拨款" },
|
||||
{ label: "年度结余", value: "年度结余" },
|
||||
{ label: "社会赞助", value: "社会赞助" },
|
||||
{ label: "其他收入", value: "其他收入" },
|
||||
{ label: "支出", value: "支出" }
|
||||
];
|
||||
},
|
||||
// 收入类型集合
|
||||
INCOME_TYPES() {
|
||||
return ["会费收入", "校工会拨款", "社会赞助", "其它"];
|
||||
return ["会费收入", "校工会拨款", "社会赞助", "其他收入"];
|
||||
},
|
||||
// 支出类型集合
|
||||
EXPEND_TYPES() {
|
||||
@@ -725,7 +732,13 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
// 计算年度结余
|
||||
calcSurplus(row) {
|
||||
const total = (row.lastYearSurplus || 0) + (row.income || 0) + (row.allocate || 0) + (row.support || 0) - (row.totalExpend || 0);
|
||||
const lastYearSurplusVal = this.lastYearSurplus !== null ? this.lastYearSurplus : (row.lastYearSurplus || 0);
|
||||
const income = row.income || 0;
|
||||
const allocate = row.allocate || 0;
|
||||
const support = row.support || 0;
|
||||
const otherIncome = row.otherIncome || 0;
|
||||
const totalExpend = row.totalExpend || 0;
|
||||
const total = Number(lastYearSurplusVal) + Number(income) + Number(allocate) + Number(support) + Number(otherIncome) - Number(totalExpend);
|
||||
return this.formatNumber(total);
|
||||
},
|
||||
// 表单校验通用方法
|
||||
@@ -782,14 +795,44 @@ layout("/layouts/platform.html"){
|
||||
data.year = data.year?.toString() || new Date().getFullYear() + "";
|
||||
this.formData = data;
|
||||
// 初始化财务数据
|
||||
this.financeData.incomeCensus = data.incomeCensus || [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, totalExpend: 0, surplus: 0 }];
|
||||
this.financeData.incomeDetailed = data.detailedList || [];
|
||||
this.financeData.incomeCensus = data.incomeCensus || [{ lastYearSurplus: 0, income: 0, allocate: 0, support: 0, otherIncome: 0, totalExpend: 0, surplus: 0 }];
|
||||
|
||||
// 从统计数据中提取去年年度结余
|
||||
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
|
||||
this.lastYearSurplus = this.financeData.incomeCensus[0].lastYearSurplus || 0;
|
||||
}
|
||||
|
||||
if (data.detailedList && data.detailedList.length > 0) {
|
||||
this.financeData.incomeDetailed = this.sortIncomeDetailed(data.detailedList);
|
||||
} else {
|
||||
this.financeData.incomeDetailed = [];
|
||||
}
|
||||
// 初始化成员数据
|
||||
await this.fetchClubUserNum(data.clubId);
|
||||
await this.fetchMemberList(data.clubId);
|
||||
// 检查是否已登记
|
||||
await this.checkIsRegistered();
|
||||
},
|
||||
sortIncomeDetailed(list) {
|
||||
const defaultContents = [new Date().getFullYear() - 1 + "年度结余", "会费收入", "校工会拨款"];
|
||||
const defaultItems = [];
|
||||
const customItems = [];
|
||||
|
||||
list.forEach(item => {
|
||||
if (item.content && defaultContents.includes(item.content)) {
|
||||
defaultItems.push(item);
|
||||
} else {
|
||||
customItems.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
// 按默认顺序排列前三条
|
||||
const sortedDefaults = defaultContents.map(content =>
|
||||
defaultItems.find(item => item.content === content)
|
||||
).filter(item => item !== undefined);
|
||||
|
||||
return [...sortedDefaults, ...customItems];
|
||||
},
|
||||
// 获取社团成员数量
|
||||
async fetchClubUserNum(clubId) {
|
||||
const resp = await this.$axios.post("/platform/club/examine/apply/getClubUserNum", {
|
||||
@@ -830,6 +873,11 @@ layout("/layouts/platform.html"){
|
||||
year: this.formData.year
|
||||
});
|
||||
this.lastYearSurplus = resp.data || 0;
|
||||
|
||||
// 同步更新到统计表格
|
||||
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
|
||||
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
|
||||
}
|
||||
},
|
||||
// 获取上年度社团数据
|
||||
async fetchLastClubData() {
|
||||
@@ -897,22 +945,27 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
// 删除财务明细项
|
||||
deleteFinanceItem(row, index) {
|
||||
// 扣除对应统计金额
|
||||
this.financeData.incomeCensus[0].income = (this.financeData.incomeCensus[0].income || 0) - (Number(row.income) || 0);
|
||||
this.financeData.incomeCensus[0].support = (this.financeData.incomeCensus[0].support || 0) - (Number(row.income) || 0);
|
||||
this.financeData.incomeCensus[0].totalExpend = (this.financeData.incomeCensus[0].totalExpend || 0) - (Number(row.expend) || 0);
|
||||
// 根据收支类型扣除对应统计金额
|
||||
const income = Number(row.income) || 0;
|
||||
const expend = Number(row.expend) || 0;
|
||||
|
||||
if (row.incomeType === "会费收入") {
|
||||
this.financeData.incomeCensus[0].income = (this.financeData.incomeCensus[0].income || 0) - income;
|
||||
} else if (row.incomeType === "校工会拨款") {
|
||||
this.financeData.incomeCensus[0].allocate = (this.financeData.incomeCensus[0].allocate || 0) - income;
|
||||
} else if (row.incomeType === "社会赞助") {
|
||||
this.financeData.incomeCensus[0].support = (this.financeData.incomeCensus[0].support || 0) - income;
|
||||
} else if (row.incomeType === "其他收入") {
|
||||
this.financeData.incomeCensus[0].otherIncome = (this.financeData.incomeCensus[0].otherIncome || 0) - income;
|
||||
} else if (row.incomeType === "支出") {
|
||||
this.financeData.incomeCensus[0].totalExpend = (this.financeData.incomeCensus[0].totalExpend || 0) - expend;
|
||||
}
|
||||
|
||||
// 删除明细项
|
||||
this.financeData.incomeDetailed.splice(index, 1);
|
||||
// 清空统计数据
|
||||
if (this.financeData.incomeDetailed.length === 0) {
|
||||
this.financeData.incomeCensus = [{
|
||||
income: this.dueIncome,
|
||||
allocate: this.unionAllocate,
|
||||
support: 0,
|
||||
totalExpend: 0,
|
||||
surplus: 0
|
||||
}];
|
||||
}
|
||||
|
||||
// 重新计算统计数据,确保准确性
|
||||
this.recalculateCensus();
|
||||
},
|
||||
// 收支类型变化处理
|
||||
handleIncomeTypeChange(row) {
|
||||
@@ -924,6 +977,10 @@ layout("/layouts/platform.html"){
|
||||
this.$set(row, "expend", null);
|
||||
this.calcSupportTotal();
|
||||
break;
|
||||
case "其他收入":
|
||||
this.$set(row, "expend", null);
|
||||
this.calcOtherIncomeTotal();
|
||||
break;
|
||||
case "支出":
|
||||
this.$set(row, "income", null);
|
||||
this.calcExpendTotal();
|
||||
@@ -933,27 +990,33 @@ layout("/layouts/platform.html"){
|
||||
// 年初余额输入处理
|
||||
handleQcMoneyInput(row) {
|
||||
this.lastYearSurplus = Number(row.qcMoney) || 0;
|
||||
// 同步更新到统计表格
|
||||
if (this.financeData.incomeCensus && this.financeData.incomeCensus.length > 0) {
|
||||
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
|
||||
}
|
||||
// 更新后强制重新计算统计数据
|
||||
this.$forceUpdate();
|
||||
},
|
||||
// 收入输入处理
|
||||
handleIncomeInput(row) {
|
||||
// 计算总收入
|
||||
let totalIncome = 0;
|
||||
this.financeData.incomeDetailed.forEach(item => {
|
||||
totalIncome += Number(item.income) || 0;
|
||||
});
|
||||
this.financeData.incomeCensus[0].income = totalIncome;
|
||||
// 按类型更新对应统计
|
||||
if (row.incomeType === "社会赞助") this.calcSupportTotal();
|
||||
if (row.incomeType === "校工会拨款") this.calcAllocateTotal();
|
||||
if (row.incomeType === "会费收入") this.calcDueIncomeTotal();
|
||||
if (row.incomeType === "社会赞助") {
|
||||
this.calcSupportTotal();
|
||||
} else if (row.incomeType === "校工会拨款") {
|
||||
this.calcAllocateTotal();
|
||||
} else if (row.incomeType === "会费收入") {
|
||||
this.calcDueIncomeTotal();
|
||||
} else if (row.incomeType === "其他收入") {
|
||||
this.calcOtherIncomeTotal();
|
||||
}
|
||||
// 重新计算所有统计数据,确保一致性
|
||||
this.recalculateCensus();
|
||||
},
|
||||
// 支出输入处理
|
||||
handleExpendInput: function() {
|
||||
let totalExpend = 0;
|
||||
this.financeData.incomeDetailed.forEach(item => {
|
||||
totalExpend += Number(item.expend) || 0;
|
||||
});
|
||||
this.financeData.incomeCensus[0].totalExpend = totalExpend;
|
||||
this.calcExpendTotal();
|
||||
// 重新计算所有统计数据,确保一致性
|
||||
this.recalculateCensus();
|
||||
},
|
||||
// 计算校工会拨款合计
|
||||
calcAllocateTotal() {
|
||||
@@ -970,6 +1033,13 @@ layout("/layouts/platform.html"){
|
||||
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
|
||||
this.financeData.incomeCensus[0].support = total;
|
||||
},
|
||||
// 计算其他收入合计
|
||||
calcOtherIncomeTotal() {
|
||||
const total = this.financeData.incomeDetailed
|
||||
.filter(item => item.incomeType === "其他收入")
|
||||
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
|
||||
this.financeData.incomeCensus[0].otherIncome = total;
|
||||
},
|
||||
// 计算会费收入合计
|
||||
calcDueIncomeTotal() {
|
||||
const total = this.financeData.incomeDetailed
|
||||
@@ -984,6 +1054,51 @@ layout("/layouts/platform.html"){
|
||||
.reduce((sum, item) => sum + (Number(item.expend) || 0), 0);
|
||||
this.financeData.incomeCensus[0].totalExpend = total;
|
||||
},
|
||||
// 重新计算所有统计数据
|
||||
recalculateCensus() {
|
||||
// 计算会费收入总额
|
||||
const dueIncomeTotal = this.financeData.incomeDetailed
|
||||
.filter(item => item.incomeType === "会费收入")
|
||||
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
|
||||
|
||||
// 计算校工会拨款总额
|
||||
const allocateTotal = this.financeData.incomeDetailed
|
||||
.filter(item => item.incomeType === "校工会拨款")
|
||||
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
|
||||
|
||||
// 计算社会赞助总额
|
||||
const supportTotal = this.financeData.incomeDetailed
|
||||
.filter(item => item.incomeType === "社会赞助")
|
||||
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
|
||||
|
||||
// 计算其他收入总额
|
||||
const otherIncomeTotal = this.financeData.incomeDetailed
|
||||
.filter(item => item.incomeType === "其他收入")
|
||||
.reduce((sum, item) => sum + (Number(item.income) || 0), 0);
|
||||
|
||||
// 计算总支出
|
||||
const totalExpend = this.financeData.incomeDetailed
|
||||
.filter(item => item.incomeType === "支出")
|
||||
.reduce((sum, item) => sum + (Number(item.expend) || 0), 0);
|
||||
|
||||
// 更新统计数据
|
||||
this.financeData.incomeCensus[0].income = dueIncomeTotal;
|
||||
this.financeData.incomeCensus[0].allocate = allocateTotal;
|
||||
this.financeData.incomeCensus[0].support = supportTotal;
|
||||
this.financeData.incomeCensus[0].otherIncome = otherIncomeTotal;
|
||||
this.financeData.incomeCensus[0].totalExpend = totalExpend;
|
||||
// 确保去年年度结余不丢失
|
||||
this.financeData.incomeCensus[0].lastYearSurplus = this.lastYearSurplus;
|
||||
// 同步写回结余,避免保存后统计值与页面展示不一致
|
||||
this.financeData.incomeCensus[0].surplus = Number(this.calcSurplus(this.financeData.incomeCensus[0]));
|
||||
|
||||
// 同步更新全局变量
|
||||
this.dueIncome = dueIncomeTotal;
|
||||
this.unionAllocate = allocateTotal;
|
||||
|
||||
// 强制更新视图,确保年度结余重新计算
|
||||
this.$forceUpdate();
|
||||
},
|
||||
|
||||
/************************ 事件处理方法 ************************/
|
||||
// 年度变化处理
|
||||
@@ -1049,6 +1164,7 @@ layout("/layouts/platform.html"){
|
||||
// 保存
|
||||
async handleSave() {
|
||||
try {
|
||||
this.recalculateCensus();
|
||||
const resp = await this.$axios.post("/platform/club/examine/apply/save", {
|
||||
data: JSON.stringify(this.formData),
|
||||
incomeDetailed: JSON.stringify(this.financeData.incomeDetailed),
|
||||
@@ -1065,6 +1181,7 @@ layout("/layouts/platform.html"){
|
||||
// 提交(新增)
|
||||
async handleSubmit() {
|
||||
try {
|
||||
this.recalculateCensus();
|
||||
await this.$confirm("确定要提交此申请吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
@@ -1090,6 +1207,7 @@ layout("/layouts/platform.html"){
|
||||
// 提交(任务处理)
|
||||
async handleFinishTask() {
|
||||
try {
|
||||
this.recalculateCensus();
|
||||
await this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
|
||||
@@ -73,6 +73,10 @@ layout("/layouts/platform.html"){
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||
</el-form-item>
|
||||
<el-form-item label="电子签名" prop="tf_userSign"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<pc-signature v-model="formData.tf_userSign"></pc-signature>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row type="flex" justify="end">
|
||||
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
|
||||
@@ -124,22 +128,27 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
handleTaskAction(val) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.guava.index()
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.guava.index()
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
@@ -68,8 +68,12 @@ const EXAMINE_INFO_COMPONENT = {
|
||||
<el-table-column label="会费收入" prop="income"></el-table-column>
|
||||
<el-table-column label="校工会拨款" prop="allocate"></el-table-column>
|
||||
<el-table-column label="社会赞助" prop="support"></el-table-column>
|
||||
<el-table-column label="其他收入" prop="otherIncome"></el-table-column>
|
||||
<el-table-column label="年度总支出" prop="totalExpend"></el-table-column>
|
||||
<el-table-column label="本年度结余" prop="surplus">
|
||||
<template slot-scope="{row}">
|
||||
{{ getIncomeCensusSurplus(row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
@@ -132,6 +136,19 @@ const EXAMINE_INFO_COMPONENT = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 历史数据可能没有落库存量结余,这里按统计项兜底重算
|
||||
getIncomeCensusSurplus(row) {
|
||||
if (!row) {
|
||||
return 0
|
||||
}
|
||||
const lastYearSurplus = Number(row.lastYearSurplus) || 0
|
||||
const income = Number(row.income) || 0
|
||||
const allocate = Number(row.allocate) || 0
|
||||
const support = Number(row.support) || 0
|
||||
const otherIncome = Number(row.otherIncome) || 0
|
||||
const totalExpend = Number(row.totalExpend) || 0
|
||||
return lastYearSurplus + income + allocate + support + otherIncome - totalExpend
|
||||
},
|
||||
async onOpen(row) {
|
||||
this.row = row
|
||||
const resp = await this.$axios.post("/platform/club/examine/common/findOne", { id: row.id })
|
||||
|
||||
@@ -50,11 +50,13 @@ layout("/layouts/platform.html"){
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300">
|
||||
<el-table-column label="操作" width="420">
|
||||
<template v-slot="{row}">
|
||||
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||
<el-button @click="doExportPlan(row)" size="mini" type="primary">导出活动计划</el-button>
|
||||
<el-button @click="doExportActivity(row)" size="mini" type="primary">导出活动开展情况</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -73,6 +75,10 @@ layout("/layouts/platform.html"){
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||
</el-form-item>
|
||||
<el-form-item label="电子签名" prop="tf_userSign"
|
||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||
<pc-signature v-model="formData.tf_userSign"></pc-signature>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row type="flex" justify="end">
|
||||
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
|
||||
@@ -124,22 +130,27 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
handleTaskAction(val) {
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
submitType: val
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.guava.index()
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$refs.guava.index()
|
||||
this.$message.success(res.msg)
|
||||
this.doSearch()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -157,6 +168,12 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
})
|
||||
},
|
||||
doExportPlan(row) {
|
||||
this.$downLoad("/platform/club/examine/schoolLeaderAudit/doExportPlan", { id: row.id })
|
||||
},
|
||||
doExportActivity(row) {
|
||||
this.$downLoad("/platform/club/examine/schoolLeaderAudit/doExportActivity", { id: row.id })
|
||||
},
|
||||
async pageData() {
|
||||
let form = clone(this.pageForm)
|
||||
if (form.isAudit === null) {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
<style></style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<guava ref="guava">
|
||||
<template>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="所属社团">
|
||||
<el-select v-model="pageForm.clubId" placeholder="请选择社团" clearable filterable style="width: 100%">
|
||||
<el-option v-for="item in clubList" :key="item.id" :label="item.clubName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="姓名/工号">
|
||||
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
</search-item>
|
||||
<search-item label="教职工类别">
|
||||
<dict-select code="USER_PERSON_TYPE" placeholder="请选择人员类型" clearable v-model="pageForm.personType"></dict-select>
|
||||
</search-item>
|
||||
<search-item label="在职状态">
|
||||
<dict-select code="USER_STATE" placeholder="请选择人员状态" clearable v-model="pageForm.userState"></dict-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool label="退会人员列表"></table-tool>
|
||||
<el-table :data="tableData">
|
||||
<el-table-column :index="indexMethod" label="序号" type="index" width="70"></el-table-column>
|
||||
<el-table-column label="工号" prop="loginName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="姓名" prop="userName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="性别" prop="sex" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="电话" prop="mobile" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属社团" prop="clubName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属单位" prop="unitName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="身份" prop="roleName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="入会时间" prop="joinTime" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="退会时间" prop="exitTime" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template v-slot="{row}">
|
||||
<el-button size="mini" type="primary" @click="onView(row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<template #view>
|
||||
<info ref="infoRef"></info>
|
||||
</template>
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("info.js"){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"info": clubExitInfo,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
clubList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
async getClubList() {
|
||||
const resp = await this.$axios.post("/platform/club/infoManage/exitManage/getClubList")
|
||||
if (resp.code === 0) {
|
||||
this.clubList = resp.data
|
||||
}
|
||||
},
|
||||
async pageData() {
|
||||
const resp = await this.$axios.post("/platform/club/infoManage/exitManage/pageData", this.pageForm)
|
||||
if (resp.code === 0) {
|
||||
this.tableData = resp.data.list
|
||||
this.pageForm.totalCount = resp.data.totalCount
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.getClubList()
|
||||
await this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,95 @@
|
||||
const clubExitInfo = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<div class="process-title">
|
||||
退会信息
|
||||
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
|
||||
</div>
|
||||
<el-descriptions border>
|
||||
<el-descriptions-item label="姓名">{{viewData.userName}}</el-descriptions-item>
|
||||
<el-descriptions-item label="工号">{{viewData.loginName}}</el-descriptions-item>
|
||||
<el-descriptions-item label="性别">{{viewData.sex}}</el-descriptions-item>
|
||||
<el-descriptions-item label="出生年月">{{$moment(viewData.birthday).format('YYYY-MM-DD')}}</el-descriptions-item>
|
||||
<el-descriptions-item label="联系电话">{{viewData.mobile}}</el-descriptions-item>
|
||||
<el-descriptions-item label="电子信箱">{{viewData.email}}</el-descriptions-item>
|
||||
<el-descriptions-item label="分工会">{{viewData.unionName}}</el-descriptions-item>
|
||||
<el-descriptions-item label="部门" :span="2">{{viewData.unitName}}</el-descriptions-item>
|
||||
<el-descriptions-item label="职务">{{viewData.position}}</el-descriptions-item>
|
||||
<el-descriptions-item label="职称" :span="2">{{viewData.technicalTitle}}</el-descriptions-item>
|
||||
<el-descriptions-item label="学历">{{viewData.education}}</el-descriptions-item>
|
||||
<el-descriptions-item label="学位" :span="2">{{viewData.academicDegree}}</el-descriptions-item>
|
||||
<el-descriptions-item label="同时参加其他社团情况" :span="3">{{viewData.sameTimeJoinOtherClubSituation}}</el-descriptions-item>
|
||||
<el-descriptions-item label="文化、体育方面的活动经历、获奖情况" :span="3">{{viewData.awardsExperience}}</el-descriptions-item>
|
||||
<el-descriptions-item label="照片" :span="3">
|
||||
<img :src="viewData.avatar" alt="" style="width: 120px;height: 150px" v-if="viewData.avatar">
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="签字" :span="3">
|
||||
<el-image v-if="viewData.signature" :src="viewData.signature" class="signature-image"></el-image>
|
||||
<span v-else>暂无</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<template v-for="task in doneTasks">
|
||||
<div class="mt10">
|
||||
<div class="process-title">{{ task.displayName }}</div>
|
||||
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-if="task.ext.isFirstTaskNode">
|
||||
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})</el-descriptions-item>
|
||||
<el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办理结果">
|
||||
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
|
||||
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})</el-descriptions-item>
|
||||
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="办理结果">
|
||||
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE" :value="task.ext.submitType"></dict-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="办理意见" v-if="!task.ext.isFirstTaskNode">{{ task.taskFormData.opinion }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</template>
|
||||
<snaker-chart ref="snakerChartRef"></snaker-chart>
|
||||
</div>
|
||||
`,
|
||||
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||
data() {
|
||||
return {
|
||||
viewData: {},
|
||||
row: {},
|
||||
doneTasks: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onOpen(row) {
|
||||
this.row = row
|
||||
this.$axios.post("/platform/club/infoManage/exitManage/info", { id: row.id }).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.viewData = res.data
|
||||
}
|
||||
})
|
||||
this.getDoneTasks()
|
||||
},
|
||||
getDoneTasks() {
|
||||
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.doneTasks = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
openChart(){
|
||||
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
|
||||
}
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.el-descriptions-item__label {
|
||||
width: 200px;
|
||||
min-width: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
.el-tabs__header {
|
||||
margin: 0;
|
||||
}
|
||||
`
|
||||
}
|
||||
@@ -37,6 +37,7 @@ const CLUB_INFO_MANAGE_TEMPLATE = {
|
||||
<el-table-column label="电话" prop="mobile" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="所属单位" prop="unitName" sortable show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="身份" prop="roleName" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="入会时间" prop="joinTime" show-overflow-tooltip sortable></el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="{row}">
|
||||
<el-dropdown>
|
||||
|
||||
@@ -58,7 +58,8 @@ const CLUB_SPONSOR_TEMPLATE = {
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
sponsorData: [],
|
||||
// 发起人至少需要 3 人,默认先展示 3 行,方便录入。
|
||||
sponsorData: [{}, {}, {}],
|
||||
userOptions: []
|
||||
}
|
||||
},
|
||||
@@ -91,6 +92,10 @@ const CLUB_SPONSOR_TEMPLATE = {
|
||||
})
|
||||
},
|
||||
sponsorDeleteRow(row, index) {
|
||||
if (this.sponsorData.length <= 3) {
|
||||
this.$message.warning("发起人至少保留3行")
|
||||
return
|
||||
}
|
||||
this.sponsorData.splice(index, 1)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ layout("/layouts/platform.html"){
|
||||
<el-button v-if="activeName === 1" type="primary" @click="activeName = 0">上一步</el-button>
|
||||
<el-button v-if="activeName === 2" type="primary" @click="activeName = 1">上一步</el-button>
|
||||
<el-button v-if="activeName === 0" type="primary" @click="nextStep">下一步</el-button>
|
||||
<el-button v-if="activeName === 1" type="primary" @click="activeName = 2">下一步</el-button>
|
||||
<el-button v-if="activeName === 1" type="primary" @click="nextSponsorStep">下一步</el-button>
|
||||
|
||||
<el-button type="primary" plain @click="onSave">保存</el-button>
|
||||
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
|
||||
@@ -73,6 +73,14 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validateSponsorCount() {
|
||||
const sponsorList = this.$refs.clubSponsorRef.sponsorData.filter((o) => o.userId !== "" && o.userId !== undefined)
|
||||
if (sponsorList.length < 3) {
|
||||
this.$message.warning({ title: "温馨提醒", message: "发起人不少于3人" })
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
nextStep() {
|
||||
let valid = true
|
||||
this.$refs.clubFormRef.$refs.form.validateField(["clubName"], (errMsg) => {
|
||||
@@ -85,6 +93,13 @@ layout("/layouts/platform.html"){
|
||||
if (valid) return
|
||||
this.activeName = 1
|
||||
},
|
||||
nextSponsorStep() {
|
||||
// 第二步进入第三步前,先校验发起人数量,避免遗漏必填人数要求。
|
||||
if (!this.validateSponsorCount()) {
|
||||
return
|
||||
}
|
||||
this.activeName = 2
|
||||
},
|
||||
async onSave() {
|
||||
let valid = true
|
||||
this.$refs.clubFormRef.$refs.form.validateField("clubName", (errMsg) => {
|
||||
@@ -122,8 +137,7 @@ layout("/layouts/platform.html"){
|
||||
formData.sponsor = this.$refs.clubSponsorRef.sponsorData
|
||||
.filter((o) => o.userId !== "" && o.userId !== undefined)
|
||||
.map((o) => o.userId)
|
||||
if (['onFinishTask', 'onSubmit'].includes(type) && formData.sponsor && formData.sponsor.length < 3) {
|
||||
this.$message.warning({ title: "警告", message: "发起人要求不少于3人" })
|
||||
if (['onFinishTask', 'onSubmit'].includes(type) && !this.validateSponsorCount()) {
|
||||
return
|
||||
}
|
||||
let manageValid = false
|
||||
@@ -200,7 +214,6 @@ layout("/layouts/platform.html"){
|
||||
let users = resp.data.clubUser.map((o) => o.userId)
|
||||
let array = []
|
||||
if (resp.data.sponsor) {
|
||||
this.sponsorData = []
|
||||
array = resp.data.sponsor.split(",")
|
||||
formData.sponsor = array
|
||||
}
|
||||
@@ -211,12 +224,16 @@ layout("/layouts/platform.html"){
|
||||
if (users) {
|
||||
this.$refs.clubManagerRef.userOptions = await this.queryUserByIds(users)
|
||||
}
|
||||
this.$refs.clubSponsorRef.sponsorData = []
|
||||
array.forEach((item, index) => {
|
||||
let row = {}
|
||||
row.userId = item
|
||||
this.$refs.clubSponsorRef.sponsorPersonChange(item, row, index)
|
||||
this.$refs.clubSponsorRef.sponsorData.push(row)
|
||||
})
|
||||
while (this.$refs.clubSponsorRef.sponsorData.length < 3) {
|
||||
this.$refs.clubSponsorRef.sponsorData.push({})
|
||||
}
|
||||
this.$refs.clubFormRef.formData = formData
|
||||
this.$refs.clubFormRef.concatPersonChange(resp.data.concatPerson)
|
||||
}
|
||||
|
||||
+8
-6
@@ -31,12 +31,14 @@ layout("/layouts/platform.html"){
|
||||
</el-card>
|
||||
<el-card shadow="never" class="mt10">
|
||||
<table-tool label="温馨提示:请先更新拨付金额后再点击核对按钮">
|
||||
<el-button @click="closeAudit(false)" size="mini" type="primary">
|
||||
开启核对入口
|
||||
</el-button>
|
||||
<el-button @click="closeAudit(true)" size="mini" type="danger">
|
||||
取消核对入口
|
||||
</el-button>
|
||||
<template v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_CLUB_ADMIN'])">
|
||||
<el-button @click="closeAudit(false)" size="mini" type="primary">
|
||||
开启核对入口
|
||||
</el-button>
|
||||
<el-button @click="closeAudit(true)" size="mini" type="danger">
|
||||
取消核对入口
|
||||
</el-button>
|
||||
</template>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" style="width: 100%" row-key="id"
|
||||
v-loading="tableLoading" :size="tableSize" class="vi-table">
|
||||
|
||||
+587
-24
@@ -2,6 +2,42 @@
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.reimbursement-tabs {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.invoice-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.invoice-toolbar-title {
|
||||
font-size: 14px;
|
||||
color: #1867b0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.invoice-summary-tip {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.invoice-file-name {
|
||||
color: #1867b0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.invoice-file-name:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
@@ -12,7 +48,9 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||
class="flow-task-form">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-tabs class="reimbursement-tabs" v-model="activeTabName">
|
||||
<el-tab-pane label="申请基本信息" name="basic">
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="经办人">{{formData.userName}}</el-descriptions-item>
|
||||
<el-descriptions-item label="工号">{{formData.loginName}}</el-descriptions-item>
|
||||
<!-- <el-descriptions-item label="报销类别">-->
|
||||
@@ -26,7 +64,7 @@ layout("/layouts/platform.html"){
|
||||
<!-- </el-descriptions-item>-->
|
||||
<el-descriptions-item label="报销项目" span="2">
|
||||
<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">
|
||||
<el-radio :label="item.code" border v-for="item in reimburseProjectList">
|
||||
{{item.name}}
|
||||
</el-radio>
|
||||
@@ -82,11 +120,32 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="户名" v-if="formData.paymentWay === 'UNION_REIMBURSE_PAYMENT_WAY_2'">
|
||||
<el-form-item label="户名" prop="bankUserName">
|
||||
<el-select
|
||||
v-model="formData.bankUserName"
|
||||
@change="handleBankUserNameChange"
|
||||
clearable
|
||||
filterable
|
||||
allow-create
|
||||
default-first-option
|
||||
placeholder="请输入户名"
|
||||
style="width: 100%">
|
||||
<el-option
|
||||
v-for="(item, index) in bankHistoryUserNames"
|
||||
:key="index"
|
||||
:label="item"
|
||||
:value="item">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="开户行" v-if="formData.paymentWay === 'UNION_REIMBURSE_PAYMENT_WAY_2'">
|
||||
<el-form-item label="开户行" prop="bankOfDeposit">
|
||||
<el-select
|
||||
v-model="formData.bankOfDeposit"
|
||||
@change="getUserBankHistory"
|
||||
@change="fillBankInfoFromHistory"
|
||||
clearable
|
||||
filterable
|
||||
allow-create
|
||||
@@ -107,7 +166,7 @@ layout("/layouts/platform.html"){
|
||||
<el-form-item label="银行卡号" prop="bankCardNumber" >
|
||||
<el-select
|
||||
v-model="formData.bankCardNumber"
|
||||
@change="getUserBankHistory"
|
||||
@change="fillBankInfoFromHistory"
|
||||
clearable
|
||||
filterable
|
||||
allow-create
|
||||
@@ -268,8 +327,7 @@ layout("/layouts/platform.html"){
|
||||
|
||||
<el-descriptions-item label="报销金额" v-if="formData.reimburseProject !== 'UNION_REIMBURSE_PROJECT_1'">
|
||||
<el-form-item label="报销金额" prop="money">
|
||||
<el-input v-model="formData.money" placeholder="输入报销金额"
|
||||
type="number"></el-input>
|
||||
<el-input v-model="formData.money" placeholder="自动汇总发票金额" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
@@ -282,15 +340,6 @@ layout("/layouts/platform.html"){
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="发票张数">
|
||||
<el-form-item label="发票张数" prop="invoiceNumber">
|
||||
<el-input-number v-model="formData.invoiceNumber"
|
||||
:max="1000" :min="0" controls-position="right"
|
||||
placeholder="请填写发票张数"
|
||||
style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item label="慰问时间" v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
||||
<el-form-item label="慰问时间" prop="condolenceTime">
|
||||
<el-date-picker v-model="formData.condolenceTime"
|
||||
@@ -396,13 +445,13 @@ layout("/layouts/platform.html"){
|
||||
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="报销事由" :span="2">
|
||||
<el-descriptions-item label="报销事由" :span="2" v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
||||
<el-form-item prop="paymentNotes" label="报销事由">
|
||||
<el-input maxlength="500" v-model="formData.paymentNotes" placeholder="请填写报销事由"
|
||||
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
|
||||
</el-form-item>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">
|
||||
<el-descriptions-item label="备注" :span="2" v-if="formData.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">
|
||||
<el-form-item prop="notes" label="备注">
|
||||
<el-input maxlength="500" v-model="formData.notes" placeholder="需要填写:发票编号、开具方、金额"
|
||||
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
|
||||
@@ -436,7 +485,83 @@ layout("/layouts/platform.html"){
|
||||
<!-- <pc-signature v-model="formData.userSign"></pc-signature>-->
|
||||
<!-- </el-form-item>-->
|
||||
<!-- </el-descriptions-item>-->
|
||||
</el-descriptions>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="发票信息" name="invoice" v-if="showInvoiceTab">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报销金额" prop="money">
|
||||
<el-input v-model="formData.money" placeholder="自动汇总发票金额" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发票张数" prop="invoiceNumber">
|
||||
<el-input v-model="formData.invoiceNumber" placeholder="自动统计发票数量" readonly></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="paymentNotes" label="支付内容">
|
||||
<el-input maxlength="500" v-model="formData.paymentNotes" placeholder="请填写支付内容"
|
||||
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item prop="notes" label="备注">
|
||||
<el-input maxlength="500" v-model="formData.notes" placeholder="补充说明"
|
||||
type="textarea" :autosize="{ minRows: 3, maxRows: 6}"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div class="invoice-toolbar">
|
||||
<div>
|
||||
<div class="invoice-toolbar-title">发票明细列表</div>
|
||||
<div class="invoice-summary-tip">
|
||||
每条明细对应一个发票文件,可上传图片或 PDF;报销金额和发票张数会根据下表自动汇总。
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-switch
|
||||
v-model="formData.invoiceVerifyEnabled"
|
||||
@change="handleVerifySwitchChange"
|
||||
active-text="自动校验"
|
||||
inactive-text="手工录入">
|
||||
</el-switch>
|
||||
<el-button @click="openInvoiceDialog('add')" plain type="primary" style="margin-left: 12px">新增发票</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="formData.invoiceDetails" border empty-text="暂无发票明细">
|
||||
<el-table-column align="center" label="序号" type="index" width="70"></el-table-column>
|
||||
<el-table-column label="文件名称" min-width="170">
|
||||
<template slot-scope="scope">
|
||||
<span class="invoice-file-name"
|
||||
v-if="getInvoiceFile(scope.row)"
|
||||
@click="previewInvoiceFile(scope.row)">
|
||||
{{ getInvoiceFile(scope.row).name || getInvoiceFile(scope.row).filename }}
|
||||
</span>
|
||||
<span v-else>未上传</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="发票号码" min-width="140" prop="invoiceNo"></el-table-column>
|
||||
<el-table-column align="right" label="发票金额" min-width="110" prop="invoiceAmount"></el-table-column>
|
||||
<el-table-column label="销售方信息名称" min-width="180" prop="sellerName"></el-table-column>
|
||||
<el-table-column label="项目名称" min-width="180" prop="itemName"></el-table-column>
|
||||
<el-table-column label="备注" min-width="150" prop="remark"></el-table-column>
|
||||
<el-table-column align="center" fixed="right" label="操作" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-button @click="openInvoiceDialog('edit', scope.row, scope.$index)" size="mini" type="text">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button @click="removeInvoiceDetail(scope.$index)" size="mini" type="text">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-form>
|
||||
<el-row type="flex" justify="end" class="mt20">
|
||||
<el-button type="primary" plain @click="onSave">保存</el-button>
|
||||
@@ -444,6 +569,70 @@ layout("/layouts/platform.html"){
|
||||
<el-button type="primary" @click="onFinishTask" v-else>提交</el-button>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :close-on-click-modal="false"
|
||||
:title="invoiceDialogMode === 'edit' ? '编辑发票明细' : '新增发票明细'"
|
||||
:visible.sync="invoiceDialogVisible"
|
||||
append-to-body
|
||||
width="820px">
|
||||
<el-form :model="detailForm" :rules="detailRules" label-position="right"
|
||||
label-suffix=":" label-width="120px" ref="invoiceDetailForm">
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="发票文件" prop="invoiceFiles">
|
||||
<file-upload
|
||||
:value.sync="detailForm.invoiceFiles"
|
||||
:upload_number="1"
|
||||
upload_return_id_api="/platform/sys/file/uploadDynamicReturnUrl"
|
||||
upload_result_type="id"
|
||||
upload_result_category="array"
|
||||
complete_result
|
||||
upload_mode="drag"
|
||||
accept=".jpg,.jpeg,.png,.pdf">
|
||||
</file-upload>
|
||||
<div class="invoice-summary-tip">
|
||||
上传发票文件后会自动识别发票号码、金额、销售方信息名称和项目名称;如已开启自动校验,还会继续校验发票信息。
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发票号码" prop="invoiceNo">
|
||||
<el-input placeholder="请输入发票号码" v-model="detailForm.invoiceNo"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发票金额" prop="invoiceAmount">
|
||||
<el-input-number :controls="false" :min="0" :precision="2"
|
||||
placeholder="请输入发票金额" style="width: 100%"
|
||||
v-model="detailForm.invoiceAmount"></el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="销售方信息名称" prop="sellerName">
|
||||
<el-input placeholder="请输入销售方信息名称" v-model="detailForm.sellerName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="项目名称" prop="itemName">
|
||||
<el-input placeholder="请输入项目名称" v-model="detailForm.itemName"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input :autosize="{ minRows: 3, maxRows: 5}"
|
||||
placeholder="请输入备注"
|
||||
type="textarea"
|
||||
v-model="detailForm.remark"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<span class="dialog-footer" slot="footer">
|
||||
<el-button @click="invoiceDialogVisible = false">取 消</el-button>
|
||||
<el-button @click="saveInvoiceDetail" type="primary">保 存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -456,12 +645,31 @@ layout("/layouts/platform.html"){
|
||||
return {
|
||||
bizId: GetQueryString("bizId"),
|
||||
taskId: GetQueryString("taskId"),
|
||||
activeTabName: "basic",
|
||||
formData: {
|
||||
reimburseType: "",
|
||||
hospitalizationTimeRange: [],
|
||||
reimburseProject:''
|
||||
reimburseProject:'',
|
||||
invoiceDetails: [],
|
||||
invoiceVerifyEnabled: true
|
||||
},
|
||||
historyData: [],
|
||||
invoiceDialogVisible: false,
|
||||
invoiceDialogMode: "add",
|
||||
detailFormIndex: -1,
|
||||
lastRecognizedFileId: "",
|
||||
recognizingInvoice: false,
|
||||
detailForm: {
|
||||
invoiceFiles: [],
|
||||
invoiceNo: "",
|
||||
invoiceAmount: null,
|
||||
sellerName: "",
|
||||
itemName: "",
|
||||
remark: "",
|
||||
invoiceCode: "",
|
||||
invoiceDate: "",
|
||||
invoiceCheckCode: ""
|
||||
},
|
||||
condolenceWays: [
|
||||
{label: "慰问金(A)", value: "慰问金(A)"},
|
||||
{label: "提货券(B)", value: "提货券(B)"},
|
||||
@@ -492,7 +700,10 @@ layout("/layouts/platform.html"){
|
||||
paymentNotes: [{required: true, message: "请填写支付内容", trigger: ["change", "blur"]}],
|
||||
activityName: [{required: true, message: "请填写活动名称", trigger: ["change", "blur"]}],
|
||||
money: [{required: true, message: "请填写报销金额", trigger: ["change", "blur"]}],
|
||||
mobile: [{required: true, message: "请填写联系方式", trigger: ["change", "blur"]}],
|
||||
mobile: [
|
||||
{required: true, message: "请填写联系方式", trigger: ["change", "blur"]},
|
||||
{pattern: /^(1[3-9]\d{9}|0\d{2,3}-?\d{7,8})$/, message: "请输入正确的联系方式", trigger: "blur"}
|
||||
],
|
||||
files: [{required: true, message: "请上传附件", trigger: ["change", "blur"]}],
|
||||
userSign: [{required: true, message: "请签名", trigger: ["change", "blur"]}],
|
||||
// certifierUserId: [{required: true, message: "请填写认证人", trigger: ["change", "blur"]}],
|
||||
@@ -508,6 +719,13 @@ layout("/layouts/platform.html"){
|
||||
activityTime: [{required: true, message: "请选择活动时间", trigger: ["change", "blur"]}],
|
||||
activityNumber: [{required: true, message: "请输入活动人数", trigger: ["change", "blur"]}]
|
||||
},
|
||||
detailRules: {
|
||||
invoiceFiles: [{required: true, message: "请上传发票文件", trigger: ["change", "blur"]}],
|
||||
invoiceNo: [{required: true, message: "请输入发票号码", trigger: ["change", "blur"]}],
|
||||
invoiceAmount: [{required: true, message: "请输入发票金额", trigger: ["change", "blur"]}],
|
||||
sellerName: [{required: true, message: "请输入销售方信息名称", trigger: ["change", "blur"]}],
|
||||
itemName: [{required: true, message: "请输入项目名称", trigger: ["change", "blur"]}]
|
||||
},
|
||||
chooseType: {},
|
||||
userOptions: [],
|
||||
typeOptions: [],
|
||||
@@ -519,7 +737,37 @@ layout("/layouts/platform.html"){
|
||||
payerOptions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showInvoiceTab() {
|
||||
return this.formData.reimburseProject !== "UNION_REIMBURSE_PROJECT_1"
|
||||
},
|
||||
bankHistoryUserNames() {
|
||||
const userNameMap = {}
|
||||
return (this.historyData || []).reduce((result, item) => {
|
||||
if (item.bankUserName && !userNameMap[item.bankUserName]) {
|
||||
userNameMap[item.bankUserName] = true
|
||||
result.push(item.bankUserName)
|
||||
}
|
||||
return result
|
||||
}, [])
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
"detailForm.invoiceFiles": {
|
||||
handler(newVal) {
|
||||
const file = newVal && newVal.length ? newVal[0] : null
|
||||
const currentFileId = this.getInvoiceFileId(file)
|
||||
if (!currentFileId) {
|
||||
this.lastRecognizedFileId = ""
|
||||
return
|
||||
}
|
||||
if (currentFileId === this.lastRecognizedFileId) {
|
||||
return
|
||||
}
|
||||
this.recognizeCurrentInvoice(false)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
"formData.hospitalizationTimeRange"(newVal) {
|
||||
if (newVal && newVal.length === 2) {
|
||||
this.$set(this.formData, "hospitalizationStartTime", newVal[0]);
|
||||
@@ -543,12 +791,38 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
buildDefaultDetailForm() {
|
||||
return {
|
||||
invoiceFiles: [],
|
||||
invoiceNo: "",
|
||||
invoiceAmount: null,
|
||||
sellerName: "",
|
||||
itemName: "",
|
||||
remark: "",
|
||||
invoiceCode: "",
|
||||
invoiceDate: "",
|
||||
invoiceCheckCode: ""
|
||||
}
|
||||
},
|
||||
ensureFormData(formData) {
|
||||
const nextFormData = formData || {}
|
||||
if (!Array.isArray(nextFormData.invoiceDetails)) {
|
||||
this.$set(nextFormData, "invoiceDetails", [])
|
||||
}
|
||||
if (!Array.isArray(nextFormData.files)) {
|
||||
this.$set(nextFormData, "files", [])
|
||||
}
|
||||
if (typeof nextFormData.invoiceVerifyEnabled !== "boolean") {
|
||||
this.$set(nextFormData, "invoiceVerifyEnabled", true)
|
||||
}
|
||||
return nextFormData
|
||||
},
|
||||
createRemoteMethodForPayer(keyword) {
|
||||
this.selectQueryUserForPayer(keyword, this.payerOptions)
|
||||
},
|
||||
selectQueryUserForPayer(keyword, options) {
|
||||
options.length = 0
|
||||
this.$axios.post("/platform/UnionReimburse/apply/listUser", {keyword: keyword}).then((res) => {
|
||||
this.$axios.post("/platform/unionReimburse/apply/listUser", {keyword: keyword}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
options.push(...res.data)
|
||||
}
|
||||
@@ -585,10 +859,44 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
})
|
||||
},
|
||||
fillBankInfoFromHistory() {
|
||||
const matchItem = this.historyData.find((item) => {
|
||||
if (this.formData.bankUserName && item.bankUserName !== this.formData.bankUserName) {
|
||||
return false
|
||||
}
|
||||
if (this.formData.bankCardNumber && item.bankCardNumber !== this.formData.bankCardNumber) {
|
||||
return false
|
||||
}
|
||||
if (this.formData.bankOfDeposit && item.bankOfDeposit !== this.formData.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)
|
||||
}
|
||||
},
|
||||
handleBankUserNameChange(value) {
|
||||
const matchItem = this.historyData.find((item) => item.bankUserName === value)
|
||||
if (matchItem) {
|
||||
this.$set(this.formData, "bankCardNumber", matchItem.bankCardNumber)
|
||||
this.$set(this.formData, "bankOfDeposit", matchItem.bankOfDeposit)
|
||||
}
|
||||
},
|
||||
handleVerifySwitchChange(value) {
|
||||
this.$set(this.formData, "invoiceVerifyEnabled", !!value)
|
||||
if (value && this.invoiceDialogVisible) {
|
||||
this.recognizeCurrentInvoice(true)
|
||||
}
|
||||
},
|
||||
|
||||
async payerUserChange(){
|
||||
if (this.formData.payer) {
|
||||
await this.getUserBankHistory();
|
||||
} else {
|
||||
this.historyData = []
|
||||
}
|
||||
const user = this.payerOptions.find(o => o.id === this.formData.payer)
|
||||
if (user) {
|
||||
@@ -637,6 +945,253 @@ layout("/layouts/platform.html"){
|
||||
this.$set(this.formData, "typeName", name)
|
||||
}
|
||||
},
|
||||
handleReimburseProjectChange(value) {
|
||||
if (value === "UNION_REIMBURSE_PROJECT_1") {
|
||||
this.$set(this, "activeTabName", "basic")
|
||||
this.$set(this.formData, "invoiceDetails", [])
|
||||
this.$set(this.formData, "invoiceNumber", "")
|
||||
this.$set(this.formData, "money", null)
|
||||
} else {
|
||||
this.rebuildInvoiceSummary()
|
||||
}
|
||||
},
|
||||
openInvoiceDialog(mode, row, index) {
|
||||
this.invoiceDialogMode = mode
|
||||
this.detailFormIndex = typeof index === "number" ? index : -1
|
||||
this.lastRecognizedFileId = ""
|
||||
if (mode === "edit" && row) {
|
||||
this.$set(this, "detailForm", JSON.parse(JSON.stringify(row)))
|
||||
} else {
|
||||
this.$set(this, "detailForm", this.buildDefaultDetailForm())
|
||||
}
|
||||
this.invoiceDialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.invoiceDetailForm) {
|
||||
this.$refs.invoiceDetailForm.clearValidate()
|
||||
}
|
||||
})
|
||||
},
|
||||
getInvoiceFile(row) {
|
||||
if (!row || !row.invoiceFiles || row.invoiceFiles.length === 0) {
|
||||
return null
|
||||
}
|
||||
return row.invoiceFiles[0]
|
||||
},
|
||||
/**
|
||||
* 兼容上传组件返回完整对象、历史地址回显等多种场景,统一提取文件 id 给识别接口使用。
|
||||
*/
|
||||
getInvoiceFileId(file) {
|
||||
if (!file) {
|
||||
return ""
|
||||
}
|
||||
if (file.id) {
|
||||
return file.id
|
||||
}
|
||||
if (file.response && file.response.data) {
|
||||
if (typeof file.response.data === "string") {
|
||||
const data = file.response.data
|
||||
const idIndex = data.indexOf("id=")
|
||||
if (idIndex > -1) {
|
||||
return data.substring(idIndex + 3)
|
||||
}
|
||||
return data
|
||||
}
|
||||
if (file.response.data.id) {
|
||||
return file.response.data.id
|
||||
}
|
||||
}
|
||||
if (file.downloadPath && typeof file.downloadPath === "string") {
|
||||
const downloadPath = file.downloadPath
|
||||
const idIndex = downloadPath.indexOf("id=")
|
||||
if (idIndex > -1) {
|
||||
return downloadPath.substring(idIndex + 3)
|
||||
}
|
||||
}
|
||||
if (file.url && typeof file.url === "string") {
|
||||
const url = file.url
|
||||
const idIndex = url.indexOf("id=")
|
||||
if (idIndex > -1) {
|
||||
return url.substring(idIndex + 3)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
},
|
||||
previewInvoiceFile(row) {
|
||||
const file = this.getInvoiceFile(row)
|
||||
const fileId = this.getInvoiceFileId(file)
|
||||
if (!fileId) {
|
||||
this.$message.warning("暂无发票文件")
|
||||
return
|
||||
}
|
||||
window.open("/platform/sys/file/download?id=" + fileId)
|
||||
},
|
||||
recognizeCurrentInvoice(showLoading) {
|
||||
const invoiceFile = this.getInvoiceFile(this.detailForm)
|
||||
const invoiceFileId = this.getInvoiceFileId(invoiceFile)
|
||||
if (!invoiceFileId) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
this.lastRecognizedFileId = invoiceFileId
|
||||
this.recognizingInvoice = !!showLoading
|
||||
return this.$axios.get("/platform/unionReimburse/apply/recognizeInvoice", {
|
||||
params: {
|
||||
fileId: invoiceFileId,
|
||||
verifySwitch: this.formData.invoiceVerifyEnabled
|
||||
}
|
||||
}).then((resp) => {
|
||||
if (resp.code !== 0) {
|
||||
this.$message.warning(resp.msg)
|
||||
return false
|
||||
}
|
||||
const data = resp.data || {}
|
||||
if (data.invoiceNo) {
|
||||
this.$set(this.detailForm, "invoiceNo", data.invoiceNo)
|
||||
}
|
||||
if (data.invoiceAmount !== null && data.invoiceAmount !== undefined && data.invoiceAmount !== "") {
|
||||
this.$set(this.detailForm, "invoiceAmount", Number(data.invoiceAmount))
|
||||
}
|
||||
if (data.sellerName) {
|
||||
this.$set(this.detailForm, "sellerName", data.sellerName)
|
||||
}
|
||||
if (data.itemName) {
|
||||
this.$set(this.detailForm, "itemName", data.itemName)
|
||||
}
|
||||
if (data.invoiceCode) {
|
||||
this.$set(this.detailForm, "invoiceCode", data.invoiceCode)
|
||||
}
|
||||
if (data.invoiceDate) {
|
||||
this.$set(this.detailForm, "invoiceDate", data.invoiceDate)
|
||||
}
|
||||
if (data.invoiceCheckCode) {
|
||||
this.$set(this.detailForm, "invoiceCheckCode", data.invoiceCheckCode)
|
||||
}
|
||||
if (this.detailForm.invoiceNo) {
|
||||
return this.validateInvoiceDuplicateBeforeSave()
|
||||
}
|
||||
return true
|
||||
}).catch((error) => {
|
||||
const errorMsg = error && error.response && error.response.data && error.response.data.msg
|
||||
? error.response.data.msg
|
||||
: (error && error.msg ? error.msg : "发票识别请求失败,请稍后重试")
|
||||
this.$message.error(errorMsg)
|
||||
return false
|
||||
}).finally(() => {
|
||||
this.recognizingInvoice = false
|
||||
})
|
||||
},
|
||||
async validateInvoiceDuplicateBeforeSave() {
|
||||
const invoiceNo = this.detailForm.invoiceNo ? String(this.detailForm.invoiceNo).trim() : ""
|
||||
if (!invoiceNo) {
|
||||
return false
|
||||
}
|
||||
const duplicateRows = []
|
||||
const invoiceDetails = this.formData.invoiceDetails || []
|
||||
for (let i = 0; i < invoiceDetails.length; i++) {
|
||||
if (this.detailFormIndex > -1 && i === this.detailFormIndex) {
|
||||
continue
|
||||
}
|
||||
const currentNo = invoiceDetails[i].invoiceNo ? String(invoiceDetails[i].invoiceNo).trim() : ""
|
||||
if (currentNo && currentNo === invoiceNo) {
|
||||
duplicateRows.push(i + 1)
|
||||
}
|
||||
}
|
||||
if (duplicateRows.length > 0) {
|
||||
this.$message.warning("发票号码【" + invoiceNo + "】与本次提交的第" + duplicateRows.join("、") + "条发票重复,不能保存")
|
||||
return false
|
||||
}
|
||||
const resp = await this.$axios.get("/platform/unionReimburse/apply/checkInvoiceDuplicate", {
|
||||
params: {
|
||||
invoiceNo: invoiceNo,
|
||||
reimburseId: this.formData.id || ""
|
||||
}
|
||||
})
|
||||
if (resp.code !== 0) {
|
||||
this.$message.warning(resp.msg)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
async saveInvoiceDetail() {
|
||||
this.$refs.invoiceDetailForm.validate(async (valid) => {
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
const duplicateValid = await this.validateInvoiceDuplicateBeforeSave()
|
||||
if (!duplicateValid) {
|
||||
return
|
||||
}
|
||||
const detailData = JSON.parse(JSON.stringify(this.detailForm))
|
||||
if (this.detailFormIndex > -1) {
|
||||
this.$set(this.formData.invoiceDetails, this.detailFormIndex, detailData)
|
||||
} else {
|
||||
this.formData.invoiceDetails.push(detailData)
|
||||
}
|
||||
this.rebuildInvoiceSummary()
|
||||
this.invoiceDialogVisible = false
|
||||
})
|
||||
},
|
||||
removeInvoiceDetail(index) {
|
||||
this.$confirm("确定删除这条发票明细吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
this.formData.invoiceDetails.splice(index, 1)
|
||||
this.rebuildInvoiceSummary()
|
||||
})
|
||||
},
|
||||
rebuildInvoiceSummary() {
|
||||
if (this.formData.reimburseProject === "UNION_REIMBURSE_PROJECT_1") {
|
||||
return
|
||||
}
|
||||
let totalMoney = 0
|
||||
let fileCount = 0
|
||||
const invoiceDetails = this.formData.invoiceDetails || []
|
||||
for (let i = 0; i < invoiceDetails.length; i++) {
|
||||
if (invoiceDetails[i].invoiceAmount !== null && invoiceDetails[i].invoiceAmount !== undefined && invoiceDetails[i].invoiceAmount !== "") {
|
||||
totalMoney = totalMoney + Number(invoiceDetails[i].invoiceAmount)
|
||||
}
|
||||
if (invoiceDetails[i].invoiceFiles && invoiceDetails[i].invoiceFiles.length > 0) {
|
||||
fileCount = fileCount + 1
|
||||
}
|
||||
}
|
||||
this.$set(this.formData, "money", totalMoney ? totalMoney.toFixed(2) : "0.00")
|
||||
this.$set(this.formData, "invoiceNumber", String(fileCount))
|
||||
},
|
||||
validateInvoiceDetailsBeforeSubmit() {
|
||||
if (this.formData.reimburseProject === "UNION_REIMBURSE_PROJECT_1") {
|
||||
return true
|
||||
}
|
||||
const invoiceDetails = this.formData.invoiceDetails || []
|
||||
if (!invoiceDetails.length) {
|
||||
this.$message.warning("请至少维护一条发票明细")
|
||||
return false
|
||||
}
|
||||
for (let i = 0; i < invoiceDetails.length; i++) {
|
||||
const currentDetail = invoiceDetails[i]
|
||||
if (!currentDetail.invoiceFiles || currentDetail.invoiceFiles.length === 0) {
|
||||
this.$message.warning("第" + (i + 1) + "条发票明细请上传发票文件")
|
||||
return false
|
||||
}
|
||||
if (!currentDetail.invoiceNo) {
|
||||
this.$message.warning("第" + (i + 1) + "条发票明细请填写发票号码")
|
||||
return false
|
||||
}
|
||||
if (!currentDetail.invoiceAmount || Number(currentDetail.invoiceAmount) <= 0) {
|
||||
this.$message.warning("第" + (i + 1) + "条发票明细请填写正确的发票金额")
|
||||
return false
|
||||
}
|
||||
if (!currentDetail.sellerName) {
|
||||
this.$message.warning("第" + (i + 1) + "条发票明细请填写销售方信息名称")
|
||||
return false
|
||||
}
|
||||
if (!currentDetail.itemName) {
|
||||
this.$message.warning("第" + (i + 1) + "条发票明细请填写项目名称")
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
//
|
||||
// typeChange(id) {
|
||||
// this.chooseType = this.typeOptions.find(o => o.id === id)
|
||||
@@ -647,6 +1202,7 @@ layout("/layouts/platform.html"){
|
||||
// },
|
||||
// 保存
|
||||
onSave() {
|
||||
this.rebuildInvoiceSummary()
|
||||
this.$confirm("您确定保存吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
@@ -665,6 +1221,12 @@ layout("/layouts/platform.html"){
|
||||
return new Promise((resolve) => {
|
||||
this.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
if (!this.validateInvoiceDetailsBeforeSubmit()) {
|
||||
this.$set(this, "activeTabName", "invoice")
|
||||
resolve(false)
|
||||
return
|
||||
}
|
||||
this.rebuildInvoiceSummary()
|
||||
resolve(true)
|
||||
} else {
|
||||
this.$message.warning("请完善必填信息")
|
||||
@@ -842,14 +1404,15 @@ layout("/layouts/platform.html"){
|
||||
if (this.bizId) {
|
||||
this.$axios.post("/platform/unionReimburse/apply/info", {id: this.bizId}).then(async (res) => {
|
||||
if (res.code === 0) {
|
||||
this.formData = res.data
|
||||
this.formData = this.ensureFormData(res.data)
|
||||
await this.selectQueryUser(this.formData.certifierLoginName, this.userOptions)
|
||||
this.rebuildInvoiceSummary()
|
||||
// this.chooseType = this.typeOptions.find(o => o.id === this.formData.type)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const {username, loginname, id, unit, union, mobile} = this.$store.state.user
|
||||
this.formData = {
|
||||
this.formData = this.ensureFormData({
|
||||
userName: username,
|
||||
loginName: loginname,
|
||||
unitId: unit?.id,
|
||||
@@ -861,7 +1424,7 @@ layout("/layouts/platform.html"){
|
||||
paymentWay: 'UNION_REIMBURSE_PAYMENT_WAY_2',
|
||||
mobile: mobile,
|
||||
userId: id,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+16
-11
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
|
||||
<search-item label="姓名/工号">
|
||||
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<search-item label="所属工会" v-if="isAdmin">
|
||||
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择所属工会" clearable>
|
||||
<el-option v-for="item in unionOptions"
|
||||
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="所属单位">
|
||||
<search-item label="所属单位" v-if="isAdmin">
|
||||
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择所属单位" clearable>
|
||||
<el-option v-for="item in unitOptions"
|
||||
@@ -53,10 +53,10 @@ layout("/layouts/platform.html"){
|
||||
</table-tool>
|
||||
<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 prop="loginName" label="经办人工号"></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="unionName" label="所属工会"></el-table-column>
|
||||
<el-table-column prop="unitName" label="所属单位"></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="certifierUserName" label="证明人">
|
||||
<template slot-scope="{row}">
|
||||
{{row.certifierUserName}}({{row.certifierLoginName}})
|
||||
@@ -69,7 +69,7 @@ layout("/layouts/platform.html"){
|
||||
</dict-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="reimburseProject" label="报销项目">
|
||||
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
|
||||
<template slot-scope="{row}">
|
||||
<dict-tag :options="dict.type.UNION_REIMBURSE_PROJECT"
|
||||
:value="row.reimburseProject">
|
||||
@@ -77,7 +77,7 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="money" label="金额"></el-table-column>
|
||||
<el-table-column prop="createTime" label="申请时间"></el-table-column>
|
||||
<el-table-column prop="createTime" label="申请时间" sortable="custom"></el-table-column>
|
||||
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
|
||||
<el-table-column prop="instanceState" label="流程状态">
|
||||
<template slot-scope="{row}">
|
||||
@@ -151,6 +151,11 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
}
|
||||
,
|
||||
computed: {
|
||||
isAdmin() {
|
||||
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(() => {
|
||||
@@ -214,10 +219,10 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
//工会查询
|
||||
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
|
||||
//单位查询
|
||||
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
|
||||
if (this.isAdmin) {
|
||||
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
|
||||
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+33
-26
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
|
||||
<search-item label="姓名/工号">
|
||||
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<search-item label="所属工会" v-if="isAdmin">
|
||||
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择所属工会" clearable>
|
||||
<el-option v-for="item in unionOptions"
|
||||
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="所属单位">
|
||||
<search-item label="所属单位" v-if="isAdmin">
|
||||
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择所属单位" clearable>
|
||||
<el-option v-for="item in unitOptions"
|
||||
@@ -51,12 +51,12 @@ layout("/layouts/platform.html"){
|
||||
</table-tool>
|
||||
<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 prop="loginName" label="经办人工号"></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="unionName" label="所属工会"></el-table-column>
|
||||
<el-table-column prop="unitName" label="所属单位"></el-table-column>
|
||||
<el-table-column prop="createTime" label="申请时间"></el-table-column>
|
||||
<el-table-column prop="reimburseProject" label="报销项目">
|
||||
<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>
|
||||
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
|
||||
<template slot-scope="{row}">
|
||||
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">慰问</span>
|
||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
|
||||
@@ -85,7 +85,7 @@ layout("/layouts/platform.html"){
|
||||
<el-table-column label="操作" fixed="right" width="350px">
|
||||
<template slot-scope="{row}">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||
<el-button @click="openEdit(row)" size="mini" type="primary">实际金额</el-button>
|
||||
<el-button v-if="isAdmin" @click="openEdit(row)" size="mini" type="primary">实际金额</el-button>
|
||||
<el-button v-if="row.stateId == 3" @click="doPrint(row)" size="mini" type="primary">打印</el-button>
|
||||
<el-button v-if="$auth.hasRole('SYSADMIN')" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
|
||||
</template>
|
||||
@@ -144,6 +144,11 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
}
|
||||
,
|
||||
computed: {
|
||||
isAdmin() {
|
||||
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.$refs.guava.edit(()=>{
|
||||
@@ -174,30 +179,32 @@ layout("/layouts/platform.html"){
|
||||
|
||||
// 弹窗关闭时的处理
|
||||
handleDialogClose() {
|
||||
this.$refs.editForm.resetFields();
|
||||
if (this.$refs.editForm) {
|
||||
this.$refs.editForm.resetFields();
|
||||
}
|
||||
},
|
||||
|
||||
// 保存实际报销金额
|
||||
saveFinallyMoney() {
|
||||
this.$refs.editForm.validate(async (valid) => {
|
||||
this.$refs.editForm.validate((valid) => {
|
||||
if (valid) {
|
||||
const resp = await this.$axios.post("/platform/unionReimburse/collect/updateActuallyAmount", {
|
||||
id: this.editFormData.id,
|
||||
realMoney: this.editFormData.realMoney
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('保存成功');
|
||||
this.editDialogVisible = false;
|
||||
this.$refs.editForm.resetFields();
|
||||
this.pageData();
|
||||
}
|
||||
})
|
||||
this.$axios.post("/platform/unionReimburse/collect/updateActuallyAmount", {
|
||||
id: this.editFormData.id,
|
||||
realMoney: this.editFormData.realMoney
|
||||
}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$message.success('保存成功');
|
||||
this.editDialogVisible = false;
|
||||
this.$refs.editForm.resetFields();
|
||||
this.pageData();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
exportSkr() {
|
||||
const {year = '', unionId = '', unitId = '', reimburseProject = ''} = this.pageForm
|
||||
window.open('/platform/unionReimburse/collect/exportSkr?year=' + year + "&unionId=" + unionId + '&unitId=' + unitId + "&reiItemId=" + reimburseProject)
|
||||
window.open('/platform/unionReimburse/collect/exportSkr?year=' + year + "&unionId=" + unionId + '&unitId=' + unitId + "&reimburseProject=" + reimburseProject)
|
||||
},
|
||||
doPrint(row) {
|
||||
if (row.reimburseProject != "UNION_REIMBURSE_PROJECT_1") {
|
||||
@@ -212,10 +219,10 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
//工会查询
|
||||
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
|
||||
//单位查询
|
||||
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
|
||||
if (this.isAdmin) {
|
||||
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
|
||||
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+16
-11
@@ -12,7 +12,7 @@ layout("/layouts/platform.html"){
|
||||
<search-item label="姓名/工号">
|
||||
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<search-item label="所属工会" v-if="isAdmin">
|
||||
<el-select v-model="pageForm.unionId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择所属工会" clearable>
|
||||
<el-option v-for="item in unionOptions"
|
||||
@@ -22,7 +22,7 @@ layout("/layouts/platform.html"){
|
||||
></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="所属单位">
|
||||
<search-item label="所属单位" v-if="isAdmin">
|
||||
<el-select v-model="pageForm.unitId" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择所属单位" clearable>
|
||||
<el-option v-for="item in unitOptions"
|
||||
@@ -48,12 +48,12 @@ layout("/layouts/platform.html"){
|
||||
<table-tool></table-tool>
|
||||
<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 prop="loginName" label="经办人工号"></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="unionName" label="所属工会"></el-table-column>
|
||||
<el-table-column prop="unitName" label="所属单位"></el-table-column>
|
||||
<el-table-column prop="createTime" label="申请时间"></el-table-column>
|
||||
<el-table-column prop="reimburseProject" label="报销项目">
|
||||
<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>
|
||||
<el-table-column prop="reimburseProject" label="报销项目" sortable="custom">
|
||||
<template slot-scope="{row}">
|
||||
<span v-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_1'">慰问</span>
|
||||
<span v-else-if="row.reimburseProject === 'UNION_REIMBURSE_PROJECT_2'">文体活动</span>
|
||||
@@ -119,6 +119,11 @@ layout("/layouts/platform.html"){
|
||||
}
|
||||
}
|
||||
,
|
||||
computed: {
|
||||
isAdmin() {
|
||||
return this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.$refs.guava.view(() => {
|
||||
@@ -177,10 +182,10 @@ layout("/layouts/platform.html"){
|
||||
},
|
||||
created() {
|
||||
this.pageData()
|
||||
//工会查询
|
||||
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
|
||||
//单位查询
|
||||
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
|
||||
if (this.isAdmin) {
|
||||
this.$businessTool.listUnion().then((res) => (this.unionOptions = res))
|
||||
this.$businessTool.listUnit().then((res) => (this.unitOptions = res))
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user