Compare commits

33 Commits
Author SHA1 Message Date
c-chenxs1 f51b24686f Merge branch 'feat_可同步长江大学的优化_fix' 2026-11-02 11:30:17 +08:00
c-chenxs1 3f7b5dc27a feat: 优化活动相关模块 2026-10-29 09:43:43 +08:00
c-chenxs1 e944ebf85f Merge branch 'feat_本工会单独业务' 2026-10-28 17:58:29 +08:00
c-chenxs1 a0732fdb08 Merge branch 'feat_可同步长江大学的优化_fix' into feat_本工会单独业务 2026-10-28 15:26:58 +08:00
c-chenxs1 db26813635 feat: move 2026-10-28 15:22:43 +08:00
c-chenxs1 d5f1c642c4 Merge branch 'feat_可同步长江大学的优化_fix' 2026-10-28 15:21:46 +08:00
c-chenxs1 a09cd7b8fd feat: 优化批量导入人员角色 2026-10-28 15:21:27 +08:00
c-chenxs1 d18d9bda6d Merge branch 'feat_可同步长江大学的优化_fix'
# Conflicts:
#	.gitignore
2026-10-28 13:54:48 +08:00
c-chenxs1 919f8c9dec feat: 同步地大代码-打开密码sso验证 2026-10-28 13:53:45 +08:00
c-chenxs1 0fb779ff5a feat: v3版疗休养优化9 2026-10-27 11:59:57 +08:00
c-chenxs1 55e94de004 feat: v3版疗休养优化8 2026-10-27 09:12:52 +08:00
c-chenxs1 d452d4ad92 feat: v3版疗休养优化7 2026-10-26 18:19:28 +08:00
c-chenxs1 6ea864cb64 feat: v3版疗休养优化6 2026-10-26 17:33:07 +08:00
c-chenxs1 56cc3fee91 feat: v3版疗休养优化6 2026-10-26 16:50:49 +08:00
c-chenxs1 4c03b389d4 feat: v3版疗休养优化5 2026-10-26 15:27:53 +08:00
c-chenxs1 fcb6ba7e2d feat: v3版疗休养优化4 2026-10-26 14:28:19 +08:00
c-chenxs1 65fac78cfb feat: v3版疗休养优化3 2026-10-26 13:35:39 +08:00
c-chenxs1 2d20959355 feat: v3版疗休养优化2 2026-10-26 09:49:06 +08:00
c-chenxs1 1a1946b1f8 feat: v3版疗休养优化 2026-10-26 09:45:30 +08:00
c-chenxs1 7f2ac97dea feat: v3版疗休养 2026-10-26 09:21:26 +08:00
c-chenxs1 82713327db feat: v3版疗休养 2026-10-26 09:19:45 +08:00
c-chenxs1 d598f1bf0f feat: 补充角色工作流 2026-10-23 17:12:29 +08:00
c-chenxs1 01e2443db8 feat: 俱乐部增加导入社团 2026-10-23 16:58:42 +08:00
c-chenxs1 bb4c44443d feat: 本地开发1登录 2026-10-23 14:50:06 +08:00
c-chenxs1 15d3ec0ddd feat:
给校工会增加角色时,如果已经给这个用户增加了,再增加会报错,并且页面无提示

分工会干部 加一个 编辑按钮, 只有超级管理员可以看到,另外添加这里的届次改为非必填
2026-10-23 14:36:43 +08:00
c-chenxs1 713e174650 feat: prd -> dev 2026-10-23 14:02:16 +08:00
c-chenxs1 6e351c6829 feat: 优化 2026-10-23 11:03:32 +08:00
c-chenxs1 5d160f660f feat: 同步地大更新 2026-10-22 18:24:14 +08:00
c-chenxs1 57d84724cb feat: 恢复密码不匹配时抛出“用户名或者密码不正确”,阻止登录。 2026-10-22 18:11:59 +08:00
c-chenxs1 018ee96402 feat: 提案配置不存在、校领导单位列表为 null 或为空时,记录警告并跳过角色刷新,继续人员全量更新 2026-10-22 17:50:19 +08:00
c-chenxs1 98c7804c28 feat: 新增 [CAS诊断] 日志 2026-10-22 17:15:49 +08:00
c-chenxs1 e257f4bae2 feat: 优化配置和人员拉取 2026-10-22 16:57:21 +08:00
c-chenxs1 054cf966c3 feat: 优化3 2026-10-22 15:04:33 +08:00
240 changed files with 49806 additions and 718 deletions
+1
View File
@@ -49,3 +49,4 @@ Thumbs.db
.trae/pr-creator/SKILL.md .trae/pr-creator/SKILL.md
.trae/update-docs/SKILL.md .trae/update-docs/SKILL.md
.trae/webapp-testing/SKILL.md .trae/webapp-testing/SKILL.md
outputs
@@ -83,6 +83,7 @@ public class MainLauncher {
Globals.AppBase = Mvcs.getServletContext().getContextPath(); Globals.AppBase = Mvcs.getServletContext().getContextPath();
Globals.AppRoot = Mvcs.getServletContext().getRealPath("/"); Globals.AppRoot = Mvcs.getServletContext().getRealPath("/");
init_sys(); init_sys();
ioc.get(com.budwk.app.zhgh.staffbenefit.therapyRecuperation.TherapyRecuperationModule.class);
// 2026年10月3日 12:01:28;操作人:wxg:先升级会员表及补齐历史资料,再处理缴费快照和启动计划任务;不依赖 DEBUG。 // 2026年10月3日 12:01:28;操作人:wxg:先升级会员表及补齐历史资料,再处理缴费快照和启动计划任务;不依赖 DEBUG。
SysClubUserService members = ioc.get(SysClubUserService.class, "sysClubUserServiceImpl"); SysClubUserService members = ioc.get(SysClubUserService.class, "sysClubUserServiceImpl");
members.upgradeMemberSchema(); members.upgradeMemberSchema();
@@ -50,6 +50,11 @@ RoleConstant {
BRANCH_UNION_SHENGGHUO_WY("分工会生活委员"), BRANCH_UNION_SHENGGHUO_WY("分工会生活委员"),
BRANCH_UNION_TIAOJIE_WY("分工会调解委员"), BRANCH_UNION_TIAOJIE_WY("分工会调解委员"),
BRANCH_UNION_WENTI_SPORTS("分工会文体福利委员"), BRANCH_UNION_WENTI_SPORTS("分工会文体福利委员"),
BRANCH_UNION_YOUTH_WORK_COMMITTEE("分工会青工委委员"),
BRANCH_UNION_WOMEN_WORK_COMMITTEE("分工会女工委委员"),
BRANCH_UNION_WELFARE_COMMITTEE("分工会福利委员"),
BRANCH_UNION_SPORTS_COMMITTEE("分工会文体委员"),
BRANCH_UNION_PUBLICITY_COMMITTEE("分工会宣传委员"),
UNIT_PARTY_SECRETARY("单位党委书记"), UNIT_PARTY_SECRETARY("单位党委书记"),
@@ -61,8 +61,8 @@ public class SmsServiceImpl implements SmsService {
*/ */
@Override @Override
public MsgPlatformResponse sendSms(MsgPlatformSmsRequest request) { public MsgPlatformResponse sendSms(MsgPlatformSmsRequest request) {
if ("prd".equalsIgnoreCase(conf.get("nutz.profiles.active"))) { if (Strings.isNotBlank(conf.get("custom.msg.platform.app-id"))) {
return zjnuMsgService.send(request, "SMS"); return zjnuMsgService.send(request, conf.getBoolean("msg.platform.IntelligenceMode", false) ? "IntelligenceMode" : "SMS");
} }
validateCommonRequest(request); validateCommonRequest(request);
JSONObject payload = buildCommonPayload(request, true); JSONObject payload = buildCommonPayload(request, true);
@@ -112,7 +112,7 @@ public class SmsServiceImpl implements SmsService {
*/ */
@Override @Override
public MsgPlatformResponse sendWechat(MsgPlatformWechatRequest request) { public MsgPlatformResponse sendWechat(MsgPlatformWechatRequest request) {
if ("prd".equalsIgnoreCase(conf.get("nutz.profiles.active"))) { if (Strings.isNotBlank(conf.get("custom.msg.platform.app-id"))) {
return zjnuMsgService.send(request, "WeChat"); return zjnuMsgService.send(request, "WeChat");
} }
validateCommonRequest(request); validateCommonRequest(request);
@@ -350,7 +350,7 @@ public class SmsServiceImpl implements SmsService {
* @param request 平台请求参数 * @param request 平台请求参数
*/ */
private void fillDefaultSenderInfo(MsgPlatformBaseRequest request) { private void fillDefaultSenderInfo(MsgPlatformBaseRequest request) {
if ("prd".equalsIgnoreCase(conf.get("nutz.profiles.active"))) { if (Strings.isNotBlank(conf.get("custom.msg.platform.app-id"))) {
return; return;
} }
request.setSendUserId(getRequiredConfig("msg.platform.default-send-user-id", "请先配置 msg.platform.default-send-user-id")); request.setSendUserId(getRequiredConfig("msg.platform.default-send-user-id", "请先配置 msg.platform.default-send-user-id"));
@@ -0,0 +1,54 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import java.util.List;
public class FlowBranchUnionPublicityCommitteeHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
Sys_role role = sysRoleService.getByCode(RoleConstant.BRANCH_UNION_PUBLICITY_COMMITTEE);
if (role == null || role.isDisabled()) {
throw new BaseException("分工会宣传委员角色未配置或已禁用,请联系校工会!");
}
String unionId = StrUtil.blankToDefault(execution.getArgs().getStr(FlowConst.INITIATOR_UNIT_UNION_ID), SecurityUtil.getUnionId());
if (StrUtil.isBlank(unionId)) {
throw new BaseException("无法确定所属分工会,请联系校工会!");
}
List<Sys_user_role> relations = dao.query(Sys_user_role.class,
Cnd.where(Sys_user_role::getRoleId, "=", role.getId())
.and(Sys_user_role::getUnionId, "=", unionId)
.and(Sys_user_role::getEnable, "=", true));
List<String> userIds = relations.stream().map(Sys_user_role::getUserId)
.filter(StrUtil::isNotBlank).distinct().toList();
if (userIds.isEmpty()) {
throw new BaseException("分工会宣传委员没有设置,请联系校工会!");
}
return userIds;
}
@Override
public String getMessage() {
return "流程发起人所属分工会宣传委员";
}
@Override
public int getOrder() {
return 15;
}
}
@@ -0,0 +1,54 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import java.util.List;
public class FlowBranchUnionSportsCommitteeHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
Sys_role role = sysRoleService.getByCode(RoleConstant.BRANCH_UNION_SPORTS_COMMITTEE);
if (role == null || role.isDisabled()) {
throw new BaseException("分工会文体委员角色未配置或已禁用,请联系校工会!");
}
String unionId = StrUtil.blankToDefault(execution.getArgs().getStr(FlowConst.INITIATOR_UNIT_UNION_ID), SecurityUtil.getUnionId());
if (StrUtil.isBlank(unionId)) {
throw new BaseException("无法确定所属分工会,请联系校工会!");
}
List<Sys_user_role> relations = dao.query(Sys_user_role.class,
Cnd.where(Sys_user_role::getRoleId, "=", role.getId())
.and(Sys_user_role::getUnionId, "=", unionId)
.and(Sys_user_role::getEnable, "=", true));
List<String> userIds = relations.stream().map(Sys_user_role::getUserId)
.filter(StrUtil::isNotBlank).distinct().toList();
if (userIds.isEmpty()) {
throw new BaseException("分工会文体委员没有设置,请联系校工会!");
}
return userIds;
}
@Override
public String getMessage() {
return "流程发起人所属分工会文体委员";
}
@Override
public int getOrder() {
return 14;
}
}
@@ -0,0 +1,54 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import java.util.List;
public class FlowBranchUnionWelfareCommitteeHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
Sys_role role = sysRoleService.getByCode(RoleConstant.BRANCH_UNION_WELFARE_COMMITTEE);
if (role == null || role.isDisabled()) {
throw new BaseException("分工会福利委员角色未配置或已禁用,请联系校工会!");
}
String unionId = StrUtil.blankToDefault(execution.getArgs().getStr(FlowConst.INITIATOR_UNIT_UNION_ID), SecurityUtil.getUnionId());
if (StrUtil.isBlank(unionId)) {
throw new BaseException("无法确定所属分工会,请联系校工会!");
}
List<Sys_user_role> relations = dao.query(Sys_user_role.class,
Cnd.where(Sys_user_role::getRoleId, "=", role.getId())
.and(Sys_user_role::getUnionId, "=", unionId)
.and(Sys_user_role::getEnable, "=", true));
List<String> userIds = relations.stream().map(Sys_user_role::getUserId)
.filter(StrUtil::isNotBlank).distinct().toList();
if (userIds.isEmpty()) {
throw new BaseException("分工会福利委员没有设置,请联系校工会!");
}
return userIds;
}
@Override
public String getMessage() {
return "流程发起人所属分工会福利委员";
}
@Override
public int getOrder() {
return 13;
}
}
@@ -0,0 +1,54 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import java.util.List;
public class FlowBranchUnionWomenWorkCommitteeHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
Sys_role role = sysRoleService.getByCode(RoleConstant.BRANCH_UNION_WOMEN_WORK_COMMITTEE);
if (role == null || role.isDisabled()) {
throw new BaseException("分工会女工委委员角色未配置或已禁用,请联系校工会!");
}
String unionId = StrUtil.blankToDefault(execution.getArgs().getStr(FlowConst.INITIATOR_UNIT_UNION_ID), SecurityUtil.getUnionId());
if (StrUtil.isBlank(unionId)) {
throw new BaseException("无法确定所属分工会,请联系校工会!");
}
List<Sys_user_role> relations = dao.query(Sys_user_role.class,
Cnd.where(Sys_user_role::getRoleId, "=", role.getId())
.and(Sys_user_role::getUnionId, "=", unionId)
.and(Sys_user_role::getEnable, "=", true));
List<String> userIds = relations.stream().map(Sys_user_role::getUserId)
.filter(StrUtil::isNotBlank).distinct().toList();
if (userIds.isEmpty()) {
throw new BaseException("分工会女工委委员没有设置,请联系校工会!");
}
return userIds;
}
@Override
public String getMessage() {
return "流程发起人所属分工会女工委委员";
}
@Override
public int getOrder() {
return 12;
}
}
@@ -0,0 +1,54 @@
package com.budwk.app.flow.handler;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.engine.AssignmentHandler;
import com.budwk.app.flow.engine.core.Execution;
import com.budwk.app.flow.engine.core.ServiceContext;
import com.budwk.app.flow.engine.model.TaskModel;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import java.util.List;
public class FlowBranchUnionYouthWorkCommitteeHandler implements AssignmentHandler {
@Override
public List<String> assign(TaskModel model, Execution execution) {
Dao dao = ServiceContext.find(Dao.class);
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
Sys_role role = sysRoleService.getByCode(RoleConstant.BRANCH_UNION_YOUTH_WORK_COMMITTEE);
if (role == null || role.isDisabled()) {
throw new BaseException("分工会青工委委员角色未配置或已禁用,请联系校工会!");
}
String unionId = StrUtil.blankToDefault(execution.getArgs().getStr(FlowConst.INITIATOR_UNIT_UNION_ID), SecurityUtil.getUnionId());
if (StrUtil.isBlank(unionId)) {
throw new BaseException("无法确定所属分工会,请联系校工会!");
}
List<Sys_user_role> relations = dao.query(Sys_user_role.class,
Cnd.where(Sys_user_role::getRoleId, "=", role.getId())
.and(Sys_user_role::getUnionId, "=", unionId)
.and(Sys_user_role::getEnable, "=", true));
List<String> userIds = relations.stream().map(Sys_user_role::getUserId)
.filter(StrUtil::isNotBlank).distinct().toList();
if (userIds.isEmpty()) {
throw new BaseException("分工会青工委委员没有设置,请联系校工会!");
}
return userIds;
}
@Override
public String getMessage() {
return "流程发起人所属分工会青工委委员";
}
@Override
public int getOrder() {
return 11;
}
}
@@ -1,34 +1,29 @@
package com.budwk.app.sys.controller; package com.budwk.app.sys.controller;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil; import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import com.budwk.app.base.constant.RoleConstant; import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.models.Sys_home_template; import com.budwk.app.sys.models.Sys_home_template;
import com.budwk.app.sys.models.Sys_menu; import com.budwk.app.sys.models.Sys_menu;
import com.budwk.app.sys.services.SysHomeActivityService;
import com.budwk.app.sys.services.SysHomeNewsService; import com.budwk.app.sys.services.SysHomeNewsService;
import com.budwk.app.sys.services.SysMenuService; import com.budwk.app.sys.services.SysMenuService;
import com.budwk.app.sys.services.SysUserService; import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.web.commons.auth.utils.AuthUtil; import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.FieldFilter; import org.nutz.dao.FieldFilter;
import org.nutz.dao.Sqls; import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos; import org.nutz.dao.util.Daos;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings; import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log; import org.nutz.log.Log;
import org.nutz.log.Logs; import org.nutz.log.Logs;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
@@ -52,7 +47,7 @@ public class SysHomeController {
@Inject @Inject
private SysUserService sysUserService; private SysUserService sysUserService;
@Inject @Inject
private ActivityBasicScopeService activityBasicScopeService; private SysHomeActivityService sysHomeActivityService;
@Inject @Inject
private SysHomeNewsService sysHomeNewsService; private SysHomeNewsService sysHomeNewsService;
@@ -201,71 +196,16 @@ public class SysHomeController {
} }
/**
* includeEnded可选:true供PC首页展示已结束活动,缺省false保持既有调用行为。
* 返回Result,data为当前登录用户可见的活动实体列表,含名称、封面、链接及起止时间,不含内部SQL和类路径。
*/
@At @At
@SaCheckLogin @SaCheckLogin
@ApiOperation("首页推送活动") @ApiOperation("首页推送活动")
@Ok("json") @Ok("json")
public Result listHomeActivity() { public Result listHomeActivity(@Param(value = "includeEnded", df = "false") boolean includeEnded) {
FieldFilter fieldFilter = FieldFilter.locked(Sys_home_activity.class, "classPath"); return Result.success(sysHomeActivityService.listHomeActivity(SecurityUtil.getUserId(), includeEnded));
List<Sys_home_activity> list = Daos.ext(dao, fieldFilter).query(Sys_home_activity.class, Cnd.where("enable", "=", 1).desc("top"));
String userId = SecurityUtil.getUserId();
List<Sys_home_activity> allowActivityList = new ArrayList<>();
// 今天的时间
Date today = DateUtil.date();
for (Sys_home_activity activity : list) {
// 该活动的时间范围
Date startDate = activity.getStartDate();
Date endDate = activity.getEndDate();
// 判断当前时间是否在活动范围内,不在就过滤掉
// if (!DateUtil.isIn(today, startDate, endDate)) {
// continue;
// }
// 只过滤结束的
if (DateUtil.compare(today, endDate) > 0) {
continue;
}
Integer allowUserGroupId = activity.getAllowUserGroupId();
String allowUserSql = activity.getAllowUserSql();
activity.setAllowUserSql(null);
if (allowUserGroupId == null && StrUtil.isBlank(allowUserSql)) {
allowActivityList.add(activity);
continue;
}
if (allowUserGroupId != null) {
if (activityBasicScopeService.isUserInGroup(allowUserGroupId, userId)) {
allowActivityList.add(activity);
continue;
}
}
if (StrUtil.isNotBlank(allowUserSql)) {
Sql sql = Sqls.create(allowUserSql).setParam("userId", userId);
sql.setCallback(Sqls.callback.map());
dao.execute(sql);
NutMap nutMap = (NutMap) sql.getResult();
if (Lang.isNotEmpty(nutMap) && StrUtil.isNotBlank(nutMap.getString("userId"))) {
allowActivityList.add(activity);
}
}
}
return Result.success(allowActivityList);
//
//
//
//
// FieldFilter fieldFilter = FieldFilter.locked(Sys_home_activity.class, "allowUserSql|classPath");
// List<Sys_home_activity> list = Daos.ext(dao, fieldFilter).query(Sys_home_activity.class, Cnd.where("enable", "=", 1).desc("top"));
//
// List<Sys_menu> menus = sysUserService.getMenus(SecurityUtil.getUserId());
// Set<String> hrefs = menus.stream().map(Sys_menu::getHref).collect(Collectors.toSet());
//
// List<Sys_home_activity> hasPermisiionList = list.stream().filter(activity -> {
// String url = activity.getUrl();
// String h5Url = activity.getH5Url();
// return hrefs.contains(url) || hrefs.contains(h5Url);
// }).toList().stream().toList();
// return Result.success(hasPermisiionList);
} }
@At @At
@@ -173,19 +173,40 @@ public class SysLoginController {
} }
} }
@At(value = "/platform/sso/login", top = true) @At(value = {"/platform/sso/login", "/sso/login"}, top = true)
@Ok("re") @Ok("re")
@ApiOperation("用户cas登录统一入口") @ApiOperation("用户cas登录统一入口")
public String ssoLogin(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response) { public String ssoLogin(HttpSession httpSession, HttpServletRequest request, HttpServletResponse response) {
Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
String tokenName = StpUtil.getTokenName();
boolean tokenCookiePresent = request.getCookies() != null && java.util.Arrays.stream(request.getCookies())
.anyMatch(cookie -> tokenName.equals(cookie.getName()) && StrUtil.isNotBlank(cookie.getValue()));
log.infof("[CAS诊断] 回调进入 uri=%s, ticketPresent=%s, sessionNew=%s, requestedSessionValid=%s, sessionAssertion=%s, requestAssertion=%s, tokenCookiePresent=%s, secure=%s",
request.getRequestURI(), StrUtil.isNotBlank(request.getParameter("ticket")), httpSession.isNew(),
request.isRequestedSessionIdValid(), assertion != null && assertion.getPrincipal() != null,
request.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) != null, tokenCookiePresent, request.isSecure());
if (null == assertion || assertion.getPrincipal() == null) { if (null == assertion || assertion.getPrincipal() == null) {
log.warn("[CAS诊断] Session 中没有有效认证结果,未执行本地登录,即将跳转首页");
return ">>:/platform/home"; return ">>:/platform/home";
} }
String loginName = assertion.getPrincipal().getName(); String loginName = assertion.getPrincipal().getName();
sysUserService.checkThirdPlatformLoginName(loginName); String stage = "查询本地用户";
Sys_user sysUser = sysUserService.loginByLoginName(loginName); try {
sysUserService.checkThirdPlatformLoginName(loginName);
return ">>:" + sysUserService.loginPlus(sysUser, LoginType.CAS, request); Sys_user sysUser = sysUserService.loginByLoginName(loginName);
stage = "建立本地登录态";
log.info("[CAS诊断] 本地用户查询成功,开始执行 loginPlus");
String redirect = sysUserService.loginPlus(sysUser, LoginType.CAS, request);
boolean tokenCookieWritten = response.getHeaders("Set-Cookie").stream()
.anyMatch(header -> header.startsWith(tokenName + "="));
log.infof("[CAS诊断] 本地登录完成 loggedIn=%s, tokenCookieWritten=%s, responseCommitted=%s, appDomain=%s, redirectPath=%s",
StpUtil.isLogin(), tokenCookieWritten, response.isCommitted(), Globals.AppDomain,
redirect == null ? null : redirect.split("[?#]", 2)[0]);
return ">>:" + redirect;
} catch (RuntimeException e) {
log.warnf("[CAS诊断] 回调失败 stage=%s, exceptionType=%s", stage, e.getClass().getName());
throw e;
}
} }
@At(value = "/platform/wxwork/oauth2/callback", top = true) @At(value = "/platform/wxwork/oauth2/callback", top = true)
@@ -0,0 +1,461 @@
package com.budwk.app.sys.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
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.utils.CommonDownloadUtil;
import com.budwk.app.sys.models.*;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
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.util.NutMap;
import org.nutz.lang.random.R;
import org.nutz.trans.Atom;
import org.nutz.trans.Trans;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@IocBean
@At("/platform/sys/unionCadreImport")
@Ok("json:full")
public class SysUnionCadreImportController {
private static final String[] HEADERS = {"工会编码", "工号", "角色编码", "届次编码(选填)", "所属单位编码(书记必填)"};
private static final int MAX_ROWS = 1000;
@Inject
private Dao dao;
@Inject
private SysDictService sysDictService;
@Inject
private SysUnionController sysUnionController;
@Inject
private SysRoleService sysRoleService;
@Inject
private SysUserService sysUserService;
@SuppressWarnings("unchecked")
private List<NutMap> roleOptions() {
return (List<NutMap>) sysUnionController.branchUnionRoleOptions().getData();
}
@At
@Ok("void")
@SaCheckRole("SYSADMIN")
@SaCheckPermission("sys.manager.union.branchOfficer")
public void downloadTemplate(HttpServletResponse response) {
Workbook workbook = new XSSFWorkbook();
Sheet data = createSheet(workbook, "干部导入", HEADERS);
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(workbook.createDataFormat().getFormat("@"));
for (int i = 0; i < HEADERS.length; i++) {
data.setDefaultColumnStyle(i, textStyle);
}
Sheet notes = createSheet(workbook, "填写说明", "字段", "填写要求");
notes.setColumnWidth(1, 100 * 256);
append(notes, "导入范围", "仅导入第一个工作表;每行一个人员角色,最多1000行;请保留表头,工号和编码按文本填写。");
append(notes, "工会编码", "必填,参考工会对照表。人员必须属于该分工会。");
append(notes, "工号", "必填,填写系统中已存在的人员工号,不填写姓名。");
append(notes, "角色编码", "必填,参考角色对照表,不填写角色名称。");
append(notes, "届次编码(选填)", "可留空;填写时使用届次对照表中的编码,与单个添加一致。");
append(notes, "所属单位编码(书记必填)", "仅二级党委书记填写,多个单位用英文逗号分隔,必须为当前分工会的二级单位;其他角色留空。");
append(notes, "重复记录", "普通干部按人员和角色跳过;二级党委书记按人员、角色和工会跳过。禁用的已有关系也跳过,不覆盖。");
append(notes, "保存方式", "系统管理员直接授权,批量校验并保存干部及角色记录,统一清理权限缓存,不发起审批。校验失败行不写入;保存异常时拆分定位失败行,其他有效行继续导入。");
append(notes, "已有干部记录", "已有在任或待审核干部记录但未分配角色时跳过,避免重复创建或绕过已有审批。");
Sheet unions = createSheet(workbook, "工会对照", "工会编码", "工会名称");
List<Sys_union> unionList = dao.query(Sys_union.class, Cnd.NEW().asc("unionCode"));
for (Sys_union union : unionList) {
append(unions, union.getUnionCode(), union.getName());
}
Sheet roles = createSheet(workbook, "角色对照", "角色编码", "角色名称");
for (NutMap role : roleOptions()) {
append(roles, role.getString("code"), role.getString("name"));
}
Sheet terms = createSheet(workbook, "届次对照", "届次编码", "届次名称");
for (Sys_dict term : sysDictService.getSubListByCode("TEACHER_CONGRESS_J")) {
append(terms, term.getCode(), term.getName());
}
Sheet units = createSheet(workbook, "所属单位对照", "单位编码", "单位名称", "工会编码", "工会名称");
for (Sys_unit unit : dao.query(Sys_unit.class, Cnd.where("unitLevel", "=", 2).asc("unitcode"))) {
for (Sys_union union : unionList) {
if (union.getId().equals(unit.getUnionId())) {
append(units, unit.getUnitcode(), unit.getName(), union.getUnionCode(), union.getName());
break;
}
}
}
CommonDownloadUtil.download("批量添加分工会干部模板.xlsx", workbook, response);
}
@At
@SaCheckRole("SYSADMIN")
@SaCheckPermission("sys.manager.union.branchOfficer")
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Result doImport(@Param("file") TempFile file) {
if (file == null) {
return Result.error("请选择Excel文件");
}
List<NutMap> rows = new ArrayList<>();
// 先完整读取文件,避免文件格式错误时已写入部分数据却无法返回逐行结果。
try (InputStream input = file.getInputStream(); Workbook workbook = WorkbookFactory.create(input)) {
if (workbook.getNumberOfSheets() == 0) {
return Result.error("文件没有工作表,请使用下载的模板");
}
Sheet sheet = workbook.getSheetAt(0);
DataFormatter formatter = new DataFormatter();
for (int i = 0; i < HEADERS.length; i++) {
if (!HEADERS[i].equals(cellText(sheet.getRow(0), i, formatter))) {
return Result.error("模板表头不正确,请使用下载的模板并保留第一行表头");
}
}
for (Row row : sheet) {
if (row.getRowNum() == 0) {
continue;
}
String[] values = new String[HEADERS.length];
for (int j = 0; j < values.length; j++) {
values[j] = cellText(row, j, formatter);
}
if (Arrays.stream(values).allMatch(StrUtil::isBlank)) {
continue;
}
if (rows.size() >= MAX_ROWS) {
return Result.error("每次最多导入1000行有效数据,请拆分文件后导入");
}
rows.add(NutMap.NEW().addv("rowNumber", row.getRowNum() + 1).addv("unionCode", values[0])
.addv("loginname", values[1]).addv("roleCode", values[2])
.addv("j", values[3]).addv("unitCodes", values[4]));
}
} catch (Exception e) {
log.warn("读取分工会干部导入文件失败", e);
return Result.error("无法读取文件,请上传未加密的xls或xlsx模板文件,编码列不要使用公式");
}
if (rows.isEmpty()) {
return Result.error("文件中没有需要导入的数据");
}
Set<String> roleCodes = sysDictService.getSubListByCode("BRANCH_UNION_ROLES").stream()
.map(Sys_dict::getCode).collect(Collectors.toSet());
roleCodes.add(RoleConstant.UNIT_PARTY_SECRETARY.name());
Set<String> terms = sysDictService.getSubListByCode("TEACHER_CONGRESS_J").stream()
.map(Sys_dict::getCode).collect(Collectors.toSet());
List<String> unionCodes = values(rows, "unionCode");
List<String> loginnames = values(rows, "loginname");
List<String> inputRoleCodes = values(rows, "roleCode");
List<String> unitCodes = rows.stream().flatMap(row -> splitUnitCodes(row.getString("unitCodes")).stream())
.distinct().toList();
// 各类基础数据及已有关系按表一次查询,逐行校验时不再访问数据库。
Map<String, List<Sys_union>> unions = group(unionCodes.isEmpty() ? List.of()
: dao.query(Sys_union.class, Cnd.where("unionCode", "in", unionCodes)), Sys_union::getUnionCode);
Map<String, List<View_user>> users = group(loginnames.isEmpty() ? List.of()
: dao.query(View_user.class, Cnd.where("loginname", "in", loginnames)), View_user::getLoginname);
Map<String, List<Sys_role>> roles = group(inputRoleCodes.isEmpty() ? List.of()
: dao.query(Sys_role.class, Cnd.where("code", "in", inputRoleCodes)), Sys_role::getCode);
Map<String, List<Sys_unit>> units = group(unitCodes.isEmpty() ? List.of()
: dao.query(Sys_unit.class, Cnd.where("unitcode", "in", unitCodes)), Sys_unit::getUnitcode);
List<String> userIds = users.values().stream().flatMap(List::stream).map(View_user::getId).distinct().toList();
List<String> roleIds = roles.values().stream().flatMap(List::stream).map(Sys_role::getId).distinct().toList();
Set<List<String>> existingRoles = new HashSet<>();
if (!userIds.isEmpty() && !roleIds.isEmpty()) {
for (Sys_user_role relation : dao.query(Sys_user_role.class,
Cnd.where("userId", "in", userIds).and("roleId", "in", roleIds))) {
existingRoles.add(roleKey(relation.getUserId(), relation.getRoleId(), relation.getUnionId(),
roles.getOrDefault(RoleConstant.UNIT_PARTY_SECRETARY.name(), List.of()).stream()
.anyMatch(role -> role.getId().equals(relation.getRoleId()))));
}
}
Set<List<String>> existingCadres = new HashSet<>();
if (!userIds.isEmpty() && !inputRoleCodes.isEmpty() && !unionCodes.isEmpty()) {
List<String> unionIds = unions.values().stream().flatMap(List::stream).map(Sys_union::getId).distinct().toList();
if (!unionIds.isEmpty()) {
for (Sys_union_cadre cadre : dao.query(Sys_union_cadre.class, Cnd.where("userId", "in", userIds)
.and("roleCode", "in", inputRoleCodes).and("unionId", "in", unionIds).and("isServing", "=", true))) {
existingCadres.add(Arrays.asList(cadre.getUserId(), cadre.getRoleCode(), cadre.getUnionId()));
}
}
}
List<ImportEntry> entries = new ArrayList<>();
Map<List<String>, Integer> fileRoles = new java.util.HashMap<>();
String operator = SecurityUtil.getUserId();
for (NutMap row : rows) {
ImportEntry entry = prepareRow(row, roleCodes, terms, unions, users, roles, units,
existingRoles, existingCadres, fileRoles, operator);
if (entry != null) {
entries.add(entry);
}
}
saveBatch(entries);
int success = (int) rows.stream().filter(row -> "成功".equals(row.getString("status"))).count();
int skipped = (int) rows.stream().filter(row -> "跳过".equals(row.getString("status"))).count();
if (success > 0) {
sysRoleService.clearCache();
sysUserService.clearCache();
}
return Result.success(NutMap.NEW().addv("success", success).addv("skipped", skipped)
.addv("failed", rows.size() - success - skipped).addv("rows", rows));
}
private List<String> values(List<NutMap> rows, String field) {
return rows.stream().map(row -> row.getString(field)).filter(StrUtil::isNotBlank).distinct().toList();
}
private List<String> splitUnitCodes(String codes) {
return Arrays.stream(codes.split("[,,]")).map(String::trim).filter(StrUtil::isNotBlank).distinct().toList();
}
private <T> Map<String, List<T>> group(List<T> items, Function<T, String> key) {
return items.stream().collect(Collectors.groupingBy(key));
}
private List<String> roleKey(String userId, String roleId, String unionId, boolean secretary) {
return Arrays.asList(userId, roleId, secretary ? unionId : "");
}
private <T> T unique(Map<String, List<T>> records, String code, String label, List<String> errors) {
if (StrUtil.isBlank(code)) {
errors.add(label + "不能为空");
return null;
}
List<T> matches = records.getOrDefault(code, List.of());
if (matches.isEmpty()) {
errors.add(label + "【" + code + "】不存在");
return null;
}
if (matches.size() > 1) {
errors.add(label + "【" + code + "】匹配到" + matches.size() + "条记录,需先处理系统中的重复编码");
return null;
}
return matches.get(0);
}
private ImportEntry prepareRow(NutMap row, Set<String> roleCodes, Set<String> terms,
Map<String, List<Sys_union>> unions, Map<String, List<View_user>> users,
Map<String, List<Sys_role>> roles, Map<String, List<Sys_unit>> units,
Set<List<String>> existingRoles, Set<List<String>> existingCadres,
Map<List<String>, Integer> fileRoles, String operator) {
String unionCode = row.getString("unionCode");
String loginname = row.getString("loginname");
String roleCode = row.getString("roleCode");
String j = row.getString("j");
List<String> errors = new ArrayList<>();
Sys_union union = unique(unions, unionCode, "工会编码", errors);
View_user user = unique(users, loginname, "工号", errors);
Sys_role role = unique(roles, roleCode, "角色编码", errors);
if (StrUtil.isNotBlank(roleCode) && !roleCodes.contains(roleCode)) {
errors.add("角色编码【" + roleCode + "】不在允许导入的分工会干部角色范围内,请参照角色对照表");
}
if (!errors.isEmpty()) {
outcome(row, "失败", String.join(";", errors));
return null;
}
boolean secretary = RoleConstant.UNIT_PARTY_SECRETARY.name().equals(roleCode);
List<String> key = roleKey(user.getId(), role.getId(), union.getId(), secretary);
if (existingRoles.contains(key)) {
outcome(row, "跳过", "工号【" + loginname + "】已分配角色【" + roleCode + "】"
+ (secretary ? "(工会编码【" + unionCode + "】)" : "") + ",保留原有记录(含禁用关系)");
return null;
}
if (!union.getId().equals(user.getUnionId())) {
errors.add("工号【" + loginname + "】所属工会为【" + StrUtil.blankToDefault(user.getUnionName(), "未分配工会")
+ "】,与填写的工会【" + union.getName() + "(" + unionCode + ")】不一致");
}
if (StrUtil.isNotBlank(j) && !terms.contains(j)) {
errors.add("届次编码【" + j + "】不存在,请参照届次对照表或留空");
}
if (existingCadres.contains(Arrays.asList(user.getId(), roleCode, union.getId()))) {
outcome(row, "跳过", "工号【" + loginname + "】在工会【" + unionCode + "】已有角色【" + roleCode
+ "】的在任或待审核干部记录,请通过原记录处理");
return null;
}
List<String> unitIds = new ArrayList<>();
String unitCodes = row.getString("unitCodes");
if (secretary) {
List<String> codes = splitUnitCodes(unitCodes);
if (codes.isEmpty()) {
errors.add("角色【二级党委书记】必须填写所属单位编码,请参照所属单位对照表");
}
for (String code : codes) {
List<Sys_unit> matches = units.getOrDefault(code, List.of());
List<Sys_unit> valid = matches.stream().filter(unit -> union.getId().equals(unit.getUnionId())
&& Integer.valueOf(2).equals(unit.getUnitLevel())).toList();
if (matches.isEmpty()) {
errors.add("所属单位编码【" + code + "】不存在");
} else if (valid.isEmpty()) {
boolean inUnion = matches.stream().anyMatch(unit -> union.getId().equals(unit.getUnionId()));
errors.add(inUnion ? "所属单位编码【" + code + "】属于工会【" + unionCode + "】,但单位级别不是二级"
: "所属单位编码【" + code + "】不属于填写的工会【" + union.getName() + "(" + unionCode + ")】");
} else if (valid.size() > 1) {
errors.add("所属单位编码【" + code + "】在工会【" + unionCode + "】下匹配到" + valid.size() + "个二级单位,编码不唯一");
} else {
unitIds.add(valid.get(0).getId());
}
}
} else if (StrUtil.isNotBlank(unitCodes)) {
errors.add("角色【" + roleCode + "】不是二级党委书记,所属单位编码【" + unitCodes + "】应留空");
}
if (!errors.isEmpty()) {
outcome(row, "失败", String.join(";", errors));
return null;
}
Integer previousRow = fileRoles.putIfAbsent(key, row.getInt("rowNumber"));
if (previousRow != null) {
outcome(row, "跳过", "与本文件第" + previousRow + "行的人员角色授权重复");
return null;
}
Sys_union_cadre cadre = new Sys_union_cadre();
cadre.setId(R.UU32());
cadre.setUserId(user.getId());
cadre.setUnionId(union.getId());
cadre.setMobile(user.getMobile());
cadre.setUnionName(user.getUnionName());
cadre.setLoginName(user.getLoginname());
cadre.setUserName(user.getUsername());
cadre.setRoleCode(roleCode);
cadre.setJ(j);
cadre.setApplyDate(new Date());
cadre.setIsServing(true);
cadre.setIsJoin(true);
// fastInsert不执行实体插入拦截器,显式补齐主键及审计字段。
cadre.setCreatedBy(operator);
cadre.setUpdatedBy(operator);
cadre.setCreatedAt(System.currentTimeMillis());
cadre.setUpdatedAt(cadre.getCreatedAt());
cadre.setDelFlag(false);
List<Sys_user_role> relations = new ArrayList<>();
for (String unitId : secretary ? unitIds : java.util.Collections.singletonList((String) null)) {
Sys_user_role relation = new Sys_user_role();
relation.setUserId(user.getId());
relation.setRoleId(role.getId());
relation.setUnionId(union.getId());
relation.setUnitId(unitId);
relations.add(relation);
}
return new ImportEntry(row, cadre, relations);
}
private void saveBatch(List<ImportEntry> entries) {
if (entries.isEmpty()) {
return;
}
try {
// 两张表各批量写入一次,同一事务保证干部记录和角色授权同时生效。
Trans.exec((Atom) () -> {
dao.fastInsert(entries.stream().map(entry -> entry.cadre).toList());
dao.fastInsert(entries.stream().flatMap(entry -> entry.relations.stream()).toList());
});
entries.forEach(entry -> outcome(entry.row, "成功", "添加成功"));
} catch (Exception e) {
if (entries.size() > 1) {
// 仅保存异常时拆分批次定位坏行,正常导入不产生逐行写入。
int middle = entries.size() / 2;
saveBatch(entries.subList(0, middle));
saveBatch(entries.subList(middle, entries.size()));
} else {
NutMap row = entries.get(0).row;
log.error("导入分工会干部保存失败,行号:{},工号:{},角色编码:{}",
row.getInt("rowNumber"), row.getString("loginname"), row.getString("roleCode"), e);
outcome(row, "失败", saveFailure(e));
}
}
}
private String saveFailure(Exception error) {
for (Throwable cause = error; cause != null; cause = cause.getCause()) {
if (cause instanceof SQLException) {
SQLException sql = (SQLException) cause;
String state = sql.getSQLState();
if ("23505".equals(state) || sql.getErrorCode() == 1062) {
return "保存时发生唯一键冲突,可能已有相同干部或角色授权记录;本行已回滚";
}
if ("22001".equals(state) || sql.getErrorCode() == 1406) {
return "干部信息字段超出数据库长度限制,请检查工号、姓名、手机号、工会名称及届次长度;本行已回滚";
}
if ("23502".equals(state) || sql.getErrorCode() == 1048 || sql.getErrorCode() == 1364) {
return "干部记录或角色授权缺少数据库要求的必填值,请检查该人员的基础信息及干部表必填字段;本行已回滚";
}
if ("23503".equals(state) || sql.getErrorCode() == 1452) {
return "人员、工会、角色或所属单位的关联记录已不存在,请核对对应系统数据;本行已回滚";
}
if (state != null && state.startsWith("23")) {
return "干部记录或角色授权违反数据库必填、关联或唯一性约束,请核对人员、工会和角色数据;本行已回滚";
}
if (state != null && state.startsWith("08")) {
return "保存干部及角色授权时数据库连接异常,本行未完成导入,可稍后重新导入";
}
if (state != null && state.startsWith("40")) {
return "保存干部及角色授权时发生事务冲突,本行已回滚,可重新导入";
}
}
}
return "干部记录或角色授权写入异常,本行未完成导入;请管理员按Excel行号、工号及角色编码查看导入日志";
}
private static class ImportEntry {
private final NutMap row;
private final Sys_union_cadre cadre;
private final List<Sys_user_role> relations;
private ImportEntry(NutMap row, Sys_union_cadre cadre, List<Sys_user_role> relations) {
this.row = row;
this.cadre = cadre;
this.relations = relations;
}
}
private void outcome(NutMap row, String status, String message) {
row.setv("status", status).setv("message", message);
}
private String cellText(Row row, int column, DataFormatter formatter) {
Cell cell = row == null ? null : row.getCell(column);
if (cell != null && cell.getCellType() == CellType.FORMULA) {
throw new IllegalArgumentException("导入内容不支持公式");
}
return formatter.formatCellValue(cell).trim();
}
private Sheet createSheet(Workbook workbook, String name, String... headers) {
Sheet sheet = workbook.createSheet(name);
Row header = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
header.createCell(i).setCellValue(headers[i]);
sheet.setColumnWidth(i, 30 * 256);
}
sheet.createFreezePane(0, 1);
return sheet;
}
private void append(Sheet sheet, String... values) {
Row row = sheet.createRow(sheet.getLastRowNum() + 1);
for (int i = 0; i < values.length; i++) {
row.createCell(i).setCellValue(values[i] == null ? "" : values[i]);
}
}
}
@@ -556,6 +556,28 @@ public class SysUnionController {
return Result.success(); return Result.success();
} }
@At
@ApiOperation("修改分工会干部届次")
@SaCheckPermission("sys.manager.union.branchOfficer")
public Result updateBranchUnionUserJ(String id, String j) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
return Result.error("仅超级管理员可编辑");
}
if (StrUtil.isBlank(id)) {
return Result.error("请选择干部记录");
}
Sys_union_cadre unionCadre = dao.fetch(Sys_union_cadre.class, id);
if (Lang.isEmpty(unionCadre)) {
return Result.error("未找到对应干部记录");
}
if (StrUtil.isNotBlank(j) && sysDictService.getSubListByCode("TEACHER_CONGRESS_J").stream()
.noneMatch(item -> j.equals(item.getCode()))) {
return Result.error("请选择有效届次");
}
dao.update(Sys_union_cadre.class, Chain.make("j", StrUtil.isBlank(j) ? "" : j), Cnd.where("id", "=", id));
return Result.success();
}
@At @At
@ApiOperation("分工会干部离任") @ApiOperation("分工会干部离任")
@SaCheckPermission("sys.manager.union.branchOfficer") @SaCheckPermission("sys.manager.union.branchOfficer")
@@ -22,7 +22,6 @@ import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.sys.services.SysRoleService; import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.sys.services.SysUnitService; import com.budwk.app.sys.services.SysUnitService;
import com.budwk.app.sys.services.SysUserService; import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.sys.utils.DataCenterUtil;
import com.budwk.app.sys.views.View_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.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil; import com.budwk.app.web.commons.auth.utils.SecurityUtil;
@@ -215,9 +214,9 @@ public class SysUnitController {
if (AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) { if (AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if (Strings.isBlank(pid)) { if (Strings.isBlank(pid)) {
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId()); cnd.and("parentId", "=", "").or("parentId", "is", null);
} else { } else {
cnd.and("parentId", "=", pid).and("id", "<>", pid); cnd.and("parentId", "=", pid);
} }
cnd.asc("location").asc("path"); cnd.asc("location").asc("path");
list = sysUnitService.query(cnd); list = sysUnitService.query(cnd);
@@ -228,9 +227,9 @@ public class SysUnitController {
} else { } else {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if (Strings.isBlank(pid)) { if (Strings.isBlank(pid)) {
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId()); cnd.and("parentId", "=", "").or("parentId", "is", null);
} else { } else {
cnd.and("parentId", "=", pid).and("id", "<>", pid); cnd.and("parentId", "=", pid);
} }
cnd.asc("location").asc("path"); cnd.asc("location").asc("path");
list = sysUnitService.query(cnd); list = sysUnitService.query(cnd);
@@ -259,9 +258,9 @@ public class SysUnitController {
if (StpUtil.hasRole("SYSADMIN")) { if (StpUtil.hasRole("SYSADMIN")) {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if (Strings.isBlank(pid)) { if (Strings.isBlank(pid)) {
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId()); cnd.and("parentId", "=", "").or("parentId", "is", null);
} else { } else {
cnd.and("parentId", "=", pid).and("id", "<>", pid); cnd.and("parentId", "=", pid);
} }
cnd.asc("location").asc("path"); cnd.asc("location").asc("path");
list = sysUnitService.query(cnd); list = sysUnitService.query(cnd);
@@ -272,9 +271,9 @@ public class SysUnitController {
} else { } else {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if (Strings.isBlank(pid)) { if (Strings.isBlank(pid)) {
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId()); cnd.and("parentId", "=", "").or("parentId", "is", null);
} else { } else {
cnd.and("parentId", "=", pid).and("id", "<>", pid); cnd.and("parentId", "=", pid);
} }
cnd.asc("location").asc("path"); cnd.asc("location").asc("path");
list = sysUnitService.query(cnd); list = sysUnitService.query(cnd);
@@ -296,27 +295,37 @@ public class SysUnitController {
} }
} }
/**
* 获取以指定单位为根的单位树。
*
* @param pid 根单位 ID;未传时使用系统根单位 0
* @param req 当前 HTTP 请求
* @return Result 对象;code 为 0 时 data 为树数组,节点包含 id、parentId、name、children、unitTypeCode;
* unitTypeCode 为 0 表示其他类、1 表示部门类,历史空值仅在返回时按 0 展示
*/
@At("/tree") @At("/tree")
@Ok("json") @Ok("json")
@SaCheckLogin @SaCheckLogin
public Object tree(@Param("pid") String pid, HttpServletRequest req) { public Object tree(@Param("pid") String pid, HttpServletRequest req) {
try { try {
String rootId = StrUtil.blankToDefault(pid, "0");
String virtualRootId = "root"; String virtualRootId = "root";
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
cnd.asc("unitcode"); cnd.asc("unitcode");
List<Sys_unit> list = sysUnitService.query(cnd); List<Sys_unit> list = sysUnitService.query(cnd);
String rootId = StrUtil.isBlank(pid) ? DataCenterUtil.findRootUnit(list).getId() : pid;
List<TreeNode<String>> nodeList = CollUtil.newArrayList(); List<TreeNode<String>> nodeList = CollUtil.newArrayList();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
Sys_unit unit = list.get(i); Sys_unit unit = list.get(i);
/* /*
* 动态查询根挂到虚拟根下,兼容根节点父级为空或指向自身的数据。 * 单位根节点存在 id 与 parentId 都为 0 的自引用数据。
* 构建树时把当前查询根挂到虚拟根下,避免“中国地质大学”和 parentId=0 的学院被构造成同级。
*/ */
String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId(); String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId();
nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i) nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i)
.setExtra( .setExtra(
Map.of( Map.of(
// 历史手工新建单位可能未设置类型,展示时按其他类处理,避免空值使整棵树加载失败。
"unitTypeCode", unit.getUnitTypeCode() == null ? 0 : unit.getUnitTypeCode() "unitTypeCode", unit.getUnitTypeCode() == null ? 0 : unit.getUnitTypeCode()
) )
)); ));
@@ -324,23 +333,37 @@ public class SysUnitController {
List<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId); List<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId);
return Result.success(treeList); return Result.success(treeList);
} catch (Exception e) { } catch (Exception e) {
log.error("加载单位树失败", e);
return Result.error(); return Result.error();
} }
} }
/**
* 新建当前单位的下设单位。
*
* @param unit 表单数据;name 为单位名称,unitcode 为唯一编码,unitLevel 为单位等级,unionId 为所属工会;
* unitTypeCode 为部门类别,0 表示其他类、1 表示部门类,未传时由 service 按其他类保存
* @param parentId 当前选中上级单位的 ID,必须对应已存在的单位
* @param req 当前 HTTP 请求
* @return Result 对象;code 为 0 表示保存成功,非 0 表示失败,msg 为提示信息,data 为空
*/
@At @At
@Ok("json") @Ok("json")
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("sys.manager.unit.add") @SaCheckPermission("sys.manager.unit.add")
@SLog(tag = "新建单位", msg = "单位名称:${args[0].name}") @SLog(tag = "新建单位", msg = "单位名称:${args[0].name}")
public Object addDo(@Param("..") Sys_unit unit, @Param("parentId") String parentId, HttpServletRequest req) { public Object addDo(@Param("..") Sys_unit unit, @Param("parentId") String parentId, HttpServletRequest req) {
try { try {
if ("root".equals(parentId)) { if (Strings.isBlank(unit.getName()) || Strings.isBlank(unit.getUnitcode()) || Strings.isBlank(parentId) || "root".equals(parentId)) {
parentId = ""; return Result.error("单位名称、单位编码和上级单位不能为空");
} }
unit.setCreatedBy(SecurityUtil.getUserId()); unit.setCreatedBy(SecurityUtil.getUserId());
sysUnitService.save(unit, parentId); sysUnitService.save(unit, parentId);
return Result.success(); return Result.success();
} catch (BaseException e) {
return Result.error(e.getMessage());
} catch (Exception e) { } catch (Exception e) {
log.error("新建单位失败", e);
return Result.error(); return Result.error();
} }
} }
@@ -210,9 +210,9 @@ public class Sys_user extends BaseModel implements Serializable {
private String dutySituation; private String dutySituation;
@Column @Column
@Comment("教职工类别码") @Comment("人员类型")
@ColDefine(type = ColType.VARCHAR, width = 30) @ColDefine(type = ColType.VARCHAR, width = 30)
@DataCenterColumn(name = "教职工类别码", key = "RYLX", dict = "USER_PERSON_TYPE") @DataCenterColumn(name = "人员类型", key = "RYLX", dict = "USER_PERSON_TYPE")
private String personType; private String personType;
@Column @Column
@@ -3,5 +3,17 @@ package com.budwk.app.sys.services;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_activity;
import java.util.List;
public interface SysHomeActivityService extends BaseService<Sys_home_activity> { public interface SysHomeActivityService extends BaseService<Sys_home_activity> {
/**
* 获取指定用户有权查看的已启用首页活动。
*
* @param userId 当前登录用户ID,用于人员分组及自定义SQL的可见范围校验
* @param includeEnded true包含已结束活动并按状态、置顶和开始时间排序;false保持原有过滤和排序
* @return 活动实体列表,包含id、name、cover、url、h5Url、startDate、endDate等展示字段,
* 不返回classPath和allowUserSql内部配置
*/
List<Sys_home_activity> listHomeActivity(String userId, boolean includeEnded);
} }
@@ -351,8 +351,12 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
// 6. 处理其他任务 // 6. 处理其他任务
// 6.1 更新提案的校领导角色,发送订阅 // 6.1 更新提案的校领导角色,发送订阅
ProposalConfig config = dao.fetch(ProposalConfig.class, Cnd.where("delFlag", "=", false).desc("updatedAt")); ProposalConfig config = dao.fetch(ProposalConfig.class, Cnd.where("delFlag", "=", false).desc("updatedAt"));
for (String unitId : config.getSchoolLeaderUnitIds()) { if (config == null || config.getSchoolLeaderUnitIds() == null || config.getSchoolLeaderUnitIds().isEmpty()) {
RoleEventPublisher.broadcast(new RoleEventMsg(unitId, RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name(), RoleEventMsg.RENEW_ROLE)); log.warn("未配置提案校领导单位,跳过校领导角色刷新,继续完成人员全量更新");
} else {
for (String unitId : config.getSchoolLeaderUnitIds()) {
RoleEventPublisher.broadcast(new RoleEventMsg(unitId, RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name(), RoleEventMsg.RENEW_ROLE));
}
} }
/* /*
@@ -130,7 +130,7 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
rawDataList.addAll(DataCenterUtil.pullData(getDmpUrl(DMP_TEACHER_KEY))); rawDataList.addAll(DataCenterUtil.pullData(getDmpUrl(DMP_TEACHER_KEY)));
// 将浙师大字段转为现有中间表映射使用的键,保留Token模式的字段协议。 // 将浙师大字段转为现有中间表映射使用的键,保留Token模式的字段协议。
Map<String, String> fieldAliases = Map.of("XBMC", "XB", "SJHM", "YDDH", Map<String, String> fieldAliases = Map.of("XBMC", "XB", "SJHM", "YDDH",
"LXRQ", "LXNY", "DQZTMC", "DQZT", "YRFSDM", "RYLX", "SZDWDM", "SZDWH"); "LXRQ", "LXNY", "DQZTMC", "DQZT", "YRFSDM", "RYLX", "SZDWDM", "SZDWH", "MZDM", "MZM");
for (JSONObject raw : rawDataList) { for (JSONObject raw : rawDataList) {
fieldAliases.forEach((source, target) -> raw.set(target, raw.get(source))); fieldAliases.forEach((source, target) -> raw.set(target, raw.get(source)));
} }
@@ -229,9 +229,8 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
sysUser.setUnitName(resolvedUnit.getName()); sysUser.setUnitName(resolvedUnit.getName());
sysUser.setUnitPath(resolvedUnit.getPath()); sysUser.setUnitPath(resolvedUnit.getPath());
} }
if (!dataCenterProperties.isTokenEnabled() if (resolvedUnit == null || StrUtil.isBlank(resolvedUnit.getPath())) {
&& (resolvedUnit == null || StrUtil.isBlank(resolvedUnit.getPath()))) { log.warn("人员{}所属机构{}不存在或路径为空,保留当前机构号并继续拉取", sysUser.getLoginname(), sysUser.getUnitId());
throw new BaseException("人员{}所属机构不存在或路径为空,中止本次同步", sysUser.getLoginname());
} }
// 设置拉取时间 // 设置拉取时间
@@ -1,15 +1,87 @@
package com.budwk.app.sys.services.impl; package com.budwk.app.sys.services.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_home_activity; import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.sys.services.SysHomeActivityService; import com.budwk.app.sys.services.SysHomeActivityService;
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
@IocBean(args = {"refer:dao"}) @IocBean(args = {"refer:dao"})
public class SysHomeActivityServiceImpl extends BaseServiceImpl<Sys_home_activity> implements SysHomeActivityService { public class SysHomeActivityServiceImpl extends BaseServiceImpl<Sys_home_activity> implements SysHomeActivityService {
@Inject
private ActivityBasicScopeService activityBasicScopeService;
public SysHomeActivityServiceImpl(Dao dao) { public SysHomeActivityServiceImpl(Dao dao) {
super(dao); super(dao);
} }
/**
* 沿用首页原有的启用及人员可见范围校验,仅在调用方明确要求时展示已结束活动。
* 参数和返回结构见服务接口;查询过程不更新活动配置。
*/
@Override
public List<Sys_home_activity> listHomeActivity(String userId, boolean includeEnded) {
FieldFilter fieldFilter = FieldFilter.locked(Sys_home_activity.class, "classPath");
List<Sys_home_activity> list = Daos.ext(dao(), fieldFilter).query(Sys_home_activity.class,
Cnd.where("enable", "=", 1).desc("top"));
List<Sys_home_activity> allowActivityList = new ArrayList<>();
// 同一次请求使用同一个时间点,保证过滤与排序对活动是否结束的判断一致。
Date today = DateUtil.date();
for (Sys_home_activity activity : list) {
// 未传includeEnded的既有调用继续过滤已结束活动,保留原来的日期比较口径。
if (!includeEnded && DateUtil.compare(today, activity.getEndDate()) > 0) {
continue;
}
Integer allowUserGroupId = activity.getAllowUserGroupId();
String allowUserSql = activity.getAllowUserSql();
// 自定义SQL仅用于服务端判断可见范围,禁止随活动列表返回前端。
activity.setAllowUserSql(null);
if (allowUserGroupId == null && StrUtil.isBlank(allowUserSql)) {
allowActivityList.add(activity);
continue;
}
if (allowUserGroupId != null) {
if (activityBasicScopeService.isUserInGroup(allowUserGroupId, userId)) {
allowActivityList.add(activity);
continue;
}
}
if (StrUtil.isNotBlank(allowUserSql)) {
Sql sql = Sqls.create(allowUserSql).setParam("userId", userId);
sql.setCallback(Sqls.callback.map());
dao().execute(sql);
NutMap nutMap = (NutMap) sql.getResult();
if (Lang.isNotEmpty(nutMap) && StrUtil.isNotBlank(nutMap.getString("userId"))) {
allowActivityList.add(activity);
}
}
}
if (includeEnded) {
// 未结束活动整体在前,已结束置顶活动也不能越组;组内置顶优先,再按开始时间倒序,空开始时间排后。
allowActivityList.sort(Comparator
.comparing((Sys_home_activity activity) -> DateUtil.compare(today, activity.getEndDate()) > 0)
.thenComparing(activity -> Boolean.TRUE.equals(activity.getTop()), Comparator.reverseOrder())
.thenComparing(Sys_home_activity::getStartDate, Comparator.nullsLast(Comparator.reverseOrder())));
}
return allowActivityList;
}
} }
@@ -25,6 +25,7 @@ import org.nutz.integration.jedis.JedisAgent;
import org.nutz.integration.jedis.RedisService; import org.nutz.integration.jedis.RedisService;
import org.nutz.integration.jedis.pubsub.PubSubService; import org.nutz.integration.jedis.pubsub.PubSubService;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json; import org.nutz.json.Json;
@@ -62,6 +63,8 @@ public class SysMsgServiceImpl extends BaseServiceImpl<Sys_msg> implements SysMs
private ManyAddOrRenewUtil manyAddOrRenewUtil; private ManyAddOrRenewUtil manyAddOrRenewUtil;
@Inject @Inject
private SmsService smsService; private SmsService smsService;
@Inject
private PropertiesProxy conf;
private static NutMap typeMap = NutMap.NEW().addv("system", "系统消息").addv("user", "用户消息"); private static NutMap typeMap = NutMap.NEW().addv("system", "系统消息").addv("user", "用户消息");
@@ -106,7 +109,10 @@ public class SysMsgServiceImpl extends BaseServiceImpl<Sys_msg> implements SysMs
ThreadUtil.execute(() -> { ThreadUtil.execute(() -> {
for (String loginName : loginNames) { for (String loginName : loginNames) {
smsService.sendSmsByAccount(loginName,sysMsg.getNote()); smsService.sendSmsByAccount(loginName,sysMsg.getNote());
smsService.sendWechatTextByAccountOrMobile(loginName,sysMsg.getNote()); if (!(Strings.isNotBlank(conf.get("custom.msg.platform.app-id"))
&& conf.getBoolean("msg.platform.IntelligenceMode", false))) {
smsService.sendWechatTextByAccountOrMobile(loginName,sysMsg.getNote());
}
} }
}); });
@@ -30,6 +30,7 @@ import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql; import org.nutz.dao.sql.Sql;
import org.nutz.integration.jedis.RedisService; import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop; import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang; import org.nutz.lang.Lang;
@@ -67,6 +68,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
private RedisService redisService; private RedisService redisService;
@Inject @Inject
private ValidateService validateService; private ValidateService validateService;
@Inject
private PropertiesProxy conf;
@Override @Override
@CacheResult(cacheKey = "${userId}_getPermissionList") @CacheResult(cacheKey = "${userId}_getPermissionList")
@@ -359,10 +362,9 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
// base64解码密码 // base64解码密码
String decodePwd = Base64Decoder.decodeStr(passowrd); String decodePwd = Base64Decoder.decodeStr(passowrd);
String hashedPassword = PwdUtil.getPassword(decodePwd, user.getSalt()); String hashedPassword = PwdUtil.getPassword(decodePwd, user.getSalt());
if (!Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) { if (!"dev".equals(conf.get("nutz.profiles.active"))
// if (Globals.sso) { && !Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
// throw new BaseException("用户名或者密码不正确"); throw new BaseException("用户名或者密码不正确");
// }
} }
user = this.fetchLinks(user, "unit"); user = this.fetchLinks(user, "unit");
if (Lang.isNotEmpty(user.getUnit()) && StrUtil.isNotBlank(user.getUnit().getUnionId())) { if (Lang.isNotEmpty(user.getUnit()) && StrUtil.isNotBlank(user.getUnit().getUnionId())) {
@@ -59,12 +59,8 @@ public class Globals {
private SysTaskService sysTaskService; private SysTaskService sysTaskService;
@Inject @Inject
private PropertiesProxy conf; private PropertiesProxy conf;
private static String productionAppDomain;
public void init() { public void init() {
if ("prd".equalsIgnoreCase(conf.get("nutz.profiles.active"))) {
productionAppDomain = conf.get("custom.app-domain");
}
initSysConfig(sysConfigService); initSysConfig(sysConfigService);
initRoute(sysRouteService); initRoute(sysRouteService);
initTask(sysTaskService); initTask(sysTaskService);
@@ -99,9 +95,6 @@ public class Globals {
default -> Globals.MyConfig.put(sysConfig.getConfigKey(), sysConfig.getConfigValue()); default -> Globals.MyConfig.put(sysConfig.getConfigKey(), sysConfig.getConfigValue());
} }
} }
if (Strings.isNotBlank(productionAppDomain)) {
Globals.AppDomain = productionAppDomain;
}
} }
public static void initRoute(SysRouteService sysRouteService) { public static void initRoute(SysRouteService sysRouteService) {
@@ -10,7 +10,6 @@ import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log; import org.nutz.log.Log;
import org.nutz.log.Logs; import org.nutz.log.Logs;
import org.nutz.plugins.mvc.websocket.AbstractWsEndpoint; import org.nutz.plugins.mvc.websocket.AbstractWsEndpoint;
import org.nutz.plugins.mvc.websocket.NutWsConfigurator;
import org.nutz.plugins.mvc.websocket.WsHandler; import org.nutz.plugins.mvc.websocket.WsHandler;
import redis.clients.jedis.*; import redis.clients.jedis.*;
@@ -21,7 +20,7 @@ import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ServerEndpoint(value = "/websocket", configurator = NutWsConfigurator.class) @ServerEndpoint(value = "/websocket", configurator = WkWsConfigurator.class)
@IocBean(create = "init") // 使用NutWsConfigurator的必备条件 @IocBean(create = "init") // 使用NutWsConfigurator的必备条件
public class WkWebSocket extends AbstractWsEndpoint implements PubSub { public class WkWebSocket extends AbstractWsEndpoint implements PubSub {
protected static final Log log = Logs.get(); protected static final Log log = Logs.get();
@@ -0,0 +1,20 @@
package com.budwk.app.web.commons.ext.websocket;
import org.nutz.plugins.mvc.websocket.NutWsConfigurator;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
public class WkWsConfigurator extends NutWsConfigurator {
@Override
public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
// WebSocket升级不一定经过Nutz请求链,只使用当前握手的会话,避免读取已回收的MVC请求。
Object session = request.getHttpSession();
if (session == null) {
config.getUserProperties().remove("HttpSession");
} else {
config.getUserProperties().put("HttpSession", session);
}
}
}
@@ -163,6 +163,15 @@ public class WkFailProcessor extends ViewProcessor {
*/ */
private void notLoginRedirect(HttpServletRequest request, HttpServletResponse response) throws Throwable { private void notLoginRedirect(HttpServletRequest request, HttpServletResponse response) throws Throwable {
Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION); Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
if (Globals.sso) {
String tokenName = cn.dev33.satoken.stp.StpUtil.getTokenName();
boolean tokenCookiePresent = request.getCookies() != null && java.util.Arrays.stream(request.getCookies())
.anyMatch(cookie -> tokenName.equals(cookie.getName()) && StrUtil.isNotBlank(cookie.getValue()));
log.infof("[CAS诊断] 未登录跳转 uri=%s, sessionAssertion=%s, requestedSessionValid=%s, tokenCookiePresent=%s, tokenHeaderPresent=%s, tokenParameterPresent=%s, secure=%s, appDomain=%s",
request.getRequestURI(), assertion != null && assertion.getPrincipal() != null,
request.isRequestedSessionIdValid(), tokenCookiePresent, StrUtil.isNotBlank(request.getHeader(tokenName)),
StrUtil.isNotBlank(request.getParameter(tokenName)), request.isSecure(), Globals.AppDomain);
}
if (assertion != null && assertion.getPrincipal() != null) { if (assertion != null && assertion.getPrincipal() != null) {
// //判断cas里面是否有用户名 那么造成的原因就是系统中没他的信息 // //判断cas里面是否有用户名 那么造成的原因就是系统中没他的信息
// //就是cas已经认证了 但是本地系统没有认证 // //就是cas已经认证了 但是本地系统没有认证
@@ -189,7 +198,7 @@ public class WkFailProcessor extends ViewProcessor {
if (Globals.sso) { if (Globals.sso) {
//1.判断是否为企业微信浏览器并且对接了企业微信 //1.判断是否为企业微信浏览器并且对接了企业微信
if (browserPlatform == BrowserPlatform.QI_YE_WEI_XIN && propertiesProxy.getBoolean("wxwork.enable", false) if (browserPlatform == BrowserPlatform.QI_YE_WEI_XIN && propertiesProxy.getBoolean("wxwork.enable", false)
&& "prd".equalsIgnoreCase(propertiesProxy.get("nutz.profiles.active"))) { && "/platform/qywechat/getCode".equals(propertiesProxy.get("wxwork.redirectUri"))) {
new ServerRedirectView("/platform/qywechat/oauth?redirect=" + redirect).render(request, response, null); new ServerRedirectView("/platform/qywechat/oauth?redirect=" + redirect).render(request, response, null);
} else if (browserPlatform == BrowserPlatform.QI_YE_WEI_XIN && propertiesProxy.getBoolean("wxwork.enable", false)) { } else if (browserPlatform == BrowserPlatform.QI_YE_WEI_XIN && propertiesProxy.getBoolean("wxwork.enable", false)) {
//进行企业微信授权 //进行企业微信授权
@@ -54,9 +54,8 @@ public class ActivityBasicSettingsController {
if (parentId != null) { if (parentId != null) {
parentId.setChild(child(parentId.getId())); parentId.setChild(child(parentId.getId()));
list.add(parentId); list.add(parentId);
return Result.success().addData(list);
} }
return Result.success(); return Result.success(list);
} }
private List<ActivityBasicSettings> child(String parentId) { private List<ActivityBasicSettings> child(String parentId) {
@@ -73,6 +72,9 @@ public class ActivityBasicSettingsController {
Cnd cnd = Cnd.NEW(); Cnd cnd = Cnd.NEW();
if (StrUtil.isBlank(parentId)) { if (StrUtil.isBlank(parentId)) {
ActivityBasicSettings rootSetting = dao.fetch(ActivityBasicSettings.class, Cnd.where("parentId", "=", 0)); ActivityBasicSettings rootSetting = dao.fetch(ActivityBasicSettings.class, Cnd.where("parentId", "=", 0));
if (rootSetting == null) {
return Result.success(new Pagination<ActivityBasicSettings>(pageForm.getPageNumber(), pageForm.getPageSize(), 0, new ArrayList<ActivityBasicSettings>()));
}
cnd.and("parentId", "=", rootSetting.getId()); cnd.and("parentId", "=", rootSetting.getId());
} else { } else {
cnd.and("parentId", "=", parentId); cnd.and("parentId", "=", parentId);
@@ -116,7 +118,13 @@ public class ActivityBasicSettingsController {
@At @At
public Result getActivityTwoLevelType(String code) { public Result getActivityTwoLevelType(String code) {
if (StrUtil.isBlank(code)) {
return Result.success(new ArrayList<ActivityBasicSettings>());
}
ActivityBasicSettings fetch = dao.fetch(ActivityBasicSettings.class, Cnd.where("code", "=", code)); ActivityBasicSettings fetch = dao.fetch(ActivityBasicSettings.class, Cnd.where("code", "=", code));
if (fetch == null) {
return Result.success(new ArrayList<ActivityBasicSettings>());
}
List<ActivityBasicSettings> query = dao.query(ActivityBasicSettings.class, Cnd.where("parentId", "=", fetch.getId()).asc("code")); List<ActivityBasicSettings> query = dao.query(ActivityBasicSettings.class, Cnd.where("parentId", "=", fetch.getId()).asc("code"));
return Result.success(query); return Result.success(query);
} }
@@ -0,0 +1,35 @@
package com.budwk.app.zhgh.activity.basic.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnion;
import org.nutz.lang.util.NutMap;
/**
* 活动工会资料同步及组成单位维护,保留活动模块独立维护的临时分工会。
*/
public interface ActivityBasicUnionService extends BaseService<ActivityBasicUnion> {
/**
* 无请求参数,按 sys_union.id 新增缺少的活动工会,仅更新已有非临时工会的名称,不删除记录。
*
* @return NutMap;insertCount 为新增工会数,updateCount 为名称实际变更的工会数
*/
NutMap syncUnions();
/**
* 获取全部二级活动单位,不按现有分工会归属过滤候选项。
*
* @param unionId 当前活动分工会ID,用于回显已选组成单位
* @return NutMap;allUnits 为二级单位列表,selectUnitIds 为当前分工会已选二级单位ID列表
*/
NutMap getPartUnitTransferData(String unionId);
/**
* 设置当前活动分工会的组成单位,选中单位允许从其他活动分工会转入。
*
* @param unionId 当前活动分工会ID
* @param unitIds 二级活动单位ID数组,传空数组或 null 表示清空当前工会组成单位
* @return 无返回值;包含不存在或非二级单位的ID时抛出异常,不修改归属
*/
void setPartUnits(String unionId, String[] unitIds);
}
@@ -0,0 +1,19 @@
package com.budwk.app.zhgh.activity.basic.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnit;
import org.nutz.lang.util.NutMap;
/**
* 活动单位基础资料同步,活动工会归属仍由活动模块独立维护。
*/
public interface ActivityBasicUnitService extends BaseService<ActivityBasicUnit> {
/**
* 将系统单位同步到活动单位,不删除活动单位,不覆盖已有活动单位的工会归属。
*
* @return NutMap;insertCount 为新增单位数,updateCount 为更新基础资料的已有单位数,
* pendingUnionCount 为新增单位中未能匹配活动工会、需要配置归属的数量
*/
NutMap syncUnits();
}
@@ -0,0 +1,115 @@
package com.budwk.app.zhgh.activity.basic.service.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnion;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnit;
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicUnionService;
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.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class ActivityBasicUnionServiceImpl extends BaseServiceImpl<ActivityBasicUnion> implements ActivityBasicUnionService {
public ActivityBasicUnionServiceImpl(Dao dao) {
super(dao);
}
/**
* 无请求参数,按来源工会ID同步全部工会组织;返回新增数和名称实际变更数。
* 已有工会只更新名称及修改审计信息,不覆盖编码、联系方式、校区、组成单位和管理员关系。
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public NutMap syncUnions() {
List<Sys_union> sourceUnions = dao().query(Sys_union.class, Cnd.NEW());
Map<String, ActivityBasicUnion> existingUnions = dao().query(ActivityBasicUnion.class, Cnd.NEW()).stream()
.collect(Collectors.toMap(ActivityBasicUnion::getId, union -> union));
String operatorId = SecurityUtil.getUserId();
long updateTime = System.currentTimeMillis();
int insertCount = 0;
int updateCount = 0;
for (Sys_union sourceUnion : sourceUnions) {
if (StrUtil.isBlank(sourceUnion.getId())) {
throw new BaseException("工会组织存在空ID,本次同步已取消,请先检查工会组织资料");
}
ActivityBasicUnion existingUnion = existingUnions.get(sourceUnion.getId());
if (existingUnion == null) {
// 按列插入以避开实体UUID生成拦截器,保留来源ID,保证重复同步不会重复新增。
dao().insert(ActivityBasicUnion.class, Chain.make("id", sourceUnion.getId())
.add("name", sourceUnion.getName()).add("unionCode", sourceUnion.getUnionCode())
.add("telephone", sourceUnion.getTelephone()).add("campus", sourceUnion.getCampus())
.add("source", "sys").add("createdBy", operatorId).add("createdAt", updateTime)
.add("updatedBy", operatorId).add("updatedAt", updateTime).add("delFlag", false));
insertCount++;
} else if (!"activity".equals(existingUnion.getSource())
&& !Objects.equals(existingUnion.getName(), sourceUnion.getName())) {
// 临时分工会即使与来源ID意外相同也不覆盖;来源中已不存在的工会自然保留。
dao().update(ActivityBasicUnion.class, Chain.make("name", sourceUnion.getName())
.add("updatedBy", operatorId).add("updatedAt", updateTime),
Cnd.where("id", "=", sourceUnion.getId()));
updateCount++;
}
}
return NutMap.NEW().addv("insertCount", insertCount).addv("updateCount", updateCount);
}
/**
* 按单位层级查询全部二级活动单位,单位类别和现有工会归属不影响候选范围。
*
* @param unionId 当前活动分工会ID,仅用于计算回显的选中项
* @return NutMap;allUnits 为候选单位实体列表,selectUnitIds 为当前工会已选二级单位ID列表
*/
@Override
public NutMap getPartUnitTransferData(String unionId) {
List<ActivityBasicUnit> units = dao().query(ActivityBasicUnit.class,
Cnd.where("unitLevel", "=", 2).asc("unitcode"));
List<String> selectUnitIds = units.stream()
.filter(unit -> Objects.equals(unit.getUnionId(), unionId))
.map(ActivityBasicUnit::getId).toList();
return NutMap.NEW().addv("selectUnitIds", selectUnitIds).addv("allUnits", units);
}
/**
* 校验全部选中单位均为二级单位后,替换当前活动分工会的组成单位关系。
*
* @param unionId 当前活动分工会ID
* @param unitIds 二级活动单位ID数组,空数组或 null 表示清空组成单位
* @return 无返回值;无效单位参数在修改归属之前抛出异常
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void setPartUnits(String unionId, String[] unitIds) {
List<String> selectedIds = unitIds == null ? List.of() : Arrays.stream(unitIds).distinct().toList();
if (!selectedIds.isEmpty()) {
// 必须先完整校验再解除原归属,防止提交三级、空ID或不存在的单位时丢失已有组成单位。
if (selectedIds.stream().anyMatch(StrUtil::isBlank)
|| dao().count(ActivityBasicUnit.class,
Cnd.where("id", "in", selectedIds).and("unitLevel", "=", 2)) != selectedIds.size()) {
throw new BaseException("组成单位只能选择有效的二级单位,请刷新后重新选择");
}
}
// 保存时替换当前组成单位,历史误选的三级单位也随本次重新设置解除关联。
dao().update(ActivityBasicUnit.class, Chain.make("unionId", null), Cnd.where("unionId", "=", unionId));
if (!selectedIds.isEmpty()) {
// 允许将已属于其他活动分工会的二级单位转入,不增加原工会归属限制。
dao().update(ActivityBasicUnit.class, Chain.make("unionId", unionId),
Cnd.where("id", "in", selectedIds).and("unitLevel", "=", 2));
}
}
}
@@ -0,0 +1,93 @@
package com.budwk.app.zhgh.activity.basic.service.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_unit;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnion;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnit;
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicUnitService;
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.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class ActivityBasicUnitServiceImpl extends BaseServiceImpl<ActivityBasicUnit> implements ActivityBasicUnitService {
public ActivityBasicUnitServiceImpl(Dao dao) {
super(dao);
}
/**
* 无请求参数,按 sys_unit.id 同步全部系统单位;返回新增数、更新数和新增单位待配置活动工会数。
* 已有记录只更新基础字段,连原有的空工会归属也保留,避免覆盖活动模块人工维护的组成单位关系。
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public NutMap syncUnits() {
List<Sys_unit> sourceUnits = dao().query(Sys_unit.class, Cnd.NEW());
Set<String> existingIds = dao().query(ActivityBasicUnit.class, Cnd.NEW()).stream()
.map(ActivityBasicUnit::getId).collect(Collectors.toSet());
Set<String> activityUnionIds = dao().query(ActivityBasicUnion.class, Cnd.NEW()).stream()
.map(ActivityBasicUnion::getId).collect(Collectors.toSet());
int insertCount = 0;
int updateCount = 0;
int pendingUnionCount = 0;
String operatorId = SecurityUtil.getUserId();
long updateTime = System.currentTimeMillis();
for (Sys_unit sourceUnit : sourceUnits) {
if (StrUtil.isBlank(sourceUnit.getId())) {
throw new BaseException("系统单位存在空ID,本次同步已取消,请先检查系统单位资料");
}
Chain fields = buildBasicFields(sourceUnit)
.add("updatedBy", operatorId).add("updatedAt", updateTime);
if (existingIds.contains(sourceUnit.getId())) {
// 更新列中不包含 unionId、unionGroupId 和 id,保留现有归属及报名记录使用的单位ID。
dao().update(ActivityBasicUnit.class, fields, Cnd.where("id", "=", sourceUnit.getId()));
updateCount++;
} else {
// 新单位仅继承已存在于活动工会表的归属,不能将普通工会ID直接当作有效活动工会。
String unionId = StrUtil.isNotBlank(sourceUnit.getUnionId()) && activityUnionIds.contains(sourceUnit.getUnionId())
? sourceUnit.getUnionId() : null;
if (unionId == null) {
pendingUnionCount++;
}
fields.add("id", sourceUnit.getId()).add("unionId", unionId)
.add("createdBy", operatorId).add("createdAt", updateTime).add("delFlag", false);
// 按列插入避开实体的 UUID 生成拦截器,确保活动单位ID始终等于系统单位ID。
dao().insert(ActivityBasicUnit.class, fields);
existingIds.add(sourceUnit.getId());
insertCount++;
}
}
return NutMap.NEW().addv("insertCount", insertCount).addv("updateCount", updateCount)
.addv("pendingUnionCount", pendingUnionCount);
}
/**
* 只列出允许从系统单位更新的基础资料;工会、小组归属和审计创建信息不属于基础同步字段。
* 父级、路径与层级沿用源值,树展示需要的根节点适配在接口内存中完成,不改写单位关系。
*
* @param unit sys_unit 中的完整单位记录
* @return 可供 DAO 按列新增或更新的 Chain,不含单位ID和工会归属
*/
private Chain buildBasicFields(Sys_unit unit) {
return Chain.make("parentId", unit.getParentId()).add("path", unit.getPath())
.add("name", unit.getName()).add("aliasName", unit.getAliasName()).add("unitcode", unit.getUnitcode())
.add("note", unit.getNote()).add("address", unit.getAddress()).add("telephone", unit.getTelephone())
.add("email", unit.getEmail()).add("website", unit.getWebsite()).add("location", unit.getLocation())
.add("hasChildren", unit.isHasChildren()).add("logo", unit.getLogo()).add("unitLevel", unit.getUnitLevel())
.add("divisionCollegeCode", unit.getDivisionCollegeCode()).add("institutionType", unit.getInstitutionType())
.add("unitType", unit.getUnitType()).add("unitTypeCode", unit.getUnitTypeCode());
}
}
@@ -0,0 +1,40 @@
package com.budwk.app.zhgh.activity.sports.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import java.math.BigDecimal;
/** 一条获奖成绩的奖品人数归属,与积分分配独立;一人一次获奖对应一份奖品。 */
@Data
@EqualsAndHashCode(callSuper = true)
@Table("activity_results_prize")
@Comment("活动成绩奖品人数分配")
@TableIndexes({@Index(name = "ARP_RESULT_UNION", fields = {"resultId", "prizeUnionId"}, unique = true)})
public class ActivityResultsPrize extends BaseModel {
@Name
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@Comment("成绩主记录ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String resultId;
@Column
@Comment("领取奖品的正式分工会ID,对应sys_union")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String prizeUnionId;
@Column
@Comment("奖品领取工会名称快照")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String prizeUnionName;
@Column
@Comment("实际获奖人数,个人成绩合计为1,团体成绩合计等于获奖总人数")
@ColDefine(type = ColType.INT)
// 接收时保留原始数值精度,避免JSON直接绑定Integer时把3.5截断为3;保存前严格转为int范围整数。
private BigDecimal numberOfPeople;
}
@@ -0,0 +1,40 @@
package com.budwk.app.zhgh.activity.sports.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.*;
import java.math.BigDecimal;
/** 一次团体获奖在正式分工会之间的积分分配,不代表新增获奖或人数分配。 */
@Data
@EqualsAndHashCode(callSuper = true)
@Table("activity_results_score")
@Comment("活动成绩积分分配")
@TableIndexes({@Index(name = "ARS_RESULT_UNION", fields = {"resultId", "scoreUnionId"}, unique = true)})
public class ActivityResultsScore extends BaseModel {
@Name
@ColDefine(type = ColType.VARCHAR, width = 32)
private String id;
@Column
@Comment("成绩主记录ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String resultId;
@Column
@Comment("正式计分工会ID,对应sys_union")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String scoreUnionId;
@Column
@Comment("计分工会名称快照")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String scoreUnionName;
@Column
@Comment("分配积分,合计必须等于主成绩总积分")
@ColDefine(customType = "decimal(10,2)")
private BigDecimal integral;
}
@@ -649,8 +649,11 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
fillCourseResponsibles(courseList); fillCourseResponsibles(courseList);
courseList.forEach(c -> { courseList.forEach(c -> {
dao().fetchLinks(c, "^(courseTimeList)$", Cnd.NEW().asc("courseStartTime"));
if (c.getCourseTimeList() == null) {
c.setCourseTimeList(new ArrayList<>());
}
if (StrUtil.isNotBlank(c.getCourseType())) { if (StrUtil.isNotBlank(c.getCourseType())) {
dao().fetchLinks(c, "^(courseTimeList)$", Cnd.NEW().asc("courseStartTime"));
int courseCount = statisticsService.queryCourseCount(c.getId(), c.getCourseType()); int courseCount = statisticsService.queryCourseCount(c.getId(), c.getCourseType());
c.setHasRegisterNum(courseCount); c.setHasRegisterNum(courseCount);
int courseWaitCount = statisticsService.queryCourseWaitCount(c.getId(), c.getCourseType()); int courseWaitCount = statisticsService.queryCourseWaitCount(c.getId(), c.getCourseType());
@@ -0,0 +1,150 @@
package com.budwk.app.zhgh.club.controller.infoManage;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.sys.models.Sys_dict;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.zhgh.club.service.ClubRegisterImportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@IocBean
@At("/platform/club/infoManage/registerImport")
@Ok("json:full")
public class ClubRegisterImportController {
private static final String[] HEADERS = {"社团名称", "社团编码(选填)", "社团类型编码", "成立日期", "会长工号", "秘书长工号",
"发起人工号", "副会长工号(选填)", "副秘书长工号(选填)", "联系人工号(选填)", "会费标准(选填)",
"联系电话(选填)", "联系邮箱(选填)", "社团介绍及宗旨(选填)", "活动形式(选填)", "缩略图地址(选填)",
"申请成立报告文件ID(选填)", "章程草案文件ID(选填)", "经费管理办法文件ID(选填)", "年度计划文件ID(选填)", "其他附件文件ID(选填)"};
@Inject
private ClubRegisterImportService clubRegisterImportService;
@Inject
private SysDictService sysDictService;
@At
@Ok("void")
@SaCheckRole("SYSADMIN")
@SaCheckPermission("club.infoManage.manage")
public void downloadTemplate(HttpServletResponse response) {
Workbook workbook = new XSSFWorkbook();
Sheet data = sheet(workbook, "社团导入", HEADERS);
CellStyle style = workbook.createCellStyle();
style.setDataFormat(workbook.createDataFormat().getFormat("@"));
for (int i = 0; i < HEADERS.length; i++) data.setDefaultColumnStyle(i, style);
Sheet notes = sheet(workbook, "填写说明", "参数", "填写要求");
notes.setColumnWidth(1, 100 * 256);
append(notes, "导入规则", "仅读取第一个工作表,每行一个社团,最多1000行有效数据;保留表头,工号与编码按文本填写。");
append(notes, "必填", "社团名称、社团类型编码、成立日期、会长工号、秘书长工号、至少3名不同发起人工号。");
append(notes, "社团编码", "选填,留空按单个注册的年度编号规则生成;已有名称或编码直接跳过,不覆盖草稿、审批中或已解散记录。");
append(notes, "成立日期", "按yyyy-MM-dd填写,如2026-10-23;支持Excel日期单元格。");
append(notes, "人员", "使用系统内已有工号。会长和秘书长各1人;副职可选多人,用逗号分隔,理事机构人员不得重复。");
append(notes, "发起人", "至少3名不同人员,用逗号分隔;可与理事机构人员重合。");
append(notes, "联系人", "选填工号,电话及邮箱默认取人员资料;单独填写电话、邮箱时使用填写值。");
append(notes, "社团类型", "参照社团类型工作表填写编码,不填写名称。");
append(notes, "其他资料", "会费标准、介绍、活动形式、缩略图地址均选填;介绍及活动形式按纯文本导入。");
append(notes, "附件", "选填系统已上传文件的ID,多文件用逗号分隔,每类最多5个;Excel不上传附件本身,留空可后续在维护页面补充。");
append(notes, "直接通过", "保存社团、发起人、理事会员、入会时间和年度缴费记录,授予社团角色;直接通过,不生成审批任务。");
append(notes, "导入结果", "逐行独立保存,已存在的跳过,失败行回滚并显示原因,不影响其他行。");
Sheet types = sheet(workbook, "社团类型", "类型编码", "类型名称");
for (Sys_dict type : sysDictService.getSubListByCode("CLUB_REGISTER_TYPE")) append(types, type.getCode(), type.getName());
CommonDownloadUtil.download("社团批量注册模板.xlsx", workbook, response);
}
@At
@SaCheckRole("SYSADMIN")
@SaCheckPermission("club.infoManage.manage")
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Result doImport(@Param("file") TempFile file) {
if (file == null) return Result.error("请选择Excel文件");
List<String[]> rows = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();
try (InputStream input = file.getInputStream(); Workbook workbook = WorkbookFactory.create(input)) {
if (workbook.getNumberOfSheets() == 0) return Result.error("文件中没有工作表");
Sheet sheet = workbook.getSheetAt(0);
DataFormatter formatter = new DataFormatter();
for (int i = 0; i < HEADERS.length; i++) {
if (!HEADERS[i].equals(text(sheet.getRow(0), i, formatter))) return Result.error("表头不匹配,请使用下载的模板并保留完整表头");
}
for (Row row : sheet) {
if (row.getRowNum() == 0) continue;
String[] values = new String[HEADERS.length];
for (int i = 0; i < values.length; i++) values[i] = text(row, i, formatter);
if (Arrays.stream(values).allMatch(StrUtil::isBlank)) continue;
if (rows.size() >= 1000) return Result.error("每次最多导入1000行有效数据");
rows.add(values);
numbers.add(row.getRowNum() + 1);
}
} catch (Exception e) {
log.warn("读取社团注册导入文件失败", e);
return Result.error("文件读取失败,请使用未加密的xls或xlsx模板,不要使用公式");
}
if (rows.isEmpty()) return Result.error("文件中没有需要导入的数据");
List<NutMap> results = new ArrayList<>();
int success = 0;
int skipped = 0;
for (int i = 0; i < rows.size(); i++) {
String[] values = rows.get(i);
NutMap result;
try {
result = clubRegisterImportService.importRow(values);
} catch (IllegalArgumentException e) {
result = NutMap.NEW().addv("status", "失败").addv("message", e.getMessage());
} catch (Exception e) {
log.error("社团批量注册失败,行号:{}", numbers.get(i), e);
result = NutMap.NEW().addv("status", "失败").addv("message", "保存失败,该行已回滚,请检查数据或联系管理员");
}
result.setv("rowNumber", numbers.get(i)).setv("clubName", values[0]);
if (!result.containsKey("clubCode")) result.setv("clubCode", values[1]);
if ("成功".equals(result.getString("status"))) success++;
if ("跳过".equals(result.getString("status"))) skipped++;
results.add(result);
}
return Result.success(NutMap.NEW().addv("success", success).addv("skipped", skipped)
.addv("failed", results.size() - success - skipped).addv("rows", results));
}
private String text(Row row, int index, DataFormatter formatter) {
Cell cell = row == null ? null : row.getCell(index);
if (cell != null && cell.getCellType() == CellType.FORMULA) throw new IllegalArgumentException("不支持公式");
if (index == 3 && cell != null && cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell)) {
return cell.getLocalDateTimeCellValue().toLocalDate().toString();
}
return formatter.formatCellValue(cell).trim();
}
private Sheet sheet(Workbook workbook, String name, String... headers) {
Sheet sheet = workbook.createSheet(name);
Row row = sheet.createRow(0);
for (int i = 0; i < headers.length; i++) {
row.createCell(i).setCellValue(headers[i]);
sheet.setColumnWidth(i, 28 * 256);
}
sheet.createFreezePane(0, 1);
return sheet;
}
private void append(Sheet sheet, String... values) {
Row row = sheet.createRow(sheet.getLastRowNum() + 1);
for (int i = 0; i < values.length; i++) row.createCell(i).setCellValue(values[i]);
}
}
@@ -0,0 +1,104 @@
package com.budwk.app.zhgh.club.controller.statistics;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.zhgh.club.service.SysClubService;
import com.budwk.app.zhgh.club.service.impl.SysClubUserServiceImpl;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.util.NutMap;
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/statistics/member")
public class ClubMemberStatisticsController {
@Inject
private SysClubService sysClubService;
@At("")
@Ok("beetl:/platform/zhgh/club/statistics/member.html")
@SaCheckPermission("club.statistics.member")
public void index() {
}
@At
@SaCheckPermission("club.statistics.member")
public Result pageData(@Valid PageForm pageForm, String clubId, String userId, String keyWord, String unitName, String userState, String sex) {
Sql sql = generateSql(false, clubId, userId, keyWord, unitName, userState, sex);
Pagination pagination = sysClubService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
List<NutMap> members = pagination.getList(NutMap.class);
for (NutMap member : members) {
List<String> roles = StrUtil.isBlank(member.getString("roleCode"))
? List.of() : Json.fromJsonAsList(String.class, member.getString("roleCode"));
member.put("roleName", SysClubUserServiceImpl.convertRoleName(roles));
member.put("roleCode", roles);
}
pagination.setList(members);
return Result.success(pagination);
}
@At
@SaCheckPermission("club.statistics.member")
public Result clubOptions() {
return Result.success(sysClubService.listMap(generateSql(true, null, null, null, null, null, null)));
}
private Sql generateSql(boolean options, String clubId, String userId, String keyWord, String unitName, String userState, String sex) {
String fields = options ? "DISTINCT club.id, club.clubCode, club.clubName" : """
c.id, c.userId, club.clubCode, club.clubName,
COALESCE(NULLIF(u.username, ''), c.userName) AS userName,
COALESCE(NULLIF(u.loginname, ''), c.loginName) AS loginName,
u.sex, COALESCE(NULLIF(u.mobile, ''), c.mobile) AS mobile,
u.unitname AS unitName, u.userState, c.roleCode, c.joinTime
""";
Sql sql = Sqls.create("SELECT " + fields + "\n" + """
FROM sys_club club
INNER JOIN club_user c ON c.clubId = club.id
LEFT JOIN vw_user u ON u.id = c.userId
$condition
AND EXISTS (
SELECT 1 FROM wf_process_instance registerInstance
INNER JOIN wf_process_define registerDefine
ON registerDefine.id = registerInstance.processDefineId
WHERE registerInstance.businessNo = club.id
AND registerInstance.state = @finishedState
AND registerInstance.delFlag = 0
AND registerDefine.name = @registerProcessKey
AND registerDefine.delFlag = 0
)
ORDER BY club.clubCode, club.id
""" + (options ? "" : ", c.id"));
Cnd cnd = Cnd.where("club.dismiss", "=", false);
cnd.and("club.delFlag", "=", false);
cnd.and("c.delFlag", "=", false);
cnd.andEX("club.id", "=", clubId);
cnd.andEX("c.userId", "=", userId);
cnd.andEX("u.userState", "=", userState);
cnd.andEX("u.sex", "=", sex);
if (StrUtil.isNotBlank(unitName)) {
cnd.and("u.unitname", "=", unitName);
}
if (StrUtil.isNotBlank(keyWord)) {
cnd.and(Cnd.exps("COALESCE(NULLIF(u.username, ''), c.userName)", "like", "%" + keyWord + "%")
.or("COALESCE(NULLIF(u.loginname, ''), c.loginName)", "like", "%" + keyWord + "%"));
}
sql.setCondition(cnd);
sql.setParam("finishedState", ProcessInstanceStateEnum.FINISHED.getCode());
sql.setParam("registerProcessKey", "XHZC");
return sql;
}
}
@@ -129,7 +129,21 @@ public class ClubStatisticsController {
u.mobile, u.mobile,
u.unitname as unitName, u.unitname as unitName,
u.userState, u.userState,
c.* c.id,
c.clubId,
c.userId,
c.roleCode,
c.clubPosition,
c.email,
c.avatar,
c.sameTimeJoinOtherClubSituation,
c.awardsExperience,
c.joinTime,
c.createdBy,
c.createdAt,
c.updatedBy,
c.updatedAt,
c.delFlag
FROM FROM
club_user c club_user c
LEFT JOIN `vw_user` u ON u.id = c.userId LEFT JOIN `vw_user` u ON u.id = c.userId
@@ -0,0 +1,186 @@
package com.budwk.app.zhgh.club.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.flow.constant.FlowConst;
import com.budwk.app.flow.entity.ProcessDefine;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.sys.models.*;
import com.budwk.app.sys.services.SysDictService;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.club.model.SysClub;
import com.budwk.app.zhgh.club.model.SysClubSponsor;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
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 java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@IocBean
public class ClubRegisterImportService {
@Inject
private Dao dao;
@Inject
private SysClubService sysClubService;
@Inject
private SysDictService sysDictService;
@Inject
private SysRoleService sysRoleService;
@Inject
private SysUserService sysUserService;
@Aop(TransAop.READ_COMMITTED)
public NutMap importRow(String[] values) {
String name = values[0];
String code = values[1];
if (StrUtil.isBlank(name)) {
throw new IllegalArgumentException("社团名称不能为空");
}
if (dao.count(SysClub.class, Cnd.where("clubName", "=", name)) > 0
|| (StrUtil.isNotBlank(code) && dao.count(SysClub.class, Cnd.where("clubCode", "=", code)) > 0)) {
return NutMap.NEW().addv("status", "跳过").addv("message", "社团名称或编码已存在,保留原记录(含草稿、审批中及已解散社团)");
}
if (name.length() > 100 || code.length() > 100) {
throw new IllegalArgumentException("社团名称和编码不能超过100个字符");
}
if (sysDictService.getSubListByCode("CLUB_REGISTER_TYPE").stream().noneMatch(item -> values[2].equals(item.getCode()))) {
throw new IllegalArgumentException("请选择类型对照表中的社团类型编码");
}
try {
LocalDate.parse(values[3]);
} catch (Exception e) {
throw new IllegalArgumentException("成立日期必填,格式为yyyy-MM-dd");
}
List<NutMap> managers = new ArrayList<>();
Set<String> managerIds = new HashSet<>();
addManagers(managers, managerIds, values[4], "CLUB_PRESIDENT", true);
addManagers(managers, managerIds, values[5], "CLUB_SECRETARY", true);
addManagers(managers, managerIds, values[7], "CLUB_VICE_PRESIDENT", false);
addManagers(managers, managerIds, values[8], "CLUB_VICE_SECRETARY", false);
List<SysClubSponsor> sponsors = new ArrayList<>();
for (String loginname : split(values[6])) {
SysClubSponsor sponsor = new SysClubSponsor();
sponsor.setSponsorId(findUser(loginname).getId());
sponsors.add(sponsor);
}
if (sponsors.size() < 3) {
throw new IllegalArgumentException("发起人至少需要3名不同人员,多个工号用逗号分隔");
}
ProcessDefine define = dao.fetch(ProcessDefine.class, Cnd.where("name", "=", "XHZC").and("state", "=", 1).desc("version"));
if (define == null) {
throw new IllegalArgumentException("未配置可用的社团注册定义,无法记录直接通过状态");
}
if (StrUtil.isBlank(code)) {
int sequence = dao.count(SysClub.class, Cnd.where("year(createTime)", "=", DateUtil.thisYear())) + 1;
do {
code = DateUtil.thisYear() + String.format("%02d", sequence++);
} while (dao.count(SysClub.class, Cnd.where("clubCode", "=", code)) > 0);
}
SysClub club = new SysClub();
club.setClubName(name);
club.setClubCode(code);
club.setClubType(values[2]);
club.setFoundTime(values[3]);
club.setSponsors(sponsors);
club.setDue(values[10]);
if (values[10].length() > 50 || values[11].length() > 20 || values[12].length() > 100 || values[15].length() > 1000) {
throw new IllegalArgumentException("会费标准、联系电话、邮箱或缩略图地址超出字段长度限制");
}
if (StrUtil.isNotBlank(values[9])) {
Sys_user contact = findUser(values[9]);
club.setConcatPerson(contact.getId());
club.setConcatPersonMobile(contact.getMobile());
club.setConcatPersonEmail(contact.getEmail());
}
if (StrUtil.isNotBlank(values[11])) club.setConcatPersonMobile(values[11]);
if (StrUtil.isNotBlank(values[12])) club.setConcatPersonEmail(values[12]);
club.setIntroduce(escapeText(values[13]));
club.setPurpose(escapeText(values[14]));
club.setThumbnail(values[15]);
club.setEstablishReport(files(values[16]));
club.setRulesFile(files(values[17]));
club.setManageFile(files(values[18]));
club.setYearPlanFile(files(values[19]));
club.setFiles(files(values[20]));
// 复用单个注册:社团、发起人、理事会员资料及入会时间、年度缴费记录和快照。
sysClubService.doAdd(club, managers);
// 与注册通过后的角色授权一致,但不启动流程或创建审批任务。
for (NutMap manager : managers) {
Sys_role role = sysRoleService.getByCode(manager.getString("roleCode"));
if (role == null) throw new IllegalArgumentException("社团角色不存在:" + manager.getString("roleCode"));
Sys_user_role relation = new Sys_user_role();
relation.setUserId(manager.getString("userId"));
relation.setRoleId(role.getId());
relation.setClubId(club.getId());
dao.insert(relation);
}
// 现有社团查询通过已完成实例识别有效社团;保留可追溯的管理员直接通过记录。
ProcessInstance instance = new ProcessInstance();
instance.setProcessDefineId(define.getId());
instance.setBusinessNo(club.getId());
instance.setOperator(SecurityUtil.getUserId());
instance.setState(ProcessInstanceStateEnum.FINISHED.getCode());
instance.setVariable(JSONUtil.toJsonStr(NutMap.NEW()
.addv(FlowConst.FORM_DATA, JSONUtil.toJsonStr(club))
.addv(FlowConst.AUTO_GEN_TITLE, name + "(系统管理员批量导入直接通过)")
.addv("directImport", true)));
dao.insert(instance);
sysUserService.clearCache();
sysRoleService.clearCache();
return NutMap.NEW().addv("status", "成功").addv("message", "注册成功,已直接通过").addv("clubCode", code);
}
private void addManagers(List<NutMap> managers, Set<String> ids, String text, String roleCode, boolean required) {
List<String> names = split(text);
if (required && names.size() != 1) throw new IllegalArgumentException("会长、秘书长各需填写1名人员工号");
if (!names.isEmpty() && sysRoleService.getByCode(roleCode) == null) {
throw new IllegalArgumentException("系统未配置社团角色:" + roleCode);
}
for (String name : names) {
Sys_user user = findUser(name);
if (!ids.add(user.getId())) throw new IllegalArgumentException("理事机构人员不能重复:" + name);
managers.add(NutMap.NEW().addv("userId", user.getId()).addv("roleCode", roleCode));
}
}
private Sys_user findUser(String loginname) {
List<Sys_user> users = dao.query(Sys_user.class, Cnd.where("loginname", "=", loginname));
if (users.size() != 1) throw new IllegalArgumentException("工号不存在或不唯一:" + loginname);
return users.get(0);
}
private List<String> split(String text) {
return Arrays.stream(text.split("[,,]|;|;")).map(String::trim).filter(StrUtil::isNotBlank).distinct().toList();
}
private List<JSONObject> files(String text) {
List<JSONObject> result = new ArrayList<>();
List<String> ids = split(text);
if (ids.size() > 5) throw new IllegalArgumentException("每类附件最多5个文件");
for (String id : ids) {
Sys_file file = dao.fetch(Sys_file.class, id);
if (file == null || Boolean.TRUE.equals(file.getDelFlag())) throw new IllegalArgumentException("附件文件不存在:" + id);
result.add(JSONUtil.parseObj(file));
}
return result;
}
private String escapeText(String text) {
return text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
.replace("\r\n", "\n").replace("\n", "<br>");
}
}
@@ -68,7 +68,8 @@ public class PersonApiConfigServiceImpl extends BaseServiceImpl<PersonApiConfig>
public Pagination pageData(PageForm pageForm, String configName, String sourceType, Boolean enabled) { public Pagination pageData(PageForm pageForm, String configName, String sourceType, Boolean enabled) {
CndPlus cnd = CndPlus.create(); CndPlus cnd = CndPlus.create();
cnd.andEX("configName", "like", Strings.isBlank(configName) ? null : "%" + configName + "%"); cnd.andEX("configName", "like", Strings.isBlank(configName) ? null : "%" + configName + "%");
cnd.andEX("sourceType", "=", Strings.isBlank(sourceType) ? null : sourceType); // 兼容其他调用方传入空字符串,空来源类型表示不按来源筛选。
cnd.andEX("sourceType", "=", Strings.isBlank(sourceType) ? null : sourceType.trim());
cnd.andEX("enabled", "=", enabled); cnd.andEX("enabled", "=", enabled);
// 历史保存可能将删除标记写为NULL;仅明确标记为true的配置不在列表展示。 // 历史保存可能将删除标记写为NULL;仅明确标记为true的配置不在列表展示。
cnd.and(Cnd.exps("delFlag", "=", false).or("delFlag", "is", null)).desc("updatedAt"); cnd.and(Cnd.exps("delFlag", "=", false).or("delFlag", "is", null)).desc("updatedAt");
@@ -0,0 +1,197 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation;
import com.budwk.app.sys.models.*;
import com.budwk.app.sys.services.SysMenuService;
import com.budwk.app.sys.services.SysRoleService;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.*;
import org.nutz.dao.*;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.trans.Trans;
import java.util.*;
@IocBean(create = "init")
public class TherapyRecuperationModule {
public static final String ROOT = "/platform/inclusiveTherapyV3";
public static final String[][] SCREENS = {
{"config", "基础设置", "/TheRapyConfig", "TheRapyConfig"},
{"agency", "旅行社管理", "/travelAgency", "travelAgency"},
{"line", "线路管理", "/line", "line"},
{"base", "目的地管理", "/baseManagement", "TheBaseManagement"},
{"branchSelect", "分工会选择线路", "/lineFghSelect?mode=1", "lineFghSelect"},
{"schoolSelect", "校工会选择线路", "/lineXghSelect?mode=2", "lineXghSelect"},
{"overview", "线路选择查询", "/lineSelectionOverview", "lineSelectionOverview"},
{"cluster", "线路组团", "/lineCluster", "lineCluster"},
{"adjustment", "线路调剂", "/lineAdjustment", "line.adjustment"},
{"import", "参加人员导入", "/joinUserImport", "joinUser.import"},
{"branchAudit", "分工会审核", "/TheRapyAudit", "TheRapyAudit"},
{"travelAudit", "自由组团审核", "/TheRapyTravelAudit", "TheRapyTravelAudit"},
{"schoolAudit", "校工会审核", "/TheRapyXghAudit", "TheRapyXghAudit"},
{"branchQuery", "分工会信息查询", "/query", "TheRapyQuery"},
{"userQuery", "校工会信息查询", "/user/query", "TheRapyUserQuery"},
{"queryStatistics", "满意度统计", "/query/statics", "queryStatics"},
{"lineStatistics", "成团结果通知", "/statistics", "statistics"},
{"agencyStatistics", "人数统计", "/travelAgencyMonthlyStatistics", "travelAgencyMonthlyStatistics"},
{"unionStatistics", "分工会线路选择统计", "/statistics/unionLineNumberStatistics", "unionLineNumberStatistics"}
};
public static final List<String> MENU_SCREENS = List.of("agency", "line", "branchSelect", "schoolSelect",
"queryStatistics", "branchQuery", "userQuery", "overview", "lineStatistics", "config",
"unionStatistics", "agencyStatistics");
@Inject
private Dao dao;
@Inject
private SysMenuService sysMenuService;
@Inject
private SysRoleService sysRoleService;
@Inject
private SysUserService sysUserService;
public void init() {
Class<?>[] tables = {TheRapyRecuperationBaseManagement.class, TheRapyRecuperationCluster.class,
TheRapyRecuperationClusterMember.class, TheRapyRecuperationConfig.class,
TheRapyRecuperationEnroll.class, TheRapyRecuperationEnrollBed.class,
TheRapyRecuperationEnrollChangeRecord.class, TheRapyRecuperationEnrollCompanion.class,
TheRapyRecuperationLine.class, TheRapyRecuperationLineUnionSelect.class,
TheRapyRecuperationLot.class, TheRapyRecuperationTravelAgency.class,
TherapyAudit.class, TherapyAuditState.class};
for (Class<?> table : tables) dao.create(table, false);
createView("inclusive_therapy_v3_user", "SELECT u.*, u.arrivalAtSchoolDate AS schoolTime FROM vw_user u");
createView("inclusive_therapy_v3_union", "SELECT u.*, u.name AS unionname FROM sys_union u");
createView("inclusive_therapy_v3_unit", "SELECT u.* FROM sys_unit u");
Trans.exec(() -> {
seedStates();
seedVersion();
seedConfig();
seedMenus();
});
}
private void createView(String name, String select) {
org.nutz.dao.sql.Sql exists = Sqls.create("SELECT COUNT(1) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name=@name");
exists.setParam("name", name);
exists.setCallback(Sqls.callback.integer());
dao.execute(exists);
if (exists.getInt() == 0) dao.execute(Sqls.create("CREATE VIEW " + name + " AS " + select));
}
private void seedStates() {
int[] ids = {2710, 2715, 2720, 2725, 2730, 2735, 2750};
String[] names = {"待分工会审核", "分工会审核不通过", "待选择线路分工会审核", "选择线路分工会不通过",
"待校工会审核", "校工会审核不通过", "审核通过"};
for (int i = 0; i < ids.length; i++) {
if (dao.fetch(TherapyAuditState.class, ids[i]) != null) continue;
TherapyAuditState state = new TherapyAuditState();
state.setStateId(ids[i]);
state.setStateName(names[i]);
state.setStateColor(ids[i] == 2750 ? "#67c23a" : ids[i] % 10 == 5 ? "#f56c6c" : "#e6a23c");
dao.insert(state);
}
}
private void seedVersion() {
if (dao.fetch(Sys_config.class, "staffTherapyRecuperationVersion") != null) return;
Sys_config setting = new Sys_config();
setting.setConfigKey("staffTherapyRecuperationVersion");
setting.setConfigValue("zjnu");
setting.setNote("普惠疗休养独立子模块报名规则版本");
dao.insert(setting);
}
private void seedConfig() {
if (dao.count(TheRapyRecuperationConfig.class) != 0) return;
TheRapyRecuperationConfig config = new TheRapyRecuperationConfig();
config.setConfigName("普惠疗休养配置");
config.setIsSnLine(false);
config.setIsSwLine(false);
config.setTravelAudit(false);
config.setBedInfo(true);
config.setFamilyInfo(1);
config.setOutsideQuotaProportion(0D);
config.setUnionLineNumberConfigs(new ArrayList<>());
dao.insert(config);
}
private void seedMenus() {
Sys_menu existing = dao.fetch(Sys_menu.class, Cnd.where("href", "like", "/platform/recuperation%").and("platform", "=", "pc"));
Sys_module module = existing == null ? null : dao.fetch(Sys_module.class, existing.getModuleId());
if (module == null) module = dao.fetch(Sys_module.class, Cnd.where("name", "=", "职工福利").and("platform", "=", "pc"));
if (module == null) {
module = new Sys_module();
module.setName("职工福利");
module.setPlatform("pc");
module.setSortNum(50);
module.setFaIcon("fa fa-heart");
dao.insert(module);
}
Sys_menu root = addMenu(module.getId(), "", "普惠疗休养", ROOT, "inclusiveTherapyV3", "pc");
List<Sys_role> roles = dao.query(Sys_role.class, Cnd.where("disabled", "=", false));
for (String[] screen : SCREENS) {
Sys_menu menu = addMenu(module.getId(), root.getId(), screen[1], ROOT + screen[2],
"inclusiveTherapyV3." + screen[3], "pc");
int position = MENU_SCREENS.indexOf(screen[0]);
dao.update(Sys_menu.class, Chain.make("showit", position >= 0)
.add("location", position >= 0 ? position + 1 : MENU_SCREENS.size() + 1), Cnd.where("id", "=", menu.getId()));
for (Sys_role role : roles) {
String code = role.getCode();
boolean school = List.of("sysadmin", "superadmin", "A06", "SchoolUnionMemberAdmin", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "SCHOOL_UNION_MEMBER_ADMIN").contains(code);
boolean branch = List.of("H03", "H04", "H06", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN").contains(code)
&& Set.of("line", "base", "branchSelect", "branchAudit", "travelAudit", "branchQuery", "overview", "cluster", "adjustment").contains(screen[0]);
if (school || branch) {
grant(role.getId(), root.getId());
grant(role.getId(), menu.getId());
}
}
}
Sys_menu signup = addMenu(module.getId(), root.getId(), "疗休养报名", ROOT + "/mobile/index", "inclusiveTherapyV3.signup", "pc");
dao.update(Sys_menu.class, Chain.make("showit", false), Cnd.where("id", "=", signup.getId()));
Sys_module h5Module = dao.fetch(Sys_module.class, Cnd.where("name", "=", module.getName()).and("platform", "=", "h5"));
if (h5Module == null) {
h5Module = new Sys_module();
h5Module.setName(module.getName());
h5Module.setPlatform("h5");
h5Module.setSortNum(module.getSortNum());
h5Module.setFaIcon("fa fa-heart");
dao.insert(h5Module);
}
Sys_menu mobile = addMenu(h5Module.getId(), "", "普惠疗休养", ROOT + "/mobile/index", "inclusiveTherapyV3.mobile", "h5");
for (Sys_role role : roles) {
if (List.of("public", "PUBLIC", "MEMBER", "sysadmin", "superadmin", "SYSADMIN").contains(role.getCode())) {
grant(role.getId(), root.getId());
grant(role.getId(), signup.getId());
grant(role.getId(), mobile.getId());
}
}
sysMenuService.clearCache();
sysRoleService.clearCache();
sysUserService.clearCache();
}
private Sys_menu addMenu(String moduleId, String parentId, String name, String href, String permission, String platform) {
Sys_menu menu = dao.fetch(Sys_menu.class, Cnd.where("permission", "=", permission));
if (menu != null) return menu;
menu = new Sys_menu();
menu.setModuleId(moduleId);
menu.setName(name);
menu.setHref(href);
menu.setPermission(permission);
menu.setPlatform(platform);
menu.setType("menu");
menu.setTarget("_self");
menu.setIcon("fa fa-heart");
menu.setShowit(true);
menu.setDisabled(false);
sysMenuService.save(menu, parentId, Collections.emptyList());
return menu;
}
private void grant(String roleId, String menuId) {
if (dao.count("sys_role_menu", Cnd.where("roleId", "=", roleId).and("menuId", "=", menuId)) == 0) {
dao.insert("sys_role_menu", Chain.make("roleId", roleId).add("menuId", menuId));
}
}
}
@@ -0,0 +1,32 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
public class TherapyRecuperationCommon {
public static String getRemarkBySchoolTime(String schoolTime) {
if(StrUtil.isNotBlank(schoolTime)) {
String[] patterns = {
"yyyy-MM-dd",
"yyyy/MM/dd",
"yyyy-MM",
"yyyy/MM",
"yyyyMM",
"yyyyMMdd",
"yyyy年MM月dd日",
"yyyy年M月d日"
};
DateTime schoolDate = DateUtil.parse(schoolTime, patterns);
DateTime time = DateUtil.parse(DateUtil.thisYear() + "-07-01");
int compareResult = DateUtil.compare(schoolDate, time);
return compareResult >= 0 ? ("入校时间为:" + schoolTime + ",疗休养额度为1500。") : "";
} else {
return "";
}
}
}
@@ -0,0 +1,24 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant;
import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
import java.util.Date;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationJoinUserImportExcelMode
* @Description: 参加人员导入excel mode
* @Author zxc
* @Date 2022/6/14:11:10
* @Version V1.0
**/
@Data
public class TheRapyRecuperationJoinUserImportExcelMode {
@Excel(name = "工号")
private String loginName;
@Excel(name = "参加时间", format = "yyyyMMdd")
private Date takePartInTime;
}
@@ -0,0 +1,33 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode
* @Description: 线路创建模式
* @Author zxc
* @Date 2022/6/2:15:22
* @Version V1.0
**/
@AllArgsConstructor
@Getter
@SelectEnum
public enum TheRapyRecuperationLineCreateMode {
/**
* 分工会
*/
UNION(1, "分工会"),
/**
* 校工会
*/
SCHOOL(2, "校工会");
private final int value;
private final String label;
}
@@ -0,0 +1,31 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType
* @Description: TODO
* @Author zxc
* @Date 2022/6/2:14:08
* @Version V1.0
**/
@AllArgsConstructor
@Getter
@SelectEnum
public enum TheRapyRecuperationProvinceType {
/**
* 省内
*/
provinceIn("省内线路", "省内"),
/**
* 省外
*/
provinceOut("省外线路", "省外");
private final String label;
private final String value;
}
@@ -0,0 +1,34 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode
* @Description: 报名模式
* @Author zxc
* @Date 2022/6/2:15:22
* @Version V1.0
**/
@AllArgsConstructor
@Getter
@SelectEnum
public enum TheRapyRecuperationSignUpMode {
/**
* 分工会模式
*/
UNION(1, "分工会组织", new String[]{"H04", "A06", "sysadmin"}),
/**
* 自由模式
*/
FREE(2, "校工会组织", new String[]{"A06", "sysadmin"});
private final int value;
private final String label;
private final String[] roles;
}
@@ -0,0 +1,39 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant;
/**
* 审核状态
*/
public interface TheRapyRecuperationState {
/**
* 待分工会审核
*/
Integer UNIT = 2710;
/**
* 分工会审核不通过
*/
Integer UNITFAIL = 2715;
/**
* 待选择线路分工会审核
*/
Integer LINEUNIT = 2720;
/**
* 选择线路分工会不通过
*/
Integer LINEUNITFAIL = 2725;
/**
* 待校工会审核
*/
Integer SCHOOL = 2730;
/**
* 校工会审核不通过
*/
Integer SCHOOLFAIL = 2735;
/**
* 审核通过
*/
Integer PASS = 2750;
}
@@ -0,0 +1,70 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType
* @Description: 疗休养分类
* @Author zxc
* @Date 2022/6/2:14:02
* @Version V1.0
**/
@AllArgsConstructor
@Getter
@SelectEnum
public enum TheRapyRecuperationType {
/**
* 省内线路
*/
provinceInLine("省内线路", 0, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/in.png"),
/**
* 省外线路
*/
provinceOutLine("省外线路", 1, TheRapyRecuperationProvinceType.provinceOut.getValue(), "/assets/staffbenefit/therapyRecuperation/img/out.png"),
/**
* 省内旅行社
*/
provinceInTravelAgency("自由组团", 2, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/lxs.png"),
/**
* 酒店
*/
provinceInHotel("目的地疗休养", 3, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/lxs.png");
/**
* 学校自由组织
*/
// schoolFree("学校自由报名", 3, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/lxs.png");
private final String label;
private final int value;
private final String regionType;
/**
* 缓存状态map k->value v->TheRapyRecuperationProvinceType.value
*/
public static Map<Integer, String> typeMap = new HashMap<>();
/**
* 缓存状态map k->value v->TheRapyRecuperationProvinceType
*/
public static Map<Integer, TheRapyRecuperationType> objMap = new HashMap<>();
static {
TheRapyRecuperationType[] values = TheRapyRecuperationType.values();
for (TheRapyRecuperationType t : values) {
typeMap.put(t.getValue(), t.getRegionType());
objMap.put(t.getValue(), t);
}
}
private final String imgUrl;
}
@@ -0,0 +1,156 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.sys.enums.SysFileEngineTypeEnum;
import com.budwk.app.sys.models.*;
import com.budwk.app.sys.services.SysFileService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.*;
import org.nutz.dao.*;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
@IocBean
@At("/platform/inclusiveTherapyV3/common")
@Ok("json:full")
public class TherapyCommonController {
@Inject
private Dao dao;
@Inject
private SysFileService sysFileService;
@At
@SaCheckLogin
public Result enumOptions(String enumName) throws ReflectiveOperationException {
if (!Set.of("TheRapyRecuperationType", "TheRapyRecuperationProvinceType", "TheRapyRecuperationSignUpMode",
"TheRapyRecuperationLineCreateMode").contains(enumName)) return Result.error("未知选项类型");
Class<?> type = Class.forName("com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant." + enumName);
List<NutMap> options = new ArrayList<>();
for (Object value : type.getEnumConstants()) {
NutMap option = NutMap.NEW().addv("label", type.getMethod("getLabel").invoke(value))
.addv("value", type.getMethod("getValue").invoke(value));
if ("TheRapyRecuperationType".equals(enumName)) {
option.addv("imgUrl", type.getMethod("getImgUrl").invoke(value));
option.addv("regionType", type.getMethod("getRegionType").invoke(value));
}
options.add(option);
}
return Result.success(options);
}
@At({"/unions", "/getUnion"})
@SaCheckLogin
public Result unions(Boolean isPermission) {
Cnd cnd = Cnd.NEW();
cnd.asc("unionCode");
if (Boolean.TRUE.equals(isPermission) && !TherapyContext.hasAnyRoles("sysadmin,A06")) {
cnd.and("id", "=", TherapyContext.getUnionId());
}
return Result.success(dao.query(TherapyUnion.class, cnd));
}
@At({"/units", "/getUnit", "/unionUnits", "/getUnitsByUnions"})
@SaCheckLogin
public Result units(String unionId, String unionid) {
String id = Strings.isBlank(unionId) ? unionid : unionId;
return Result.success(dao.query(Sys_unit.class, Cnd.NEW().andEX("unionId", "=", id).asc("location")));
}
@At
@SaCheckLogin
public Result dictOptions(String code) {
Sys_dict parent = dao.fetch(Sys_dict.class, Cnd.where("code", "=", code));
return Result.success(parent == null ? Collections.emptyList() : dao.query(Sys_dict.class,
Cnd.where("parentId", "=", parent.getId()).and("disabled", "=", false).asc("location")));
}
@At
@SaCheckLogin
public Result getValue(String key) {
if (!Set.of("recuperationVersion", "staffTherapyRecuperationVersion").contains(key)) return Result.error("未知配置");
Sys_config config = dao.fetch(Sys_config.class, "staffTherapyRecuperationVersion");
return Result.success((Object) (config == null ? "zjnu" : config.getConfigValue()));
}
@At
@SaCheckLogin
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Result uploadFile(TempFile file) {
if (file == null) return Result.error("请选择文件");
String id = sysFileService.uploadReturnId(SysFileEngineTypeEnum.MINIO.getValue(), file);
Sys_file uploaded = sysFileService.fetch(id);
return Result.success(fileInfo(uploaded));
}
private NutMap fileInfo(Sys_file file) {
return NutMap.NEW().addv("id", file.getId()).addv("filename", file.getName())
.addv("filepath", file.getDownloadPath()).addv("url", file.getDownloadPath())
.addv("name", file.getName()).addv("downloadPath", file.getDownloadPath())
.addv("engine", file.getEngine()).addv("bucket", file.getBucket())
.addv("objName", file.getObjName()).addv("storagePath", file.getStoragePath())
.addv("suffix", file.getSuffix()).addv("sizeKb", file.getSizeKb()).addv("sizeInfo", file.getSizeInfo());
}
@At
@SaCheckLogin
public Result fileInfo(String[] ids) {
List<NutMap> result = new ArrayList<>();
if (ids != null) for (String id : ids) {
Sys_file file = sysFileService.fetch(id);
if (file != null) result.add(fileInfo(file));
}
return Result.success(result);
}
@At
@SaCheckLogin
@POST
public Result deleteFile(String id) {
if (Strings.isBlank(id)) return Result.error("缺少文件ID");
Sys_file file = sysFileService.fetch(id);
if (file == null) return Result.success();
if (!Objects.equals(file.getCreatedBy(), TherapyContext.getUserId())
&& !TherapyContext.hasAnyRoles("sysadmin,A06")) return Result.error("无权删除此文件");
sysFileService.delete(Collections.singletonList(id));
return Result.success();
}
@At({"/preview", "/download"})
@SaCheckLogin
@Ok("void")
public void preview(String id, HttpServletRequest request, HttpServletResponse response) throws IOException {
if (id != null && id.startsWith("/platform/sys/file/download?id=")) {
id = id.substring(id.indexOf("?id=") + 4);
}
sysFileService.download(id, request, response);
}
@At
@SaCheckLogin
@Ok("void")
public void downloadTemplate(String filePath, String fileName, HttpServletResponse response) throws IOException {
String name = filePath == null ? "" : filePath.substring(filePath.lastIndexOf('/') + 1);
if (!Set.of("TravelAgencyImport.xlsx", "TravelEnrollImport.xlsx").contains(name)) {
response.sendError(404);
return;
}
try (InputStream in = getClass().getResourceAsStream("/static/assets/staffbenefit/therapyRecuperation/templates/" + name)) {
if (in == null) {
response.sendError(404);
return;
}
TherapyDownload.excelResponse(response, Strings.isBlank(fileName) ? name : fileName);
in.transferTo(response.getOutputStream());
}
}
}
@@ -0,0 +1,44 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.TherapyRecuperationModule;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@IocBean
@At("/platform/inclusiveTherapyV3")
public class TherapyWorkspaceController {
@At("")
@SaCheckLogin
@Ok("void")
public void index(String screen, HttpServletResponse response) throws IOException {
if (screen == null) {
for (String key : TherapyRecuperationModule.MENU_SCREENS) {
for (String[] candidate : TherapyRecuperationModule.SCREENS) {
if (candidate[0].equals(key) && StpUtil.hasPermission("inclusiveTherapyV3." + candidate[3])) {
screen = key;
break;
}
}
if (screen != null) break;
}
}
String url = TherapyRecuperationModule.ROOT + "/mobile/index";
if (screen != null && !"signup".equals(screen)) {
boolean found = false;
for (String[] candidate : TherapyRecuperationModule.SCREENS) {
if (candidate[0].equals(screen)) {
StpUtil.checkPermission("inclusiveTherapyV3." + candidate[3]);
url = TherapyRecuperationModule.ROOT + candidate[2];
found = true;
break;
}
}
if (!found) throw new IllegalArgumentException("未知的普惠疗休养页面");
}
response.sendRedirect(url);
}
}
@@ -0,0 +1,617 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.audit;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAuditState;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.aop.interceptor.ioc.TransAop;
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.Daos;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.trans.Trans;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@IocBean
@At("/platform/inclusiveTherapyV3/TheRapyAudit")
@Ok("json:full")
public class TheRapyRecuperationAuditController {
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyAudit.html")
@SaCheckPermission("inclusiveTherapyV3.TheRapyAudit")
public void index() {
}
@Inject
private TherapyContext vi;
@Inject
private TheRapyRecuperationAuditService auditService;
@Inject
private Dao dao;
@Inject
private TherapyMessage msgApi;
@At
@ViReturn
@SaCheckLogin
public Object getXlByUnion(Integer state, String unionId, String regionalNature, String year, String endYear, Integer signUpMode, String agencyId) {
List<NutMap> xlByUnion = auditService.getXlByUnion(state, unionId, regionalNature, year, endYear, signUpMode, agencyId);
return xlByUnion;
}
@At
@ViReturn
@SaCheckLogin
public Object getXlByUnionAudit(String unionId, String regionalNature, String year, Integer signUpMode) {
Sql sql = Sqls.create("""
SELECT
line.id,
line.lineName,
line.regionalNature,
ts.id as selectId,
ts.playStartTime,
ts.playEndTime
FROM
inclusive_therapy_v3_line_union_select ts
LEFT JOIN inclusive_therapy_v3_line line ON line.id = ts.lineId
$condition
""");
Cnd cnd = Cnd.NEW();
if (TherapyContext.hasAnyRoles("sysadmin,A06")) {
cnd.andEX("ts.unionId", "=", unionId);
} else {
cnd.and("ts.unionId", "=", vi.getUnionId());
}
cnd.andEX("YEAR(ts.selectTime)", "=", year);
cnd.andEX("line.regionalNature", "=", regionalNature);
cnd.andEX("line.signUpMode", "=", signUpMode);
cnd.groupBy("line.id");
sql.setCondition(cnd);
return auditService.listMap(sql);
}
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyAudit")
public Object pageData(PageForm pageForm, String year, String unionId,
String unitId, String state, String takePartInLineId,
String isAudit, String regionalNature, String lotId,
String selectId) {
Sql sql = Sqls.create("""
SELECT
enroll.*,
lineu.lineId,
line.lineName,
line.regionalNature,
'教职工' userNature,
state.stateColor,
state.stateName,
CONCAT(DATE_FORMAT(lineu.playStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.playEndTime,'%m月%d日')) AS linePlayTime,
IF
( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) isFamily,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) num
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN inclusive_therapy_v3_line_union_select lineu ON lineu.id=enroll.takePartInLineId
LEFT JOIN inclusive_therapy_v3_line line ON line.id = lineu.lineId
LEFT JOIN inclusive_therapy_v3_audit_state state ON state.stateId = enroll.stateId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("line.lotId", "=", lotId);
cnd.andEX("line.regionalNature", "=", regionalNature);
cnd.andEX("YEAR(enroll.signingUptime)", "=", year);
cnd.andEX("enroll.selfUnionId", "=", unionId);
cnd.and("enroll.takePartInLineId", "is not", null);
cnd.andEX("enroll.selfUnitId", "=", unitId);
cnd.andEX("lineu.lineId", "=", takePartInLineId);
cnd.andEX("enroll.isNormal", "=", true);
cnd.andEX("lineu.signUpMode", "=", 1);
cnd.andEX("lineu.id", "=", selectId);
if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) {
cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword());
}
if (Strings.isNotBlank(state)) {
if (state.equals("1")) {
cnd.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId());
cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId());
} else if (state.equals("2")) {
cnd.andEX("enroll.takePartInUnionId", "!=", TherapyContext.getUnionId());
cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId());
} else if (state.equals("3")) {
cnd.andEX("enroll.selfUnionId", "!=", TherapyContext.getUnionId());
cnd.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId());
}
}
if (Strings.isNotBlank(isAudit)) {
if (isAudit.equals("true")) {
if (state.equals("2") || state.equals("1")) {
cnd.and(new Static("""
(( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s ) AND enroll.selfUnionId = '%s' )
""".formatted(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNIT, TheRapyRecuperationState.PASS, vi.getUnionId())));
} else if (state.equals("3")) {
cnd.and(new Static("""
((enroll.stateId = %s OR enroll.stateId=%s )AND enroll.takePartInUnionId='%s')
""".formatted(TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.PASS, vi.getUnionId())));
} else {
/*cnd.and(new Static("""
((( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s ) AND enroll.selfUnionId = '%s' )
OR
((enroll.stateId = %s OR enroll.stateId=%s )AND enroll.takePartInUnionId='%s'))
""".formatted(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNIT, TheRapyRecuperationState.PASS, vi.getUnionId(), TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.PASS, vi.getUnionId())));*/
cnd.and(new Static("""
((enroll.stateId = %s OR enroll.stateId=%s )AND enroll.takePartInUnionId='%s')
""".formatted(TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.PASS, vi.getUnionId())));
}
} else {
cnd.and(new Static("""
((enroll.stateId = %s AND enroll.selfUnionId='%s')OR (enroll.stateId = %s AND enroll.takePartInUnionId='%s'))
""".formatted(TheRapyRecuperationState.UNIT, vi.getUnionId(), TheRapyRecuperationState.LINEUNIT, vi.getUnionId())));
}
} else {
//屏蔽了本工会选择其他工会线路的人员
// cnd.and(Cnd.exps("enroll.selfUnionId", "=", vi.getUnionId()).or("enroll.takePartInUnionId", "=", vi.getUnionId()));
cnd.and("enroll.takePartInUnionId", "=", vi.getUnionId());
}
cnd.desc("enroll.signingUptime");
cnd.desc("enroll.unitName");
// cnd.having(Cnd.where("isTransferIn","=",0));
sql.setCondition(cnd);
return auditService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
@SaCheckLogin
public Object findOne(String id) {
NutMap one = auditService.findOne(id);
return one;
}
/**
* 单个审核
*
* @param id
* @param flag
* @param isTransferIn
* @param auditOpinion
* @return
*/
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyAudit")
public Object doAudit(String id, boolean flag, Boolean adjustment, boolean isTransferIn, String auditOpinion) {
Trans.exec(() -> {
TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id);
TherapyAudit audit = new TherapyAudit();
audit.setAuditOpinion(auditOpinion);
audit.setAuditor(TherapyContext.getUserId());
audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname"));
audit.setUsername((String) TherapyContext.getPrincipalProperty("username"));
audit.setAuditTime(new Date());
audit.setAuditPass(flag);
TherapyAudit insert = auditService.insert(audit);
if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) {
enroll.setSelfUnionAuditId(insert.getId());
} else {
enroll.setJoinLineUnionAuditId(insert.getId());
}
//如果通过
if (flag) {
//如果参加的线路分工会是自己分工会的,并且状态等于分工会审核
if (enroll.getTakePartInUnionId().equals(TherapyContext.getUnionId()) && enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) {
enroll.setStateId(TheRapyRecuperationState.PASS);
} else {
//否则就是不是参加的自己分工会线路,就需要线路分工会审核
if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) {
enroll.setStateId(TheRapyRecuperationState.LINEUNIT);
} else {
enroll.setStateId(TheRapyRecuperationState.PASS);
}
}
} else {
if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) {
enroll.setStateId(TheRapyRecuperationState.UNITFAIL);
} else {
enroll.setStateId(TheRapyRecuperationState.LINEUNITFAIL);
}
}
auditService.updateIgnoreNull(enroll);
auditMsg(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId());
if (adjustment) {
// enroll.setNormal(false);
auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "=", enroll.getId()));
}
});
return null;
}
/**
* 撤回
*
* @param id
* @return
*/
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyAudit")
public Object doRecall(String id) {
TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id);
TheRapyRecuperationLineUnionSelect unionSelect = auditService.dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("id", "=", enroll.getTakePartInLineId()));
if (enroll.getStateId().equals(TheRapyRecuperationState.UNITFAIL)) {
enroll.setStateId(TheRapyRecuperationState.UNIT);
enroll.setSelfUnionAuditId(null);
} else if (enroll.getStateId().equals(TheRapyRecuperationState.LINEUNIT)) {
enroll.setStateId(TheRapyRecuperationState.UNIT);
enroll.setSelfUnionAuditId(null);
} else if (enroll.getStateId().equals(TheRapyRecuperationState.LINEUNITFAIL)) {
enroll.setStateId(TheRapyRecuperationState.LINEUNIT);
enroll.setSelfUnionAuditId(null);
// } else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getSelfUnionId().equals(vi.getUnionId())) {
} else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getSelfUnionId().equals(unionSelect.getUnionId())) {
enroll.setStateId(TheRapyRecuperationState.UNIT);
enroll.setSelfUnionAuditId(null);
// } else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getTakePartInUnionId().equals(vi.getUnionId())) {
} else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getTakePartInUnionId().equals(unionSelect.getUnionId())) {
enroll.setStateId(TheRapyRecuperationState.LINEUNIT);
enroll.setJoinLineUnionAuditId(null);
}
auditService.update(enroll);
return null;
}
/**
* 批量审核
*
* @param ids
* @param auditOpinion
* @param flag
* @return
*/
@At
@ViReturn
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("inclusiveTherapyV3.TheRapyAudit")
public Object doOnekeyAudit(String[] ids, String auditOpinion, boolean flag, Boolean adjustment) {
TherapyAudit audit = new TherapyAudit();
audit.setAuditOpinion(auditOpinion);
audit.setAuditor(TherapyContext.getUserId());
audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname"));
audit.setUsername((String) TherapyContext.getPrincipalProperty("username"));
audit.setAuditTime(new Date());
audit.setAuditPass(flag);
TherapyAudit insert = auditService.insert(audit);
List<String> enrollIdList = new ArrayList<>();
for (String id : ids) {
TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id);
//如果状态等于分工会审核,并且参加的线路分工会也是自己的工会,就代表自己参加自己的工会线路
if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT) && enroll.getTakePartInUnionId().equals(vi.getUnionId())) {
enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.UNITFAIL);
enroll.setSelfUnionAuditId(insert.getId());
//如果状态等于分工会审核,并且参加的线路分工会不是自己的工会,就代表参加的不是自己工会的线路,就需要线路分工会审核
} else if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT) && !enroll.getTakePartInUnionId().equals(vi.getUnionId())) {
enroll.setStateId(flag ? TheRapyRecuperationState.LINEUNIT : TheRapyRecuperationState.UNITFAIL);
enroll.setSelfUnionAuditId(insert.getId());
} else {
enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.LINEUNITFAIL);
enroll.setJoinLineUnionAuditId(insert.getId());
}
if (adjustment) {
// enroll.setNormal(false);
enrollIdList.add(id);
}
auditService.updateIgnoreNull(enroll);
auditMsg(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId());
}
auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIdList));
return null;
}
/**
* 审核发短信
*
* @param stateId
* @param loginName
* @param takePartInLineId
*/
private void auditMsg(Integer stateId, String loginName, Boolean adjustment, String takePartInLineId) {
TherapyUser user = auditService.dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", loginName));
TheRapyRecuperationLineUnionSelect unionSelect = auditService.dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("id", "=", takePartInLineId));
TheRapyRecuperationLine theRapyRecuperationLine = auditService.dao().fetch(TheRapyRecuperationLine.class, Cnd.where("id", "=", unionSelect.getLineId()));
TherapyAuditState auditState = auditService.dao().fetch(TherapyAuditState.class, Cnd.where("stateId", "=", stateId));
String content = "【智慧工会】%s老师您好,您报名的%s线路因报名人数不足已取消,请尽快进入智慧工会重新选择线路。"
.formatted(user.getUsername(), theRapyRecuperationLine.getLineName());
List list = List.of(Map.of("type", "User", "userId", user.getLoginname(), "name", user.getUsername()));
if (stateId.equals(TheRapyRecuperationState.PASS)) {
content = "【智慧工会】%s老师您好,您报名的%s线路已组团成功,请按约定出行。"
.formatted(user.getUsername(), theRapyRecuperationLine.getLineName());
}
//msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", MsgApi.sendMode.normal.name());
}
/**
* 查询报名人员的工会有哪些,并分组
*
* @return
*/
@At
@ViReturn
@SaCheckLogin
public Object getBmUserUnion() {
Sql sql = Sqls.create("""
SELECT
unionName unionname,
selfUnionId id
FROM
`inclusive_therapy_v3_enroll`
$condition
""");
Cnd cnd = Cnd.NEW();
if (!TherapyContext.hasAnyRoles("sysadmin,H06")) {
cnd.and("takePartInLineId", "IS NOT", null);
cnd.and("takePartInLineId", "!=", "");
cnd.and(Cnd.exps("takePartInUnionId", "=", vi.getUnionId()).or("selfUnionId", "=", vi.getUnionId()));
//cnd.and("selfUnionId", "=", vi.getUnionId());
}
cnd.groupBy("selfUnionId");
sql.setCondition(cnd);
List<NutMap> unionList = auditService.listMap(sql);
return unionList;
}
/**
* 查询报名数量
*
* @return
*/
@At
@ViReturn
@SaCheckLogin
public Object getApplyNumAudit(String takePartInLineId, String mode, String isAudit, Integer year, String selectId) {
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
String unionId = TherapyContext.getUnionId();
Sql sql = Sqls.create("""
SELECT
COUNT(1) as signUpNum,
$val as familyNumber
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN inclusive_therapy_v3_line_union_select lineu ON lineu.id = enroll.takePartInLineId
$condition
""");
String val = "";
if (config.getFamilyInfo() == 1) {
val = "IFNULL(sum(familyNumber),0)";
} else {
val = "IFNULL((select count(1) from inclusive_therapy_v3_enroll_companion where trreId = enroll.id),0)";
}
sql.setVar("val", val);
Sql sql2 = sql;
Sql sql3 = sql;
Sql sql4 = sql;
if (StrUtil.isBlank(isAudit)) {
//本公会人员(自己线路)
Cnd cnd1 = Cnd.NEW();
cnd1.andEX("takePartInUnionId", "=", unionId)
.and("selfUnionId", "=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.andEX("signUpMode", "=", 1)
.andEX("lineu.id", "=", selectId);
if (StrUtil.isNotBlank(mode)) {
cnd1.and("stateId", "=", TheRapyRecuperationState.PASS);
}
sql.setCondition(cnd1);
NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber", 0)));
//本工会人员(其他路线)
Cnd cnd2 = Cnd.NEW();
cnd2.and("takePartInUnionId", "!=", unionId)
.and("selfUnionId", "=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.andEX("signUpMode", "=", 1)
.andEX("lineu.id", "=", selectId);
if (StrUtil.isNotBlank(mode)) {
cnd2.and("stateId", "=", TheRapyRecuperationState.PASS);
}
sql2.setCondition(cnd2);
NutMap map2 = (NutMap) Daos.query(dao, sql2.toString(), Sqls.callback.map());
int count2 = Integer.parseInt(String.valueOf(map2.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map2.getOrDefault("familyNumber", 0)));
//其他工会人员(选我线路)
Cnd cnd3 = Cnd.NEW();
cnd3.and("takePartInUnionId", "=", unionId)
.and("selfUnionId", "!=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.andEX("signUpMode", "=", 1)
.andEX("lineu.id", "=", selectId);
if (StrUtil.isNotBlank(mode)) {
cnd3.and("stateId", "=", TheRapyRecuperationState.PASS);
}
sql3.setCondition(cnd3);
NutMap map3 = (NutMap) Daos.query(dao, sql3.toString(), Sqls.callback.map());
int count3 = Integer.parseInt(String.valueOf(map3.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map3.getOrDefault("familyNumber", 0)));
//选择校工会线路人员
Cnd cnd4 = Cnd.NEW();
cnd4.and("selfUnionId", "=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.andEX("signUpMode", "=", 2)
.andEX("lineu.id", "=", selectId);
if (StrUtil.isNotBlank(mode)) {
cnd4.and("stateId", "=", TheRapyRecuperationState.PASS);
}
sql4.setCondition(cnd4);
NutMap map4 = (NutMap) Daos.query(dao, sql4.toString(), Sqls.callback.map());
int count4 = Integer.parseInt(String.valueOf(map4.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map4.getOrDefault("familyNumber", 0)));
return Map.of("count1", count1, "count2", count2, "count3", count3, "count4", count4);
}
if ("true".equals(isAudit)) {
//本公会人员(自己线路)
Cnd cnd1 = Cnd.NEW();
cnd1.and("takePartInUnionId", "=", unionId)
.and("selfUnionId", "=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.and("stateId", ">", TheRapyRecuperationState.UNIT)
.andEX("signUpMode", "=", 1);
sql.setCondition(cnd1);
NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber", 0)));
//本工会人员(其他路线)
// Cnd cnd2 = Cnd.NEW();
// cnd2.and("takePartInUnionId", "!=", unionId)
// .and("selfUnionId", "=", unionId)
// .and("isNormal", "=", true)
// .and("takePartInLineId", "is not", null)
// .andEX("YEAR(signingUptime)", "=", year)
// .and("stateId", ">", TheRapyRecuperationState.UNIT)
// .andEX("signUpMode", "=", 1);
// sql2.setCondition(cnd2);
// int count2 = auditService.count(sql2);
//其他工会人员(选我线路)
Cnd cnd3 = Cnd.NEW();
cnd3.and("takePartInUnionId", "=", unionId)
.and("selfUnionId", "!=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.and("stateId", ">", TheRapyRecuperationState.LINEUNIT)
.andEX("signUpMode", "=", 1);
sql3.setCondition(cnd3);
NutMap map3 = (NutMap) Daos.query(dao, sql3.toString(), Sqls.callback.map());
int count3 = Integer.parseInt(String.valueOf(map3.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map3.getOrDefault("familyNumber", 0)));
// return Map.of("count1", count1, "count2", count2, "count3", count3);
return Map.of("count1", count1, "count3", count3);
}
if ("false".equals(isAudit)) {
//本公会人员(自己线路)
Cnd cnd1 = Cnd.NEW();
cnd1.and("takePartInUnionId", "=", unionId)
.and("selfUnionId", "=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.and("stateId", "=", TheRapyRecuperationState.UNIT)
.andEX("signUpMode", "=", 1);
sql.setCondition(cnd1);
NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber", 0)));
//本工会人员(其他路线)
// Cnd cnd2 = Cnd.NEW();
// cnd2.and("takePartInUnionId", "!=", unionId)
// .and("selfUnionId", "=", unionId)
// .and("isNormal", "=", true)
// .and("takePartInLineId", "is not", null)
// .andEX("YEAR(signingUptime)", "=", year)
// .and("stateId", "=", TheRapyRecuperationState.UNIT)
// .andEX("signUpMode", "=", 1);
// sql2.setCondition(cnd2);
// int count2 = auditService.count(sql2);
//其他工会人员(选我线路)
Cnd cnd3 = Cnd.NEW();
cnd3.and("takePartInUnionId", "=", unionId)
.and("selfUnionId", "!=", unionId)
.and("isNormal", "=", true)
.and("takePartInLineId", "is not", null)
.andEX("lineu.lineId", "=", takePartInLineId)
.andEX("YEAR(signingUptime)", "=", year)
.and("stateId", "=", TheRapyRecuperationState.LINEUNIT)
.andEX("signUpMode", "=", 1);
sql3.setCondition(cnd3);
NutMap map3 = (NutMap) Daos.query(dao, sql3.toString(), Sqls.callback.map());
int count3 = Integer.parseInt(String.valueOf(map3.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map3.getOrDefault("familyNumber", 0)));
// return Map.of("count1", count1, "count2", count2, "count3", count3);
return Map.of("count1", count1, "count3", count3);
}
return null;
}
}
@@ -0,0 +1,237 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.audit;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.aop.interceptor.ioc.TransAop;
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.Daos;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.trans.Trans;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @version 1.0
* @Author zzr
* @name:TheRapyRecuperationTranlAuditController
* @Date 2024/5/22 9:59
* @注释
*/
@IocBean
@At("/platform/inclusiveTherapyV3/TheRapyTravelAudit")
@Ok("json:full")
public class TheRapyRecuperationTravelAuditController {
@Inject
private TheRapyRecuperationAuditService theRapyRecuperationAuditService;
@Inject
private TherapyContext vi;
@Inject
private Dao dao;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyTravelAudit.html")
@SaCheckPermission("inclusiveTherapyV3.TheRapyTravelAudit")
public void index() {
}
@At
@ViReturn
public Object pageData(PageForm pageForm,
@Param(value = "agencyId") String agencyId,
@Param(value = "year") String year,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId,
@Param(value = "isAudit") String isAudit){
Sql sql = Sqls.create("""
SELECT
enroll.*,
state.stateColor,
state.stateName,
ta.travelAgencyName,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) isFamily
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN inclusive_therapy_v3_audit_state state ON state.stateId = enroll.stateId
left join inclusive_therapy_v3_travel_agency ta on ta.id = enroll.takePartInTravelAgencyId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("YEAR(enroll.signingUptime)", "=", year);
cnd.and("enroll.selfUnionId", "=", StrUtil.isBlank(unionId) ? TherapyContext.getUnionId() : unionId);
cnd.and("enroll.takePartInTravelAgencyId", "is not", null);
cnd.and("enroll.takePartInTravelAgencyId", "!=", "");
cnd.andEX("enroll.selfUnitId", "=", unitId);
cnd.andEX("enroll.isNormal", "=", true);
cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId);
if (isAudit.equals("true")) {
cnd.and("enroll.stateId", ">", TheRapyRecuperationState.UNIT);
} else if (isAudit.equals("false")){
cnd.and("enroll.stateId", "=", TheRapyRecuperationState.UNIT);
}
if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) {
cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword());
}
cnd.desc("enroll.signingUptime");
cnd.desc("enroll.unitName");
sql.setCondition(cnd);
return theRapyRecuperationAuditService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
@SaCheckLogin
public Object getBmUserUnion() {
Sql sql = Sqls.create("""
SELECT
unionName unionname,
selfUnionId id
FROM
`inclusive_therapy_v3_enroll`
$condition
""");
Cnd cnd = Cnd.NEW();
if (!TherapyContext.hasAnyRoles("sysadmin,H06")) {
cnd.and("takePartInTravelAgencyId", "IS NOT", null);
cnd.and("takePartInTravelAgencyId", "!=", "");
cnd.and("selfUnionId", "=", vi.getUnionId());
}
cnd.groupBy("selfUnionId");
sql.setCondition(cnd);
List<NutMap> unionList = theRapyRecuperationAuditService.listMap(sql);
return unionList;
}
@At
@ViReturn
@SaCheckLogin
public Object getApplyNumAudit(String agencyId, String isAudit, Integer year) {
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
String unionId = TherapyContext.getUnionId();
Sql sql = Sqls.create("""
SELECT
count(1) as signUpNum,
$val as familyNumber
FROM
`inclusive_therapy_v3_enroll` enroll
$condition
""");
String val = "";
if(config.getFamilyInfo() == 1) {
val = "IFNULL(sum(familyNumber),0)";
} else {
val = "IFNULL((select count(1) from inclusive_therapy_v3_enroll_companion where trreId = enroll.id),0)";
}
sql.setVar("val", val);
Cnd cnd = Cnd.NEW();
if (isAudit.equals("true")) {
cnd.and("enroll.stateId", ">", TheRapyRecuperationState.UNIT);
} else if (isAudit.equals("false")){
cnd.and("enroll.stateId", "=", TheRapyRecuperationState.UNIT);
}
cnd.andEX("takePartInTravelAgencyId", "=", agencyId);
cnd.andEX("year(signingUptime)", "=", year);
cnd.and("takePartInTravelAgencyId", "is not", null);
cnd.and("takePartInTravelAgencyId", "!=", "");
cnd.and("selfUnionId", "=", unionId);
cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId);
sql.setCondition(cnd);
NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum",0)))
+ Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber",0)));
return Map.of("count1", count1);
}
@At
@ViReturn
@SaCheckLogin
public Object doAudit(String id, boolean flag,Boolean adjustment, String auditOpinion) {
Trans.exec(() -> {
TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, id);
TherapyAudit audit = new TherapyAudit();
audit.setAuditOpinion(auditOpinion);
audit.setAuditor(TherapyContext.getUserId());
audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname"));
audit.setUsername((String) TherapyContext.getPrincipalProperty("username"));
audit.setAuditTime(new Date());
audit.setAuditPass(flag);
TherapyAudit insert = dao.insert(audit);
enroll.setSelfUnionAuditId(insert.getId());
enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.UNITFAIL);
dao.updateIgnoreNull(enroll);
// auditMsg(enroll.getStateId(), enroll.getLoginName(),adjustment, enroll.getTakePartInLineId());
if (adjustment){
// enroll.setNormal(false);
dao.clear(TheRapyRecuperationEnroll.class,Cnd.where("id","=",enroll.getId()));
}
});
return null;
}
@At
@ViReturn
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
public Object doOnekeyAudit(String[] ids, String auditOpinion, boolean flag, Boolean adjustment) {
TherapyAudit audit = new TherapyAudit();
audit.setAuditOpinion(auditOpinion);
audit.setAuditor(TherapyContext.getUserId());
audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname"));
audit.setUsername((String) TherapyContext.getPrincipalProperty("username"));
audit.setAuditTime(new Date());
audit.setAuditPass(flag);
TherapyAudit insert = dao.insert(audit);
List<String> enrollIdList = new ArrayList<>();
for (String id : ids) {
TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, id);
enroll.setSelfUnionAuditId(insert.getId());
enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.UNITFAIL);
dao.updateIgnoreNull(enroll);
//auditMsg(enroll.getStateId(), enroll.getLoginName(),adjustment, enroll.getTakePartInLineId());
}
dao.clear(TheRapyRecuperationEnroll.class,Cnd.where("id","in",enrollIdList));
return null;
}
@At
@ViReturn
@SaCheckLogin
public Object doRecall(String id) {
TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, id);
enroll.setStateId(TheRapyRecuperationState.UNIT);
enroll.setSelfUnionAuditId(null);
dao.update(enroll);
return null;
}
}
@@ -0,0 +1,355 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.audit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.aop.interceptor.ioc.TransAop;
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.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.trans.Trans;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@IocBean
@At("/platform/inclusiveTherapyV3/TheRapyXghAudit")
@Ok("json:full")
public class TheRapyRecuperationXghAuditController {
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyXghAudit.html")
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public void index() {
}
@Inject
private TherapyContext vi;
@Inject
private TheRapyRecuperationAuditService auditService;
@Inject
private Dao dao;
@Inject("refer:staffTherapyDataService")
private BaseService baseService;
@Inject("refer:staffTherapyDataService")
private TherapyService viService;
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public Object pageData(PageForm pageForm, String year, String unionId,
String unitId, String state, String takePartInLineId,
String isAudit, String regionalNature, String lotId,
String selectId) {
Sql sql = Sqls.create("""
SELECT
enroll.*,
line.lineName,
line.id as lineId,
line.regionalNature,
'教职工' userNature,
state.stateColor,
state.stateName,
CONCAT(DATE_FORMAT(rs.playStartTime,'%m月%d日'),'-',DATE_FORMAT(rs.playEndTime,'%m月%d日')) AS linePlayTime,
IF
( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) isFamily,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) num
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN `inclusive_therapy_v3_line_union_select` rs ON rs.id = enroll.takePartInLineId
LEFT JOIN `inclusive_therapy_v3_line` line on line.id=rs.lineId
LEFT JOIN inclusive_therapy_v3_audit_state state ON state.stateId = enroll.stateId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("line.lotId", "=", lotId);
cnd.andEX("line.regionalNature", "=", regionalNature);
cnd.andEX("YEAR(enroll.signingUptime)", "=", year);
cnd.andEX("enroll.selfUnionId", "=", unionId);
cnd.and("enroll.takePartInLineId", "is not", null);
cnd.andEX("enroll.selfUnitId", "=", unitId);
cnd.andEX("line.id", "=", takePartInLineId);
cnd.andEX("enroll.isNormal", "=", true);
cnd.andEX("rs.signUpMode", "=", "2");
cnd.andEX("rs.id", "=", selectId);
if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) {
cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword());
}
if (Strings.isNotBlank(isAudit)) {
if (isAudit.equals("true")) {
cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.PASS)));
} else {
cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.SCHOOL)));
}
} else {
cnd.and(new Static("( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s)".
formatted(TheRapyRecuperationState.SCHOOL, TheRapyRecuperationState.SCHOOLFAIL, TheRapyRecuperationState.PASS)));
}
cnd.desc("enroll.signingUptime");
cnd.desc("enroll.unitName");
sql.setCondition(cnd);
return auditService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public Object getLineNumber(PageForm pageForm, String year, String unionId,
String unitId, String state, String takePartInLineId,
String isAudit, String regionalNature, String lotId, String selectId) {
Sql sql = Sqls.create("""
SELECT
enroll.*,
line.lineName,
line.id as lineId,
line.regionalNature,
'教职工' userNature,
state.stateColor,
state.stateName,
IF
( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) isFamily,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) num
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN `inclusive_therapy_v3_line_union_select` rs ON rs.id = enroll.takePartInLineId
LEFT JOIN `inclusive_therapy_v3_line` line on line.id=rs.lineId
LEFT JOIN inclusive_therapy_v3_audit_state state ON state.stateId = enroll.stateId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("line.lotId", "=", lotId);
cnd.andEX("line.regionalNature", "=", regionalNature);
cnd.andEX("YEAR(enroll.signingUptime)", "=", year);
cnd.andEX("enroll.selfUnionId", "=", unionId);
cnd.and("enroll.takePartInLineId", "is not", null);
cnd.andEX("enroll.selfUnitId", "=", unitId);
cnd.andEX("line.id", "=", takePartInLineId);
cnd.andEX("enroll.isNormal", "=", true);
cnd.andEX("rs.signUpMode", "=", "2");
cnd.andEX("rs.id", "=", selectId);
if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) {
cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword());
}
if (Strings.isNotBlank(isAudit)) {
if (isAudit.equals("true")) {
cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.PASS)));
} else {
cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.SCHOOL)));
}
} else {
cnd.and(new Static("( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s)".
formatted(TheRapyRecuperationState.SCHOOL, TheRapyRecuperationState.SCHOOLFAIL, TheRapyRecuperationState.PASS)));
}
cnd.desc("enroll.signingUptime");
cnd.desc("enroll.unitName");
sql.setCondition(cnd);
List<NutMap> nutMaps = auditService.listMap(sql);
int familyNumber = nutMaps.stream().filter(o -> StrUtil.isNotBlank(o.getString("familyNumber"))).mapToInt(o -> o.getInt("familyNumber")).sum();
return familyNumber + nutMaps.size();
}
/**
* 单个审核
*
* @param id
* @param flag
* @param isTransferIn
* @param auditOpinion
* @return
*/
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public Object doAudit(String id, boolean flag, boolean isTransferIn, String auditOpinion, Boolean adjustment) {
Trans.exec(() -> {
TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id);
TherapyAudit audit = new TherapyAudit();
audit.setAuditOpinion(auditOpinion);
audit.setAuditor(TherapyContext.getUserId());
audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname"));
audit.setUsername((String) TherapyContext.getPrincipalProperty("username"));
audit.setAuditTime(new Date());
audit.setAuditPass(flag);
TherapyAudit insert = auditService.insert(audit);
enroll.setSchoolUnionAuditId(insert.getId());
//如果通过
if (flag) {
enroll.setStateId(TheRapyRecuperationState.PASS);
} else {//审核不通过
enroll.setStateId(TheRapyRecuperationState.SCHOOLFAIL);
}
auditService.updateIgnoreNull(enroll);
auditService.schoolAudit(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId());
if (adjustment) {
// enroll.setNormal(false);
auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "=", enroll.getId()));
}
});
return null;
}
/**
* 撤回
*
* @param id
* @return
*/
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public Object doRecall(String id) {
TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id);
enroll.setStateId(TheRapyRecuperationState.SCHOOL);
enroll.setSchoolUnionAuditId(null);
auditService.update(enroll);
return null;
}
/**
* 批量审核
*
* @param ids
* @param auditOpinion
* @param flag
* @return
*/
@At
@ViReturn
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public Object doOnekeyAudit(String[] ids, String auditOpinion, boolean flag, Boolean adjustment) {
TherapyAudit audit = new TherapyAudit();
audit.setAuditOpinion(auditOpinion);
audit.setAuditor(TherapyContext.getUserId());
audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname"));
audit.setUsername((String) TherapyContext.getPrincipalProperty("username"));
audit.setAuditTime(new Date());
audit.setAuditPass(flag);
TherapyAudit insert = auditService.insert(audit);
//List<TheRapyRecuperationEnroll> enrollList = auditService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", ids));
List<String> enrollIdList = new ArrayList<>();
for (String id : ids) {
TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id);
enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.SCHOOLFAIL);
enroll.setSchoolUnionAuditId(insert.getId());
auditService.updateIgnoreNull(enroll);
auditService.schoolAudit(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId());
if (adjustment) {
// enroll.setNormal(false);
enrollIdList.add(id);
}
}
auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIdList));
return null;
}
/**
* 校工会选择线路查询
*
* @return
*/
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.TheRapyXghAudit")
public Object getXghLine() {
Sql sql = Sqls.create("""
SELECT
line.*,
un.unionname
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN inclusive_therapy_v3_line_union_select lineu ON lineu.id = enroll.takePartInLineId
LEFT JOIN inclusive_therapy_v3_line line ON line.id = lineu.lineId
LEFT JOIN inclusive_therapy_v3_union un ON un.id = enroll.takePartInUnionId
where line.signUpMode='2' and line.createMode='2'
group by line.id
""");
return baseService.listMap(sql);
}
@At
@ViReturn
@SaCheckLogin
public Object getLinePlayTimeByLineId(String lineId,
@Param(value = "signUpMode") Integer signUpMode,
@Param(value = "year") Integer year,
@Param(value = "startYear")Integer startYear,
@Param(value = "endYear")Integer endYear,
@Param(value = "flag") Boolean flag) {
Cnd cnd = Cnd.NEW();
cnd.and("lineId", "=", lineId);
if (flag == null || !flag){
cnd.andEX("signUpMode", "=", signUpMode);
cnd.and("YEAR(selectTime)", "=", year);
} else {
cnd.and("YEAR(selectTime)", ">=", startYear);
cnd.and("YEAR(selectTime)", "<=", endYear);
}
List<TheRapyRecuperationLineUnionSelect> query = dao.query(TheRapyRecuperationLineUnionSelect.class, cnd);
//.and("selectUserId", "=", ShiroUtil.getUserId()).and("unionId", "=", Vi.getUnionId()));
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
List<NutMap> nutMaps = new ArrayList<>();
query.forEach(v -> {
String startTime = DateUtil.formatChineseDate(v.getPlayStartTime(), false, false).substring(5);
String endTime = DateUtil.formatChineseDate(v.getPlayEndTime(), false, false).substring(5);
NutMap map = new NutMap();
List<TheRapyRecuperationEnroll> enrollList = dao.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", v.getId())
.and("isNormal", "=", true)
.and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)));
int hasSignNumber;
if (config.getFamilyInfo() == 1) {
int sum = enrollList.stream().mapToInt(TheRapyRecuperationEnroll::getFamilyNumber).sum();
hasSignNumber = enrollList.size() + sum;
} else {
List<String> list = enrollList.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList());
List<TheRapyRecuperationEnrollCompanion> companions = dao.query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", list));
hasSignNumber = enrollList.size() + companions.size();
}
map.setv("times", startTime + "-" + endTime + "(报名人数:" + hasSignNumber + ",其中家属:" + (hasSignNumber - enrollList.size()) + "人)");
map.setv("selectId", v.getId());
nutMaps.add(map);
});
return nutMaps;
}
}
@@ -0,0 +1,360 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.baseManage;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.base.dao.CndPlus;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.baseManage.TheRapyRecuperationBaseManagerService;
import org.apache.poi.ss.usermodel.Workbook;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
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.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.stream.Collectors;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.baseManage.TheBaseManagerController
* @Description: 疗休养基地管理
* @Author zzr
* @Date 2023/6/5
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/baseManagement")
@Ok("json:full")
public class TheRapyRecuperationBaseManagerController {
@Inject("refer:staffTherapyDataService")
private BaseService baseService;
@Inject
private Dao dao;
@Inject
private TheRapyRecuperationBaseManagerService theRapyRecuperationBaseManagerService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/baseManage/baseManagement.html")
@SaCheckPermission("inclusiveTherapyV3.TheBaseManagement")
public void index() {
}
/**
* 分页展示
*
* @param pageForm 分页对象
* @param year 查询参数
* @param lotId 标段时间
* @param baseName 基地名
* @param unionId 分工会
* @param travelAgencyId 旅行社
* @param regionalNature 活动范围
* @return {@link Object}
*/
@At
@POST
@Ok("json:full")
@ViReturn
@SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR)
public Object pageData(PageForm pageForm, Integer year, String lotId, String baseName, String unionId, String travelAgencyId, String regionalNature) {
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
tb.id,
tb.sortNumber,
tb.baseName,
tb.regionalNature,
tb.year,
tb.isDisabled,
tb.lotId,
tb.createUnionId,
tb.signUpStartTime,
tb.signUpEndTime,
tb.changeEndTime,
tb.createMode,
tb.activityStartTime,
tb.activityEndTime,
tb.files,
tb.baseContactPerson,
tb.baseContactNumber,
tb.files AS fileId,
gh.unionname createUnionName,
u.username createUserName,
ta.travelAgencyName,
ta.contact,
ta.contactMobileNumber,
ta.officialWebsite
FROM
`inclusive_therapy_v3_base_management` tb
LEFT JOIN inclusive_therapy_v3_travel_agency ta ON ta.id = tb.travelAgencyId
LEFT JOIN inclusive_therapy_v3_union gh ON gh.id = tb.createUnionid
LEFT JOIN inclusive_therapy_v3_user u ON u.id = tb.opBy
$condition
""");
cnd.where().andEX("tb.`year`", "=", year);
cnd.where().andEX("tb.lotId", "=", lotId);
cnd.and(Cnd.likeEX("tb.baseName", baseName));
cnd.and(Cnd.likeEX("tb.travelAgencyId", travelAgencyId));
cnd.and(Cnd.likeEX("tb.regionalNature", regionalNature));
cnd.desc("tb.`year`");
cnd.asc("tb.sortNumber");
cnd.asc("tb.id");
if (!TherapyContext.hasAnyRoles(List.of("sysadmin", "A06"))) {
if (TherapyContext.hasRole("H04")) {
cnd.and("tb.createUnionId", "=", TherapyContext.getUnionId());
}
} else {
cnd.andEX("tb.createUnionId", "=", unionId);
}
sql.setCondition(cnd);
return baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
/**
* 是否启用基地线路
*
* @param id 基地线路id
* @return {@link Object}
*/
@At("/openClosedBase/?")
@POST
@ViReturn
@SaCheckLogin
public Object openClosedBase(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
//位运算 取反
dao.update(TheRapyRecuperationBaseManagement.class, Chain.makeSpecial("isDisabled", "isDisabled ^ 1"), Cnd.where("id", "=", id));
return null;
}
/**
* 查询一条基地线路
*
* @param id
* @return
*/
@At("/selectBaseManageById/?")
@ViReturn
@SaCheckLogin
public Object selectBaseManageById(String id) {
Assert.notBlank(id);
return dao.fetchLinks(dao.fetch(TheRapyRecuperationBaseManagement.class, id), "travelAgency");
}
/**
* 新增/修改
*
* @param baseManagement 基地线路
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
@SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR)
public Object doSubmit(@Param("base") TheRapyRecuperationBaseManagement baseManagement) {
baseManagement.setOpBy((String) TherapyContext.getPrincipalProperty("id"));
baseManagement.setCreateUnionId((String) TherapyContext.getPrincipalProperty("unionid"));
baseManagement.setOpAt(String.valueOf(new Date().getTime()));
dao.insertOrUpdate(baseManagement);
return null;//deleteBase
}
/**
* 删除线路
*
* @param id 线路id
* @return {@link Object}
*/
@At("/deleteBase/?")
@POST
@ViReturn
@SaCheckLogin
public Object deleteBase(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
dao.delete(TheRapyRecuperationBaseManagement.class, id);
return null;
}
/**
* 查询所有酒店
*
* @return {@link Object}
*/
@At("/listAllBase")
@POST
@ViReturn
@SaCheckLogin
public Object listAllBase(String startYear, String endYear, String year) {
Sql sql = Sqls.create("select * from `inclusive_therapy_v3_base_management` tb left join `inclusive_therapy_v3_lot` lot on lot.id=tb.lotId $condition");
CndPlus cnd = new CndPlus();
cnd.andEX("tb.`year`", ">=", startYear);
cnd.andEX("tb.`year`", "<=", endYear);
cnd.andEX("tb.`year`", "=", year);
sql.setCondition(cnd);
return baseService.listMap(sql);
}
/**
* 手机端酒店介绍所有信息
*
* @param id id
* @return {@link Object}
*/
@At("/selectBaseAllInfo")
@GET
@ViReturn
@SaCheckLogin
public Object selectBaseAllInfo(@Param("id") String id) {
Assert.notBlank(id);
return theRapyRecuperationBaseManagerService.selectBaseAllInfo(id);
}
/**
* 目的地导入模版
*
* @param response
*/
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.TheBaseManagement")
public void exportTemplate(HttpServletResponse response) {
try {
//查旅行社,转数组
List<TheRapyRecuperationTravelAgency> travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber"));
List<String> excelTravelAgencyList = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList());
String[] excelTravelAgencyArrs = excelTravelAgencyList.toArray(new String[excelTravelAgencyList.size()]);
//查标段,转数组
List<TheRapyRecuperationLot> lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id"));
List<String> excelLotList = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList());
String[] excelLotArrs = excelLotList.toArray(new String[excelLotList.size()]);
TherapyDownload.excelResponse(response, "目的地导入模版.xls");
Class<TheRapyRecuperationBaseManagement> excelModeClass = TheRapyRecuperationBaseManagement.class;
Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields();
//字段过滤
List<Field> needAddReplaceFields = Arrays.stream(excelModeClassDeclaredFields).filter(v -> List.of("travelAgencyId", "lotId", "regionalNature", "isDisabled", "createMode").contains(v.getName())).collect(Collectors.toList());
for (Field field : needAddReplaceFields) {
Excel excelAnnotation = field.getAnnotation(Excel.class);
if (Lang.isNotEmpty(excelAnnotation)) {
InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map e = (Map) memberValues.get(invocationHandler);
e.put("addressList", true);
if (field.getName().equals("travelAgencyId")) {
e.put("replace", excelTravelAgencyArrs);
} else if (field.getName().equals("lotId")) {
e.put("replace", excelLotArrs);
} else if (field.getName().equals("regionalNature")) {
e.put("replace", new String[]{"省内_省内", "省外_省外"});
} else if (field.getName().equals("createMode")) {
e.put("replace", new String[]{"校工会_1", "分工会_2"});
} else if (field.getName().equals("isDisabled")) {
e.put("replace", new String[]{"是_1", "否_0"});
}
}
}
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyRecuperationBaseManagement.class, new ArrayList<>());
ServletOutputStream outputStream = response.getOutputStream();
sheets.write(outputStream);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 目的地导入
*
* @param file
* @return
*/
@At
@ViReturn
@SaCheckLogin
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@Aop(TransAop.READ_COMMITTED)
public Object importBaseManager(TempFile file) {
if (Lang.isEmpty(file)) {
return Result.error("上传的文件不能为空");
}
String extName = FileUtil.extName(file.getFile());
if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) {
return Result.error("请上传xls,xlsx文件");
}
List<TheRapyRecuperationBaseManagement> excelList;
try {
ImportParams importParams = new ImportParams();
excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyRecuperationBaseManagement.class, importParams);
} catch (Exception e) {
e.printStackTrace();
return Result.error("读取不到数据,请检查excel文件格式");
}
if (Lang.isEmpty(excelList)) {
return Result.error("读取不到数据,请检查excel文件格式");
}
try {
if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getBaseName())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyId()))) {
return Result.error("目的地名称和旅行社名称不能为空");
}
if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getRegionalNature()))) {
return Result.error("时间标段和活动范围不能为空");
}
excelList.forEach(v -> v.setOpBy((String) TherapyContext.getPrincipalProperty("id")));
dao.insertOrUpdate(excelList);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,728 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.annotation.Excel;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
import com.budwk.app.sys.models.Sys_office_template;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload;
import com.budwk.app.sys.models.Sys_user_source;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationLineCreateMode;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportExcelMode;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportImageMode;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyTravelLineExcelMode;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.stream.Collectors;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage.TheRapyRecuperationLineController
* @Description: 疗休养线路管理
* @Author zxc
* @Date 2022/5/31:09:34
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/line")
@Ok("json:full")
@Slf4j
public class TheRapyRecuperationLineController {
/**
* 新线路导入模板表头占用1行,图片锚点行号需减去表头行数后才能对应导入数据下标。
*/
private static final int LINE_IMPORT_HEADER_ROWS = 1;
/**
* 新线路导入模板中“联系方式”列下标,设置为文本格式避免手机号被Excel转成科学计数法。
*/
private static final int LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX = 12;
/**
* 新线路导入模板中“移动端缩略图”列下标,用于定位Excel内嵌图片。
*/
private static final int LINE_IMPORT_THUMBNAIL_COLUMN_INDEX = 15;
@Inject
private TheRapyRecuperationLineService lineService;
@Inject
private Dao dao;
@Inject
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.line")
public void downloadTemplate(HttpServletResponse response) throws IOException {
String templateCode = "inclusive_therapy_v3_line_import";
try (InputStream in = sysOfficeTemplateUtil.getTemplate(templateCode)) {
Sys_office_template template = dao.fetch(Sys_office_template.class, Cnd.where("templateCode", "=", templateCode));
TherapyDownload.excelResponse(response, template.getTemplateName());
if (template.getTemplateName().toLowerCase(Locale.ROOT).endsWith(".xls")) {
response.setContentType("application/vnd.ms-excel");
}
in.transferTo(response.getOutputStream());
}
}
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html")
@SaCheckPermission("inclusiveTherapyV3.line")
public void index() {
}
/**
* 页面数据
*
* @param pageForm 分页参数
* @return {@link Object}
*/
@At
@POST
@Ok("json:full")
@ViReturn
@SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR)
public Object pageData(PageForm pageForm, Integer startYear , Integer endYear, String keywords, String travelAgencyId, String lineName, String unionId, String lotId, Integer signUpMode) {
Cnd cnd = Cnd.NEW();
cnd.andEX("line.`year`", ">=", startYear);
cnd.andEX("line.`year`", "<=", endYear);
cnd.andEX("line.travelAgencyId", "=", travelAgencyId);
cnd.andEX("line.lotId", "=", lotId);
cnd.andEX("line.signUpMode", "=", signUpMode);
cnd.and(Cnd.likeEX("line.lineName", lineName));
/*if (StrUtil.isNotBlank(keywords)) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("line.lineName", keywords);
seg.orLike("line.travelAgencyName", keywords);
cnd.and(seg);
}*/
if (!com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasAnyRoles(List.of("sysadmin", "A06"))) {
if (com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasRole("H04")) {
cnd.and("line.createUnionId", "=", TherapyContext.getUnionId());
}
} else {
cnd.andEX("line.createUnionId", "=", unionId);
}
cnd.desc("line.year").asc("line.serialNumber");
return lineService.pageData(pageForm, cnd);
}
@At
@POST
@ViReturn
@SaCheckLogin
@SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR)
public Object getNo() {
Object serialNumber = dao.func2(TheRapyRecuperationLine.class, "max", "serialNumber");
serialNumber = Objects.requireNonNullElse(serialNumber, 0);
return Integer.parseInt(serialNumber.toString()) + 1;
}
/**
* 提交
*
* @param line 线路
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
@SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR)
public Object doSubmit(TheRapyRecuperationLine line) {
if (StrUtil.isBlank(line.getId())) {
if (lineService.count(Cnd.where("serialNumber", "=", line.getSerialNumber())) > 0) {
return Result.error("编号已存在");
}
lineService.addLine(line);
} else {
if (lineService.count(Cnd.where("serialNumber", "=", line.getSerialNumber()).and("id", "!=", line.getId())) > 0) {
return Result.error("编号已存在");
}
lineService.editLine(line);
}
return null;
}
/**
* 开启或关闭线路
*
* @param id 线路id
* @return {@link Object}
*/
@At("/openClosedLine/?")
@POST
@ViReturn
@SaCheckLogin
public Object openClosedLine(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
lineService.openClosedLine(id);
return null;
}
/**
* 删除线路
*
* @param id 线路id
* @return {@link Object}
*/
@At("/deleteLine/?")
@POST
@ViReturn
@SaCheckLogin
public Object deleteLine(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
lineService.deleteLine(id);
return null;
}
/**
* 查询线路详细信息
*
* @param id id
* @return {@link Object}
*/
@At("/selectLineInfoById/?")
@ViReturn
@SaCheckLogin
public Object selectLineInfoById(String id) {
Assert.notBlank(id);
return lineService.selectLineInfoById(id);
}
/**
* 根据分工会选择的线路id查询所该线路报名的人
*
* @param pageForm 页面形式
* @param id id
* @return {@link Object}
*/
@At("/selectLineUser")
@ViReturn
@SaCheckLogin
public Object selectLineUser(PageForm pageForm, String id, String unionId) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
return lineService.selectLineUser(pageForm, id, unionId);
}
@At("/getCreateMode")
@ViReturn
@SaCheckLogin
public Object getCreateMode() {
boolean hasSchoolAdminRole = com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasAnyRoles(List.of("sysadmin", "A06"));
if (hasSchoolAdminRole) {
return TheRapyRecuperationLineCreateMode.SCHOOL.getValue();
}
return TheRapyRecuperationLineCreateMode.UNION.getValue();
}
/**
* 查看各个分工会设置的时间信息
*
* @param id 线路id
* @return {@link Object}
*/
@At("/viewUnionSelectTimeInfo/?")
@ViReturn
@SaCheckLogin
public Object viewUnionSelectTimeInfo(String id) {
Assert.notBlank(id);
return lineService.viewUnionSelectTimeInfo(id);
}
/**
* 是否有权限
*
* @return {@link Object}
*/
@At
@ViReturn
@SaCheckLogin
public Object hasAnyRoles(@Param("roles") String[] roles) {
boolean b = TherapyContext.hasAnyRoles(roles);
return b;
}
/**
* 旅行社
*
* @return {@link Object}
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.line")
public Object getTravelAgencyOptions(Integer year) {
List<TheRapyRecuperationTravelAgency> travelAgencies = lineService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().andEX("year","=",year).asc("serialNumber"));
return travelAgencies;
}
/**
* 线路导入
*
* @param file
* @return
*/
@At
@ViReturn
@SaCheckLogin
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@Aop(TransAop.READ_COMMITTED)
public Object travelLineImport(TempFile file) {
if (Lang.isEmpty(file)) {
return Result.error("上传的文件不能为空");
}
String extName = FileUtil.extName(file.getFile());
if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) {
return Result.error("请上传xls,xlsx文件");
}
List<TheRapyTravelLineExcelMode> excelList;
try {
ImportParams importParams = new ImportParams();
excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelLineExcelMode.class, importParams);
} catch (Exception e) {
log.error(e.getMessage());
return Result.error("读取不到数据,请检查excel文件格式");
}
if (Lang.isEmpty(excelList)) {
return Result.error("读取不到数据,请检查excel文件格式");
}
try {
if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyId()))) {
return Result.error("旅行社名称不能为空");
}
if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getRegionalNature()))) {
return Result.error("时间标段和活动范围不能为空");
}
List<TheRapyRecuperationLine> list = new ArrayList<>();
for (TheRapyTravelLineExcelMode mode : excelList) {
TheRapyRecuperationLine line = new TheRapyRecuperationLine();
line.setYear(mode.getYear());
line.setSerialNumber(mode.getSerialNumber());
line.setLineName(mode.getLineName());
line.setTravelAgencyId(mode.getTravelAgencyId());
line.setRegionalNature(mode.getRegionalNature());
line.setContent(mode.getContent());
line.setMinimumGroupSize(mode.getMinimumGroupSize());
if (mode.getIsDisabled().equals("是")) {
line.setDisabled(false);
} else if (mode.getIsDisabled().equals("否")) {
line.setDisabled(true);
}
line.setEstimatedCost(mode.getEstimatedCost());
line.setLotId(mode.getLotId());
// line.setLineContact(mode.getLineContact());
// line.setLineContactPhone(mode.getLineContactPhone());
list.add(line);
}
dao.insert(list);
} catch (Exception e) {
log.error(e.getMessage());
return Result.error("导入失败");
}
return null;
}
/**
* 线路导入模版
*
* @param response
*/
/**
* 按线路管理页面字段导入线路。
*
* @param file Excel文件
* @return 导入结果
*/
@At
@ViReturn
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.line")
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@Aop(TransAop.READ_COMMITTED)
public Object importLineByPageFields(TempFile file) {
if (Lang.isEmpty(file)) {
return Result.error("上传的文件不能为空");
}
String extName = FileUtil.extName(file.getFile());
if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) {
return Result.error("请上传xls,xlsx文件");
}
List<TheRapyLineImportExcelMode> excelList;
Map<Integer, TheRapyLineImportImageMode> imageMap;
try {
ImportParams importParams = new ImportParams();
excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyLineImportExcelMode.class, importParams);
fillLineImportContactPhone(excelList, file.getFile());
imageMap = extractLineImportImages(file.getFile(), extName);
} catch (Exception e) {
log.error(e.getMessage());
return Result.error("读取不到数据,请检查excel文件格式");
}
if (Lang.isEmpty(excelList)) {
return Result.error("读取不到数据,请检查excel文件格式");
}
try {
int count = lineService.importLineByPageFields(excelList, imageMap);
return Result.success("成功导入" + count + "条线路");
} catch (Exception e) {
log.error(e.getMessage());
return Result.error(e.getMessage());
}
}
/**
* 下载按线路管理页面字段生成的新线路导入模板。
*
* @param response 响应对象
*/
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.line")
public void exportPageFieldsTemplate(HttpServletResponse response) {
try {
// 标段下拉复用页面配置接口返回的标段数据。
List<TheRapyRecuperationLot> lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id"));
List<String> excelLots = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList());
List<Field> needAddReplaceFields = Arrays.stream(TheRapyLineImportExcelMode.class.getDeclaredFields())
.filter(v -> List.of("lotId", "regionalNature", "signUpMode", "isEnabled", "familySignUp").contains(v.getName()))
.collect(Collectors.toList());
for (Field field : needAddReplaceFields) {
Excel excelAnnotation = field.getAnnotation(Excel.class);
if (Lang.isEmpty(excelAnnotation)) {
continue;
}
InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map e = (Map) memberValues.get(invocationHandler);
e.put("addressList", true);
if (field.getName().equals("lotId")) {
e.put("replace", excelLots.toArray(new String[0]));
} else if (field.getName().equals("regionalNature")) {
e.put("replace", buildRegionalNatureExcelOptions());
} else if (field.getName().equals("signUpMode")) {
e.put("replace", buildSignUpModeExcelOptions());
} else if (field.getName().equals("isEnabled") || field.getName().equals("familySignUp")) {
e.put("replace", new String[]{"是_是", "否_否"});
}
}
TherapyDownload.excelResponse(response, "线路导入模板.xlsx");
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyLineImportExcelMode.class, new ArrayList<>());
applyLineImportTemplateCellStyle(sheets);
ServletOutputStream outputStream = response.getOutputStream();
sheets.write(outputStream);
outputStream.close();
} catch (Exception e) {
log.error(e.getMessage());
}
}
/**
* 设置新线路导入模板的关键列格式。
*
* @param workbook 导出的模板工作簿
*/
private void applyLineImportTemplateCellStyle(Workbook workbook) {
Sheet sheet = workbook.getSheetAt(0);
DataFormat dataFormat = workbook.createDataFormat();
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat(dataFormat.getFormat("@"));
// 联系方式按字符串字段处理,模板层面先把整列设置为文本格式。
sheet.setDefaultColumnStyle(LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX, textStyle);
sheet.setColumnWidth(LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX, 20 * 256);
sheet.setColumnWidth(LINE_IMPORT_THUMBNAIL_COLUMN_INDEX, 20 * 256);
}
/**
* 按Excel显示文本重读“联系方式”列,确保长手机号等内容按字符串导入。
*
* @param excelList EasyPoi读取出的导入数据
* @param excelFile Excel文件
* @throws Exception Excel读取失败时抛出异常
*/
private void fillLineImportContactPhone(List<TheRapyLineImportExcelMode> excelList, File excelFile) throws Exception {
DataFormatter dataFormatter = new DataFormatter();
try (InputStream inputStream = new FileInputStream(excelFile);
Workbook workbook = WorkbookFactory.create(inputStream)) {
Sheet sheet = workbook.getSheetAt(0);
for (int i = 0; i < excelList.size(); i++) {
Row row = sheet.getRow(i + LINE_IMPORT_HEADER_ROWS);
if (row == null) {
continue;
}
Cell cell = row.getCell(LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX);
if (cell == null) {
continue;
}
// 使用DataFormatter读取用户看到的文本,避免联系方式被当作数值转成科学计数法。
String phone = dataFormatter.formatCellValue(cell);
if (StrUtil.isNotBlank(phone)) {
excelList.get(i).setLineContactPhone(phone.trim());
}
}
}
}
/**
* 提取新线路导入模板“移动端缩略图”列中的内嵌图片。
*
* @param excelFile Excel文件
* @param extName 文件扩展名
* @return key为导入数据行下标、value为图片内容的映射
* @throws Exception Excel读取失败时抛出异常
*/
private Map<Integer, TheRapyLineImportImageMode> extractLineImportImages(File excelFile, String extName) throws Exception {
if ("xlsx".equalsIgnoreCase(extName)) {
return extractXlsxLineImportImages(excelFile);
}
return extractXlsLineImportImages(excelFile);
}
/**
* 解析xlsx模板中的内嵌图片,按图片左上角锚点匹配到“移动端缩略图”列。
*
* @param excelFile xlsx文件
* @return 图片映射
* @throws Exception Excel读取失败时抛出异常
*/
private Map<Integer, TheRapyLineImportImageMode> extractXlsxLineImportImages(File excelFile) throws Exception {
Map<Integer, TheRapyLineImportImageMode> imageMap = new HashMap<>();
try (InputStream inputStream = new FileInputStream(excelFile);
XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
XSSFSheet sheet = workbook.getSheetAt(0);
XSSFDrawing drawing = sheet.getDrawingPatriarch();
if (drawing == null) {
return imageMap;
}
for (XSSFShape shape : drawing.getShapes()) {
if (!(shape instanceof XSSFPicture)) {
continue;
}
XSSFPicture picture = (XSSFPicture) shape;
if (!(picture.getAnchor() instanceof XSSFClientAnchor)) {
continue;
}
XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();
XSSFPictureData pictureData = picture.getPictureData();
addLineImportImage(imageMap, anchor.getRow1(), anchor.getCol1(), anchor.getCol2(), pictureData.suggestFileExtension(), pictureData.getData());
}
}
return imageMap;
}
/**
* 解析xls模板中的内嵌图片,按图片左上角锚点匹配到“移动端缩略图”列。
*
* @param excelFile xls文件
* @return 图片映射
* @throws Exception Excel读取失败时抛出异常
*/
private Map<Integer, TheRapyLineImportImageMode> extractXlsLineImportImages(File excelFile) throws Exception {
Map<Integer, TheRapyLineImportImageMode> imageMap = new HashMap<>();
try (InputStream inputStream = new FileInputStream(excelFile);
HSSFWorkbook workbook = new HSSFWorkbook(inputStream)) {
HSSFSheet sheet = workbook.getSheetAt(0);
HSSFPatriarch drawing = sheet.getDrawingPatriarch();
if (drawing == null) {
return imageMap;
}
for (HSSFShape shape : drawing.getChildren()) {
if (!(shape instanceof HSSFPicture)) {
continue;
}
HSSFPicture picture = (HSSFPicture) shape;
if (!(picture.getAnchor() instanceof HSSFClientAnchor)) {
continue;
}
HSSFClientAnchor anchor = (HSSFClientAnchor) picture.getAnchor();
HSSFPictureData pictureData = picture.getPictureData();
addLineImportImage(imageMap, anchor.getRow1(), anchor.getCol1(), anchor.getCol2(), pictureData.suggestFileExtension(), pictureData.getData());
}
}
return imageMap;
}
/**
* 将匹配到缩略图列的图片加入映射,重复图片只保留同一行第一张。
*
* @param imageMap 图片映射
* @param rowIndex 图片左上角锚点行下标
* @param colIndex 图片左上角锚点列下标
* @param endColIndex 图片右下角锚点列下标
* @param extension 图片扩展名
* @param data 图片二进制内容
*/
private void addLineImportImage(Map<Integer, TheRapyLineImportImageMode> imageMap, int rowIndex, int colIndex, int endColIndex, String extension, byte[] data) {
int imageEndColIndex = Math.max(colIndex, endColIndex);
boolean coverThumbnailColumn = colIndex <= LINE_IMPORT_THUMBNAIL_COLUMN_INDEX && imageEndColIndex >= LINE_IMPORT_THUMBNAIL_COLUMN_INDEX;
if (rowIndex < LINE_IMPORT_HEADER_ROWS || !coverThumbnailColumn || data == null || data.length == 0) {
return;
}
int dataIndex = rowIndex - LINE_IMPORT_HEADER_ROWS;
TheRapyLineImportImageMode imageMode = new TheRapyLineImportImageMode();
imageMode.setRowIndex(dataIndex);
imageMode.setExtension(extension);
imageMode.setFileName("line-thumbnail-" + (dataIndex + 1) + "." + StrUtil.blankToDefault(extension, "png"));
imageMode.setData(data);
imageMap.putIfAbsent(dataIndex, imageMode);
}
/**
* 构建与页面线路类型一致的Excel下拉选项。
*
* @return 线路类型下拉选项
*/
private String[] buildRegionalNatureExcelOptions() {
if (!TherapyContext.hasAnyRoles(new String[]{"sysadmin", "A06"})) {
return new String[]{"省内线路_省内"};
}
return new String[]{"省内线路_省内", "省外线路_省外"};
}
/**
* 构建与页面组织形式一致的Excel下拉选项。
*
* @return 组织形式下拉选项
*/
private String[] buildSignUpModeExcelOptions() {
List<String> options = new ArrayList<>();
if (TherapyContext.hasAnyRoles(new String[]{"sysadmin", "A06", "H04"})) {
options.add("分工会组织_1");
}
if (TherapyContext.hasAnyRoles(new String[]{"sysadmin", "A06"})) {
options.add("校工会组织_2");
}
return options.toArray(new String[0]);
}
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.line")
public void exportTemplate(HttpServletResponse response) {
try {
//查旅行社,转数组
List<TheRapyRecuperationTravelAgency> travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber"));
List<String> excelTravelAgencys = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList());
String[] excelTravelAgencyArrs = excelTravelAgencys.toArray(new String[excelTravelAgencys.size()]);
//查标段,转数组
List<TheRapyRecuperationLot> lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id"));
List<String> excelLots = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList());
String[] excelLotArrs = excelLots.toArray(new String[excelLots.size()]);
TherapyDownload.excelResponse(response, "线路导入模版.xls");
Class<TheRapyTravelLineExcelMode> excelModeClass = TheRapyTravelLineExcelMode.class;
Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields();
//字段过滤
List<Field> needAddReplaceFields = Arrays.stream(excelModeClassDeclaredFields).filter(v -> List.of("travelAgencyId", "lotId", "regionalNature").contains(v.getName())).collect(Collectors.toList());
//循环TheRapyTravelLineExcelMode需要下拉数据的字段
for (Field field : needAddReplaceFields) {
Excel excelAnnotation = field.getAnnotation(Excel.class);
if (Lang.isNotEmpty(excelAnnotation)) {
InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map e = (Map) memberValues.get(invocationHandler);
e.put("addressList", true);
if (field.getName().equals("travelAgencyId")) {
e.put("replace", excelTravelAgencyArrs);
} else if (field.getName().equals("lotId")) {
e.put("replace", excelLotArrs);
} else if (field.getName().equals("regionalNature")) {
e.put("replace", new String[]{"省内_省内", "省外_省外"});
}
}
}
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyTravelLineExcelMode.class, new ArrayList<>());
ServletOutputStream outputStream = response.getOutputStream();
sheets.write(outputStream);
outputStream.close();
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
@@ -0,0 +1,395 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
import com.budwk.app.sys.models.Sys_office_template;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.PageUtil;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyTravelAgencyExcelMode;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationTravelAgencyService;
import lombok.extern.slf4j.Slf4j;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.nutz.trans.Trans;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.math.BigDecimal;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.http.HttpServletResponse;
/**
* 疗休养旅行社管理
*
* @author jug
* @date 2022/05/31
*/
@IocBean
@At("/platform/inclusiveTherapyV3/travelAgency")
@Ok("json:full")
@Slf4j
public class TheRapyRecuperationTravelAgencyController {
@Inject
private TheRapyRecuperationTravelAgencyService travelAgencyService;
@Inject
private Dao dao;
@Inject
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html")
@SaCheckPermission("inclusiveTherapyV3.travelAgency")
public void index() {
}
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.travelAgency")
public void downloadTemplate(HttpServletResponse response) throws IOException {
String templateCode = "inclusive_therapy_v3_travel_agency_import";
try (InputStream in = sysOfficeTemplateUtil.getTemplate(templateCode)) {
Sys_office_template template = dao.fetch(Sys_office_template.class, Cnd.where("templateCode", "=", templateCode));
TherapyDownload.excelResponse(response, template.getTemplateName());
if (template.getTemplateName().toLowerCase(java.util.Locale.ROOT).endsWith(".xls")) {
response.setContentType("application/vnd.ms-excel");
}
in.transferTo(response.getOutputStream());
}
}
/**
* 页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object pageData(PageForm pageForm, Integer year, String keywords) {
Cnd cnd = Cnd.NEW();
cnd.andEX("year", "=", year);
if (StrUtil.isNotBlank(keywords)) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("contact", keywords);
seg.orLike("travelAgencyName", keywords);
seg.orLike("serialNumber", keywords);
cnd.and(seg);
}
if (StrUtil.isAllNotBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
} else {
cnd.asc("serialNumber * 1");
}
return travelAgencyService.pageData(pageForm, cnd);
}
/**
* 提交
*
* @param travelAgency 旅行社
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object doSubmit(@Param("travelAgency") TheRapyRecuperationTravelAgency travelAgency) {
if (StrUtil.isBlank(travelAgency.getId())) {
if (travelAgencyService.count(Cnd.where("serialNumber", "=", travelAgency.getSerialNumber())) > 0) {
return Result.error("编号已存在");
}
travelAgencyService.addTravelAgency(travelAgency);
} else {
if (travelAgencyService.count(Cnd.where("serialNumber", "=", travelAgency.getSerialNumber()).and("id", "!=", travelAgency.getId())) > 0) {
return Result.error("编号已存在");
}
travelAgencyService.editTravelAgency(travelAgency);
}
return null;
}
/**
* 开启或关闭旅行社
*
* @param id 旅行社id
* @return {@link Object}
*/
@At("/openClosedTravelAgency/?")
@POST
@ViReturn
@SaCheckLogin
public Object openClosedTravelAgency(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
travelAgencyService.openTravelAgency(id);
return null;
}
/**
* 删除旅行社
*
* @param id 旅行社id
* @return {@link Object}
*/
@At("/deleteTravelAgency/?")
@POST
@ViReturn
@SaCheckLogin
public Object deleteTravelAgency(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
travelAgencyService.deleteTravelAgency(id);
return null;
}
/**
* 查询旅行社
*
* @param year 年度
* @return {@link Object}
*/
@At("/selectTravelAgency")
@ViReturn
@SaCheckLogin
public Object selectTravelAgency(Integer year) {
Cnd cnd = Cnd.NEW();
cnd.andEX("year", "=", year);
return travelAgencyService.selectAllTravelAgencyByYear(cnd);
}
/**
* 年度区间查询旅行社
*
* @param startYear 开始一年
* @param endYear 结束一年
* @return {@link Object}
*/
@At("/selectTravelAgencyByYears")
@ViReturn
@SaCheckLogin
public Object selectTravelAgencyByYears(Integer startYear, Integer endYear, Integer year) {
Cnd cnd = Cnd.NEW();
if(startYear != null && endYear != null) {
cnd.andEX("year", ">=", startYear);
cnd.andEX("year", "<=", endYear);
}else {
cnd.andEX("year", "=", year);
}
return travelAgencyService.selectAllTravelAgencyByYear(cnd);
}
/**
* 根据旅行社id查线路
*
* @param agencyId 代理id
* @return {@link Object}
*/
@At("/selectLineByAgencyId")
@ViReturn
@SaCheckLogin
public Object selectLineByAgencyId(String agencyId) {
Sql sql = Sqls.create("""
SELECT id,lineName FROM `inclusive_therapy_v3_line` WHERE travelAgencyId=@travelAgencyId
""").setParam("travelAgencyId", agencyId);
return travelAgencyService.listMap(sql);
}
/**
* 旅行社导入
*
* @param file
* @return
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.travelAgency")
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Object travelAgencyImport(TempFile file) {
if (Lang.isEmpty(file)) {
return Result.error("上传的文件不能为空");
}
String extName = FileUtil.extName(file.getFile());
if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) {
return Result.error("请上传xls,xlsx文件");
}
List<TheRapyTravelAgencyExcelMode> excelList = new ArrayList<>();
List<Integer> excelRowNumbers = new ArrayList<>();
try (Workbook workbook = WorkbookFactory.create(file.getFile())) {
Sheet sheet = workbook.getSheetAt(0);
Row header = sheet.getRow(0);
if (header == null) return Result.error("第一行必须是模板表头");
DataFormatter formatter = new DataFormatter();
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
Map<String, Integer> headers = new java.util.LinkedHashMap<>();
for (Cell cell : header) {
String name = formatter.formatCellValue(cell).trim().replace("(可填)", "").replace("(可填)", "");
if ("编号".equals(name)) name = "排序编号";
if ("是否启用".equals(name)) name = "是否启用(是/否)";
if (StrUtil.isBlank(name)) continue;
if (headers.putIfAbsent(name, cell.getColumnIndex()) != null) return Result.error("模板表头重复:" + name);
}
for (String name : List.of("年度", "排序编号", "旅行社名称", "是否自由组团(是/否)", "旅行社联系人", "联系电话")) {
if (!headers.containsKey(name)) return Result.error("模板缺少必填列:" + name);
}
for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
Row dataRow = sheet.getRow(rowIndex);
if (dataRow == null) continue;
Map<String, String> values = new java.util.HashMap<>();
for (Map.Entry<String, Integer> column : headers.entrySet()) {
Cell cell = dataRow.getCell(column.getValue());
String value = formatter.formatCellValue(cell, evaluator).trim();
if (cell != null && ("年度".equals(column.getKey()) || "最多承担人数".equals(column.getKey()))) {
CellValue evaluated = evaluator.evaluate(cell);
if (evaluated != null && evaluated.getCellType() == CellType.NUMERIC) {
value = BigDecimal.valueOf(evaluated.getNumberValue()).toPlainString();
}
}
values.put(column.getKey(), value);
}
if (values.values().stream().allMatch(StrUtil::isBlank)) continue;
TheRapyTravelAgencyExcelMode travel = new TheRapyTravelAgencyExcelMode();
try {
if (StrUtil.isNotBlank(values.get("年度"))) {
travel.setYear(new BigDecimal(values.get("年度")).intValueExact());
}
} catch (NumberFormatException | ArithmeticException e) {
return Result.error("第" + (rowIndex + 1) + "行:年度须填写4位整数");
}
try {
if (StrUtil.isNotBlank(values.get("最多承担人数"))) {
travel.setMaxUndertakeNumber(new BigDecimal(values.get("最多承担人数")).intValueExact());
}
} catch (NumberFormatException | ArithmeticException e) {
return Result.error("第" + (rowIndex + 1) + "行:最多承担人数须填写有效整数");
}
travel.setSerialNumber(values.get("排序编号"));
travel.setTravelAgencyName(values.get("旅行社名称"));
travel.setSignUpTravelAgency(values.get("是否自由组团(是/否)"));
travel.setContact(values.get("旅行社联系人"));
travel.setContactMobileNumber(values.get("联系电话"));
travel.setEmail(values.get("邮箱"));
travel.setOfficialWebsite(values.get("官网"));
travel.setNote(values.get("备注"));
travel.setIsDisabled(values.get("是否启用(是/否)"));
excelList.add(travel);
excelRowNumbers.add(rowIndex + 1);
}
} catch (Exception e) {
log.error("读取旅行社导入文件失败", e);
return Result.error("读取失败,请使用新模板;年度和最多承担人数须填写整数");
}
if (Lang.isEmpty(excelList)) {
return Result.error("读取不到数据,请检查excel文件格式");
}
List<TheRapyRecuperationTravelAgency> list = new ArrayList<>();
Map<String, Integer> importedNumbers = new java.util.HashMap<>();
for (int index = 0; index < excelList.size(); index++) {
TheRapyTravelAgencyExcelMode travel = excelList.get(index);
String row = "第" + excelRowNumbers.get(index) + "行:";
travel.setSerialNumber(StrUtil.trim(travel.getSerialNumber()));
travel.setTravelAgencyName(StrUtil.trim(travel.getTravelAgencyName()));
travel.setContact(StrUtil.trim(travel.getContact()));
travel.setContactMobileNumber(StrUtil.trim(travel.getContactMobileNumber()));
travel.setSignUpTravelAgency(StrUtil.trim(travel.getSignUpTravelAgency()));
travel.setIsDisabled(StrUtil.trim(travel.getIsDisabled()));
travel.setEmail(StrUtil.trim(travel.getEmail()));
travel.setOfficialWebsite(StrUtil.trim(travel.getOfficialWebsite()));
if (travel.getYear() == null || travel.getYear() < 1000 || travel.getYear() > 9999) {
return Result.error(row + "年度须填写4位整数");
}
if (StrUtil.isBlank(travel.getSerialNumber()) || StrUtil.isBlank(travel.getTravelAgencyName())
|| StrUtil.isBlank(travel.getContact()) || StrUtil.isBlank(travel.getContactMobileNumber())) {
return Result.error(row + "编号、旅行社名称、旅行社联系人和联系电话不能为空");
}
if (!List.of("是", "否").contains(travel.getSignUpTravelAgency() == null ? "" : travel.getSignUpTravelAgency())) {
return Result.error(row + "是否自由组团须填写是或否");
}
if (StrUtil.isBlank(travel.getIsDisabled())) travel.setIsDisabled("是");
if (!List.of("是", "否").contains(travel.getIsDisabled())) return Result.error(row + "是否启用须填写是或否");
if (!travel.getContactMobileNumber().matches("^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$")) {
return Result.error(row + "联系电话格式不正确");
}
if (travel.getSerialNumber().length() > 50 || travel.getTravelAgencyName().length() > 50
|| travel.getContact().length() > 10 || StrUtil.length(travel.getEmail()) > 50
|| StrUtil.length(travel.getOfficialWebsite()) > 100 || StrUtil.length(travel.getNote()) > 100) {
return Result.error(row + "字段长度超限:编号/名称/邮箱最多50字,联系人10字,官网/备注100字");
}
if (StrUtil.isNotBlank(travel.getEmail()) && !cn.hutool.core.lang.Validator.isEmail(travel.getEmail())) {
return Result.error(row + "邮箱格式不正确");
}
if (StrUtil.isNotBlank(travel.getOfficialWebsite()) && !cn.hutool.core.lang.Validator.isUrl(travel.getOfficialWebsite())) {
return Result.error(row + "官网须填写完整网址");
}
if (travel.getMaxUndertakeNumber() != null && travel.getMaxUndertakeNumber() < 0) {
return Result.error(row + "最多承担人数不能小于0");
}
Integer previousRow = importedNumbers.putIfAbsent(travel.getSerialNumber(), excelRowNumbers.get(index));
if (previousRow != null) return Result.error(row + "编号与第" + previousRow + "行重复");
List<TheRapyRecuperationTravelAgency> existing = dao.query(TheRapyRecuperationTravelAgency.class,
Cnd.where("serialNumber", "=", travel.getSerialNumber()));
if (existing.size() > 1) return Result.error(row + "数据库中该编号对应多条旅行社记录");
TheRapyRecuperationTravelAgency agency = existing.isEmpty() ? new TheRapyRecuperationTravelAgency() : existing.get(0);
agency.setDisabled("否".equals(travel.getIsDisabled()));
agency.setSignUpTravelAgency("是".equals(travel.getSignUpTravelAgency()));
agency.setContact(travel.getContact());
agency.setTravelAgencyName(travel.getTravelAgencyName());
agency.setSerialNumber(travel.getSerialNumber());
agency.setEmail(travel.getEmail());
agency.setMaxUndertakeNumber(travel.getMaxUndertakeNumber());
agency.setContactMobileNumber(travel.getContactMobileNumber());
agency.setNote(travel.getNote());
agency.setYear(travel.getYear());
agency.setOfficialWebsite(travel.getOfficialWebsite());
list.add(agency);
}
try {
Trans.exec(() -> dao.insertOrUpdate(list));
} catch (Exception e) {
log.error("导入旅行社失败", e);
return Result.error("导入旅行社失败");
}
return Result.success("成功导入" + list.size() + "条旅行社");
}
}
@@ -0,0 +1,74 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.mobile;
import cn.dev33.satoken.annotation.SaCheckLogin;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
/**
* @Author JyuHsin
* @Date 2022/6/2
* @Description 疗休养页面跳转controller
*/
@IocBean
@At("/platform/inclusiveTherapyV3/mobile")
@Ok("json:full")
public class MobileTheRapyRecuperationEnrollController {
/**
* 手机端 首页
*/
@At("/index")
@Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/index.html")
@SaCheckLogin
public void index() {
}
/**
* 手机端 线路列表页面
*/
@At("/mobileLineListPage")
@Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/lineList.html")
@SaCheckLogin
public void mobileLinePage() {
}
/**
* 手机端 线路详情页面
*/
@At("/lineInfo")
@Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/lineInfo.html")
@SaCheckLogin
public void lineInfo() {
}
/**
* 手机端 基地详情页面
*/
@At("/baseInfo")
@Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/baseManagement.html")
@SaCheckLogin
public void baseInfo() {
}
/**
* 手机端 我的疗休养页面
*/
@At("/myRecuperation")
@Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/myRecuperation.html")
@SaCheckLogin
public void myRecuperation() {
}
@At("/userSignInfo")
@Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/userSignInfo.html")
@SaCheckLogin
public void userSignInfo() {
}
}
@@ -0,0 +1,501 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationCommonService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationTravelAgencyService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.web.commons.base.Globals;
import cn.dev33.satoken.annotation.SaCheckLogin;
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.Daos;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
/**
* @FileName io.v.nutz.therapyRecuperation.controller.process.TheRapyRecuperationEnroll
* @Description: 疗休养报名报名
* @Author zxc
* @Date 2022/5/31:16:58
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/line/enroll")
@Ok("json:full")
public class TheRapyRecuperationEnrollController {
/**
* 单应用部署下按选择线路时段加锁,避免同一条线路最后一个名额被并发请求同时校验通过。
*/
private static final Map<String, ReentrantLock> LINE_SIGN_UP_LOCKS = new ConcurrentHashMap<>();
@Inject
private Dao dao;
@Inject
private TheRapyRecuperationEnrollService enrollService;
@Inject
private TheRapyRecuperationTravelAgencyService travelAgencyService;
@Inject
private TheRapyRecuperationCommonService commonService;
/**
* 线路的value集合 [0,1]
*/
static List<Integer> lineValues = new ArrayList<>() {{
add(TheRapyRecuperationType.provinceInLine.getValue());
add(TheRapyRecuperationType.provinceOutLine.getValue());
}};
static List<Integer> travelAgencies = new ArrayList<>() {{
add(TheRapyRecuperationType.provinceInTravelAgency.getValue());
}};
// static List<Integer> schoolFreeValues = new ArrayList<>() {{
// add(TheRapyRecuperationType.schoolFree.getValue());
// }};
@Inject
private TheRapyRecuperationLineService lineService;
/**
* 页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @param unionId 选择的工会id
* @param theRapyRecuperationType 线路类型 见下枚举类
* @param lineKeyword 移动端线路名称搜索关键字
* @param signUpStatus 报名状态筛选,0 全部、1 报名中、2 报名已结束
* @return {@link Object}
* @see com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object pageData(PageForm pageForm, Integer year, String unionId, int theRapyRecuperationType, Integer lineUnionType, String lineKeyword, Integer signUpStatus) {
return enrollService.enrollPageData(pageForm, year, unionId, theRapyRecuperationType, lineUnionType, lineKeyword, signUpStatus);
}
@At
@POST
@ViReturn
@SaCheckLogin
public Object getSelectLineById(String lineId, String usId, String unionId, int theRapyRecuperationType, Integer lineUnionType, Integer signUpStatus) {
return enrollService.getSelectLineById(lineId, usId, unionId, theRapyRecuperationType, lineUnionType, signUpStatus);
}
@At
@POST
@ViReturn
@SaCheckLogin
public Object openSignUser(String usId, String travelId, String searchKeyWord) {
return enrollService.openSignUser(usId, travelId, searchKeyWord);
}
//获取设置了公开线路的分工会
@At
@ViReturn
@SaCheckLogin
public Object getTheRapyUnions(Integer year, int theRapyRecuperationType) {
return enrollService.getTheRapyUnions(year, theRapyRecuperationType);
}
/**
* 线路报名及修改
*
* @param enrollInfo 登记信息
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object doSignUpForLine(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) {
if (StrUtil.isBlank(enrollInfo.getId())) {
if (StrUtil.isBlank(enrollInfo.getTakePartInLineId())) {
return Result.error("请选择线路");
}
ReentrantLock lock = LINE_SIGN_UP_LOCKS.computeIfAbsent(enrollInfo.getTakePartInLineId(), key -> new ReentrantLock());
boolean locked = false;
try {
locked = lock.tryLock(10, TimeUnit.SECONDS);
if (!locked) {
return Result.error("当前线路报名人数较多,请稍后重试");
}
Map<Boolean, String> validResult = validLineSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
if (validResult.containsKey(false)) {
return Result.error(validResult.get(false));
}
enrollService.doSignUpForLine(enrollInfo);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return Result.error("当前线路报名处理中,请稍后重试");
} finally {
if (locked) {
lock.unlock();
}
}
return null;
}
Map<Boolean, String> validResult = validLineSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
if (validResult.containsKey(false)) {
return Result.error(validResult.get(false));
}
enrollService.updateSignUpLine(enrollInfo);
return null;
}
/**
* 按当前系统疗休养版本执行线路报名校验。
*
* @param loginName 当前登录人工号
* @param enrollInfo 报名信息,新增时必须包含takePartInLineId,编辑时包含报名记录id
* @return 校验结果,包含false时表示不可继续保存,value为前端提示文案
*/
private Map<Boolean, String> validLineSignUpInfo(String loginName, TheRapyRecuperationEnroll enrollInfo) {
Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion"));
Map<Boolean, String> validResult = new HashMap<>();
if ("zjxu".equals(config.getConfigValue())) {
validResult = enrollService.validSignUpInfoForZJXU(loginName, enrollInfo);
} else if ("zjiet".equals(config.getConfigValue())) {
validResult = enrollService.validSignUpInfo(loginName, enrollInfo);
} else if ("zjnu".equals(config.getConfigValue())) {
validResult = enrollService.validSignUpInfoForZJNU(loginName, enrollInfo);
}
return validResult;
}
/**
* 报名参加旅行社
*
* @param enrollInfo 登记信息
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object doSignUpForTravelAgency(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) {
Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion"));
Map<Boolean, String> resultMap = new HashMap<>();
if("zjxu".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfoForZJXU((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
} else if("zjiet".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
} else if("zjnu".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfoForZJNU((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
}
if (resultMap.containsKey(false)) {
return Result.error(resultMap.get(false));
}
if (StrUtil.isBlank(enrollInfo.getId())) {
enrollService.doSignUpForTravelAgency(enrollInfo);
} else {
enrollService.updateSignUpTravelAgency(enrollInfo);
}
return null;
}
/**
* 报名参加酒店
*
* @param enrollInfo 登记信息
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object doSignUpForBaseManagement(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) {
Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion"));
Map<Boolean, String> resultMap = new HashMap<>();
if("zjxu".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfoForZJXU((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
} else {
resultMap = enrollService.validSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo);
}
if (resultMap.containsKey(false)) {
return Result.error(resultMap.get(false));
}
if (StrUtil.isBlank(enrollInfo.getId())) {
enrollService.doSignUpForHotel(enrollInfo);
} else {
enrollService.updateSignUpHotel(enrollInfo);
}
return null;
}
@At("/findSignUpInfoById/?")
@POST
@ViReturn
@SaCheckLogin
public Object findSignUpInfoById(String id) {
return enrollService.findSignUpInfoById(id);
}
/**
* 我报名的页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @param theRapyRecuperationType rapy恢复类型
* @param auditStateId 审核状态
* @param signUpStateId 报名状态 全部0 已报名1 已参加2 未参加3
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object mySignUpPageData(PageForm pageForm, Integer year, int theRapyRecuperationType, Integer auditStateId, int signUpStateId) {
Cnd cnd = Cnd.NEW();
cnd.and("e.loginName", "=", TherapyContext.getPrincipalProperty("loginname"));
switch (signUpStateId) {
case 1 -> cnd.and("1", "=", 1);
case 2 -> cnd.and("e.isTakePartIn", "=", 1);
default -> {
cnd.and("e.isTakePartIn", "=", 0);
}
}
return enrollService.mySignUpPageData(pageForm, cnd, theRapyRecuperationType, year);
}
@At
@POST
@ViReturn
@SaCheckLogin
public Object getType() {
List<TheRapyRecuperationLine> inList = dao.query(TheRapyRecuperationLine.class, Cnd.where("regionalNature", "=", "省内"));
List<String> inIds = inList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList());
List<TheRapyRecuperationLineUnionSelect> inSelectList = dao.query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", inIds));
List<String> inSelectIds = inSelectList.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList());
List<TheRapyRecuperationLine> outList = dao.query(TheRapyRecuperationLine.class, Cnd.where("regionalNature", "=", "省外"));
List<String> outIds = outList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList());
List<TheRapyRecuperationLineUnionSelect> outSelectList = dao.query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", outIds));
List<String> outSelectIds = outSelectList.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList());
//是否报省内
int inCount = dao.count("inclusive_therapy_v3_enroll", Cnd.where("loginName", "=", TherapyContext.getPrincipalProperty("loginname"))
.and("takePartInLineId", "in", inSelectIds).and("isNormal", "=", true));
if (inCount > 0) {
return 0;
}
//是否报省外
int outCount = dao.count("inclusive_therapy_v3_enroll", Cnd.where("loginName", "=", TherapyContext.getPrincipalProperty("loginname"))
.and("takePartInLineId", "in", outSelectIds).and("isNormal", "=", true));
if (outCount > 0) {
return 1;
}
//是否报旅行社
int travelCount = dao.count("inclusive_therapy_v3_enroll", Cnd.where("loginName", "=", TherapyContext.getPrincipalProperty("loginname"))
.and("takePartInLineId", "is", null).and("takePartInTravelAgencyId", "is not", null));
if (travelCount > 0) {
return 2;
}
return 0;
}
/**
* 验证是否能报名及修改
*
* @param enrollInfo 信息
* @return {@link Object}
*/
@At("/validSignUpInfo")
@POST
@ViReturn
@SaCheckLogin
public Object validSignUpInfo(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) {
if (StrUtil.isBlank(enrollInfo.getTakePartInBaseManagementId())
&& StrUtil.isBlank(enrollInfo.getTakePartInTravelAgencyId())
&& StrUtil.isBlank(enrollInfo.getTakePartInLineId())) {
return Result.error("线路信息不能为空");
}
if (StrUtil.isBlank(enrollInfo.getLoginName())){
enrollInfo.setLoginName(TherapyContext.getPrincipalProperty("loginname").toString());
}
Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion"));
Map<Boolean, String> resultMap = new HashMap<>();
if("zjxu".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfoForZJXU(enrollInfo.getLoginName(), enrollInfo);
} else if("zjiet".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfo(enrollInfo.getLoginName(), enrollInfo);
} else if("zjnu".equals(config.getConfigValue())) {
resultMap = enrollService.validSignUpInfoForZJNU(enrollInfo.getLoginName(), enrollInfo);
}
if (resultMap.containsKey(false)) {
return Result.error(resultMap.get(false));
}
if (resultMap.containsKey(true) && "当前线路所指定的旅行社可报名人数剩余1人,是否继续报名".equals(resultMap.get(true))) {
return Result.success(resultMap.get(true));
}
return Result.success();
}
/**
* 删除我的报名信息
*
* @param id id
* @return {@link Object}
*/
@At("/doDeleteMyEnrollInfoById/?")
@POST
@ViReturn
@SaCheckLogin
public Object doDeleteMyEnrollInfoById(String id) {
enrollService.deleteMyEnrollInfoById(id);
return null;
}
/**
* 删除我的报名信息
*
* @param id id
* @return {@link Object}
*/
@At("/doModify/?")
@POST
@ViReturn
@SaCheckLogin
public Object doModify(String id) {
enrollService.update(Chain.make("isNormal",false).add("delFlag", true),Cnd.where("id","=",id));
return null;
}
/**
* 能取消吗
*
* @param id id
* @return {@link Object}
*/
@At("/canDelete/?")
@POST
@ViReturn
@SaCheckLogin
public Object canDelete(String id) {
String errorMsg = enrollService.validateCanDeleteMyEnrollInfo(id);
if (StrUtil.isNotBlank(errorMsg)) {
return Result.error(errorMsg);
}
return null;
}
/**
* 反馈内容
*
* @param id id
* @param evaluationForTravelAgency 对旅行社的评价(几星)
* @param evaluationForLine 对线路的评价(几星)
* @param evaluationForJourney 对旅途的评价(几星)
* @param feedbackContent 反馈内容
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object doFeedBack(String id, String evaluationForTravelAgency, String evaluationForLine,
String evaluationForJourney, String feedbackContent) {
Chain chain = Chain.make("evaluationForTravelAgency", evaluationForTravelAgency);
chain.add("evaluationForLine", evaluationForLine);
chain.add("evaluationForJourney", evaluationForJourney);
chain.add("feedbackContent", feedbackContent);
dao.update(TheRapyRecuperationEnroll.class, chain, Cnd.where("id", "=", id));
return null;
}
/**
* 获取报名人数
*
* @param lineId 线路id
* @param unionId 工会
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckLogin
public Object getSignUpUserNum(String lineId, String unionId) {
TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, Cnd.where("takePartInUnionId", "=", unionId).and("takePartInLineId", "=", lineId).and("stateId", "=", TheRapyRecuperationState.PASS));
dao.fetchLinks(enroll, "companionList");
Sql sql = Sqls.create("""
select
(select count(1) from inclusive_therapy_v3_enroll where isNormal=true and takePartInUnionId = @unionId AND takePartInLineId = @lineId AND stateId = @signUpSuccessCode) as signUpUserNum,
(select count(1) from inclusive_therapy_v3_enroll_companion where trreId in (select id from inclusive_therapy_v3_enroll where isNormal=true and takePartInUnionId = @unionId AND takePartInLineId = @lineId AND stateId = @signUpSuccessCode)) as signUpUserFamilyNum
""");
sql.setParam("signUpSuccessCode", TheRapyRecuperationState.PASS);
sql.setParam("lineId", lineId);
sql.setParam("unionId", unionId);
Object result = Daos.query(dao, sql.toString(), Sqls.callback.map());
return result;
}
/**
* 手机端线路介绍所有信息
*
* @param usId 行id
* @param usUnionId 我们工会id
* @return {@link Object}
*/
@At("/selectLineAllInfo")
@GET
@ViReturn
@SaCheckLogin
public Object selectLineAllInfo(@Param("usId") String usId,
@Param("usUnionId") String usUnionId,
@Param("year") String year) {
Assert.notBlank(usId);
return enrollService.selectLineAllInfo(usId, usUnionId, year);
}
@At
@ViReturn
@SaCheckLogin
public Object getSchoolTime() {
TherapyUser sysUser = dao.fetch(TherapyUser.class, TherapyContext.getUserId());
if(StrUtil.isNotBlank(sysUser.getSchoolTime())) {
DateTime schoolDate = DateUtil.parse(sysUser.getSchoolTime());
DateTime time = DateUtil.parse(DateUtil.thisYear() + "-07-01");
int compareResult = DateUtil.compare(schoolDate, time);
return compareResult >= 0 ? sysUser.getSchoolTime() : null;
} else {
return null;
}
}
}
@@ -0,0 +1,166 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollJoinUserImportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process.TheRapyRecuperationEnrollJoinUserImport
* @Description: 导入参加人员
* @Author zxc
* @Date 2022/6/14:09:16
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/joinUserImport")
@Ok("json:full")
@Slf4j
public class TheRapyRecuperationEnrollJoinUserImportController {
@Inject
private Dao dao;
@Inject
private TheRapyRecuperationEnrollJoinUserImportService joinUserImportService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/joinUserImport.html")
@SaCheckPermission("inclusiveTherapyV3.joinUser.import")
public void index() {
}
@At
@SaCheckPermission("inclusiveTherapyV3.joinUser.import")
@ViReturn
public Object selectLineAndTravelAgencyList(Integer year, String keyword) {
return joinUserImportService.selectLineAndTravelAgencyList(year, keyword);
}
@At
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@SaCheckPermission("inclusiveTherapyV3.joinUser.import")
public Object readExcel(@Param("file") TempFile tempFile, @Param("lineId") String lineId, @Param("travelAgencyId") String travelAgencyId) {
try {
Assert.notNull(tempFile);
File file = tempFile.getFile();
String extName = FileUtil.extName(file);
if (!List.of("XLSX", "XLS").contains(extName.toUpperCase())) {
return Result.error("请上传excel文件");
}
if (StrUtil.isBlank(lineId) && StrUtil.isBlank(travelAgencyId)) {
return Result.error("参数错误");
}
ImportParams importParams = new ImportParams();
List<TheRapyRecuperationEnroll> list = ExcelImportUtil.importExcel(file, TheRapyRecuperationEnroll.class, importParams);
if (Lang.isEmpty(list)) {
return Result.error("excel无数据");
}
List<TheRapyRecuperationEnroll> matchList = new ArrayList<>();
Dao ext = Daos.ext(dao, FieldFilter.create(TheRapyRecuperationEnroll.class, "id|loginName|userName|sex|unionName|signingUptime"));
for (TheRapyRecuperationEnroll enroll : list) {
Cnd cnd = Cnd.NEW();
cnd.andEX("takePartInLineId", "=", lineId);
cnd.andEX("takePartInTravelAgencyId", "=", travelAgencyId);
cnd.and("loginName", "=", enroll.getLoginName());
TheRapyRecuperationEnroll oneEnroll = ext.fetch(TheRapyRecuperationEnroll.class, cnd);
if (Lang.isNotEmpty(oneEnroll)) {
oneEnroll.setTakePartInTime(enroll.getTakePartInTime());
matchList.add(oneEnroll);
}
}
return Result.success(Map.of("excelRows", list, "matchList", matchList));
} catch (Exception e) {
log.error(e.getMessage());
return Result.error(e.getMessage());
}
}
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.joinUser.import")
public Object selectLineOrTravelAgency(Integer year) {
return joinUserImportService.selectLineOrTravelAgency(year);
}
/**
* 导入用户
*
* @param enrolls 招收
* @return {@link Object}
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.joinUser.import")
public Object doImportTakePartInUsers(@Param("enroll") TheRapyRecuperationEnroll[] enrolls) {
for (TheRapyRecuperationEnroll enroll : enrolls) {
enroll.setTakePartIn(true);
}
dao.updateIgnoreNull(enrolls);
return null;
}
/**
* 下载模板
*
* @param response 响应
*/
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.joinUser.import")
public void downloadTemplate(HttpServletResponse response) {
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
List<TheRapyRecuperationEnroll> exampleList = new ArrayList<>();
exampleList.add(new TheRapyRecuperationEnroll().setLoginName("2000").setUserName("张三").setTakePartInTime(new Date()));
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, TheRapyRecuperationEnroll.class, exampleList);
try {
TherapyDownload.excelResponse(response, "参加人员.xlsx");
workbook.write(response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,18 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process.TheRapyRecuperationExamineController
* @Description: 疗休养报名审核
* @Author zxc
* @Date 2022/6/1:18:16
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/line/UnionSelect")
@Ok("json:full")
public class TheRapyRecuperationExamineController {
}
@@ -0,0 +1,207 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import cn.hutool.core.lang.Assert;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineAdjustmentService;
import lombok.extern.slf4j.Slf4j;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckRole;
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.Daos;
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.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineAdjustment
* @Description: 线路及人员调整
* @Author zxc
* @Date 2022/6/10:10:00
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/lineAdjustment")
@Ok("json:full")
@Slf4j
public class TheRapyRecuperationLineAdjustmentController {
@Inject
private Dao dao;
@Inject
private TherapyMessage msgApi;
@Inject
private TheRapyRecuperationLineAdjustmentService adjustmentService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineAdjustment.html")
@SaCheckPermission("inclusiveTherapyV3.line.adjustment")
public void index() {
}
/**
* 页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @return {@link Object}
*/
@At
@POST
@Ok("json:full")
@ViReturn
@SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR)
public Object pageData(PageForm pageForm,
Integer year,
String lineId,
String unionId,
String keywords,
String regionalNature,
String lotId) {
return adjustmentService.pageData(pageForm, year, lineId, unionId, keywords, regionalNature, lotId);
}
/**
* 查询分工会报名模式线路
*
* @param year 年度
* @return {@link Object}
*/
@At("/findUnionSignUpModeLineList")
@POST
@Ok("json:full")
@ViReturn
@SaCheckLogin
public Object findUnionSignUpModeLineList(Integer year) {
Sql sql = Sqls.create("""
select id,lineName from inclusive_therapy_v3_line
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue());
cnd.andEX("year", "=", year);
sql.setCondition(cnd);
return adjustmentService.listMap(sql);
}
/**
* 查询分工会模式报名的用户
*
* @param lineId lineId
* @return {@link Object}
*/
@At
@POST
@Ok("json:full")
@SaCheckLogin
public Object findUnionSignUpModeUserList(@Param("lineId") String lineId, @Param("unionId") String unionId) {
try {
Assert.notBlank(lineId);
return Result.success().addData(adjustmentService.findUnionSignUpModeUserList(lineId, unionId));
} catch (Exception e) {
log.error(e.getMessage());
return Result.error(e.getMessage());
}
}
/**
* 调整用户
*
* @param lineId 线路id
* @param loginName 登录名
* @return {@link Object}
*/
@At
@POST
@Ok("json:full")
@SaCheckLogin
public Object adjustmentUser(String lineId, @Param("loginNames") String[] loginName) {
try {
Assert.notBlank(lineId);
Assert.notNull(loginName);
Chain chain = Chain.makeSpecial("isNormal", "isNormal ^ 1");
Cnd cnd = Cnd.where("takePartInLineId", "=", lineId);
cnd.and("loginName", "in", loginName);
dao.update(TheRapyRecuperationEnroll.class, chain, cnd);
return Result.success();
} catch (Exception e) {
log.error(e.getMessage());
return Result.error(e.getMessage());
}
}
@At
@POST
@Ok("json:full")
@SaCheckLogin
public Object smsAlerts(String lineId,@Param("loginNames") String[] loginName){
try {
Sql sql = Sqls.create("""
SELECT
rlus.id,
rlus.unionId,
rlus.lineId,
rlus.selectUserId,
DATE_FORMAT( rlus.playStartTime, '%Y-%m-%d' ) AS playStartTime,
DATE_FORMAT( rlus.playEndTime, '%Y-%m-%d' ) AS playEndTime,
rl.lineName,
rl.regionalNature,
lot.lotName
FROM
`inclusive_therapy_v3_line_union_select` rlus
LEFT JOIN `inclusive_therapy_v3_line` rl ON rlus.lineId = rl.id
LEFT JOIN `inclusive_therapy_v3_lot` lot ON rl.lotId = lot.id
WHERE
rlus.id = @id
""").setParam("id",lineId);
NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
String lineName = map.getString("lineName");
String lotName = map.getString("lotName");
String regionalNature = map.getString("regionalNature");
String playStartTime = map.getString("playStartTime");
String playEndTime = map.getString("playEndTime");
List<TherapyUser> userList = dao.query(TherapyUser.class, Cnd.where("loginname", "in", loginName));
Map<String, String> usernameMap = userList.stream().collect(Collectors.toMap(TherapyUser::getLoginname, TherapyUser::getUsername));
if (Lang.isNotEmpty(loginName)){
Arrays.stream(loginName).forEach(v->{
String username = usernameMap.get(v);
String content = "%s老师您好,您报名的%s【%s-%s】(%s至%s)线路未达到成团标准,现已解散,请您选择其他线路进行报名!"
.formatted(username,lineName,lotName,regionalNature,playStartTime,playEndTime);
//msgApi.sendWxMsg(content,v);
});
}
return Result.success();
} catch (Exception e){
e.printStackTrace();
return Result.error();
}
}
}
@@ -0,0 +1,128 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import cn.hutool.core.lang.Assert;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationClusterMember;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineClusterService;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
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.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process.TheRapyRecuperationLineClusterController
* @Description: TODO
* @Author zxc
* @Date 2022/6/17:08:52
* @Version V1.0
**/
@IocBean
@At("/platform/inclusiveTherapyV3/lineCluster")
@Ok("json:full")
public class TheRapyRecuperationLineClusterController {
@Inject
private TheRapyRecuperationLineClusterService clusterService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineCluster.html")
@SaCheckPermission("inclusiveTherapyV3.lineCluster")
public void index() {
}
/**
* 页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @param keywords 关键字
* @return {@link Object}
*/
@At
@ViReturn
@POST
@SaCheckLogin
@SaCheckPermission("inclusiveTherapyV3.lineCluster")
public Object pageData(PageForm pageForm, Integer year, String keywords, String unionId) {
Pagination pagination = clusterService.pageData(pageForm, year, unionId, keywords);
return pagination;
}
/**
* 查询组团信息
*
* @param lineId 线路id
* @param usUnionId 归属工会id
* @return {@link Object}
*/
@At
@ViReturn
@POST
@SaCheckLogin
public Object findClusterInfo(@Param("lineId") String lineId, @Param("usUnionId") String usUnionId) {
Assert.notBlank(lineId);
Assert.notBlank(usUnionId);
return clusterService.findClusterInfo(lineId, usUnionId);
}
/**
* 设置组团成员
*
* @param clusters 集群
* @return {@link Object}
*/
@At
@ViReturn
@POST
@SaCheckLogin
@SLog(tag = "疗休养", msg = "设置组团人员", param = true, result = true)
public Object setClusterMembers(@Param("clusters") String clusters, @Param("lineId") String lineId) {
NutMap nutMap = Json.fromJson(NutMap.class, clusters);
List<TheRapyRecuperationCluster> clusterList = new ArrayList<>();
nutMap.forEach((k, v) -> {
if (!"unSelectedUsers".equals(k)) {
TheRapyRecuperationCluster t = Lang.map2Object((Map<?, ?>) v, TheRapyRecuperationCluster.class);
t.setLineId(lineId);
clusterList.add(t);
if (Lang.isNotEmpty(t.getMembers())) {
for (TheRapyRecuperationClusterMember member : t.getMembers()) {
member.setLineId(lineId);
}
}
}
});
clusterService.setClusterMembers(clusterList, lineId);
return null;
}
@At("/selectClusterInfo/?")
@ViReturn
@POST
@SaCheckLogin
public Object selectClusterInfo(String lineId) {
List<TheRapyRecuperationCluster> clusters = clusterService.query(Cnd.where("lineId", "=", lineId));
clusterService.fetchLinks(clusters, null);
return clusters;
}
}
@@ -0,0 +1,461 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
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.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollBed;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollChangeRecord;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollCompanion;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.LineSelectionOverviewTimeSlotVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.LineSelectionOverviewVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineUnionSelectService;
import org.apache.poi.ss.usermodel.Workbook;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.aop.interceptor.ioc.TransAop;
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.Daos;
import org.nutz.ioc.aop.Aop;
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.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 管理员查看全部分工会已选择线路。
*/
@IocBean
@At("/platform/inclusiveTherapyV3/lineSelectionOverview")
@Ok("json:full")
public class TheRapyRecuperationLineSelectionOverviewController {
@Inject
private Dao dao;
@Inject
private TheRapyRecuperationLineUnionSelectService lineUnionSelectService;
/**
* 管理员查看分工会已选择线路页面。
*/
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineSelectionOverview.html")
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
public void index() {
}
/**
* 查询管理员查看线路选择情况列表。
*
* @param pageForm 分页参数,包含 pageNumber、pageSize、pageOrderName、pageOrderBy
* @param year 年度;为空时默认当前年度
* @param keywords 线路名称或旅行社名称关键字
* @param unionId 分工会 ID;为空时查询全部分工会
* @param lotId 时间标段 ID;为空时查询全部时间标段
* @param travelAgencyId 旅行社 ID;为空时查询全部旅行社
* @param regionalNature 线路类型;传“全部”或空时查询全部类型
* @return 分页后的已选择线路 VO,list 字段为 {@link LineSelectionOverviewVo}
*/
@At
@POST
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
public Object pageData(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "keywords") String keywords,
@Param(value = "unionId") String unionId,
@Param(value = "lotId") String lotId,
@Param(value = "travelAgencyId") String travelAgencyId,
@Param(value = "regionalNature") String regionalNature) {
Sql listSql = buildSelectionOverviewSql(pageForm, year, keywords, unionId, lotId, travelAgencyId, regionalNature);
Pagination pagination = lineUnionSelectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), listSql);
List<NutMap> rowList = pagination.getList();
List<LineSelectionOverviewVo> voList = new ArrayList<>();
for (NutMap row : rowList) {
voList.add(new LineSelectionOverviewVo()
.setLineId(row.getString("lineId"))
.setLineUnionSelectId(row.getString("lineUnionSelectId"))
.setLineUnionSelectIds(row.getString("lineUnionSelectIds"))
.setYear(row.getInt("year"))
.setSerialNumber(row.getInt("serialNumber"))
.setLineName(row.getString("lineName"))
.setRegionalNature(row.getString("regionalNature"))
.setLotName(row.getString("lotName"))
.setPlayTimes(row.getString("playTimes"))
.setSignUpTimes(row.getString("signUpTimes"))
.setAdjustSignUpEndTime(row.getString("adjustSignUpEndTime"))
.setSignUpMode(row.getInt("signUpMode"))
.setUnionId(row.getString("unionId"))
.setUnionName(row.getString("unionName"))
.setIsOpen(toBoolean(row.get("isOpen"))));
}
pagination.setList(voList);
return pagination;
}
/**
* 导出管理员查看线路选择情况列表。
*
* @param pageForm 排序参数,包含 pageOrderName、pageOrderBy;导出不使用分页参数
* @param year 年度;为空时默认当前年度
* @param keywords 线路名称或旅行社名称关键字
* @param unionId 分工会 ID;为空时导出全部分工会
* @param lotId 时间标段 ID;为空时导出全部时间标段
* @param travelAgencyId 旅行社 ID;为空时导出全部旅行社
* @param regionalNature 线路类型;传“全部”或空时导出全部类型
* @param response HTTP 响应对象,方法直接写出 xlsx 文件,无 JSON 返回
*/
@At
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
public void doExportExcel(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "keywords") String keywords,
@Param(value = "unionId") String unionId,
@Param(value = "lotId") String lotId,
@Param(value = "travelAgencyId") String travelAgencyId,
@Param(value = "regionalNature") String regionalNature,
HttpServletResponse response) throws IOException {
Sql listSql = buildSelectionOverviewSql(pageForm, year, keywords, unionId, lotId, travelAgencyId, regionalNature);
List<NutMap> list = queryMapList(listSql);
ArrayList<ExcelExportEntity> exportEntities = new ArrayList<>();
exportEntities.add(new ExcelExportEntity("选择工会", "unionName", 25));
exportEntities.add(new ExcelExportEntity("线路名称", "lineName", 35));
exportEntities.add(new ExcelExportEntity("线路类型", "regionalNature", 15));
exportEntities.add(new ExcelExportEntity("报名时间", "signUpTimes", 30));
exportEntities.add(new ExcelExportEntity("出行时间", "playTimes", 40));
TherapyDownload.excelResponse(response, "线路选择情况.xlsx");
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
workbook.write(response.getOutputStream());
workbook.close();
}
/**
* 查询某个分工会已选择线路的出行时间段。
*
* @param lineId 线路 ID,对应 inclusive_therapy_v3_line.id
* @param unionId 分工会 ID,对应 sys_union.id
* @param year 年度;为空时默认当前年度
* @return 出行时间段 VO 列表,元素为 {@link LineSelectionOverviewTimeSlotVo}
*/
@At
@POST
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
public Object timeSlots(@Param("lineId") String lineId,
@Param("unionId") String unionId,
@Param(value = "year") Integer year) {
Assert.notBlank(lineId, "请选择线路");
Assert.notBlank(unionId, "请选择分工会");
Sql sql = Sqls.create("""
SELECT
us.id,
us.signUpStartTime,
us.signUpEndTime,
us.changeEndTime,
us.adjustSignUpEndTime,
us.playStartTime,
us.playEndTime,
us.travelAgencyId,
ta.travelAgencyName,
us.contact,
us.contactPhone,
us.principal,
us.principalContact,
us.trafficTools,
us.estimatedCost,
us.estimatedFamilyNumbers,
us.maxPeopleNumber,
us.enable
FROM
inclusive_therapy_v3_line_union_select us
LEFT JOIN inclusive_therapy_v3_travel_agency ta ON ta.id = us.travelAgencyId
WHERE
us.lineId = @lineId
AND us.unionId = @unionId
AND us.signUpMode = 1
AND YEAR(us.selectTime) = @year
ORDER BY
us.playStartTime ASC
""");
sql.setParam("lineId", lineId);
sql.setParam("unionId", unionId);
sql.setParam("year", year == null ? DateUtil.thisYear() : year);
List<NutMap> rowList = queryMapList(sql);
List<LineSelectionOverviewTimeSlotVo> voList = new ArrayList<>();
for (NutMap row : rowList) {
voList.add(new LineSelectionOverviewTimeSlotVo()
.setId(row.getString("id"))
.setSignUpStartTime(toDate(row.get("signUpStartTime")))
.setSignUpEndTime(toDate(row.get("signUpEndTime")))
.setChangeEndTime(toDate(row.get("changeEndTime")))
.setAdjustSignUpEndTime(toDate(row.get("adjustSignUpEndTime")))
.setPlayStartTime(toDate(row.get("playStartTime")))
.setPlayEndTime(toDate(row.get("playEndTime")))
.setTravelAgencyId(row.getString("travelAgencyId"))
.setTravelAgencyName(row.getString("travelAgencyName"))
.setContact(row.getString("contact"))
.setContactPhone(row.getString("contactPhone"))
.setPrincipal(row.getString("principal"))
.setPrincipalContact(row.getString("principalContact"))
.setTrafficTools(row.getString("trafficTools"))
.setEstimatedCost(row.getString("estimatedCost"))
.setEstimatedFamilyNumbers(row.getInt("estimatedFamilyNumbers"))
.setMaxPeopleNumber(row.getInt("maxPeopleNumber"))
.setEnable(toBoolean(row.get("enable"))));
}
return voList;
}
/**
* 管理员修改某个分工会已选择线路的出行时间段。
*
* @param lineUnionSelects 出行时间段数组,包含报名时间、出行时间、旅行社、联系人、人数和启用状态等字段
* @param lineId 线路 ID,对应 inclusive_therapy_v3_line.id
* @param unionId 分工会 ID,对应 sys_union.id
* @param year 年度;为空时默认当前年度
* @return ViReturn 统一包装结果,成功时 data 为空
*/
@At
@POST
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
@Aop(TransAop.READ_COMMITTED)
public Object saveTimeSlots(@Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects,
@Param("lineId") String lineId,
@Param("unionId") String unionId,
@Param(value = "year") Integer year) {
Assert.notBlank(lineId, "请选择线路");
Assert.notBlank(unionId, "请选择分工会");
lineUnionSelectService.adminSaveLineTimes(lineUnionSelects, lineId, unionId, year);
return null;
}
/**
* 管理员取消分工会已选择线路。
*
* @param lineId 线路 ID,对应 inclusive_therapy_v3_line.id
* @param unionId 分工会 ID,对应 sys_union.id
* @param year 年度;为空时默认当前年度
* @return ViReturn 统一包装结果,成功时 data 为空
*/
@At
@POST
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
@Aop(TransAop.READ_COMMITTED)
public Object cancelLine(@Param("lineId") String lineId,
@Param("unionId") String unionId,
@Param(value = "year") Integer year) {
Assert.notBlank(lineId, "请选择线路");
Assert.notBlank(unionId, "请选择分工会");
Integer queryYear = year == null ? DateUtil.thisYear() : year;
List<TheRapyRecuperationLineUnionSelect> unionSelects = lineUnionSelectService.query(Cnd.where("lineId", "=", lineId)
.and("unionId", "=", unionId)
.and("signUpMode", "=", 1)
.and("YEAR(selectTime)", "=", queryYear));
if (Lang.isEmpty(unionSelects)) {
throw Lang.makeThrow("未找到该分工会选择的线路");
}
// 取消线路会清理该分工会该线路下所有选择时段,以及这些时段关联的报名、床位、同伴和变更记录。
List<String> selectIds = unionSelects.stream()
.map(TheRapyRecuperationLineUnionSelect::getId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
List<TheRapyRecuperationEnroll> enrolls = lineUnionSelectService.dao()
.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", selectIds));
List<String> enrollIds = enrolls.stream()
.map(TheRapyRecuperationEnroll::getId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
List<String> bedIds = enrolls.stream()
.map(TheRapyRecuperationEnroll::getBedInfoId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
if (Lang.isNotEmpty(enrollIds)) {
List<TheRapyRecuperationEnrollCompanion> companions = lineUnionSelectService.dao()
.query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIds));
List<String> companionBedIds = companions.stream()
.map(TheRapyRecuperationEnrollCompanion::getBedInfoId)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toList());
lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIds));
lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "in", enrollIds));
if (Lang.isNotEmpty(companionBedIds)) {
lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", companionBedIds));
}
lineUnionSelectService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIds));
}
if (Lang.isNotEmpty(bedIds)) {
lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", bedIds));
}
lineUnionSelectService.clear(Cnd.where("id", "in", selectIds));
return null;
}
/**
* 查询旅行社下拉选项。
*
* @param year 年度;为空时默认当前年度
* @return 旅行社实体列表,前端使用 id 和 travelAgencyName
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
public Object travelAgencyOptions(@Param(value = "year") Integer year) {
// 旅行社按年度维护,管理员查看页切换年度时下拉框只展示该年度可选旅行社。
return dao.query(TheRapyRecuperationTravelAgency.class,
Cnd.where("year", "=", year == null ? DateUtil.thisYear() : year).asc("serialNumber"));
}
/**
* 查询时间标段下拉选项。
*
* @return 当前基础设置中的时间标段实体列表,前端使用 id 和 lotName
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.lineSelectionOverview")
public Object lotOptions() {
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
return Optional.ofNullable(config)
.map(TheRapyRecuperationConfig::getLots)
.orElseGet(ArrayList::new);
}
private Sql buildSelectionOverviewSql(PageForm pageForm, Integer year, String keywords, String unionId, String lotId,
String travelAgencyId, String regionalNature) {
Sql listSql = Sqls.create("""
SELECT
line.id AS lineId,
us.id AS lineUnionSelectId,
us.id AS lineUnionSelectIds,
line.year,
line.serialNumber,
line.lineName,
line.regionalNature,
lot.lotName,
IF(us.playStartTime IS NULL OR us.playEndTime IS NULL,
NULL,
CONCAT(DATE_FORMAT(us.playStartTime, '%Y-%m-%d %H:%i'), '至', DATE_FORMAT(us.playEndTime, '%Y-%m-%d %H:%i'), IFNULL(CONCAT('(', ta.travelAgencyName, ')'), ''))
) AS playTimes,
IF(us.signUpStartTime IS NULL OR us.signUpEndTime IS NULL,
NULL,
CONCAT(DATE_FORMAT(us.signUpStartTime, '%Y-%m-%d %H:%i'), '至', DATE_FORMAT(us.signUpEndTime, '%Y-%m-%d %H:%i'))
) AS signUpTimes,
DATE_FORMAT(us.adjustSignUpEndTime, '%Y-%m-%d %H:%i') AS adjustSignUpEndTime,
us.signUpMode,
us.unionId,
selectUnion.unionname AS unionName,
us.isOpen
FROM
inclusive_therapy_v3_line_union_select us
LEFT JOIN inclusive_therapy_v3_line line ON line.id = us.lineId
LEFT JOIN inclusive_therapy_v3_union selectUnion ON selectUnion.id = us.unionId
LEFT JOIN inclusive_therapy_v3_travel_agency ta ON ta.id = us.travelAgencyId
LEFT JOIN inclusive_therapy_v3_lot lot ON lot.id = line.lotId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("us.signUpMode", "=", 1);
cnd.and("YEAR(us.selectTime)", "=", year == null ? DateUtil.thisYear() : year);
cnd.and("line.isDisabled", "=", 0);
cnd.andEX("us.unionId", "=", unionId);
cnd.andEX("line.lotId", "=", lotId);
cnd.andEX("us.travelAgencyId", "=", travelAgencyId);
if (StrUtil.isNotBlank(regionalNature) && !"全部".equals(regionalNature)) {
cnd.and("line.regionalNature", "=", regionalNature);
}
if (StrUtil.isNotBlank(keywords)) {
cnd.and(Cnd.exps("line.lineName", "like", "%" + keywords + "%")
.or("ta.travelAgencyName", "like", "%" + keywords + "%"));
}
addPageOrder(cnd, pageForm);
listSql.setCondition(cnd);
return listSql;
}
private void addPageOrder(Cnd cnd, PageForm pageForm) {
if (pageForm == null) {
addDefaultOrder(cnd);
return;
}
String orderName = pageForm.getPageOrderName();
String orderBy = pageForm.getPageOrderBy();
if (StrUtil.isNotBlank(orderName) && StrUtil.isNotBlank(orderBy)) {
String direction = "ascending".equals(orderBy) ? "asc" : "desc";
switch (orderName) {
case "lineName" -> cnd.orderBy("line.lineName", direction);
case "regionalNature" -> cnd.orderBy("line.regionalNature", direction);
case "lotName" -> cnd.orderBy("lot.lotName", direction);
case "playTime" -> cnd.orderBy("us.playStartTime", direction);
case "signUpTimes" -> cnd.orderBy("us.signUpStartTime", direction);
case "adjustSignUpEndTime" -> cnd.orderBy("us.adjustSignUpEndTime", direction);
case "signUpMode" -> cnd.orderBy("us.signUpMode", direction);
case "unionName" -> cnd.orderBy("selectUnion.unionname", direction);
case "isOpen" -> cnd.orderBy("us.isOpen", direction);
default -> addDefaultOrder(cnd);
}
} else {
addDefaultOrder(cnd);
}
}
private void addDefaultOrder(Cnd cnd) {
// 一条出行记录对应一条线路选择记录,默认先按年度、线路编号,再按出行开始时间排序。
cnd.desc("line.year").asc("line.serialNumber").asc("us.playStartTime").asc("selectUnion.unionname");
}
private List<NutMap> queryMapList(Sql sql) {
return (List<NutMap>) Daos.query(dao, sql.toString(), Sqls.callback.maps());
}
private Date toDate(Object value) {
return value instanceof Date ? (Date) value : null;
}
private Boolean toBoolean(Object value) {
if (value instanceof Boolean) {
return (Boolean) value;
}
if (value instanceof Number) {
return ((Number) value).intValue() == 1;
}
return value != null && Boolean.parseBoolean(value.toString());
}
}
@@ -0,0 +1,447 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionLineSelectLimitVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineUnionSelectService;
import lombok.extern.slf4j.Slf4j;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
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.Daos;
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.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.annotation.Param;
import java.util.*;
import java.util.stream.Collectors;
/**
* 疗休养工会选择表
*
* @author jug
* @date 2023/06/26
*/
@IocBean
@At(value = {"/platform/inclusiveTherapyV3/lineFghSelect", "/platform/inclusiveTherapyV3/lineXghSelect", "/platform/inclusiveTherapyV3/lineUnionSelect"})
@Ok("json:full")
@Slf4j
public class TheRapyRecuperationLineUnionSelectController {
@Inject
private TherapyContext vi;
@Inject
private Dao dao;
@Inject
private TheRapyRecuperationLineUnionSelectService unionSelectService;
@At("")
@Ok("re")
// @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html")
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public String index(@Param("mode") Integer mode) {
return "beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html";
}
/**
* 页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public Object pageData(PageForm pageForm, Integer year, String keywords, int selectStatus, String unionId,
String lotId, String travelAgencyId, Integer mode, String regionalNature) {
TheRapyRecuperationConfig config = unionSelectService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
Integer queryMode = mode == null ? 1 : mode;
Cnd cnd = Cnd.NEW();
cnd.andEX("line.lotId", "=", lotId);
addTravelAgencyCondition(cnd, travelAgencyId);
if (!"全部".equals(regionalNature)) {
cnd.andEX("line.regionalNature", "=", regionalNature);
}
// 按页面入口 mode 区分已选择线路:mode=1 查当前分工会选择,mode=2 查校工会选择。
Sql hasSelectLineSql;
if (Integer.valueOf(1).equals(queryMode)) {
SqlExpressionGroup lineScope = new SqlExpressionGroup();
if (!"全部".equals(regionalNature)) {
lineScope.or(Cnd.exps("line.createUnionId", "=", TherapyContext.getUnionId()).and("line.regionalNature", "=", regionalNature));
} else {
lineScope.or("line.createUnionId", "=", TherapyContext.getUnionId());
}
lineScope.or("line.createMode", "=", 2);
cnd.and(lineScope);
hasSelectLineSql = Sqls.createf("""
select lineId from inclusive_therapy_v3_line_union_select where unionId = '%s' AND signUpMode = %s AND year(selectTime) = %s
""", TherapyContext.getUnionId(), queryMode, year == null ? DateUtil.thisYear() : year);
} else {
hasSelectLineSql = Sqls.createf("""
select lineId from inclusive_therapy_v3_line_union_select where signUpMode = %s AND year(selectTime) = %s
""", queryMode, year == null ? DateUtil.thisYear() : year);
}
/*hasSelectLineSql = Sqls.createf("""
select lineId from inclusive_therapy_v3_line_union_select where unionId = '%s'
""", Vi.getUnionId());*/
switch (selectStatus) {
//查询未选择的线路
case -1 -> {
cnd.and("line.id", "not in", hasSelectLineSql);
cnd.and("line.year", "in", year == null ? Lang.array(config.getProvinceStartYear(), config.getProvinceStartYear() + 1) : year);
}
case 0 -> {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or("us.signUpMode", "is", null);
seg.or("us.signUpMode", "=", mode);
cnd.and(seg);
}
/*case 0 -> {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or(Cnd.exps("line.id", "not in", hasSelectLineSql).and("line.createMode", "=", TheRapyRecuperationLineCreateMode.SCHOOL.getValue()));
seg.or("line.id", "in", hasSelectLineSql);
cnd.and(seg);
}*/
//查询已选择的线路
case 1 -> {
cnd.and("line.id", "in", hasSelectLineSql);
cnd.and("us.signUpMode", "=", queryMode);
cnd.and("year(us.selectTime)", "=", year == null ? DateUtil.thisYear() : year);
}
}
cnd.and("line.isDisabled", "=", 0);
if (StrUtil.isNotBlank(keywords)) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.orLike("line.lineName", keywords);
cnd.and(seg);
}
if (StrUtil.isAllNotEmpty(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), pageForm.getPageOrderBy().replace("ending", ""));
} else {
cnd.asc("createUnionId").desc("year").asc("serialNumber");
}
return unionSelectService.pageData(pageForm, cnd, year, queryMode);
}
/**
* 查询当前登录人所属分工会本年度线路选择数量要求和已选择数量。
*
* @param year 年度,页面年度筛选值;为空时按当前年度统计
* @param mode 选择线路页面类型,1 表示分工会选择线路,2 表示校工会选择线路
* @return 分工会线路选择数量提示 VO
*/
@At
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public Object getUnionLineSelectLimit(Integer year, Integer mode) {
String unionId = TherapyContext.getUnionId();
Integer queryYear = year == null ? DateUtil.thisYear() : year;
Integer queryMode = mode == null ? 1 : mode;
UnionLineSelectLimitVo vo = new UnionLineSelectLimitVo()
.setMinProvinceOutNumber(0)
.setMinProvinceInNumber(0)
.setSelectedProvinceOutNumber(0)
.setSelectedProvinceInNumber(0);
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
List<NutMap> unionLineNumberConfigs = Optional.ofNullable(config)
.map(TheRapyRecuperationConfig::getUnionLineNumberConfigs)
.orElse(Collections.emptyList());
for (NutMap lineNumberConfig : unionLineNumberConfigs) {
if (Objects.equals(unionId, lineNumberConfig.getString("unionId"))) {
vo.setMinProvinceOutNumber(Optional.ofNullable(lineNumberConfig.getInt("minProvinceOutNumber")).orElse(0));
vo.setMinProvinceInNumber(Optional.ofNullable(lineNumberConfig.getInt("minProvinceInNumber")).orElse(0));
break;
}
}
Sql selectedSql = Sqls.create("""
SELECT
line.regionalNature,
COUNT(us.id) AS selectedNumber
FROM
inclusive_therapy_v3_line_union_select us
LEFT JOIN inclusive_therapy_v3_line line ON line.id = us.lineId
WHERE
us.unionId = @unionId
AND us.signUpMode = @mode
AND YEAR(us.selectTime) = @year
GROUP BY
line.regionalNature
""");
selectedSql.setParam("unionId", unionId);
selectedSql.setParam("mode", queryMode);
selectedSql.setParam("year", queryYear);
List<NutMap> selectedList = (List<NutMap>) Daos.query(dao, selectedSql.toString(), Sqls.callback.maps());
for (NutMap selected : selectedList) {
if (Objects.equals(TheRapyRecuperationProvinceType.provinceOut.getValue(), selected.getString("regionalNature"))) {
vo.setSelectedProvinceOutNumber(Optional.ofNullable(selected.getInt("selectedNumber")).orElse(0));
} else if (Objects.equals(TheRapyRecuperationProvinceType.provinceIn.getValue(), selected.getString("regionalNature"))) {
vo.setSelectedProvinceInNumber(Optional.ofNullable(selected.getInt("selectedNumber")).orElse(0));
}
}
return vo;
}
/**
* 分工会选择线路
*
* @param us 分工会选择线路信息
* @return {@link Object}
*/
@At("/selectLine")
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
@Aop(TransAop.READ_COMMITTED)
public Object selectLine(TheRapyRecuperationLineUnionSelect us) {
unionSelectService.validateLineSelectTime(us.getMode());
unionSelectService.selectLine(us);
return null;
}
/**
* 分工会选择线路时间
*
* @param lineUnionSelects 分工会选择线路
* @return {@link Object}
*/
@At("/selectLineTimes")
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
@Aop(TransAop.READ_COMMITTED)
public Object selectLineTimes(@Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects) {
unionSelectService.selectLineTimes(lineUnionSelects);
return null;
}
@At
@POST
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public Object selectLineInfo(@Param("lineId") String lineId, @Param("unionId") String unionId, @Param("mode") Integer mode, @Param("year") Integer year) {
try {
Assert.notBlank(lineId);
Assert.notNull(mode);
unionId = StrUtil.emptyToNull(TherapyContext.getUnionId());
return Result.success(unionSelectService.selectLineInfo(lineId, unionId, mode, year));
} catch (Exception e) {
log.error(e.getMessage());
return Result.error(e.getMessage());
}
}
/**
* 查询某个分工会设置的线路时间信息
*
* @param lineId 行id
* @param usUnionId 我们工会id
* @return {@link Object}
*/
@At
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public Object findUsLineInfo(String lineId, String usUnionId) {
return unionSelectService.findUsLineInfo(lineId, usUnionId);
}
@At("/deSelect")
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
@SLog(tag = "疗休养", msg = "取消选择线路", param = true, result = true)
@Aop(TransAop.READ_COMMITTED)
public Object deSelect(@Param("lineId") String lineId, @Param("unionId") String unionId, @Param("mode") Integer mode) {
try {
unionSelectService.validateLineSelectTime(mode);
Assert.notBlank(lineId);
Assert.notBlank(unionId);
// Cnd enrollCnd = Cnd.where("takePartInUnionId", "=", unionId);
// enrollCnd.and("takePartInLineId", "=", lineId);
Cnd enrollCnd = Cnd.where("unionId", "=", unionId);
enrollCnd.and("lineId", "=", lineId);
List<TheRapyRecuperationLineUnionSelect> unionSelects = unionSelectService.query(enrollCnd);
List<String> list = unionSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList());
List<TheRapyRecuperationEnroll> enrolls = unionSelectService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", list));
List<String> enrollIdList = enrolls.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList());
List<String> bedIdList = enrolls.stream().map(TheRapyRecuperationEnroll::getBedInfoId).collect(Collectors.toList());
//同伴信息
List<TheRapyRecuperationEnrollCompanion> companions = unionSelectService.dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIdList));
List<String> comBedIdList = companions.stream().map(TheRapyRecuperationEnrollCompanion::getBedInfoId).collect(Collectors.toList());
//删除报名记录
unionSelectService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIdList));
//删除床位记录
unionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", bedIdList));
//删除同伴信息
unionSelectService.dao().clear(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIdList));
//删除变更记录
unionSelectService.dao().clear(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "in", enrollIdList));
//删除同伴床位信息
unionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", comBedIdList));
unionSelectService.clear(enrollCnd);
return Result.success();
} catch (Exception e) {
return Result.error(e.getMessage());
}
// unionSelectService.deSelect(usId);
}
/**
* 旅行社
*
* @return {@link Object}
*/
@At
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public Object getTravelAgencyOptions(Integer year) {
Cnd cnd = Cnd.NEW();
cnd.andEX("year", "=", year);
cnd.asc("serialNumber");
List<TheRapyRecuperationTravelAgency> travelAgencies = unionSelectService.dao().query(TheRapyRecuperationTravelAgency.class, cnd);
return travelAgencies;
}
/**
* 按旅行社筛选线路,兼容未选择线路的主表旅行社和已选择线路的出行时间段旅行社。
*
* @param cnd 当前页面查询条件
* @param travelAgencyId 旅行社 ID,为空时不增加过滤条件
*/
private void addTravelAgencyCondition(Cnd cnd, String travelAgencyId) {
if (StrUtil.isBlank(travelAgencyId)) {
return;
}
SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup();
travelAgencyGroup.or("us.travelAgencyId", "=", travelAgencyId);
travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId);
cnd.and(travelAgencyGroup);
}
/**
* 是否公开分工会选择线路
*
* @param id 分工会选择线路id
* @return {@link Object}
*/
@At("/isOpenUnionLine/?")
@POST
@ViReturn
@SaCheckLogin
public Object isOpenUnionLine(String id) {
if (StrUtil.isBlank(id)) {
return Result.error("参数错误");
}
dao.update(TheRapyRecuperationLineUnionSelect.class, Chain.makeSpecial("isOpen", "isOpen ^ 1"), Cnd.where("id", "=", id));
return null;
}
@At("/getLineConfig/?")
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
public Object getLineConfig(String id) {
Sql sql = Sqls.create("select lotId, travelAgencyId from inclusive_therapy_v3_line where id = @lineId");
sql.setParam("lineId", id);
NutMap lineInfo = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map());
String lotId = lineInfo != null ? lineInfo.getString("lotId") : null;
String travelAgencyId = lineInfo != null ? lineInfo.getString("travelAgencyId") : null;
TheRapyRecuperationLot lotInfo = dao.fetch(TheRapyRecuperationLot.class, lotId);
Integer cost = Optional.ofNullable(lotInfo).map(v -> v.getActivityCost()).orElse(0);
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
Integer groupNumber = Optional.ofNullable(config).map(TheRapyRecuperationConfig::getGroupNumber).orElse(0);
Integer outsideQuota = Optional.ofNullable(config).map(TheRapyRecuperationConfig::getOutsideQuota).orElse(0);
return Result.success(Map.of("cost", cost, "groupNumber", groupNumber, "outsideQuota", outsideQuota, "travelAgencyId", travelAgencyId));
}
/**
* 一键统赋时间,针对于已选择的线路
*
* @param lineIds 线路Id数组
* @param lineUnionSelects 出行时段
* @return {@link Object}
*/
@At("/setGiveLineTimes")
@POST
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
@Aop(TransAop.READ_COMMITTED)
@SLog(type = "普惠疗休养", tag = "分工会/校工会选择线路", msg = "一键统赋时间,针对于已选择的线路", param = true, result = true)
public Object setGiveLineTimes(@Param("lineIds") String[] lineIds, @Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects) {
if (Lang.isNotEmpty(lineUnionSelects) && Lang.isNotEmpty(lineIds)) {
TheRapyRecuperationLineUnionSelect lineUnionSelect = lineUnionSelects[0];
Chain chain = Chain.make("enable", 1);
if (lineUnionSelect.getSignUpStartTime() != null)
chain.add("signUpStartTime", lineUnionSelect.getSignUpStartTime());
if (lineUnionSelect.getSignUpEndTime() != null)
chain.add("signUpEndTime", lineUnionSelect.getSignUpEndTime());
if (lineUnionSelect.getChangeEndTime() != null)
chain.add("changeEndTime", lineUnionSelect.getChangeEndTime());
if (lineUnionSelect.getPlayStartTime() != null)
chain.add("playStartTime", lineUnionSelect.getPlayStartTime());
if (lineUnionSelect.getPlayEndTime() != null) chain.add("playEndTime", lineUnionSelect.getPlayEndTime());
if (lineUnionSelect.getAdjustSignUpEndTime() != null) chain.add("adjustSignUpEndTime", lineUnionSelect.getAdjustSignUpEndTime());
dao.update(TheRapyRecuperationLineUnionSelect.class, chain, Cnd.where("id", "in", lineIds));
}
return null;
}
@At
@ViReturn
@SaCheckPermission(value = {"inclusiveTherapyV3.lineFghSelect", "inclusiveTherapyV3.lineXghSelect"}, mode = SaMode.OR)
@SLog(type = "普惠疗休养", tag = "分工会/校工会选择线路", msg = "是否开放对外报名", param = true, result = true)
public Object doEditOpen(String id) {
dao.update(TheRapyRecuperationLineUnionSelect.class, Chain.makeSpecial("isOpen", "isOpen ^ 1"), Cnd.where("id", "=", id));
return null;
}
}
@@ -0,0 +1,153 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.base.service.BaseService;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import java.util.List;
import java.util.Map;
/**
* 查询统计
*
* @author zhf
* @date 2022/06/15
*/
@IocBean
@At("/platform/inclusiveTherapyV3/query/statics")
@Ok("json:full")
public class TheRapyRecuperationStatisticsController {
@Inject("refer:staffTherapyDataService")
private BaseService baseService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/queryStatics.html")
@SaCheckPermission("inclusiveTherapyV3.queryStatics")
public void index() {
}
@At
@ViReturn
@SaCheckLogin
public Object getLineBar(String regionalNature, Integer year) {
Sql sql = Sqls.create("""
SELECT
line.lineName,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll WHERE isNormal=true and line.id = takePartInLineId ) AS enrollNum,
(
SELECT
COUNT( 1 )
FROM
inclusive_therapy_v3_enroll_companion com
LEFT JOIN inclusive_therapy_v3_enroll enroll ON enroll.id = com.trreId
WHERE
line.id = enroll.takePartInLineId
AND com.loginName IS NULL
) AS companionNum
FROM
`inclusive_therapy_v3_line` line
where line.regionalNature=@regionalNature and line.year=@year
ORDER BY
signUpStartTime DESC
""").setParam("regionalNature", regionalNature).setParam("year", year);
return baseService.listMap(sql);
}
@At
@ViReturn
@SaCheckLogin
public Object getSnSwNum(Integer year) {
Sql sql = Sqls.create("""
SELECT
COUNT( 1 ) AS enrollNum,
(
SELECT
COUNT( 1 )
FROM
inclusive_therapy_v3_enroll_companion com
LEFT JOIN inclusive_therapy_v3_enroll enroll ON enroll.id = com.trreId
WHERE
line.id = enroll.takePartInLineId
AND com.loginName IS NULL
) AS companionNum
FROM
inclusive_therapy_v3_enroll enroll
LEFT JOIN inclusive_therapy_v3_line line ON line.id = enroll.takePartInLineId
$condition
""");
Cnd cndSn = Cnd.NEW();
sql.setCondition(cndSn);
cndSn.and("line.regionalNature", "=", "省内");
cndSn.and("line.year", "=", year);
List<NutMap> sn = baseService.listMap(sql);
Cnd cndSw = Cnd.NEW();
sql.setCondition(cndSw);
cndSw.and("line.regionalNature", "=", "省内");
cndSw.and("line.year", "=", year);
List<NutMap> sw = baseService.listMap(sql);
NutMap snMap = sn.get(0);
NutMap swMap = sw.get(0);
int snEnrollNum = Strings.isNotBlank(snMap.getString("enrollNum")) ? snMap.getInt("enrollNum") : 0;
int snCompanionNum = Strings.isNotBlank(snMap.getString("companionNum")) ? snMap.getInt("companionNum") : 0;
int swEnrollNum = Strings.isNotBlank(swMap.getString("enrollNum")) ? swMap.getInt("enrollNum") : 0;
int swCompanionNum = Strings.isNotBlank(swMap.getString("companionNum")) ? swMap.getInt("companionNum") : 0;
return Map.of("snNum", (snCompanionNum + snEnrollNum), "swNum", (swEnrollNum + snCompanionNum));
}
@At
@ViReturn
@SaCheckLogin
public Object getTravelAgencyRating(Integer year) {
Sql sql = Sqls.create("""
SELECT
agency.travelAgencyName,
( SELECT AVG( evaluationForTravelAgency ) FROM inclusive_therapy_v3_enroll where isNormal=true and agency.id=takePartInTravelAgencyId) AS avg
FROM
`inclusive_therapy_v3_travel_agency` agency
WHERE
agency.`year` = @year
""").setParam("year", year);
List list = baseService.listMap(sql);
return list;
}
@At
@ViReturn
@SaCheckLogin
public Object getLineRating(Integer year) {
Sql sql = Sqls.create("""
SELECT
line.lineName,
( SELECT AVG( evaluationForLine ) FROM inclusive_therapy_v3_enroll where isNormal=true and line.id=takePartInLineId) AS avg
FROM
`inclusive_therapy_v3_line` line
WHERE
line.`year` = @year
""").setParam("year", year);
List list = baseService.listMap(sql);
return list;
}
}
@@ -0,0 +1,501 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.statistics;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUnion;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionLineNumberStatisticsVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService;
import lombok.extern.slf4j.Slf4j;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
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;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* @version 1.0
* @Author zzr
* @name:TheRapyRecuperationStatisticsController
* @Date 2024/6/3 17:32
* @注释 查看报名情况
*/
@IocBean
@At("/platform/inclusiveTherapyV3/statistics")
@Ok("json:full")
@Slf4j
public class TheRapyRecuperationLineStatisticsController {
@Inject
private TheRapyRecuperationEnrollService enrollService;
@Inject
private TherapyMessage msgApi;
@Inject
private Dao dao;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/statistics/lineStatistics.html")
@SaCheckPermission("inclusiveTherapyV3.statistics")
public void index() {
}
@At("/unionLineNumberStatistics")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/statistics/unionLineNumberStatistics.html")
@SaCheckPermission("inclusiveTherapyV3.unionLineNumberStatistics")
public void unionLineNumberStatistics() {
}
/**
* 查询基础设置中各分工会配置的线路最低数量,以及当前年度已选择的省内、省外出行时间段数量。
*
* @param unionId 分工会 ID;为空时查询基础设置中所有已配置分工会
* @return 分工会线路数量统计 VO 列表,finished 表示省内、省外均达到最低数量要求
*/
@At("/unionLineNumberStatistics/pageData")
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.unionLineNumberStatistics")
public Object unionLineNumberStatisticsPageData(@Param(value = "unionId") String unionId) {
TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW());
List<NutMap> lineNumberConfigs = Optional.ofNullable(config)
.map(TheRapyRecuperationConfig::getUnionLineNumberConfigs)
.orElse(Collections.emptyList());
if (Strings.isNotBlank(unionId)) {
lineNumberConfigs = lineNumberConfigs.stream()
.filter(item -> unionId.equals(item.getString("unionId")))
.collect(Collectors.toList());
}
if (lineNumberConfigs.isEmpty()) {
return new ArrayList<>();
}
List<String> unionIds = lineNumberConfigs.stream()
.map(item -> item.getString("unionId"))
.filter(Strings::isNotBlank)
.distinct()
.collect(Collectors.toList());
if (unionIds.isEmpty()) {
return new ArrayList<>();
}
Map<String, String> unionNameMap = dao.query(TherapyUnion.class, Cnd.where("id", "in", unionIds))
.stream()
.collect(Collectors.toMap(TherapyUnion::getId, TherapyUnion::getUnionname));
Sql selectedSql = Sqls.create("""
SELECT
us.unionId,
line.regionalNature,
COUNT(us.id) AS selectedNumber
FROM
inclusive_therapy_v3_line_union_select us
LEFT JOIN inclusive_therapy_v3_line line ON line.id = us.lineId
WHERE
us.signUpMode = 1
AND YEAR(us.selectTime) = @year
GROUP BY
us.unionId,
line.regionalNature
""");
selectedSql.setParam("year", DateUtil.thisYear());
List<NutMap> selectedList = (List<NutMap>) enrollService.listMap(selectedSql);
Map<String, Integer> selectedNumberMap = new HashMap<>();
for (NutMap selected : selectedList) {
selectedNumberMap.put(selected.getString("unionId") + "#" + selected.getString("regionalNature"),
Optional.ofNullable(selected.getInt("selectedNumber")).orElse(0));
}
List<UnionLineNumberStatisticsVo> resultList = new ArrayList<>();
for (NutMap lineNumberConfig : lineNumberConfigs) {
String rowUnionId = lineNumberConfig.getString("unionId");
Integer provinceOutNumber = Optional.ofNullable(lineNumberConfig.getInt("minProvinceOutNumber")).orElse(0);
Integer provinceInNumber = Optional.ofNullable(lineNumberConfig.getInt("minProvinceInNumber")).orElse(0);
Integer selectedProvinceOutNumber = selectedNumberMap.getOrDefault(rowUnionId + "#" + TheRapyRecuperationProvinceType.provinceOut.getValue(), 0);
Integer selectedProvinceInNumber = selectedNumberMap.getOrDefault(rowUnionId + "#" + TheRapyRecuperationProvinceType.provinceIn.getValue(), 0);
boolean finished = selectedProvinceOutNumber >= provinceOutNumber && selectedProvinceInNumber >= provinceInNumber;
// 配置来源于基础设置 JSON,统计结果按当前年度分工会已选择出行时间段数量合并展示。
resultList.add(new UnionLineNumberStatisticsVo()
.setUnionId(rowUnionId)
.setUnionName(unionNameMap.getOrDefault(rowUnionId, ""))
.setProvinceOutNumber(provinceOutNumber)
.setProvinceInNumber(provinceInNumber)
.setSelectedProvinceOutNumber(selectedProvinceOutNumber)
.setSelectedProvinceInNumber(selectedProvinceInNumber)
.setFinished(finished));
}
return resultList;
}
/**
* 统计线路报名情况列表。
*
* @param pageForm 分页参数,包含 pageNumber、pageSize、排序字段等表格通用参数
* @param startYear 选择线路年度开始年份,按 lineu.selectTime 年份过滤
* @param endYear 选择线路年度结束年份,按 lineu.selectTime 年份过滤
* @param unionId 分工会 ID,管理员可传;普通分工会账号按当前登录人分工会过滤
* @param takePartInLineId 线路 ID,对应 inclusive_therapy_v3_line.id
* @param lotId 标段 ID,对应 inclusive_therapy_v3_lot.id
* @param signUpMode 报名模式,1 分工会组织,2 校工会组织
* @param selectId 线路选择记录 ID,保留给旧入口按具体出行时间段精确筛选
* @param playMonth 出行年月,格式 yyyy-MM,按 lineu.playStartTime 所属年月筛选
* @param regionalNature 线路类型,省内或省外
* @param travelAgencyId 旅行社 ID,同时匹配线路选择记录和线路主表上的旅行社字段
* @return 分页数据,data.list 为线路统计行,data.totalCount 为总条数
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.statistics")
public Object pageData(PageForm pageForm,
@Param(value = "startYear") Integer startYear,
@Param(value = "endYear") Integer endYear,
@Param(value = "unionId") String unionId,
@Param("takePartInLineId") String takePartInLineId,
@Param(value = "lotId") String lotId,
@Param(value = "signUpMode") String signUpMode,
@Param(value = "selectId") String selectId,
@Param(value = "playMonth") String playMonth,
@Param(value = "regionalNature") String regionalNature,
@Param(value = "travelAgencyId") String travelAgencyId) {
Sql sql = Sqls.create("""
SELECT
line.id,
line.lineName,
line.regionalNature,
lineu.lineId,
lineu.id as lineUId,
lineu.signUpMode,
lineu.minimumGroupSize,
lineu.estimatedFamilyNumbers,
YEAR(lineu.selectTime) as `year`,
CONCAT(DATE_FORMAT(lineu.playStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.playEndTime,'%m月%d日')) AS linePlayTime,
CONCAT(DATE_FORMAT(lineu.signUpStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.signUpEndTime,'%m月%d日')) AS signUpTime,
DATE_FORMAT(lineu.adjustSignUpEndTime, '%Y-%m-%d %H:%i') AS adjustSignUpEndTime,
lineu.playStartTime as playStartTime1,
lineu.playEndTime as playEndTime2,
IFNULL(usTa.travelAgencyName, lineTa.travelAgencyName) AS travelAgencyName,
IFNULL(usTa.contact, lineTa.contact) AS contact,
IFNULL(usTa.contactMobileNumber, lineTa.contactMobileNumber) AS contactMobileNumber,
enrollStats.usUnionId,
if(lineu.signUpMode = 2, '校工会', un.unionname) as unionname,
lot.lotName,
lot.lotValue,
enrollStats.familyNumber,
IFNULL(enrollStats.lineNum, 0) lineNum,
IFNULL(enrollStats.signUpUserFamilyNum, 0) as signUpUserFamilyNum,
IFNULL(enrollStats.adultFamilyNum, 0) as adultFamilyNum
FROM
inclusive_therapy_v3_line_union_select lineu
LEFT JOIN inclusive_therapy_v3_line line ON line.id = lineu.lineId
LEFT JOIN inclusive_therapy_v3_lot lot ON lot.id = line.lotId
LEFT JOIN inclusive_therapy_v3_travel_agency usTa ON lineu.travelAgencyId = usTa.id
LEFT JOIN inclusive_therapy_v3_travel_agency lineTa ON line.travelAgencyId = lineTa.id
LEFT JOIN inclusive_therapy_v3_union un ON un.id = lineu.unionId
LEFT JOIN (
SELECT
e.takePartInLineId,
MAX(e.takePartInUnionId) AS usUnionId,
MAX(e.familyNumber) AS familyNumber,
COUNT(DISTINCT e.id) AS lineNum,
COUNT(c.id) AS signUpUserFamilyNum,
SUM(CASE WHEN c.age >= 18 THEN 1 ELSE 0 END) AS adultFamilyNum
FROM
inclusive_therapy_v3_enroll e
LEFT JOIN inclusive_therapy_v3_enroll_companion c ON c.trreId = e.id
WHERE
e.stateId = 2750
AND e.isNormal = TRUE
$unionCnd
GROUP BY
e.takePartInLineId
) enrollStats ON enrollStats.takePartInLineId = lineu.id
$condition
ORDER BY line.serialNumber ASC, lineu.playStartTime ASC
""");
Sql countSql = Sqls.create("""
SELECT
COUNT(1)
FROM
inclusive_therapy_v3_line_union_select lineu
LEFT JOIN inclusive_therapy_v3_line line ON line.id = lineu.lineId
LEFT JOIN inclusive_therapy_v3_lot lot ON lot.id = line.lotId
$condition
""");
Cnd cnd = Cnd.NEW();
if (startYear != null) {
cnd.and("lineu.selectTime", ">=", startYear + "-01-01 00:00:00");
}
if (endYear != null) {
cnd.and("lineu.selectTime", "<", (endYear + 1) + "-01-01 00:00:00");
}
cnd.andEX("lineu.signUpMode", "=", signUpMode);
sql.setVar("unionCnd", "");
if (!TherapyContext.hasAnyRoles("sysadmin,H06")) {
String unionCndSql = "and (e.selfUnionId='%s' or e.takePartInUnionId = '%s')".formatted(TherapyContext.getUnionId(), TherapyContext.getUnionId());
sql.setVar("unionCnd", unionCndSql);
cnd.and("lineu.unionId", "=", TherapyContext.getUnionId());
} else {
if (Strings.isNotBlank(unionId)) {
cnd.and("lineu.unionId", "=", unionId);
}
}
cnd.andEX("line.lotId", "=", lotId);
cnd.andEX("line.id", "=", takePartInLineId);
cnd.andEX("lineu.id", "=", selectId);
// 出行年月筛选按出行开始时间归属月份统计,跨月线路归入开始月份。
if (Strings.isNotBlank(playMonth)) {
String playMonthStart = playMonth + "-01 00:00:00";
String playMonthEnd = DateUtil.offsetMonth(DateUtil.parse(playMonth + "-01", "yyyy-MM-dd"), 1).toDateStr() + " 00:00:00";
cnd.and("lineu.playStartTime", ">=", playMonthStart);
cnd.and("lineu.playStartTime", "<", playMonthEnd);
}
cnd.andEX("line.regionalNature", "=", regionalNature);
addTravelAgencyCondition(cnd, travelAgencyId);
sql.setCondition(cnd);
countSql.setCondition(cnd);
return enrollService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql);
}
/**
* 统计页按旅行社过滤线路选择记录。
* 旅行社可能保存在线路选择记录或线路主表,两个字段任一命中都应纳入统计结果。
*
* @param cnd 当前统计查询条件
* @param travelAgencyId 旅行社 ID,为空时不增加过滤条件
*/
private void addTravelAgencyCondition(Cnd cnd, String travelAgencyId) {
if (StrUtil.isBlank(travelAgencyId)) {
return;
}
SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup();
travelAgencyGroup.or("lineu.travelAgencyId", "=", travelAgencyId);
travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId);
cnd.and(travelAgencyGroup);
}
/**
* 根据线路查询报名详情
*
* @param searchKeyword
* @param unionId
* @param unitId
* @return
*/
@At
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.statistics")
public Object getUserDateByLine(PageForm pageForm,
@Param(value = "takePartLineId") String takePartLineId,
@Param(value = "searchKeyword") String searchKeyword,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId) {
Sql sql = Sqls.create("""
SELECT
enroll.*,
line.lineName,
line.id as lineId,
line.regionalNature,
'教职工' userNature,
state.stateColor,
state.stateName,
CONCAT(DATE_FORMAT(rs.playStartTime,'%m月%d日'),'-',DATE_FORMAT(rs.playEndTime,'%m月%d日')) AS linePlayTime,
IF
( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) isFamily,
( SELECT COUNT( 1 ) FROM inclusive_therapy_v3_enroll_companion WHERE trreId = enroll.id ) num
FROM
`inclusive_therapy_v3_enroll` enroll
LEFT JOIN `inclusive_therapy_v3_line_union_select` rs ON rs.id = enroll.takePartInLineId
LEFT JOIN `inclusive_therapy_v3_line` line on line.id=rs.lineId
LEFT JOIN inclusive_therapy_v3_audit_state state ON state.stateId = enroll.stateId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("enroll.takePartInLineId", "=", takePartLineId);
cnd.and("enroll.stateId", "=", 2750);
cnd.andEX("enroll.selfUnionId", "=", unionId);
cnd.andEX("enroll.selfUnitId", "=", unitId);
cnd.and("enroll.takePartInLineId", "is not", null);
cnd.andEX("enroll.isNormal", "=", true);
if (StrUtil.isNotBlank(searchKeyword)) {
cnd.and(Cnd.exps("enroll.loginName", "like", "%" + searchKeyword + "%").or("enroll.userName", "like", "%" + searchKeyword + "%"));
}
cnd.desc("enroll.signingUptime");
cnd.desc("enroll.unitName");
sql.setCondition(cnd);
return enrollService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
@SaCheckLogin
public Object sendSuccess(String id) {
TheRapyRecuperationLineUnionSelect unionSelect = dao.fetch(TheRapyRecuperationLineUnionSelect.class, id);
TheRapyRecuperationLine line = dao.fetch(TheRapyRecuperationLine.class, unionSelect.getLineId());
if (DateUtil.compare(new Date(), unionSelect.getSignUpEndTime()) < 0) {
return Result.error("报名还未结束,不能发送");
}
//找出报名人员
List<TheRapyRecuperationEnroll> enrolls = dao.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", id)
.and("isNormal", "=", true).and("year(signingUptime)", "=", DateUtil.thisYear())
.and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)));
//发短信
enrolls.forEach(item -> {
String content = "%s老师,您好!您报名的%s线路,出行时间为%s,达到成团条件,请准时参加疗休养活动。".formatted(
item.getUserName(),
line.getLineName(),
DateUtil.format(unionSelect.getPlayStartTime(), "yyyy-MM-dd")
);
List list = List.of(Map.of("type", "User", "userId", item.getLoginName(), "name", item.getUserName()));
msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", TherapyMessage.sendMode.normal.name());
});
return null;
}
@At
@ViReturn
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
public Object sendFail(String id) {
TheRapyRecuperationLineUnionSelect unionSelect = dao.fetch(TheRapyRecuperationLineUnionSelect.class, id);
TheRapyRecuperationLine line = dao.fetch(TheRapyRecuperationLine.class, unionSelect.getLineId());
if (DateUtil.compare(new Date(), unionSelect.getSignUpEndTime()) < 0) {
return Result.error("报名还未结束,不能发送");
}
//找出报名人员
List<TheRapyRecuperationEnroll> enrolls = dao.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", id)
.and("isNormal", "=", true).and("delFlag", "=", false).and("year(signingUptime)", "=", DateUtil.thisYear())
.and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)));
//发短信
enrolls.forEach(item -> {
String content = "%s老师,您好!您报名的%s线路,出行时间为%s,因报名人数不足未达到成团条件,请尽快进入疗休养管理系统重新选择线路,7月份线路报名截止时间延长至7月4日晚上24点,谢谢!".formatted(
item.getUserName(),
line.getLineName(),
DateUtil.format(unionSelect.getPlayStartTime(), "yyyy-MM-dd")
);
List list = List.of(Map.of("type", "User", "userId", item.getLoginName(), "name", item.getUserName()));
msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", TherapyMessage.sendMode.normal.name());
});
// 未成团通知统一保留报名数据,只将报名标记为非正常且已删除,便于后续调剂和历史追溯。
List<String> idList = enrolls.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList());
dao.update(TheRapyRecuperationEnroll.class, Chain.make("isNormal", false).add("delFlag", true), Cnd.where("id", "in", idList));
return null;
}
/**
* 补发 2026 年已删除报名记录的未成团通知。
* 仅 superadmin 可操作,避免普通统计人员误触发批量补发。
*
* @return 补发触发数量,前端展示给操作人确认
*/
@At("/resendFailNotice")
@ViReturn
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
public Object resendFailNotice() {
Object loginName = TherapyContext.getPrincipalProperty("loginname");
if (!"superadmin".equals(Strings.sNull(loginName))) {
return Result.error("仅 superadmin 可操作");
}
int count = enrollService.resendDeletedFailNotice(2026);
return Result.success("已触发补发未成团通知" + count + "条");
}
/**
* 手动发送所选线路的成团邮件给旅行社。
* 参数 lineUnionSelectIds 为统计页勾选的线路选择记录 ID 数组;返回值为统一 Result,msg 中说明实际发送邮件的旅行社数量。
*
* @param lineUnionSelectIds 线路选择记录 ID,对应 inclusive_therapy_v3_line_union_select.id
* @return Result,code=0 表示触发完成,msg 展示发送结果
*/
@At("/sendGroupMail")
@ViReturn
@SaCheckLogin
public Object sendGroupMail(@Param("lineUnionSelectIds") String[] lineUnionSelectIds) {
Object loginName = TherapyContext.getPrincipalProperty("loginname");
if (!"superadmin".equals(Strings.sNull(loginName))) {
return Result.error("仅 superadmin 可操作");
}
if (Lang.isEmpty(lineUnionSelectIds)) {
return Result.error("请选择需要发送成团邮件的线路");
}
int count = enrollService.sendTakePartInUserByLineMail(Arrays.asList(lineUnionSelectIds));
return Result.success("已发送成团邮件" + count + "封");
}
/**
* 统计页一键统赋勾选线路的报名、出行和调剂时间。
*
* @param lineUnionSelectIds 统计页勾选的线路选择记录 ID,对应 inclusive_therapy_v3_line_union_select.id
* @param lineUnionSelects 统赋时间表单数组,当前只取第一项作为批量更新模板
* @return 空数据,前端根据统一返回包装判断是否成功
*/
@At("/setGiveLineTimes")
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.statistics")
@Aop(TransAop.READ_COMMITTED)
public Object setGiveLineTimes(@Param("lineUnionSelectIds") String[] lineUnionSelectIds,
@Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects) {
if (Lang.isEmpty(lineUnionSelectIds) || Lang.isEmpty(lineUnionSelects)) {
return null;
}
TheRapyRecuperationLineUnionSelect lineUnionSelect = lineUnionSelects[0];
Chain chain = Chain.make("enable", Boolean.TRUE.equals(lineUnionSelect.getEnable()));
if (lineUnionSelect.getSignUpStartTime() != null) {
chain.add("signUpStartTime", lineUnionSelect.getSignUpStartTime());
}
if (lineUnionSelect.getSignUpEndTime() != null) {
chain.add("signUpEndTime", lineUnionSelect.getSignUpEndTime());
}
if (lineUnionSelect.getChangeEndTime() != null) {
chain.add("changeEndTime", lineUnionSelect.getChangeEndTime());
}
if (lineUnionSelect.getPlayStartTime() != null) {
chain.add("playStartTime", lineUnionSelect.getPlayStartTime());
}
if (lineUnionSelect.getPlayEndTime() != null) {
chain.add("playEndTime", lineUnionSelect.getPlayEndTime());
}
if (lineUnionSelect.getAdjustSignUpEndTime() != null) {
chain.add("adjustSignUpEndTime", lineUnionSelect.getAdjustSignUpEndTime());
}
dao.update(TheRapyRecuperationLineUnionSelect.class, chain, Cnd.where("id", "in", lineUnionSelectIds));
return null;
}
}
@@ -0,0 +1,177 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.statistics;
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.hutool.core.date.DateUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.TravelAgencyMonthlyEnrollStatisticsVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionEnrollStatisticsVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService;
import org.apache.poi.ss.usermodel.Workbook;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 旅行社月度报名统计。
*/
@IocBean
@At("/platform/inclusiveTherapyV3/travelAgencyMonthlyStatistics")
@Ok("json:full")
public class TheRapyRecuperationTravelAgencyMonthlyStatisticsController {
@Inject
private TheRapyRecuperationEnrollService enrollService;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/statistics/travelAgencyMonthlyStatistics.html")
@SaCheckPermission("inclusiveTherapyV3.travelAgencyMonthlyStatistics")
public void index() {
}
/**
* 查询指定年度各旅行社每月报名数量。
* 参数 year 为统计年度,前端年度选择器传 yyyy;为空时默认当前年度。
* 返回值为 List<TravelAgencyMonthlyEnrollStatisticsVo>,每项包含旅行社、月份和报名数量。
*
* @param year 统计年度
* @return 旅行社月度报名数量统计列表
*/
@At("/getChartData")
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.travelAgencyMonthlyStatistics")
public Object getChartData(@Param(value = "year") Integer year) {
Integer queryYear = year == null ? DateUtil.thisYear() : year;
return enrollService.getTravelAgencyMonthlyEnrollStatistics(queryYear);
}
/**
* 查询指定年度二级工会出去疗休养人数。
* 参数 year 为统计年度,前端年度选择器传 yyyy;为空时默认当前年度。
* 返回值为 List<UnionEnrollStatisticsVo>,每项包含二级工会、月份和有效报名人数。
*
* @param year 统计年度
* @return 二级工会月度出行人数统计列表
*/
@At("/getUnionChartData")
@ViReturn
@SaCheckPermission("inclusiveTherapyV3.travelAgencyMonthlyStatistics")
public Object getUnionChartData(@Param(value = "year") Integer year) {
Integer queryYear = year == null ? DateUtil.thisYear() : year;
List<UnionEnrollStatisticsVo> list = enrollService.getUnionEnrollStatistics(queryYear);
return list;
}
/**
* 导出当前年度旅行社月度报名统计。
* 参数 year 为统计年度;为空时默认当前年度。
* 返回 xlsx 文件,列为年度、旅行社和动态月份数量列。
*
* @param year 统计年度
* @param response HTTP 响应对象,方法直接写出 Excel 文件
*/
@At("/doExportExcel")
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.travelAgencyMonthlyStatistics")
public void doExportExcel(@Param(value = "year") Integer year,
HttpServletResponse response) throws IOException {
Integer queryYear = year == null ? DateUtil.thisYear() : year;
NutMap exportData = enrollService.getTravelAgencyMonthlyEnrollExportData(queryYear);
List<Integer> months = getExportMonths(exportData);
List<NutMap> list = getExportRows(exportData);
ArrayList<ExcelExportEntity> exportEntities = buildMonthExportEntities("旅行社", "travelAgencyName", months);
TherapyDownload.excelResponse(response, queryYear + "旅行社月度报名统计.xlsx");
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
workbook.write(response.getOutputStream());
workbook.close();
}
/**
* 导出当前年度二级工会出去疗休养人数统计。
* 参数 year 为统计年度;为空时默认当前年度。
* 返回 xlsx 文件,列为年度、二级工会和动态月份数量列。
*
* @param year 统计年度
* @param response HTTP 响应对象,方法直接写出 Excel 文件
*/
@At("/doExportUnionExcel")
@Ok("void")
@SaCheckPermission("inclusiveTherapyV3.travelAgencyMonthlyStatistics")
public void doExportUnionExcel(@Param(value = "year") Integer year,
HttpServletResponse response) throws IOException {
Integer queryYear = year == null ? DateUtil.thisYear() : year;
NutMap exportData = enrollService.getUnionEnrollExportData(queryYear);
List<Integer> months = getExportMonths(exportData);
List<NutMap> list = getExportRows(exportData);
ArrayList<ExcelExportEntity> exportEntities = buildMonthExportEntities("二级工会", "unionName", months);
TherapyDownload.excelResponse(response, queryYear + "二级工会月度疗休养出行人数统计.xlsx");
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
workbook.write(response.getOutputStream());
workbook.close();
}
/**
* 根据有数据的月份生成横向月份导出列。
* 固定列为年度和统计对象名称,动态列为 7月、8月 等,字段名为 month_7、month_8。
*
* @param nameTitle 统计对象列标题,例如旅行社、二级工会
* @param nameField 统计对象列字段,例如 travelAgencyName、unionName
* @param months 有数据的月份数字列表,按月份升序生成列
* @return Excel 导出列定义
*/
private ArrayList<ExcelExportEntity> buildMonthExportEntities(String nameTitle, String nameField, List<Integer> months) {
ArrayList<ExcelExportEntity> exportEntities = new ArrayList<>();
exportEntities.add(new ExcelExportEntity("年度", "year", 15));
exportEntities.add(new ExcelExportEntity(nameTitle, nameField, 35));
months.forEach(month ->{
ExcelExportEntity entity = new ExcelExportEntity(month + "月", "month_" + month, 15);
entity.setType(10);
exportEntities.add(entity);
} );
return exportEntities;
}
/**
* 从 service 返回的导出数据中读取动态月份列表。
* months 字段为 List<Integer>,用于按实际有数据的月份生成 Excel 列。
*
* @param exportData service 构建的导出数据
* @return 有数据的月份数字列表
*/
@SuppressWarnings("unchecked")
private List<Integer> getExportMonths(NutMap exportData) {
return (List<Integer>) exportData.get("months");
}
/**
* 从 service 返回的导出数据中读取 Excel 行数据。
* rows 字段为 List<NutMap>,每行包含年度、统计对象名称以及 month_月份 数量字段。
*
* @param exportData service 构建的导出数据
* @return Excel 行数据
*/
@SuppressWarnings("unchecked")
private List<NutMap> getExportRows(NutMap exportData) {
return (List<NutMap>) exportData.get("rows");
}
}
@@ -0,0 +1,152 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.theRapyConfig;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.trans.Trans;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* rapy休养配置控制器
*
* @author zhf
* @date 2022/06/01
*/
@IocBean
@At("/platform/inclusiveTherapyV3/TheRapyConfig")
@Ok("json:full")
public class TheRapyRecuperationConfigController {
@Inject
private Dao dao;
@At("")
@Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/theRapyConfig/TheRapyConfig.html")
@SaCheckPermission("inclusiveTherapyV3.TheRapyConfig")
public void index() {
}
/**
* 保存疗休养配置。
*
* @param config 配置主体,包含基本配置、服务须知以及标段列表等页面表单字段
* @param lotDeleteList 需要删除的标段 ID 数组,后台会按 ID 清理标段数据
* @param unionLineNumberConfigs 分工会线路数量配置 JSON 数组,元素包含 unionId、minProvinceOutNumber、minProvinceInNumber
* @return ViReturn 统一包装的 JSON 结果,保存成功时 data 为空
*/
@At
@ViReturn
@SaCheckLogin
@Aop(TransAop.READ_COMMITTED)
public Object operation(TheRapyRecuperationConfig config, String[] lotDeleteList, String unionLineNumberConfigs, String lots) {
if (Strings.isNotBlank(lots)) {
config.setLots(Json.fromJsonAsList(TheRapyRecuperationLot.class, lots));
}
if (config.getLots() == null) {
config.setLots(new ArrayList<>());
}
// unionLineNumberConfigs 为前端分工会线路数量配置 JSON 数组,返回保存后的配置对象仍由 findOne 接口按实体结构回显。
config.setUnionLineNumberConfigs(Strings.isBlank(unionLineNumberConfigs)
? new ArrayList<>()
: Json.fromJsonAsList(NutMap.class, unionLineNumberConfigs));
if (Strings.isNotBlank(config.getId())) {
if (Lang.isNotEmpty(lotDeleteList)) {
dao.clear(TheRapyRecuperationLot.class, Cnd.where("id", "in", lotDeleteList));
}
dao.updateWith(config, "lots");
List<TheRapyRecuperationLot> collect = config.getLots().stream().filter(v -> v.getConfigId() == null).collect(Collectors.toList());
for (TheRapyRecuperationLot obj : collect) {
obj.setConfigId(config.getId());
}
if (!collect.isEmpty()) {
dao.insert(collect);
}
} else {
dao.insertWith(config, "lots");
}
return null;
}
@At
@ViReturn
@SaCheckLogin
public Object findOne() {
return dao.fetchLinks(dao.fetch(TheRapyRecuperationConfig.class), "lots",Cnd.NEW().desc("lotValue"));
}
/**
* 查使用该标段的线路和目的地
* @param lotId
* @return
*/
@At
@ViReturn
@SaCheckLogin
public Object getLotsById(String lotId){
List<String> lineNames = new ArrayList<>();
List<String> baseNames = new ArrayList<>();
Map<String, List<String>> map = new HashMap<>();
List<TheRapyRecuperationLine> lineList = dao.query(TheRapyRecuperationLine.class, Cnd.where("lotId", "=", lotId));
if (!CollectionUtils.isEmpty(lineList)){
lineList.forEach(v-> lineNames.add(v.getLineName()));
map.put("line",lineNames);
}
List<TheRapyRecuperationBaseManagement> managementList = dao.query(TheRapyRecuperationBaseManagement.class, Cnd.where("lotId", "=", lotId));
if (!CollectionUtils.isEmpty(managementList)){
managementList.forEach(v-> baseNames.add(v.getBaseName()));
map.put("base",baseNames);
}
return map;
}
/**
* 强制删除标段时长,会删除已绑定的线路和目的地
* @param lotId
* @return
*/
@At
@ViReturn
@SaCheckLogin
public Object deleteLotById(String lotId){
Trans.exec(()->{
dao.clear(TheRapyRecuperationLot.class, Cnd.where("id","=",lotId));
List<TheRapyRecuperationLine> lineList = dao.query(TheRapyRecuperationLine.class, Cnd.where("lotId", "=", lotId));
if (!CollectionUtils.isEmpty(lineList)) {
lineList.forEach(v -> v.setLotId(null));
dao.update(lineList);
}
List<TheRapyRecuperationBaseManagement> managementList = dao.query(TheRapyRecuperationBaseManagement.class, Cnd.where("lotId", "=", lotId));
if (!CollectionUtils.isEmpty(managementList)) {
managementList.forEach(v -> v.setLotId(null));
dao.update(managementList);
}
});
return null;
}
}
@@ -0,0 +1,145 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.job;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyEmail;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @Author: JyuHsin
* @Date: 2024/6/14 10:41
* @Version: v1.0.0
* @Description: 给旅游社发送线路成团的名单,每天早上八点执行,查询报名结束时间为前一天的线路
**/
@IocBean(name = "staffTherapySendTakePartInUserByLineJob")
public class SendTakePartInUserByLineJob implements Job {
@Inject
private TherapyEmail emailUtil;
@Inject
private TheRapyRecuperationEnrollService enrollService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//获取昨天
String yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd");
//先查询符合条件的线路
List<TheRapyRecuperationLineUnionSelect> unionSelects =
enrollService.dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("Date(signUpEndTime)", "=", yesterday).and("enable", "=", true));
List<String> selectIdList = unionSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList());
Map<String, TheRapyRecuperationLineUnionSelect> selectMap = unionSelects.stream().collect(Collectors.toMap(TheRapyRecuperationLineUnionSelect::getId, o -> o));
//在查询这些线路的报名人员
Sql sql = Sqls.create("""
SELECT
e.*,
concat(l.lineName, ifnull(concat('【', ta.travelAgencyName, '】'), ''), ifnull(concat('-', su.unionname), '')) as lineName,
ta.id as travelId,
ta.travelAgencyName,
concat(s.playStartTime, '至' , s.playEndTime) as playTime,
(select count(1) from inclusive_therapy_v3_enroll_companion ec where ec.trreId = e.id and ec.age >= 18) as companionCount,
(select GROUP_CONCAT(ec.userName, '(', ec.idcard, '、', ec.mobile, ')') from inclusive_therapy_v3_enroll_companion ec where ec.trreId = e.id) as companionInfo,
u.schoolTime
FROM
inclusive_therapy_v3_enroll e
LEFT JOIN `inclusive_therapy_v3_user` u on e.loginName = u.loginname
LEFT JOIN inclusive_therapy_v3_line_union_select s ON e.takePartInLineId = s.id
left join inclusive_therapy_v3_line l on l.id = s.lineId
left join inclusive_therapy_v3_travel_agency ta on ta.id = s.travelAgencyId
left join inclusive_therapy_v3_union su on su.id = s.unionId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("takePartInLineId", "in", selectIdList);
cnd.and("isNormal", "=", true);
cnd.and("stateId", "=", TheRapyRecuperationState.PASS);
cnd.and("year(signingUptime)", "=", DateUtil.thisYear());
cnd.asc("l.serialNumber").asc("s.playStartTime").asc("e.signingUptime");
sql.setCondition(cnd);
List<NutMap> enrolls = enrollService.listMap(sql);
if (Lang.isNotEmpty(enrolls)) {
enrolls.forEach(item -> {
String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime"));
item.put("remark", remark);
});
}
//按照选择线路id分组,便于判断是否成团
Map<String, List<NutMap>> enrollGroup = enrolls.stream().collect(Collectors.groupingBy(o -> o.getString("takePartInLineId")));
// 成团人数口径与统计页保持一致:报名教职工本人 + 18 岁及以上家属人数。
List<NutMap> enrollList = enrollGroup.entrySet().stream()
.filter(entry -> selectMap.containsKey(entry.getKey()) && (entry.getValue().size() + entry.getValue().stream().mapToInt(o -> o.getInt("companionCount")).sum()) >= selectMap.get(entry.getKey()).getEstimatedFamilyNumbers())
.flatMap(entry -> entry.getValue().stream())
.collect(Collectors.toList());
//按旅行社分组
Map<String, List<NutMap>> enrollsMap = enrollList.stream().collect(Collectors.groupingBy(o -> o.getString("travelId")));
List<TheRapyRecuperationTravelAgency> travelAgencyList = enrollService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW());
for (TheRapyRecuperationTravelAgency item : travelAgencyList) {
String email = item.getEmail();
if (StrUtil.isBlank(email)) continue;
List<NutMap> userList = enrollsMap.get(item.getId());
if (Lang.isEmpty(userList)) continue;
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("姓名", "userName", 20));
entityList.add(new ExcelExportEntity("身份证号", "idCard", 20));
entityList.add(new ExcelExportEntity("联系电话", "mobile", 20));
entityList.add(new ExcelExportEntity("所属工会", "unionName", 20));
entityList.add(new ExcelExportEntity("报名线路", "lineName", 50));
entityList.add(new ExcelExportEntity("出行时间", "playTime", 50));
ExcelExportEntity entity = new ExcelExportEntity("家属信息", "companionInfo", 50);
entity.setWrap(true);
entityList.add(entity);
entityList.add(new ExcelExportEntity("旅行社名称", "travelAgencyName", 50));
entityList.add(new ExcelExportEntity("备注", "remark", 30));
File xls = new File("C:/temp/" + item.getTravelAgencyName() + "疗休养线路出行人员名单.xls");
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(xls);
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, userList);
workbook.write(fileOutputStream);
fileOutputStream.close();
emailUtil.send(email, item.getTravelAgencyName() + "疗休养线路出行人员名单", false, xls);
if (xls.exists()) {
xls.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@@ -0,0 +1,113 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.job;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyEmail;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @version 1.0
* @Author zzr
* @name:SendTakePartInUserByTravelJob
* @Date 2024/5/27 10:05
* @注释
*/
@IocBean(name = "staffTherapySendTakePartInUserByTravelJob")
public class SendTakePartInUserByTravelJob implements Job {
@Inject
private TherapyEmail emailUtil;
@Inject
private TheRapyRecuperationEnrollService enrollService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
Sql sql = Sqls.create("""
SELECT
te.*,
travel.email,
travel.travelAgencyName,
u.schoolTime
FROM
`inclusive_therapy_v3_enroll` te
LEFT JOIN `inclusive_therapy_v3_user` u on te.loginName = u.loginname
LEFT JOIN `inclusive_therapy_v3_travel_agency` travel ON travel.id = te.takePartInTravelAgencyId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("te.isNormal","=",1);
cnd.and("te.stateId","=",2750);
cnd.and("te.signingUptime",">=", DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd HH:mm:ss"));
cnd.and("te.signingUptime","<=", DateUtil.now());
cnd.and("te.takePartInTravelAgencyId","is not",null);
cnd.and("te.takePartInTravelAgencyId","!=","");
cnd.groupBy("te.loginName");
sql.setCondition(cnd);
List<NutMap> nutMaps = enrollService.listMap(sql);
if (Lang.isNotEmpty(nutMaps)) {
nutMaps.forEach(item -> {
String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime"));
item.put("remark", remark);
});
Map<String, List<NutMap>> enrollsMap = nutMaps.stream().collect(Collectors.groupingBy(v -> v.getString("takePartInTravelAgencyId")));
List<TheRapyRecuperationTravelAgency> travelAgencyList = enrollService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW());
for (TheRapyRecuperationTravelAgency item : travelAgencyList) {
String email = item.getEmail();
if (StrUtil.isBlank(email)) continue;
List<NutMap> userList = enrollsMap.get(item.getId());
if (Lang.isEmpty(userList)) continue;
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("姓名", "userName", 20));
entityList.add(new ExcelExportEntity("身份证号", "idCard", 20));
entityList.add(new ExcelExportEntity("联系电话", "mobile", 20));
entityList.add(new ExcelExportEntity("所属工会", "unionName", 20));
entityList.add(new ExcelExportEntity("旅行社名称", "travelAgencyName", 50));
entityList.add(new ExcelExportEntity("备注", "remark", 30));
File xls = new File("C:/temp/"+item.getTravelAgencyName()+"疗休养自由组团出行人员名单.xls");
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(xls);
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, userList);
workbook.write(fileOutputStream);
fileOutputStream.close();
emailUtil.send(email, item.getTravelAgencyName() + "疗休养自由组团出行人员名单", false, xls);
if (xls.exists()) {
xls.delete();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
@@ -0,0 +1,59 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode;
import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
/**
* 疗休养线路新导入模板,字段与PC端线路管理新增页面保持一致。
*/
@Data
public class TheRapyLineImportExcelMode {
@Excel(name = "年度")
private Integer year;
@Excel(name = "排序号")
private Integer serialNumber;
@Excel(name = "线路名称")
private String lineName;
@Excel(name = "时间标段")
private String lotId;
@Excel(name = "线路类型")
private String regionalNature;
@Excel(name = "旅行社名称")
private String travelAgencyName;
@Excel(name = "交通工具")
private String trafficTools;
@Excel(name = "最少成团人数包括家属")
private Integer estimatedFamilyNumbers;
@Excel(name = "预计费用(元/人次)")
private String estimatedCost;
@Excel(name = "家属报名")
private String familySignUp;
@Excel(name = "组织形式")
private String signUpMode;
@Excel(name = "联系人")
private String lineContact;
@Excel(name = "联系方式", width = 20)
private String lineContactPhone;
@Excel(name = "线路内容")
private String content;
@Excel(name = "是否启用")
private String isEnabled;
@Excel(name = "移动端缩略图", width = 20)
private String files;
}
@@ -0,0 +1,30 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode;
import lombok.Data;
/**
* 线路导入模板内嵌图片数据,承载“移动端缩略图”列解析出的图片内容。
*/
@Data
public class TheRapyLineImportImageMode {
/**
* Excel数据行下标,从0开始,对应导入明细集合下标。
*/
private Integer rowIndex;
/**
* 导入图片原始文件名,用于写入sys_file.filename。
*/
private String fileName;
/**
* 图片扩展名,用于生成FTP文件名与校验图片类型。
*/
private String extension;
/**
* 图片二进制内容,后续在service层统一上传并保存文件记录。
*/
private byte[] data;
}
@@ -0,0 +1,22 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode;
import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
import java.util.Date;
@Data
public class TheRapyRecuperationEnrollExcelMode {
@Excel(name = "工号")
private String loginName;
@Excel(name = "姓名")
private String userName;
@Excel(name = "参加时间")
private Date takePartInTime;
@Excel(name = "标段时间")
private String lotId;
}
@@ -0,0 +1,42 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode;
import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
@Data
public class TheRapyTravelAgencyExcelMode {
@Excel(name = "年度")
private Integer year;
@Excel(name = "排序编号")
private String serialNumber;
@Excel(name = "旅行社名称")
private String travelAgencyName;
@Excel(name = "是否自由组团(是/否)")
private String signUpTravelAgency;
@Excel(name = "旅行社联系人")
private String contact;
@Excel(name = "联系电话")
private String contactMobileNumber;
@Excel(name = "邮箱")
private String email;
@Excel(name = "最多承担人数")
private Integer maxUndertakeNumber;
@Excel(name = "官网")
private String officialWebsite;
@Excel(name = "备注")
private String note;
@Excel(name = "是否启用(是/否)")
private String isDisabled;
}
@@ -0,0 +1,69 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode;
import cn.afterturn.easypoi.excel.annotation.Excel;
import lombok.Data;
@Data
public class TheRapyTravelLineExcelMode {
@Excel(name = "年度")
private Integer year;
@Excel(name = "排序编号")
private Integer serialNumber;
@Excel(name = "线路名称")
private String lineName;
@Excel(name = "旅行社名称")
private String travelAgencyId;
@Excel(name = "活动范围")
private String regionalNature;
@Excel(name = "最少参与教工")
private Integer minimumGroupSize;
// @Excel(name = "创建模式(分工会/校工会)")
// private String createMode;
//
// @Excel(name = "报名模式(分工会/自由)")
// private String signUpMode;
//
// @Excel(name = "联系人")
// private String lineContact;
//
// @Excel(name = "联系方式")
// private String lineContactPhone;
//
// @Excel(name = "报名开始时间")
// private Date signUpStartTime;
//
// @Excel(name = "报名截止时间")
// private Date signUpEndTime;
//
// @Excel(name = "变更截止时间")
// private Date changeEndTime;
//
// @Excel(name = "出行开始时间")
// private Date playStartTime;
//
// @Excel(name = "出行结束时间")
// private Date playEndTime;
@Excel(name = "时间标段")
private String lotId;
@Excel(name = "预计费用")
private String estimatedCost;
// @Excel(name = "交通工具")
// private String trafficTools;
@Excel(name = "详细信息")
private String content;
@Excel(name = "是否启用(是/否)")
private String isDisabled;
}
@@ -0,0 +1,158 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.budwk.app.sys.models.Sys_file;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
import java.util.List;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement
* @Description: TODO
* @Author zzr
* @Date 2023/6/5
* @Version V1.0
**/
@Data
@Table("inclusive_therapy_v3_base_management")
@Accessors(chain = true)
public class TheRapyRecuperationBaseManagement {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.INT)
@Comment("年度")
@Excel(name = "年度")
private Integer year;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("排序编号")
@Excel(name = "排序编号")
private String sortNumber;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("基地名称")
@Excel(name = "目的地名称")
private String baseName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("旅行社Id")
@Excel(name = "所属旅行社")
private String travelAgencyId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("区域")
@Excel(name = "活动范围(省内/省外)")
private String regionalNature;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("标段Id")
@Excel(name = "时间标段")
private String lotId;
@Column
@ColDefine(customType = "text")
@Comment("疗休养详情")
@Excel(name = "详细信息")
private String content;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否禁用")
@Excel(name = "是否启用(是/否)")
private Boolean isDisabled;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("哪个分工会创建的")
private String createUnionId;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名开始时间")
@Excel(name = "报名开始时间")
private Date signUpStartTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名截至时间")
@Excel(name = "报名截至时间")
private Date signUpEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("变更截至时间")
@Excel(name = "变更截至时间")
private Date changeEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("活动开始时间")
@Excel(name = "活动开始时间")
private Date activityStartTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("活动结束时间")
@Excel(name = "活动结束时间")
private Date activityEndTime;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("预计费用")
@Excel(name = "预计费用")
private String estimatedCost;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("缩略图")
private List<Sys_file> files;
@Column
@ColDefine(type = ColType.INT)
@Comment("创建模式(1.校工会 2.分工会)")
@Excel(name = "组织形式(分工会/校工会)")
private int createMode;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("基地联系人")
@Excel(name = "目的地联系人")
private String baseContactPerson;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("基地联系人电话")
@Excel(name = "联系电话")
private String baseContactNumber;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("操作人")
private String opBy;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("操作时间")
private String opAt;
@One(field = "travelAgencyId")
private TheRapyRecuperationTravelAgency travelAgency;
}
@@ -0,0 +1,40 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.List;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster
* @Description: TODO
* @Author zxc
* @Date 2022/6/17:09:30
* @Version V1.0
**/
@Data
@Table("inclusive_therapy_v3_cluster")
@Accessors(chain = true)
public class TheRapyRecuperationCluster {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("线路id")
private String lineId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("团名")
private String clusterName;
@Many(field = "clusterId")
private List<TheRapyRecuperationClusterMember> members;
}
@@ -0,0 +1,60 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationClusterMember
* @Description: TODO
* @Author zxc
* @Date 2022/6/17:09:30
* @Version V1.0
**/
@Data
@Table("inclusive_therapy_v3_cluster_member")
@Accessors(chain = true)
public class TheRapyRecuperationClusterMember {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("线路id")
private String lineId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("团Id")
private String clusterId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("工号")
private String loginName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("姓名")
private String userName;
@Column
@ColDefine(type = ColType.CHAR, width = 1)
@Comment("性别")
private String sex;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("工会")
private String unionName;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否领队")
private Boolean isLeader;
}
@@ -0,0 +1,164 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import org.nutz.lang.util.NutMap;
import java.util.Date;
import java.util.List;
@Data
@Table("inclusive_therapy_v3_config")
@Accessors(chain = true)
public class TheRapyRecuperationConfig {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 30)
@Comment("配置名称")
private String configName;
@Column
@ColDefine(type = ColType.INT, width = 32)
@Comment("参加人员范围")
private Integer activityGroupId;
/**
* 报名开始时间,用于基础设置页面控制全局报名开放区间。
*/
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名开始时间")
private Date signUpStartTime;
/**
* 报名结束时间,用于基础设置页面控制全局报名截止区间。
*/
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名结束时间")
private Date signUpEndTime;
/**
* 选择线路开始时间,用于控制分工会/校工会选择线路开放区间。
*/
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("选择线路开始时间")
private Date lineSelectStartTime;
/**
* 选择线路结束时间,用于控制分工会/校工会选择线路截止区间。
*/
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("选择线路结束时间")
private Date lineSelectEndTime;
@Column
@ColDefine(type = ColType.INT)
@Comment("省外名额分配")
private Integer outsideQuota;
@Column
@ColDefine(type = ColType.FLOAT, width = 3, precision = 2)
@Comment("省外名额分配比例")
private Double outsideQuotaProportion;
@Column
@ColDefine(type = ColType.INT)
@Comment("省外几年去一次")
private Integer outsideNumber;
@Column
@ColDefine(type = ColType.INT)
@Comment("每年旅行频率")
private Integer travelFrequency;
@Column
@ColDefine(type = ColType.INT)
@Comment("组团人数")
private Integer groupNumber;
@Column
@ColDefine(type = ColType.INT)
@Comment("不可取消修改天数")
private Integer modifyDays;
@Column
@ColDefine(type = ColType.INT)
@Comment("可以修改几次")
private Integer modifyNumber;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("省内线路是否审核")
@Default(value = "0")
private Boolean isSnLine;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("省外线路是否审核")
@Default(value = "0")
private Boolean isSwLine;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("旅行社是否审核")
@Default(value = "0")
private Boolean travelAudit;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("标段")
private List<NutMap> modifyBd;
/**
* 分工会线路数量配置。
* 每个元素保存一个分工会的最低线路选择要求:
* unionId 为分工会 ID,minProvinceOutNumber 为最少省外线路数量,
* minProvinceInNumber 为最少省内线路数量。
*/
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("分工会线路数量配置")
private List<NutMap> unionLineNumberConfigs;
@Many(field = "configId")
private List<TheRapyRecuperationLot> lots;
@Column
@ColDefine(type = ColType.INT)
@Comment("全批次最多教职工报名人数")
private Integer allLineSignUpNumber;
@Column
@ColDefine(customType = "longtext")
@Comment("疗休养服务须知")
private String notice;
@Column
@ColDefine(type = ColType.INT)
@Comment("省内起始年份")
private Integer provinceStartYear;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("床位信息")
@Default(value = "0")
private Boolean bedInfo;
@Column
@ColDefine(type = ColType.INT)
@Comment("家属信息")
@Default(value = "0")
private Integer familyInfo;
}
@@ -0,0 +1,207 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import cn.afterturn.easypoi.excel.annotation.Excel;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
import java.util.List;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll
* @Description: 疗休养报名登记表
* @Author zxc
* @Date 2022/5/31:16:58
* @Version V1.0
**/
@EqualsAndHashCode(callSuper = true)
@Data
@Table("inclusive_therapy_v3_enroll")
@Accessors(chain = true)
public class TheRapyRecuperationEnroll extends LegacyBaseModel {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("工号")
@Excel(name = "工号")
private String loginName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("姓名")
@Excel(name = "姓名")
private String userName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1)
@Comment("性别")
private String sex;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("本人单位")
private String unitName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("本人分工会")
private String unionName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("本人单位")
private String selfUnitId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("本人分工会Id")
private String selfUnionId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("参加的分工会")
private String takePartInUnionId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("参加线路")
private String takePartInLineId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("参加旅行社")
private String takePartInTravelAgencyId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("参加酒店")
private String takePartInBaseManagementId;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名时间")
private Date signingUptime;
@Column
@ColDefine(type = ColType.DATE)
@Comment("参加时间")
@Excel(name = "参加时间", format = "yyyy-MM-dd")
private Date takePartInTime;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否参加")
private boolean isTakePartIn;
@Column
@ColDefine(type = ColType.INT)
@Comment("审核状态")
private Integer stateId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("本人分工会审核Id")
private String selfUnionAuditId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("床位信息id")
private String bedInfoId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("参加的线路分工会审核Id")
private String joinLineUnionAuditId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 18)
@Comment("身份证号")
private String idCard;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("手机号")
private String mobile;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否正常(true正常 false该报名记录已被管理员废弃)")
private boolean isNormal;
/**
* 同伴信息
*/
@Many(field = "trreId")
private List<TheRapyRecuperationEnrollCompanion> companionList;
/**
* 酒店信息
*/
@One(field = "takePartInBaseManagementId")
private TheRapyRecuperationBaseManagement managementInfo;
/**
* 线路信息
*/
// @One(field = "takePartInLineId")
private TheRapyRecuperationLine lineInfo;
private String lineId;
/**
* 床位信息
*/
@One(field = "bedInfoId")
private TheRapyRecuperationEnrollBed bedInfo;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("对旅行社的评价(几星)")
private String evaluationForTravelAgency;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("对线路的评价(几星)")
private String evaluationForLine;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("对旅途的评价(几星)")
private String evaluationForJourney;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("反馈内容")
private String feedbackContent;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("标段时间")
private String lotId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("校工会审核Id")
private String schoolUnionAuditId;
@Column
@ColDefine(type = ColType.INT)
@Comment("家属数量")
private Integer familyNumber;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否报销")
private Boolean isReimbursement;
private String firstLetter;
}
@@ -0,0 +1,48 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollBed
* @Description: 报名拼床信息
* @Author zxc
* @Date 2022/6/2:14:44
* @Version V1.0
**/
@EqualsAndHashCode(callSuper = true)
@Data
@Table("inclusive_therapy_v3_enroll_bed")
@Accessors(chain = true)
public class TheRapyRecuperationEnrollBed extends LegacyBaseModel {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("床型")
private String bedType;
@Column
@ColDefine(type = ColType.INT)
@Comment("床位数")
private Integer bedNum;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("一起睡吗 搞基")
private boolean isSleepTogether;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("意向拼房人")
private String otherSleepUser;
}
@@ -0,0 +1,37 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollChangeRecord
* @Description: 疗休养登记变更记录表
* @Author zxc
* @Date 2022/5/31:17:10
* @Version V1.0
**/
@Data
@Table("inclusive_therapy_v3_enroll_change_record")
@Accessors(chain = true)
public class TheRapyRecuperationEnrollChangeRecord {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("变更记录id")
private String enrollId;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("变更时间")
private Date changeTime;
}
@@ -0,0 +1,79 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollFamily
* @Description: TODO
* @Author zxc
* @Date 2022/5/31:17:07
* @Version V1.0
**/
@EqualsAndHashCode(callSuper = true)
@Data
@Table("inclusive_therapy_v3_enroll_companion")
@Accessors(chain = true)
public class TheRapyRecuperationEnrollCompanion extends LegacyBaseModel {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("报名记录表Id")
private String trreId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("工号")
private String loginName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("姓名")
private String userName;
@Column
@ColDefine(type = ColType.CHAR, width = 1)
@Comment("性别")
private String sex;
@Column
@ColDefine(type = ColType.INT)
@Comment("年龄")
private Integer age;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("关系")
private String relation;
@Column
@ColDefine(type = ColType.VARCHAR, width = 18)
@Comment("身份证号")
private String idCard;
@Column
@ColDefine(type = ColType.VARCHAR, width = 18)
@Comment("手机号")
private String mobile;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("床位信息id")
private String bedInfoId;
/**
* 床位信息
*/
@One(field = "bedInfoId")
private TheRapyRecuperationEnrollBed bedInfo;
}
@@ -0,0 +1,160 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel;
import com.budwk.app.sys.models.Sys_file;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
import java.util.List;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine
* @Description: 疗休养线路管理
* @Author zxc
* @Date 2022/5/31:09:13
* @Version V1.0
**/
@EqualsAndHashCode(callSuper = true)
@Data
@Table("inclusive_therapy_v3_line")
@Accessors(chain = true)
public class TheRapyRecuperationLine extends LegacyBaseModel {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.INT)
@Comment("编号")
private Integer serialNumber;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("线路名称")
private String lineName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("旅行社Id")
private String travelAgencyId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("区域性质")
private String regionalNature;
@Column
@ColDefine(type = ColType.INT)
@Comment("游玩天数")
private Integer playNumberOfDays;
@Column
@ColDefine(customType = "text")
@Comment("疗休养内容")
private String content;
@Column
@ColDefine(type = ColType.INT)
@Comment("最少参与教工")
private Integer minimumGroupSize;
@Column
@ColDefine(type = ColType.INT)
@Comment("年度")
private Integer year;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否禁用")
private boolean isDisabled;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("哪个分工会创建的")
private String createUnionId;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名开始时间")
private Date signUpStartTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名截至时间")
private Date signUpEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("变更截至时间")
private Date changeEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("游玩开始时间")
private Date playStartTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("游玩结束时间")
private Date playEndTime;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("交通工具")
private String trafficTools;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("预计费用")
private String estimatedCost;
@Column
@ColDefine(type = ColType.INT)
@Comment("成团人数包括家属")
private Integer estimatedFamilyNumbers;
@Column
@ColDefine(type = ColType.VARCHAR, width = 1000)
@Comment("缩略图")
private String files;
@Column
@ColDefine(type = ColType.INT)
@Comment("报名模式(1.分工会 2.自由)")
private Integer signUpMode;
@Column
@ColDefine(type = ColType.INT)
@Comment("创建模式(1.分工会 2.校工会)")
private int createMode;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("标段")
private String lotId;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("联系人")
private String lineContact;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("联系电话")
private String lineContactPhone;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否家属报名")
private Boolean isFamilySignUp;
@One(field = "travelAgencyId")
private TheRapyRecuperationTravelAgency travelAgency;
}
@@ -0,0 +1,158 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
/**
* 疗休养线工会选择
*
* @author jug
* @date 2023/06/26
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Table("inclusive_therapy_v3_line_union_select")
@Accessors(chain = true)
public class TheRapyRecuperationLineUnionSelect extends LegacyBaseModel {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("分工会id")
private String unionId;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("线路id")
private String lineId;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("选择时间")
private Date selectTime;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("选择用户")
private String selectUserId;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名开始时间")
private Date signUpStartTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("报名截至时间")
private Date signUpEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("变更截至时间")
private Date changeEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("调剂报名截止时间")
private Date adjustSignUpEndTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("游玩开始时间")
private Date playStartTime;
@Column
@ColDefine(type = ColType.DATETIME)
@Comment("游玩结束时间")
private Date playEndTime;
/**
* 线路信息
*/
@One(field = "lineId")
private TheRapyRecuperationLine lineInfo;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("联系人")
private String contact;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("联系电话")
private String contactPhone;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("负责人")
private String principal;
@Column
@ColDefine(type = ColType.VARCHAR)
@Comment("联系方式")
private String principalContact;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否公开")
private Boolean isOpen;
@Column
@ColDefine(type = ColType.INT)
@Comment("最少参与教工")
private Integer minimumGroupSize;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("交通工具")
private String trafficTools;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("预计费用")
private String estimatedCost;
@Column
@ColDefine(type = ColType.INT)
@Comment("成团人数包括家属")
private Integer estimatedFamilyNumbers;
@Column
@ColDefine(type = ColType.INT)
@Comment("最多人数")
private Integer maxPeopleNumber;
@Column
@ColDefine(type = ColType.INT)
@Comment("报名模式、组织形式(1.分工会 2.校工会)")
private Integer signUpMode;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否启用")
private Boolean enable;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("旅行社id")
private String travelAgencyId;
/**
* 页面提交的选择线路模式,仅用于接收请求参数,不持久化到数据库。
* 1 表示分工会选择线路,2 表示校工会选择线路。
*/
private Integer mode;
}
@@ -0,0 +1,47 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot
* @Description: TODO
* @Author zzr
* @Date 2023/6/6
* @Version V1.0
**/
@Table("inclusive_therapy_v3_lot")
@Data
@Accessors(chain = true)
public class TheRapyRecuperationLot {
@Name
@Comment("id")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("标段")
private String lotName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("标段值")
private String lotValue;
@Column
@ColDefine(type = ColType.VARCHAR, width = 10)
@Comment("费用")
private Integer activityCost;
@Column
@ColDefine(type = ColType.VARCHAR, width = 32)
@Comment("配置ID")
private String configId;
}
@@ -0,0 +1,94 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel;
import com.budwk.app.sys.models.Sys_file;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.List;
/**
* @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency
* @Description: 疗休养旅行社管理
* @Author zxc
* @Date 2022/5/31:14:39
* @Version V1.0
**/
@EqualsAndHashCode(callSuper = true)
@Data
@Table("inclusive_therapy_v3_travel_agency")
@Accessors(chain = true)
public class TheRapyRecuperationTravelAgency extends LegacyBaseModel {
@Name
@Comment("id")
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("旅行社编号")
private String serialNumber;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("旅行社名称")
private String travelAgencyName;
@Column
@ColDefine(type = ColType.VARCHAR, width = 20)
@Comment("旅行社联系人")
private String contact;
@Column
@ColDefine(type = ColType.VARCHAR, width = 11)
@Comment("旅行社联系人手机")
private String contactMobileNumber;
@Column
@ColDefine(type = ColType.VARCHAR, width = 50)
@Comment("旅行社邮箱")
private String email;
/**
* 旅行社最多承担出行人数,移动端线路报名时按该旅行社承担的所有线路合并校验。
*/
@Column
@ColDefine(type = ColType.INT)
@Comment("最多承担人数")
private Integer maxUndertakeNumber;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("旅行社官网")
private String officialWebsite;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("备注")
private String note;
@Column
@ColDefine(type = ColType.INT)
@Comment("年度")
private Integer year;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否禁用")
private boolean isDisabled;
@Column
@ColDefine(type = ColType.VARCHAR, width = 100)
@Comment("缩略图")
private String files;
@Column
@ColDefine(type = ColType.BOOLEAN)
@Comment("是否自由组团")
private Boolean signUpTravelAgency;
}
@@ -0,0 +1,105 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 管理员查看分工会已选择线路的出行时间段。
*/
@Data
@Accessors(chain = true)
public class LineSelectionOverviewTimeSlotVo {
/**
* 分工会选择线路记录 ID。
*/
private String id;
/**
* 报名开始时间。
*/
private Date signUpStartTime;
/**
* 报名结束时间。
*/
private Date signUpEndTime;
/**
* 变更截止时间。
*/
private Date changeEndTime;
/**
* 调剂报名截止时间。
*/
private Date adjustSignUpEndTime;
/**
* 出行开始时间。
*/
private Date playStartTime;
/**
* 出行结束时间。
*/
private Date playEndTime;
/**
* 旅行社名称。
*/
private String travelAgencyName;
/**
* 旅行社 ID。
*/
private String travelAgencyId;
/**
* 联系人。
*/
private String contact;
/**
* 联系电话。
*/
private String contactPhone;
/**
* 联络人。
*/
private String principal;
/**
* 联络人联系方式。
*/
private String principalContact;
/**
* 交通工具。
*/
private String trafficTools;
/**
* 预计费用。
*/
private String estimatedCost;
/**
* 最少成团人数,包含家属。
*/
private Integer estimatedFamilyNumbers;
/**
* 最多人数,为 0 时不限制。
*/
private Integer maxPeopleNumber;
/**
* 是否启用。
*/
private Boolean enable;
}
@@ -0,0 +1,87 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 管理员查看分工会已选择线路列表。
*/
@Data
@Accessors(chain = true)
public class LineSelectionOverviewVo {
/**
* 线路 ID,对应 inclusive_therapy_v3_line.id。
*/
private String lineId;
/**
* 分工会选择线路记录 ID,用于定位该线路已选择状态。
*/
private String lineUnionSelectId;
/**
* 当前列表行对应的分工会选择线路记录 ID,保留该字段用于兼容前端提交参数。
*/
private String lineUnionSelectIds;
/**
* 年度。
*/
private Integer year;
/**
* 线路序号。
*/
private Integer serialNumber;
/**
* 线路名称。
*/
private String lineName;
/**
* 线路类型,例如省内、省外。
*/
private String regionalNature;
/**
* 时间标段名称。
*/
private String lotName;
/**
* 出行时间段,多个时间段用逗号连接。
*/
private String playTimes;
/**
* 报名时间段,多个时间段用逗号连接。
*/
private String signUpTimes;
/**
* 调剂报名截止时间。
*/
private String adjustSignUpEndTime;
/**
* 组织形式,1 表示分工会,2 表示校工会。
*/
private Integer signUpMode;
/**
* 选择线路的分工会 ID。
*/
private String unionId;
/**
* 选择线路的分工会名称。
*/
private String unionName;
/**
* 是否开放对外报名。
*/
private Boolean isOpen;
}
@@ -0,0 +1,42 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 旅行社月度报名数量统计。
*/
@Data
@Accessors(chain = true)
public class TravelAgencyMonthlyEnrollStatisticsVo {
/**
* 旅行社 ID,对应 inclusive_therapy_v3_travel_agency.id。
*/
private String travelAgencyId;
/**
* 旅行社名称,用于图表分组展示。
*/
private String travelAgencyName;
/**
* 统计年度。
*/
private Integer year;
/**
* 月份数字,取值范围 1-12。
*/
private Integer month;
/**
* 月份展示名称,例如 1月、2月。
*/
private String monthName;
/**
* 当前旅行社在该月份的有效报名数量。
*/
private Integer enrollNumber;
}
@@ -0,0 +1,42 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 二级工会疗休养出行人数统计。
*/
@Data
@Accessors(chain = true)
public class UnionEnrollStatisticsVo {
/**
* 二级工会 ID,对应报名人的本人分工会 selfUnionId。
*/
private String unionId;
/**
* 二级工会名称,用于图表横轴展示。
*/
private String unionName;
/**
* 统计年度。
*/
private Integer year;
/**
* 月份数字,取值范围 1-12。
*/
private Integer month;
/**
* 月份展示名称,例如 1月、2月。
*/
private String monthName;
/**
* 当前二级工会在该月份的有效报名人数。
*/
private Integer enrollNumber;
}
@@ -0,0 +1,47 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 分工会线路数量配置与当前年度选择数量统计。
*/
@Data
@Accessors(chain = true)
public class UnionLineNumberStatisticsVo {
/**
* 分工会 ID,对应 sys_union.id。
*/
private String unionId;
/**
* 分工会名称,对应 sys_union.unionname。
*/
private String unionName;
/**
* 基础设置中配置的最低省外线路数量。
*/
private Integer provinceOutNumber;
/**
* 基础设置中配置的最低省内线路数量。
*/
private Integer provinceInNumber;
/**
* 当前年度该分工会已选择的省外线路数量。
*/
private Integer selectedProvinceOutNumber;
/**
* 当前年度该分工会已选择的省内线路数量。
*/
private Integer selectedProvinceInNumber;
/**
* 是否同时满足省外、省内最低选择数量要求。
*/
private Boolean finished;
}
@@ -0,0 +1,32 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 分工会选择线路数量提示信息。
*/
@Data
@Accessors(chain = true)
public class UnionLineSelectLimitVo {
/**
* 当前登录人所属分工会在基础设置中配置的最少省外线路选择数量。
*/
private Integer minProvinceOutNumber;
/**
* 当前登录人所属分工会在基础设置中配置的最少省内线路选择数量。
*/
private Integer minProvinceInNumber;
/**
* 当前登录人所属分工会本年度已选择的省外线路数量。
*/
private Integer selectedProvinceOutNumber;
/**
* 当前登录人所属分工会本年度已选择的省内线路数量。
*/
private Integer selectedProvinceInNumber;
}
@@ -0,0 +1,40 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import org.nutz.lang.util.NutMap;
import java.util.List;
public interface TheRapyRecuperationAuditService extends TherapyService<TherapyAudit> {
/**
* 根据分工会查询线路
*
* @param
* @param unionId
* @param regionalNature 是否省内省外 可为空
* @param year 可为空
* @return
*/
List<NutMap> getXlByUnion(Integer state, String unionId, String regionalNature, String year,String endYear, Integer signUpMode, String agencyId);
/**
*
* @param id
* @return
*/
NutMap findOne(String id);
/**
* 校工会审核
* @param stateId
* @param loginName
* @param adjustment
* @param takePartInLineId
*/
void schoolAudit(Integer stateId, String loginName,Boolean adjustment, String takePartInLineId);
}
@@ -0,0 +1,17 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType;
public interface TheRapyRecuperationCommonService extends TherapyService {
/**
* 可以报名吗
*
* @param loginName 用户名
* @return boolean
*/
boolean canSignUp(String loginName, TheRapyRecuperationType theRapyRecuperationType);
}
@@ -0,0 +1,15 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Map;
public interface TheRapyRecuperationEnrollJoinUserImportService extends TherapyService {
List<?> selectLineAndTravelAgencyList(Integer year, String keyword);
Map<String, List<NutMap>> selectLineOrTravelAgency(Integer year);
}
@@ -0,0 +1,229 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUnion;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.TravelAgencyMonthlyEnrollStatisticsVo;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionEnrollStatisticsVo;
import org.nutz.dao.Cnd;
import org.nutz.lang.util.NutMap;
import java.util.List;
import java.util.Map;
/**
* 疗休养报名service
*
* @author jug
* @date 2022/06/01
*/
public interface TheRapyRecuperationEnrollService extends TherapyService<TheRapyRecuperationEnroll> {
/**
* 报名页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @param unionId 工会 ID
* @param trrt 疗休养线路类型
* @param lineUnionType 线路筛选类型,1 本分工会、2 其他分工会、3 校工会、4 全部
* @param lineKeyword 移动端线路名称搜索关键字
* @param signUpStatus 报名状态筛选,0 全部、1 报名中、2 报名已结束
* @return {@link Pagination}
*/
Pagination enrollPageData(PageForm pageForm, Integer year, String unionId, int trrt, Integer lineUnionType, String lineKeyword, Integer signUpStatus);
List<NutMap> getSelectLineById(String lineId, String usId, String unionId, int trrt, Integer lineUnionType, Integer signUpStatus);
Object openSignUser(String usId, String travelId, String searchKeyWord);
/**
* 线路报名
*
* @param enrollInfo 登记信息
*/
void doSignUpForLine(TheRapyRecuperationEnroll enrollInfo);
/**
* 校工会代选线路报名。
*
* @param enrollInfo 包含被报名人工号和线路选择表id的报名信息
*/
void doProxySignUpForLine(TheRapyRecuperationEnroll enrollInfo);
/**
* 变更报名
*
* @param enrollInfo 登记信息
*/
void updateSignUpLine(TheRapyRecuperationEnroll enrollInfo);
/**
* 报名旅行社
*
* @param enrollInfo 登记信息
*/
void doSignUpForTravelAgency(TheRapyRecuperationEnroll enrollInfo);
/**
* 报名酒店
*
* @param enrollInfo 登记信息
*/
void doSignUpForHotel(TheRapyRecuperationEnroll enrollInfo);
void updateSignUpHotel(TheRapyRecuperationEnroll enrollInfo);
/**
* 变更报名旅行社
*
* @param enrollInfo 登记信息
*/
void updateSignUpTravelAgency(TheRapyRecuperationEnroll enrollInfo);
/**
* 验证报名登记信息
*
* @param enrollInfo 登记信息
* @param loginName 用户名
* @return {@link Map}<{@link Boolean}, {@link String}>
*/
Map<Boolean, String> validSignUpInfo(String loginName, TheRapyRecuperationEnroll enrollInfo);
Map<Boolean, String> validSignUpInfoForZJXU(String loginName, TheRapyRecuperationEnroll enrollInfo);
Map<Boolean, String> validSignUpInfoForZJNU(String loginName, TheRapyRecuperationEnroll enrollInfo);
/**
* 校工会代选线路报名校验,不校验旅行社最多承担人数。
*
* @param loginName 被报名人工号
* @param enrollInfo 报名信息
* @return {@link Map}<{@link Boolean}, {@link String}>
*/
Map<Boolean, String> validProxySignUpInfoForLine(String loginName, TheRapyRecuperationEnroll enrollInfo);
/**
* 校工会代选线路人员搜索。
*
* @param keyword 姓名或工号关键字
* @return 人员下拉列表
*/
List<NutMap> searchProxySignUpUsers(String keyword);
/**
* 校工会代选线路查询,返回校工会和分工会已选择的线路时间段。
*
* @param year 主页面选择年份
* @return 线路时间段下拉列表
*/
List<NutMap> getProxySignUpLines(Integer year);
/**
* 补发指定年度已标记删除的未成团通知。
*
* @param year 报名年度,按 signingUptime 所在年份筛选
* @return 实际触发消息发送的报名记录数量
*/
int resendDeletedFailNotice(Integer year);
/**
* 手动发送所选线路的成团邮件给旅行社。
*
* @param lineUnionSelectIds 统计页勾选的线路选择记录 ID,对应 inclusive_therapy_v3_line_union_select.id
* @return 实际发送邮件的旅行社数量
*/
int sendTakePartInUserByLineMail(List<String> lineUnionSelectIds);
/**
* 校验线路指定旅行社最多承担人数。
*
* @param enrollInfo 报名信息
* @return {@link Map}<{@link Boolean}, {@link String}>
*/
Map<Boolean, String> validTravelAgencyMaxUndertakeNumber(TheRapyRecuperationEnroll enrollInfo);
/**
* 我报名的页面数据
*
* @param pageForm 分页参数
* @param cnd cnd
* @return {@link Pagination}
*/
Pagination mySignUpPageData(PageForm pageForm, Cnd cnd, int trrt, Integer year);
/**
* 找到报名信息通过id
*
* @param id id
* @return {@link TheRapyRecuperationEnroll}
*/
TheRapyRecuperationEnroll findSignUpInfoById(String id);
/**
* 删除我的报名信息
*
* @param id id
*/
void deleteMyEnrollInfoById(String id);
/**
* 校验我的疗休养报名是否允许取消。
*
* @param id 报名记录id
* @return 为空表示允许取消;非空表示不允许取消的提示文案
*/
String validateCanDeleteMyEnrollInfo(String id);
/**
* 手机端线路介绍所有信息
*
* @param usId usId
* @param usUnionId usUnionId
* @return {@link NutMap}
*/
NutMap selectLineAllInfo(String usId, String usUnionId, String year);
List<TherapyUnion> getTheRapyUnions(Integer year, int theRapyRecuperationType);
/**
* 按旅行社统计指定年度每个月的有效报名数量。
*
* @param year 统计年度,为空时使用当前年度
* @return 旅行社月度报名数量 VO 列表,只返回有报名数据的月份
*/
List<TravelAgencyMonthlyEnrollStatisticsVo> getTravelAgencyMonthlyEnrollStatistics(Integer year);
/**
* 构建旅行社月度统计导出数据。
* 参数 year 为统计年度;返回 NutMap,其中 months 为有数据的月份数字列表,rows 为按旅行社横向展开后的导出行。
*
* @param year 统计年度,为空时使用当前年度
* @return 导出数据,包含动态月份列和行数据
*/
NutMap getTravelAgencyMonthlyEnrollExportData(Integer year);
/**
* 按报名人本人二级工会和报名月份统计指定年度有效报名人数。
*
* @param year 统计年度,为空时使用当前年度
* @return 二级工会月度出行人数 VO 列表,只返回有报名数据的月份
*/
List<UnionEnrollStatisticsVo> getUnionEnrollStatistics(Integer year);
/**
* 构建二级工会月度出行人数导出数据。
* 参数 year 为统计年度;返回 NutMap,其中 months 为有数据的月份数字列表,rows 为按二级工会横向展开后的导出行。
*
* @param year 统计年度,为空时使用当前年度
* @return 导出数据,包含动态月份列和行数据
*/
NutMap getUnionEnrollExportData(Integer year);
}
@@ -0,0 +1,16 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import java.util.List;
public interface TheRapyRecuperationLineAdjustmentService extends TherapyService {
Pagination pageData(PageForm pageForm, Integer year, String lineId, String unionId, String keywords, String regionalNature, String lotId);
List findUnionSignUpModeUserList(String lineId, String unionId);
}
@@ -0,0 +1,40 @@
package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService;
import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster;
import java.util.List;
public interface TheRapyRecuperationLineClusterService extends TherapyService<TheRapyRecuperationCluster> {
/**
* 页面数据
*
* @param pageForm 分页参数
* @param year 年度
* @param unionId 工会id
* @param keywords 关键字
* @return {@link Pagination}
*/
Pagination pageData(PageForm pageForm, Integer year, String unionId, String keywords);
/**
* 查询组团信息
*
* @param lineId 线路id
* @param lineId 归属工会id
* @return {@link Object}
*/
Object findClusterInfo(String lineId, String usUnionId);
/**
* 设置组团成员
*
* @param clusters 集群
* @param lineId 行id
*/
void setClusterMembers(List<TheRapyRecuperationCluster> clusters, String lineId);
}

Some files were not shown because too many files have changed in this diff Show More