Compare commits
60
Commits
713e174650
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5077d092c | ||
|
|
63fc01cbb3 | ||
|
|
902ad7e0e9 | ||
|
|
651435d568 | ||
|
|
2ee171b4f3 | ||
|
|
a7a7aa5e3a | ||
|
|
336bea15bc | ||
|
|
49237dc2ea | ||
|
|
faafb72eee | ||
|
|
e4e856f6b2 | ||
|
|
933daac134 | ||
|
|
803333feac | ||
|
|
22a18986d0 | ||
|
|
d6e3815b3d | ||
|
|
1ddfa7e609 | ||
|
|
e7fbf4021e | ||
|
|
c21e92e418 | ||
|
|
134a11da09 | ||
|
|
506121ac5f | ||
|
|
8c401a5132 | ||
|
|
4d9fd57d6c | ||
|
|
fd117b4fc3 | ||
|
|
060e8d5bc7 | ||
|
|
894c720bb8 | ||
|
|
39ee74f0a9 | ||
|
|
7faa2730b5 | ||
|
|
fa019786d6 | ||
|
|
ffe782e538 | ||
|
|
3c65c9d561 | ||
|
|
89a77c41af | ||
|
|
f51b24686f | ||
|
|
0f460e6b1a | ||
|
|
d1050db6b3 | ||
|
|
e3f32fe72b | ||
|
|
b885f449c7 | ||
|
|
3f441828a1 | ||
|
|
3f7b5dc27a | ||
|
|
e944ebf85f | ||
|
|
a0732fdb08 | ||
|
|
db26813635 | ||
|
|
d5f1c642c4 | ||
|
|
a09cd7b8fd | ||
|
|
d18d9bda6d | ||
|
|
919f8c9dec | ||
|
|
0fb779ff5a | ||
|
|
55e94de004 | ||
|
|
d452d4ad92 | ||
|
|
6ea864cb64 | ||
|
|
56cc3fee91 | ||
|
|
4c03b389d4 | ||
|
|
fcb6ba7e2d | ||
|
|
65fac78cfb | ||
|
|
2d20959355 | ||
|
|
1a1946b1f8 | ||
|
|
7f2ac97dea | ||
|
|
82713327db | ||
|
|
d598f1bf0f | ||
|
|
01e2443db8 | ||
|
|
bb4c44443d | ||
|
|
15d3ec0ddd |
@@ -49,3 +49,8 @@ Thumbs.db
|
||||
.trae/pr-creator/SKILL.md
|
||||
.trae/update-docs/SKILL.md
|
||||
.trae/webapp-testing/SKILL.md
|
||||
outputs
|
||||
|
||||
semgrep.json
|
||||
trivy.json
|
||||
.workbuddy
|
||||
@@ -5,6 +5,7 @@ import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import com.budwk.app.base.utils.AppIocUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.sys.services.SysTaskService;
|
||||
import com.budwk.app.task.log.TaskExecutionListener;
|
||||
import com.budwk.app.task.services.TaskPlatformService;
|
||||
import com.budwk.app.web.commons.auth.satoken.SaTokenContextImpl;
|
||||
import com.budwk.app.web.commons.auth.satoken.SaTokenDaoRedisImpl;
|
||||
@@ -20,7 +21,6 @@ import org.beetl.core.GroupTemplate;
|
||||
import org.nutz.boot.NbApp;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.impl.FileSqlManager;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.Daos;
|
||||
import org.nutz.integration.jedis.JedisAgent;
|
||||
import org.nutz.ioc.Ioc;
|
||||
@@ -31,6 +31,7 @@ import org.nutz.lang.Mirror;
|
||||
import org.nutz.mvc.Mvcs;
|
||||
import org.nutz.mvc.annotation.*;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
@@ -39,7 +40,6 @@ import java.lang.management.ManagementFactory;
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean(create = "init", depose = "depose")
|
||||
@Localization(value = "locales/", defaultLocalizationKey = "zh_CN")
|
||||
@@ -82,7 +82,9 @@ public class MainLauncher {
|
||||
Mvcs.DISABLE_X_POWERED_BY = true;
|
||||
Globals.AppBase = Mvcs.getServletContext().getContextPath();
|
||||
Globals.AppRoot = Mvcs.getServletContext().getRealPath("/");
|
||||
init_task();
|
||||
init_sys();
|
||||
ioc.get(com.budwk.app.zhgh.staffbenefit.therapyRecuperation.TherapyRecuperationModule.class);
|
||||
// 2026年10月3日 12:01:28;操作人:wxg:先升级会员表及补齐历史资料,再处理缴费快照和启动计划任务;不依赖 DEBUG。
|
||||
SysClubUserService members = ioc.get(SysClubUserService.class, "sysClubUserServiceImpl");
|
||||
members.upgradeMemberSchema();
|
||||
@@ -92,7 +94,6 @@ public class MainLauncher {
|
||||
ClubPayRecordService payRecords = ioc.get(ClubPayRecordService.class, "clubPayRecordServiceImpl");
|
||||
payRecords.upgradePayRecordSchema();
|
||||
payRecords.backfillPayRecordSnapshots();
|
||||
init_task();
|
||||
init_auth();
|
||||
ioc.get(Globals.class);
|
||||
ioc.get(FlowEngine.class);
|
||||
@@ -115,17 +116,17 @@ public class MainLauncher {
|
||||
}
|
||||
|
||||
private void init_task() {
|
||||
if (log.isDebugEnabled() && !dao.exists("sys_qrtz_triggers") && !dao.exists("sys_qrtz_triggers".toUpperCase())) {
|
||||
//执行Quartz SQL脚本
|
||||
String dbType = dao.getJdbcExpert().getDatabaseType();
|
||||
log.debug("dbType:::" + dbType);
|
||||
FileSqlManager fmq = new FileSqlManager("db/quartz/" + dbType.toLowerCase() + ".sql");
|
||||
List<Sql> sqlListq = fmq.createCombo(fmq.keys());
|
||||
Sql[] sqlsq = sqlListq.toArray(new Sql[sqlListq.size()]);
|
||||
for (Sql sql : sqlsq) {
|
||||
dao.execute(sql);
|
||||
FileSqlManager schema = new FileSqlManager("db/quartz/mysql.sql");
|
||||
for (String table : schema.keys()) {
|
||||
if (!dao.exists(table)) {
|
||||
dao.execute(schema.create(table));
|
||||
}
|
||||
}
|
||||
try {
|
||||
ioc.get(TaskExecutionListener.class).register();
|
||||
} catch (SchedulerException e) {
|
||||
throw new IllegalStateException("注册任务执行记录监听器失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void init_sys() {
|
||||
|
||||
@@ -29,13 +29,13 @@ public enum BpmProcessConstant {
|
||||
|
||||
MEMBER_BRANCH_UNION_CHANGE("会员分工会变更"),
|
||||
|
||||
CLUB_JOIN("社团入会申请"),
|
||||
CLUB_JOIN("协会入会申请"),
|
||||
|
||||
CLUB_EXAMINE("社团考核"),
|
||||
CLUB_EXAMINE("协会考核"),
|
||||
|
||||
CLUB_EVALUATE("社团评优"),
|
||||
CLUB_EVALUATE("协会评优"),
|
||||
|
||||
CLUB_REGISTER("社团注册"),
|
||||
CLUB_REGISTER("协会注册"),
|
||||
|
||||
PERSON_EVALUATE("评优评先申请"),
|
||||
|
||||
|
||||
@@ -20,16 +20,17 @@ RoleConstant {
|
||||
SCHOOL_UNION_CHAIRMAN("校工会主席"),
|
||||
SCHOOL_UNION_VICE_CHAIRMAN("校工会副主席"),
|
||||
SCHOOL_UNION_WELFARE_ADMIN("校工会福利管理员"),
|
||||
SCHOOL_UNION_WELFARE_COMMITTEE("校福利委员会"),
|
||||
SCHOOL_UNION_MEMBER_ADMIN("校工会会员管理员"),
|
||||
SCHOOL_UNION_TC_ADMIN("校工会教代会管理员"),
|
||||
SCHOOL_UNION_WC_ADMIN("校工会工代会管理员"),
|
||||
SCHOOL_UNION_DC_ADMIN("校工会民主管理员"),
|
||||
SCHOOL_UNION_PROPOSAL_ADMIN("校工会提案管理员"),
|
||||
SCHOOL_UNION_CLUB_ADMIN("校工会社团管理员"),
|
||||
SCHOOL_UNION_CLUB_ADMIN("校工会协会管理员"),
|
||||
SCHOOL_UNION_ACTIVITY_ADMIN("校工会活动管理员"),
|
||||
/** 品牌活动统计、人员调整管理员,数据范围按 trainSignUp 子活动负责人关系控制。 */
|
||||
SCHOOL_UNION_TRAIN_SIGN_UP_ADMIN("校工会品牌活动管理员"),
|
||||
SCHOOL_UNION_ARTICLE_CLUB_ADMIN("校工会社团新闻审批管理员"),
|
||||
SCHOOL_UNION_ARTICLE_CLUB_ADMIN("校工会协会新闻审批管理员"),
|
||||
SCHOOL_UNION_ARTICLE_FGH_ADMIN("校工会分工会新闻审批管理员"),
|
||||
SCHOOL_UNION_ARTICLE_ADMIN("校工会新闻审批管理员"),
|
||||
SCHOOL_OUTLAY_ADMIN("校工会经费管理员"),
|
||||
@@ -50,6 +51,11 @@ RoleConstant {
|
||||
BRANCH_UNION_SHENGGHUO_WY("分工会生活委员"),
|
||||
BRANCH_UNION_TIAOJIE_WY("分工会调解委员"),
|
||||
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("单位党委书记"),
|
||||
|
||||
@@ -80,16 +86,16 @@ RoleConstant {
|
||||
|
||||
SCHOOL_HOSPITAL_LEADER("校医院负责人"),
|
||||
|
||||
/*社团模块*/
|
||||
CLUB_MEMBER("社团会员"),
|
||||
CLUB_MANAGER("社团负责人"),
|
||||
CLUB_PRESIDENT("社团会长"),
|
||||
CLUB_VICE_PRESIDENT("社团副会长"),
|
||||
CLUB_SECRETARY("社团秘书长"),
|
||||
CLUB_VICE_SECRETARY("社团副秘书长"),
|
||||
// SCHOOL_UNION_CLUB_ADMIN("校工会社团管理员"),
|
||||
CLUB_AUDIT_LEADER("社团分管领导"),
|
||||
CLUB_OPERATOR("社团操作员"),
|
||||
/*协会模块*/
|
||||
CLUB_MEMBER("协会会员"),
|
||||
CLUB_MANAGER("协会负责人"),
|
||||
CLUB_PRESIDENT("协会会长"),
|
||||
CLUB_VICE_PRESIDENT("协会副会长"),
|
||||
CLUB_SECRETARY("协会秘书长"),
|
||||
CLUB_VICE_SECRETARY("协会副秘书长"),
|
||||
// SCHOOL_UNION_CLUB_ADMIN("校工会协会管理员"),
|
||||
CLUB_AUDIT_LEADER("协会分管领导"),
|
||||
CLUB_OPERATOR("协会操作员"),
|
||||
|
||||
/*大病基金会员*/
|
||||
AID_FUND_MEMBER("大病基金会员"),
|
||||
@@ -105,7 +111,7 @@ RoleConstant {
|
||||
LEGAL_DOCTOR("法律顾问"),
|
||||
|
||||
UNION_REIMBURSEMENT_MANAGER("分工会报销负责人"),
|
||||
CLUB_REIMBURSEMENT_MANAGER("社团报销负责人"),
|
||||
CLUB_REIMBURSEMENT_MANAGER("协会报销负责人"),
|
||||
SCHOOL_REIMBURSEMENT_MANAGER("校工会报销负责人"),
|
||||
|
||||
;
|
||||
|
||||
+54
@@ -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;
|
||||
}
|
||||
}
|
||||
+54
@@ -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;
|
||||
}
|
||||
}
|
||||
+54
@@ -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;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -22,7 +22,7 @@ import org.nutz.lang.util.NutMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 获取社团审批人根据流程变量参数(clubId) 必传
|
||||
* 获取协会审批人根据流程变量参数(clubId) 必传
|
||||
*/
|
||||
public class FlowClubPresidentByArgsAssignmentHandler implements AssignmentHandler {
|
||||
@Override
|
||||
@@ -45,7 +45,7 @@ public class FlowClubPresidentByArgsAssignmentHandler implements AssignmentHandl
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "获取社团会长(根据args中的clubId)";
|
||||
return "获取协会会长(根据args中的clubId)";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
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.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 org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FlowSchoolUnionWelfareCommitteeHandler 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.SCHOOL_UNION_WELFARE_COMMITTEE);
|
||||
if (role == null || role.isDisabled()) {
|
||||
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::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;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
@@ -47,10 +48,10 @@ public class SysDataUserPullController {
|
||||
cnd.andEX(Sys_user_source::getPullTime, "=", pageForm.getPullTime());
|
||||
cnd.and(Cnd.likeEX(Sys_user_source::getUsername, pageForm.getUserName()));
|
||||
cnd.and(Cnd.likeEX(Sys_user_source::getLoginname, pageForm.getLoginName()));
|
||||
cnd.andEX(Sys_user_source::getUnitName, "=", pageForm.getUnitName());
|
||||
cnd.andEX(Sys_user_source::getUserState, "=", pageForm.getUserState());
|
||||
addSourceFilter(cnd, "us.unitName", pageForm.getUnitName());
|
||||
addSourceFilter(cnd, "us.userState", pageForm.getUserState());
|
||||
cnd.andEX(Sys_user_source::getPreparedBy, "=", pageForm.getPreparedBy());
|
||||
cnd.andEX(Sys_user_source::getPersonType, "=", pageForm.getPersonType());
|
||||
addSourceFilter(cnd, "us.personType", pageForm.getPersonType());
|
||||
|
||||
if (StrUtil.isAllNotBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
@@ -61,6 +62,15 @@ public class SysDataUserPullController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
private void addSourceFilter(Cnd cnd, String column, String value) {
|
||||
if ("__EMPTY__".equals(value)) {
|
||||
cnd.and(new Static("(%s IS NULL OR LOWER(%s) REGEXP '^[[:space:]]*(null)?[[:space:]]*$')"
|
||||
.formatted(column, column)));
|
||||
} else {
|
||||
cnd.andEX(column, "=", value);
|
||||
}
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.data.user.pull")
|
||||
@ApiOperation("拉取用户数据")
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.budwk.app.sys.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.sys.services.SysDataUserPullService;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/sys/data/user/query")
|
||||
@Ok("json:full")
|
||||
public class SysDataUserQueryController {
|
||||
|
||||
@Inject
|
||||
private SysDataUserPullService sysUserPullService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/sys/data/user/query.html")
|
||||
@SaCheckPermission("sys.data.user.query")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("sys.data.user.query")
|
||||
public Result queryData(@Param("zgh") String zgh, @Param("xm") String xm,
|
||||
@Param("pageNumber") int pageNumber, @Param("pageSize") int pageSize) {
|
||||
return Result.success(sysUserPullService.queryUsers(zgh, xm, pageNumber, pageSize));
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,29 @@
|
||||
package com.budwk.app.sys.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.useragent.UserAgent;
|
||||
import cn.hutool.http.useragent.UserAgentUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
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_menu;
|
||||
import com.budwk.app.sys.services.SysHomeActivityService;
|
||||
import com.budwk.app.sys.services.SysHomeNewsService;
|
||||
import com.budwk.app.sys.services.SysMenuService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.dao.Cnd;
|
||||
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.lang.Lang;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
@@ -52,7 +47,7 @@ public class SysHomeController {
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
private ActivityBasicScopeService activityBasicScopeService;
|
||||
private SysHomeActivityService sysHomeActivityService;
|
||||
@Inject
|
||||
private SysHomeNewsService sysHomeNewsService;
|
||||
|
||||
@@ -201,71 +196,16 @@ public class SysHomeController {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* includeEnded可选:true供PC首页展示已结束活动,缺省false保持既有调用行为。
|
||||
* 返回Result,data为当前登录用户可见的活动实体列表,含名称、封面、链接及起止时间,不含内部SQL和类路径。
|
||||
*/
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("首页推送活动")
|
||||
@Ok("json")
|
||||
public Result listHomeActivity() {
|
||||
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"));
|
||||
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);
|
||||
public Result listHomeActivity(@Param(value = "includeEnded", df = "false") boolean includeEnded) {
|
||||
return Result.success(sysHomeActivityService.listHomeActivity(SecurityUtil.getUserId(), includeEnded));
|
||||
}
|
||||
|
||||
@At
|
||||
|
||||
@@ -147,12 +147,9 @@ public class SysLoginController {
|
||||
// 解密密码
|
||||
LoginRsaKey rsaKey = LOGIN_RSA_KEY_RING.getPrivateKey(keyId);
|
||||
if (rsaKey == null) {
|
||||
throw new BaseException("Login key expired, please refresh the login page");
|
||||
throw new BaseException("登录凭证已过期,请刷新登录页面。");
|
||||
}
|
||||
String decryptPwd = RsaUtils.decrypt(password, rsaKey.privateKey);
|
||||
if (decryptPwd == null) {
|
||||
throw new BaseException("用户登录失败");
|
||||
}
|
||||
decryptPwd = Base64Encoder.encode(decryptPwd);
|
||||
|
||||
// 用户名密码校验
|
||||
|
||||
@@ -2,15 +2,18 @@ package com.budwk.app.sys.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
import com.budwk.app.sys.models.Sys_task_execution;
|
||||
import com.budwk.app.sys.services.SysTaskService;
|
||||
import com.budwk.app.task.services.TaskPlatformService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.FieldFilter;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
@@ -18,9 +21,12 @@ import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
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 org.nutz.trans.Trans;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
;
|
||||
|
||||
@@ -32,6 +38,8 @@ public class SysTaskController {
|
||||
private SysTaskService sysTaskService;
|
||||
@Inject
|
||||
private TaskPlatformService taskPlatformService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/sys/task/index.html")
|
||||
@@ -41,10 +49,10 @@ public class SysTaskController {
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("beetl:/platform/sys/task/cron.html")
|
||||
@Ok("beetl:/platform/sys/task/index.html")
|
||||
@SaCheckPermission("sys.manager.task")
|
||||
public void cron() {
|
||||
|
||||
public void cron(HttpServletRequest req) {
|
||||
req.setAttribute("openCron", true);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -52,9 +60,9 @@ public class SysTaskController {
|
||||
@SaCheckPermission("sys.manager.task")
|
||||
public Object cronExp(@Param("cron") String cron) {
|
||||
try {
|
||||
return Result.success().addData(taskPlatformService.getCronExeTimes(cron));
|
||||
return Result.success().addData(previewCron(normalizeCron(cron)));
|
||||
} catch (Exception e) {
|
||||
return Result.error(e.getMessage());
|
||||
return taskError("获取执行时间失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,20 +81,57 @@ public class SysTaskController {
|
||||
}
|
||||
}
|
||||
|
||||
@At("/history/?")
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.task")
|
||||
public Object history(String taskId, @Param("pageNumber") int pageNumber) {
|
||||
try {
|
||||
requireTask(taskId);
|
||||
int page = Math.max(1, Math.min(pageNumber, Integer.MAX_VALUE / 10));
|
||||
Cnd condition = Cnd.where("taskId", "=", taskId);
|
||||
condition.desc("startedAt").desc("id");
|
||||
List<Sys_task_execution> list = dao.query(Sys_task_execution.class, condition, dao.createPager(page, 10),
|
||||
"^(id|taskId|startedAt|finishedAt|status)$");
|
||||
int total = dao.count(Sys_task_execution.class, Cnd.where("taskId", "=", taskId));
|
||||
return Result.success(new Pagination<>(page, 10, total, list));
|
||||
} catch (Exception e) {
|
||||
return taskError("获取执行历史失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@At("/historyLog/?/?")
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.task")
|
||||
public Object historyLog(String taskId, String executionId) {
|
||||
try {
|
||||
requireTask(taskId);
|
||||
Sys_task_execution execution = dao.fetch(Sys_task_execution.class,
|
||||
Cnd.where("id", "=", executionId).and("taskId", "=", taskId));
|
||||
return execution == null ? Result.error("执行记录不存在") : Result.success(execution);
|
||||
} catch (Exception e) {
|
||||
return taskError("获取执行日志失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@At
|
||||
@Ok("json")
|
||||
@SLog(tag = "新建任务", msg = "任务名称:${args[0].name}")
|
||||
@SaCheckPermission("sys.manager.task.add")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Object addDo(@Param("..") Sys_task task, HttpServletRequest req) {
|
||||
try {
|
||||
task.setCron(validateCron(task.getCron()));
|
||||
task.setCreatedBy(SecurityUtil.getUserId());
|
||||
Sys_task sysTask = sysTaskService.insert(task);
|
||||
taskPlatformService.add(sysTask.getId(), sysTask.getId(), sysTask.getJobClass(), sysTask.getCron(),
|
||||
sysTask.getNote(), sysTask.getData());
|
||||
task.setExeAt(null);
|
||||
task.setExeResult(null);
|
||||
Trans.exec(() -> {
|
||||
Sys_task saved = sysTaskService.insert(task);
|
||||
if (!saved.isDisabled()) {
|
||||
schedule(saved);
|
||||
}
|
||||
});
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
return taskError("新建任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,18 +152,24 @@ public class SysTaskController {
|
||||
@SaCheckPermission("sys.manager.task.edit")
|
||||
public Object editDo(@Param("..") Sys_task task, HttpServletRequest req) {
|
||||
try {
|
||||
if (task.getCron() != null) {
|
||||
task.setCron(validateCron(task.getCron()));
|
||||
}
|
||||
task.setUpdatedBy(SecurityUtil.getUserId());
|
||||
sysTaskService.updateIgnoreNull(task);
|
||||
if (taskPlatformService.isExist(task.getId(), task.getId())) {
|
||||
taskPlatformService.delete(task.getId(), task.getId());
|
||||
}
|
||||
if (!task.isDisabled()) {
|
||||
taskPlatformService.add(task.getId(), task.getId(), task.getJobClass(), task.getCron(),
|
||||
task.getNote(), task.getData());
|
||||
}
|
||||
Trans.exec(() -> {
|
||||
requireTask(task.getId());
|
||||
FieldFilter.locked(Sys_task.class, "^(exeAt|exeResult)$")
|
||||
.run(() -> sysTaskService.updateIgnoreNull(task));
|
||||
Sys_task saved = requireTask(task.getId());
|
||||
if (saved.isDisabled()) {
|
||||
taskPlatformService.delete(saved.getId(), saved.getId());
|
||||
} else {
|
||||
schedule(saved);
|
||||
}
|
||||
});
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
return taskError("修改任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,19 +180,35 @@ public class SysTaskController {
|
||||
@SaCheckPermission("sys.manager.task.delete")
|
||||
public Object delete(String id, HttpServletRequest req) {
|
||||
try {
|
||||
Sys_task sysTask = sysTaskService.fetch(id);
|
||||
try {
|
||||
if (taskPlatformService.isExist(sysTask.getId(), sysTask.getId())) {
|
||||
taskPlatformService.delete(sysTask.getId(), sysTask.getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
sysTaskService.delete(id);
|
||||
req.setAttribute("name", sysTask.getName());
|
||||
Trans.exec(() -> {
|
||||
Sys_task task = requireTask(id);
|
||||
sysTaskService.delete(id);
|
||||
taskPlatformService.delete(id, id);
|
||||
req.setAttribute("name", task.getName());
|
||||
});
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
return taskError("删除任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@At("/runOnce/?")
|
||||
@POST
|
||||
@Ok("json")
|
||||
@SaCheckPermission("sys.manager.task.edit")
|
||||
@SLog(tag = "执行任务一次", msg = "任务名:${args[1].getAttribute('name')}")
|
||||
public Object runOnce(String id, HttpServletRequest req) {
|
||||
Sys_task task = sysTaskService.fetch(id);
|
||||
if (task == null) {
|
||||
return Result.error("任务不存在");
|
||||
}
|
||||
req.setAttribute("name", task.getName());
|
||||
try {
|
||||
taskPlatformService.runOnce(task);
|
||||
return Result.success("已提交执行");
|
||||
} catch (Exception e) {
|
||||
log.error("提交单次任务失败:" + task.getName(), e);
|
||||
return Result.error("提交执行失败");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,18 +217,7 @@ public class SysTaskController {
|
||||
@SaCheckPermission("sys.manager.task.edit")
|
||||
@SLog(tag = "启用任务", msg = "任务名:${args[1].getAttribute('name')}")
|
||||
public Object enable(String id, HttpServletRequest req) {
|
||||
try {
|
||||
Sys_task sysTask = sysTaskService.fetch(id);
|
||||
req.setAttribute("name", sysTask.getName());
|
||||
sysTaskService.update(org.nutz.dao.Chain.make("disabled", false), Cnd.where("id", "=", id));
|
||||
if (!taskPlatformService.isExist(sysTask.getId(), sysTask.getId())) {
|
||||
taskPlatformService.add(sysTask.getId(), sysTask.getId(), sysTask.getJobClass(), sysTask.getCron(),
|
||||
sysTask.getNote(), sysTask.getData());
|
||||
}
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
}
|
||||
return changeDisabled(id, false, req);
|
||||
}
|
||||
|
||||
@At("/disable/?")
|
||||
@@ -169,16 +225,66 @@ public class SysTaskController {
|
||||
@SaCheckPermission("sys.manager.task.edit")
|
||||
@SLog(tag = "禁用任务", msg = "任务名:${args[1].getAttribute('name')}")
|
||||
public Object disable(String id, HttpServletRequest req) {
|
||||
return changeDisabled(id, true, req);
|
||||
}
|
||||
|
||||
private Object changeDisabled(String id, boolean disabled, HttpServletRequest req) {
|
||||
try {
|
||||
Sys_task sysTask = sysTaskService.fetch(id);
|
||||
req.setAttribute("name", sysTask.getName());
|
||||
sysTaskService.update(org.nutz.dao.Chain.make("disabled", true), Cnd.where("id", "=", id));
|
||||
if (taskPlatformService.isExist(sysTask.getId(), sysTask.getId())) {
|
||||
taskPlatformService.delete(sysTask.getId(), sysTask.getId());
|
||||
}
|
||||
Trans.exec(() -> {
|
||||
sysTaskService.update(Chain.make("disabled", disabled), Cnd.where("id", "=", id));
|
||||
Sys_task task = requireTask(id);
|
||||
req.setAttribute("name", task.getName());
|
||||
if (disabled) {
|
||||
taskPlatformService.delete(id, id);
|
||||
} else {
|
||||
schedule(task);
|
||||
}
|
||||
});
|
||||
return Result.success();
|
||||
} catch (Exception e) {
|
||||
return Result.error();
|
||||
return taskError(disabled ? "禁用任务失败" : "启用任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Sys_task requireTask(String id) {
|
||||
Sys_task task = Strings.isBlank(id) ? null : sysTaskService.fetch(id);
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException("任务不存在");
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
private void schedule(Sys_task task) {
|
||||
taskPlatformService.add(task.getId(), task.getId(), task.getJobClass(), task.getCron(),
|
||||
task.getNote(), task.getData());
|
||||
}
|
||||
|
||||
private String normalizeCron(String cron) {
|
||||
return Strings.sNull(cron).trim().replaceAll("\\s+", " ");
|
||||
}
|
||||
|
||||
private String validateCron(String cron) throws Exception {
|
||||
String normalized = normalizeCron(cron);
|
||||
previewCron(normalized);
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private List<String> previewCron(String normalized) throws Exception {
|
||||
if (normalized.length() > 50) {
|
||||
throw new IllegalArgumentException("Cron 表达式最多 50 个字符");
|
||||
}
|
||||
List<String> times = taskPlatformService.getCronExeTimes(normalized);
|
||||
if (times.isEmpty()) {
|
||||
throw new IllegalArgumentException("Cron 表达式没有未来执行时间");
|
||||
}
|
||||
return times;
|
||||
}
|
||||
|
||||
private Result taskError(String message, Exception e) {
|
||||
if (e instanceof IllegalArgumentException) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
log.error(message, e);
|
||||
return Result.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@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
|
||||
@ApiOperation("分工会干部离任")
|
||||
@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.SysUnitService;
|
||||
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.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
@@ -85,6 +84,7 @@ public class SysUnitController {
|
||||
// cnd.and("parentId", "is not", null).andEX("unitLevel", "=", unitLevel).asc("unitLevel").asc("unitcode");
|
||||
cnd.and("parentId", "is not", null);
|
||||
cnd.andEX("parentId", "=", unitId);
|
||||
cnd.andEX("id", "!=", unitId);
|
||||
// cnd.and("unitTypeCode", "=", "1");
|
||||
cnd.asc("unitcode");
|
||||
cnd.and(Cnd.likeEX("name", unitName));
|
||||
@@ -215,9 +215,9 @@ public class SysUnitController {
|
||||
if (AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (Strings.isBlank(pid)) {
|
||||
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId());
|
||||
cnd.and("parentId", "=", "").or("parentId", "is", null);
|
||||
} else {
|
||||
cnd.and("parentId", "=", pid).and("id", "<>", pid);
|
||||
cnd.and("parentId", "=", pid);
|
||||
}
|
||||
cnd.asc("location").asc("path");
|
||||
list = sysUnitService.query(cnd);
|
||||
@@ -228,9 +228,9 @@ public class SysUnitController {
|
||||
} else {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (Strings.isBlank(pid)) {
|
||||
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId());
|
||||
cnd.and("parentId", "=", "").or("parentId", "is", null);
|
||||
} else {
|
||||
cnd.and("parentId", "=", pid).and("id", "<>", pid);
|
||||
cnd.and("parentId", "=", pid);
|
||||
}
|
||||
cnd.asc("location").asc("path");
|
||||
list = sysUnitService.query(cnd);
|
||||
@@ -259,9 +259,9 @@ public class SysUnitController {
|
||||
if (StpUtil.hasRole("SYSADMIN")) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (Strings.isBlank(pid)) {
|
||||
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId());
|
||||
cnd.and("parentId", "=", "").or("parentId", "is", null);
|
||||
} else {
|
||||
cnd.and("parentId", "=", pid).and("id", "<>", pid);
|
||||
cnd.and("parentId", "=", pid);
|
||||
}
|
||||
cnd.asc("location").asc("path");
|
||||
list = sysUnitService.query(cnd);
|
||||
@@ -272,9 +272,9 @@ public class SysUnitController {
|
||||
} else {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (Strings.isBlank(pid)) {
|
||||
cnd.and("id", "=", DataCenterUtil.findRootUnit(sysUnitService.query(Cnd.NEW())).getId());
|
||||
cnd.and("parentId", "=", "").or("parentId", "is", null);
|
||||
} else {
|
||||
cnd.and("parentId", "=", pid).and("id", "<>", pid);
|
||||
cnd.and("parentId", "=", pid);
|
||||
}
|
||||
cnd.asc("location").asc("path");
|
||||
list = sysUnitService.query(cnd);
|
||||
@@ -296,27 +296,39 @@ 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")
|
||||
@Ok("json")
|
||||
@SaCheckLogin
|
||||
public Object tree(@Param("pid") String pid, HttpServletRequest req) {
|
||||
try {
|
||||
String rootId = StrUtil.blankToDefault(pid, "0");
|
||||
String virtualRootId = "root";
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.asc("unitcode");
|
||||
List<Sys_unit> list = sysUnitService.query(cnd);
|
||||
String rootId = StrUtil.isBlank(pid) ? DataCenterUtil.findRootUnit(list).getId() : pid;
|
||||
boolean defaultRoot = "0".equals(rootId);
|
||||
boolean hasDefaultRoot = defaultRoot && list.stream().anyMatch(unit -> rootId.equals(unit.getId()));
|
||||
|
||||
List<TreeNode<String>> nodeList = CollUtil.newArrayList();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Sys_unit unit = list.get(i);
|
||||
/*
|
||||
* 动态查询根挂到虚拟根下,兼容根节点父级为空或指向自身的数据。
|
||||
*/
|
||||
String parentId = rootId.equals(unit.getId()) ? virtualRootId : unit.getParentId();
|
||||
String parentId = unit.getParentId();
|
||||
if (rootId.equals(unit.getId()) || (defaultRoot && (StrUtil.isBlank(parentId)
|
||||
|| (!hasDefaultRoot && rootId.equals(parentId))))) {
|
||||
parentId = virtualRootId;
|
||||
}
|
||||
nodeList.add(new TreeNode<>(unit.getId(), parentId, unit.getName(), i)
|
||||
.setExtra(
|
||||
Map.of(
|
||||
// 历史手工新建单位可能未设置类型,展示时按其他类处理,避免空值使整棵树加载失败。
|
||||
"unitTypeCode", unit.getUnitTypeCode() == null ? 0 : unit.getUnitTypeCode()
|
||||
)
|
||||
));
|
||||
@@ -324,23 +336,37 @@ public class SysUnitController {
|
||||
List<Tree<String>> treeList = TreeUtil.build(nodeList, virtualRootId);
|
||||
return Result.success(treeList);
|
||||
} catch (Exception e) {
|
||||
log.error("加载单位树失败", e);
|
||||
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
|
||||
@Ok("json")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("sys.manager.unit.add")
|
||||
@SLog(tag = "新建单位", msg = "单位名称:${args[0].name}")
|
||||
public Object addDo(@Param("..") Sys_unit unit, @Param("parentId") String parentId, HttpServletRequest req) {
|
||||
try {
|
||||
if ("root".equals(parentId)) {
|
||||
parentId = "";
|
||||
if (Strings.isBlank(unit.getName()) || Strings.isBlank(unit.getUnitcode()) || Strings.isBlank(parentId) || "root".equals(parentId)) {
|
||||
return Result.error("单位名称、单位编码和上级单位不能为空");
|
||||
}
|
||||
unit.setCreatedBy(SecurityUtil.getUserId());
|
||||
sysUnitService.save(unit, parentId);
|
||||
return Result.success();
|
||||
} catch (BaseException e) {
|
||||
return Result.error(e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("新建单位失败", e);
|
||||
return Result.error();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.budwk.app.sys.models;
|
||||
|
||||
import lombok.Data;
|
||||
import org.nutz.dao.entity.annotation.*;
|
||||
|
||||
@Data
|
||||
@Table("sys_task_execution")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@TableIndexes(@Index(name = "IDX_SYS_TASK_EXECUTION_STARTED", fields = {"taskId", "startedAt"}))
|
||||
public class Sys_task_execution {
|
||||
public enum Status {
|
||||
RUNNING, SUCCESS, FAILED, SKIPPED, INTERRUPTED
|
||||
}
|
||||
|
||||
@Name
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String taskId;
|
||||
|
||||
@Column
|
||||
private long startedAt;
|
||||
|
||||
@Column
|
||||
private Long finishedAt;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 16)
|
||||
private String status;
|
||||
|
||||
@Column
|
||||
@ColDefine(customType = "MEDIUMTEXT")
|
||||
private String executionLog;
|
||||
}
|
||||
@@ -98,6 +98,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Column
|
||||
@Comment("证件类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@DataCenterColumn(name = "证件类型", key = "SFZJLXDM", dict = "USER_ID_CARD_TYPE")
|
||||
private String idCardType;
|
||||
|
||||
@Column
|
||||
@@ -133,6 +134,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Column
|
||||
@Comment("岗位类别")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@DataCenterColumn(name = "聘岗类型", key = "ZYJSGWLBDMMC")
|
||||
private String jobCategory;
|
||||
|
||||
@Column
|
||||
@@ -222,7 +224,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
private Integer pendingConfirmStatus;
|
||||
|
||||
@Column
|
||||
@Comment("编制类别码")
|
||||
@Comment("编制类别")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@DataCenterColumn(name = "编制类别", key = "BZLBDMMC")
|
||||
private String preparedBy;
|
||||
@@ -295,6 +297,7 @@ public class Sys_user extends BaseModel implements Serializable {
|
||||
@Comment("是否双肩挑")
|
||||
@ColDefine(type = ColType.BOOLEAN)
|
||||
@Default(value = "0")
|
||||
@DataCenterColumn(name = "是否双肩挑", key = "SFSJT")
|
||||
private Boolean manyUnit;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -61,7 +61,7 @@ public class Sys_user_role {
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("社团ID")
|
||||
@Comment("协会ID")
|
||||
private String clubId;
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.budwk.app.sys.models;
|
||||
|
||||
import com.budwk.app.sys.annotation.DataCenterColumn;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -31,6 +32,42 @@ public class Sys_user_source extends Sys_user {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||
private String unitName;
|
||||
|
||||
@Column
|
||||
@Comment("最高学历代码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
@DataCenterColumn(name = "最高学历代码", key = "ZGXLDM")
|
||||
private String educationCode;
|
||||
|
||||
@Column
|
||||
@Comment("最高学位代码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@DataCenterColumn(name = "最高学位代码", key = "XWDM")
|
||||
private String academicDegreeCode;
|
||||
|
||||
@Column
|
||||
@Comment("编制类别代码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@DataCenterColumn(name = "编制类别代码", key = "BZLBDM")
|
||||
private String preparedByCode;
|
||||
|
||||
@Column
|
||||
@Comment("聘岗类型代码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@DataCenterColumn(name = "聘岗类型代码", key = "ZYJSGWLBDM")
|
||||
private String jobCategoryCode;
|
||||
|
||||
@Column
|
||||
@Comment("专业技术职务代码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@DataCenterColumn(name = "专业技术职务代码", key = "ZYJSZWDM")
|
||||
private String professionalTitleCode;
|
||||
|
||||
@Column
|
||||
@Comment("当前状态代码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@DataCenterColumn(name = "当前状态代码", key = "DQZTDM")
|
||||
private String userStateCode;
|
||||
|
||||
@Column
|
||||
@Comment("拉取时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
|
||||
@@ -15,6 +15,12 @@ public interface SysDataUserPullService extends BaseService<Sys_user_source> {
|
||||
*/
|
||||
Date pull();
|
||||
|
||||
default NutMap queryUsers(String zgh, int pageNumber, int pageSize) {
|
||||
return queryUsers(zgh, null, pageNumber, pageSize);
|
||||
}
|
||||
|
||||
NutMap queryUsers(String zgh, String xm, int pageNumber, int pageSize);
|
||||
|
||||
/**
|
||||
* 拉取人员博士后的信息
|
||||
*/
|
||||
|
||||
@@ -7,4 +7,15 @@ import com.budwk.app.sys.param.SysDataUserUpdateParam;
|
||||
*/
|
||||
public interface SysDataUserUpdateService {
|
||||
String update(SysDataUserUpdateParam updateParam);
|
||||
|
||||
static boolean qualifiesAsUnionMember(String personType, String userState) {
|
||||
if (!"在岗".equals(userState) || personType == null) {
|
||||
return false;
|
||||
}
|
||||
return switch (personType) {
|
||||
case "在编", "兰溪编制", "聘用合同制(享受人事代理待遇)",
|
||||
"聘用合同制", "聘用制专家", "人事代理" -> true;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,17 @@ package com.budwk.app.sys.services;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -136,6 +136,9 @@ public interface SysRoleService extends BaseService<Sys_role> {
|
||||
*/
|
||||
NutMap settingMemberRole();
|
||||
|
||||
/** 为指定人员中 member=1 的用户批量补齐启用的会员角色。 */
|
||||
NutMap settingMemberRole(List<String> userIds);
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
|
||||
@@ -164,6 +164,9 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
|
||||
// 创建用户对象
|
||||
Sys_user u = new Sys_user();
|
||||
BeanUtils.copyProperties(source, u);
|
||||
if (SysDataUserUpdateService.qualifiesAsUnionMember(u.getPersonType(), u.getUserState())) {
|
||||
u.setMember(true);
|
||||
}
|
||||
|
||||
if (user == null) {
|
||||
// 新增用户,初始化数据
|
||||
@@ -298,6 +301,13 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
|
||||
return "更新失败: " + e.getMessage();
|
||||
}
|
||||
|
||||
List<String> updatedUserIds = new ArrayList<>();
|
||||
needInitUserList.forEach(user -> updatedUserIds.add(user.getId()));
|
||||
needDoUpdateList.forEach(user -> updatedUserIds.add(user.getId()));
|
||||
sysRoleService.settingMemberRole(updatedUserIds);
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
|
||||
/* // 4. 异步添加会员角色 - 不等待完成
|
||||
if (Lang.isNotEmpty(addMemberUserIds)) {
|
||||
executorService.execute(() -> {
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.budwk.app.sys.param.SysDataUserUpdateParam;
|
||||
import com.budwk.app.sys.services.SysDataUserUpdateService;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.sys.services.SysUnitService;
|
||||
import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.sys.utils.DataCenterUtil;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
||||
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin;
|
||||
@@ -44,6 +45,8 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
|
||||
private SysRoleService sysRoleService;
|
||||
@Inject
|
||||
private SysUnitService sysUnitService;
|
||||
@Inject
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@@ -123,6 +126,9 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
|
||||
//加入到系统用户表
|
||||
List<Sys_user> sysUsers = BeanUtil.copyToList(userSources, Sys_user.class);
|
||||
for (Sys_user sysUser : sysUsers) {
|
||||
if (SysDataUserUpdateService.qualifiesAsUnionMember(sysUser.getPersonType(), sysUser.getUserState())) {
|
||||
sysUser.setMember(true);
|
||||
}
|
||||
//重新设置
|
||||
sysUser.setId(R.UU32());
|
||||
String salt = R.UU32();
|
||||
@@ -161,7 +167,9 @@ public class SysDataUserIncrUpdateServiceImpl implements SysDataUserUpdateServic
|
||||
return sysUserRole;
|
||||
}).toList();
|
||||
dao.insert(sysUserRoles);
|
||||
sysRoleService.settingMemberRole(sysUsers.stream().map(Sys_user::getId).toList());
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.clearCache();
|
||||
|
||||
// 6.1 更新提案的校领导角色,发送订阅
|
||||
ProposalConfig config = dao.fetch(ProposalConfig.class, Cnd.where("delFlag", "=", false).desc("updatedAt"));
|
||||
|
||||
@@ -98,7 +98,7 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
synchronized (SysDataUserPullServiceImpl.class) {
|
||||
if (fieldMappings == null) {
|
||||
List<FieldMapping> mappings = new ArrayList<>();
|
||||
Field[] fields = Sys_user.class.getDeclaredFields();
|
||||
Field[] fields = cn.hutool.core.util.ReflectUtil.getFields(Sys_user_source.class);
|
||||
for (Field field : fields) {
|
||||
DataCenterColumn annotation = field.getAnnotation(DataCenterColumn.class);
|
||||
if (annotation != null) {
|
||||
@@ -200,6 +200,8 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
mapping.field.set(sysUser, raw.getStr(mapping.key));
|
||||
}
|
||||
}
|
||||
} else if (mapping.field.getType() == Boolean.class) {
|
||||
mapping.field.set(sysUser, raw.getBool(mapping.key));
|
||||
} else if (mapping.field.getType() == Date.class) {
|
||||
String dateText = StrUtil.trim(raw.getStr(mapping.key));
|
||||
if (StrUtil.isNotBlank(dateText)) {
|
||||
@@ -332,12 +334,50 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap queryUsers(String zgh, String xm, int pageNumber, int pageSize) {
|
||||
if (pageNumber < 1 || pageSize < 1 || pageSize > 200) {
|
||||
throw new BaseException("分页参数不合法");
|
||||
}
|
||||
String jobNumber = StrUtil.trim(zgh);
|
||||
String name = StrUtil.trim(xm);
|
||||
boolean tokenEnabled = dataCenterProperties.isTokenEnabled();
|
||||
if (!tokenEnabled && StrUtil.isBlank(name)) {
|
||||
JSONObject response = DataCenterUtil.queryPage(getDmpUrl(DMP_TEACHER_KEY), jobNumber, pageNumber, pageSize);
|
||||
JSONObject pageInfo = response.getJSONObject("pageInfo");
|
||||
JSONArray data = response.getJSONArray("dataSet");
|
||||
if (pageInfo == null || pageInfo.getLong("total") == null || data == null) {
|
||||
throw new BaseException("数据中心接口未返回有效的分页数据");
|
||||
}
|
||||
return NutMap.NEW().addv("list", data).addv("totalCount", pageInfo.getLong("total"));
|
||||
}
|
||||
List<JSONObject> records = new ArrayList<>();
|
||||
if (tokenEnabled) {
|
||||
String accessToken = getDmpAccessToken();
|
||||
records.addAll(pullDmpUsers(getDmpUrl(DMP_TEACHER_KEY), accessToken, "在岗教职工", jobNumber));
|
||||
records.addAll(pullDmpUsers(getDmpUrl(DMP_DISPATCH_KEY), accessToken, "在岗劳务派遣", jobNumber));
|
||||
} else {
|
||||
Map<String, String> params = StrUtil.isBlank(jobNumber) ? Map.of() : Map.of("zgh", jobNumber);
|
||||
records = DataCenterUtil.pullData(getDmpUrl(DMP_TEACHER_KEY), params);
|
||||
}
|
||||
if (StrUtil.isNotBlank(name)) {
|
||||
records.removeIf(record -> !StringUtils.contains(record.getStr("XM"), name));
|
||||
}
|
||||
int from = (int) Math.min((long) (pageNumber - 1) * pageSize, records.size());
|
||||
return NutMap.NEW().addv("list", records.subList(from, Math.min(from + pageSize, records.size())))
|
||||
.addv("totalCount", records.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页拉取单个人员接口数据。
|
||||
* 入参 url 为人员接口地址,accessToken 为信息中心令牌,sourceName 用于日志区分接口来源。
|
||||
* 返回值为该接口所有分页合并后的原始人员 JSON 列表。
|
||||
*/
|
||||
private List<JSONObject> pullDmpUsers(String url, String accessToken, String sourceName) {
|
||||
return pullDmpUsers(url, accessToken, sourceName, null);
|
||||
}
|
||||
|
||||
private List<JSONObject> pullDmpUsers(String url, String accessToken, String sourceName, String zgh) {
|
||||
List<JSONObject> rawDataList = new ArrayList<>();
|
||||
int page = 1;
|
||||
int maxPage = 1;
|
||||
@@ -347,11 +387,14 @@ public class SysDataUserPullServiceImpl extends BaseServiceImpl<Sys_user_source>
|
||||
// 信息中心接口单页最多返回1000条,按page循环拉完当前接口全部数据。
|
||||
HttpRequest httpRequest = HttpUtil.createPost(url);
|
||||
httpRequest.header(Header.CONTENT_TYPE, "application/json");
|
||||
httpRequest.body(JSONUtil.toJsonStr(Map.of(
|
||||
"access_token", accessToken,
|
||||
"per_page", String.valueOf(DMP_PAGE_SIZE),
|
||||
"page", String.valueOf(page)
|
||||
)));
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("access_token", accessToken);
|
||||
body.put("per_page", String.valueOf(DMP_PAGE_SIZE));
|
||||
body.put("page", String.valueOf(page));
|
||||
if (StrUtil.isNotBlank(zgh)) {
|
||||
body.put("zgh", zgh);
|
||||
}
|
||||
httpRequest.body(JSONUtil.toJsonStr(body));
|
||||
|
||||
log.info("请求{}人员数据,第{}页: {}", sourceName, page, httpRequest);
|
||||
String resBody = httpRequest.execute().body();
|
||||
|
||||
@@ -1,15 +1,87 @@
|
||||
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.sys.models.Sys_home_activity;
|
||||
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.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.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"})
|
||||
public class SysHomeActivityServiceImpl extends BaseServiceImpl<Sys_home_activity> implements SysHomeActivityService {
|
||||
|
||||
@Inject
|
||||
private ActivityBasicScopeService activityBasicScopeService;
|
||||
|
||||
public SysHomeActivityServiceImpl(Dao 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,6 +294,27 @@ public class SysRoleServiceImpl extends BaseServiceImpl<Sys_role> implements Sys
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public NutMap settingMemberRole() {
|
||||
return settingMemberRole(Cnd.where("u.member", "=", 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public NutMap settingMemberRole(List<String> userIds) {
|
||||
int addedCount = 0;
|
||||
int enabledCount = 0;
|
||||
if (userIds != null && !userIds.isEmpty()) {
|
||||
List<String> distinctIds = userIds.stream().distinct().toList();
|
||||
for (int start = 0; start < distinctIds.size(); start += 500) {
|
||||
NutMap counts = settingMemberRole(Cnd.where("u.member", "=", 1)
|
||||
.and("u.id", "in", distinctIds.subList(start, Math.min(start + 500, distinctIds.size()))));
|
||||
addedCount += counts.getInt("addedCount");
|
||||
enabledCount += counts.getInt("enabledCount");
|
||||
}
|
||||
}
|
||||
return NutMap.NEW().addv("addedCount", addedCount).addv("enabledCount", enabledCount);
|
||||
}
|
||||
|
||||
private NutMap settingMemberRole(Cnd condition) {
|
||||
// 锁定同一会员角色,使本接口的并发请求依次执行,避免重复插入用户角色关系。
|
||||
Sql roleSql = Sqls.create("SELECT * FROM sys_role WHERE code=@code FOR UPDATE");
|
||||
roleSql.setParam("code", RoleConstant.MEMBER.name());
|
||||
@@ -312,14 +333,16 @@ public class SysRoleServiceImpl extends BaseServiceImpl<Sys_role> implements Sys
|
||||
// 历史关联可能已停用或未填写 enable;恢复关联即可,无需重新插入。
|
||||
Sql enableSql = Sqls.create("UPDATE sys_user_role SET enable=1 WHERE roleId=@roleId "
|
||||
+ "AND (enable IS NULL OR enable<>1) "
|
||||
+ "AND EXISTS (SELECT 1 FROM sys_user u WHERE u.id=sys_user_role.userId AND u.member=1)");
|
||||
+ "AND EXISTS (SELECT 1 FROM sys_user u $condition AND u.id=sys_user_role.userId)");
|
||||
enableSql.setCondition(condition);
|
||||
enableSql.setParam("roleId", role.getId());
|
||||
dao().execute(enableSql);
|
||||
|
||||
// 按用户、角色判重,只为缺少会员关联的人员添加记录;不删除任何已有角色。
|
||||
Sql insertSql = Sqls.create("INSERT INTO sys_user_role (userId,roleId,enable) "
|
||||
+ "SELECT u.id,@roleId,1 FROM sys_user u WHERE u.member=1 "
|
||||
+ "SELECT u.id,@roleId,1 FROM sys_user u $condition "
|
||||
+ "AND NOT EXISTS (SELECT 1 FROM sys_user_role ur WHERE ur.userId=u.id AND ur.roleId=@roleId)");
|
||||
insertSql.setCondition(condition);
|
||||
insertSql.setParam("roleId", role.getId());
|
||||
dao().execute(insertSql);
|
||||
return NutMap.NEW().addv("addedCount", insertSql.getUpdateCount())
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.integration.jedis.RedisService;
|
||||
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.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
@@ -67,6 +68,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
|
||||
private RedisService redisService;
|
||||
@Inject
|
||||
private ValidateService validateService;
|
||||
@Inject
|
||||
private PropertiesProxy conf;
|
||||
|
||||
@Override
|
||||
@CacheResult(cacheKey = "${userId}_getPermissionList")
|
||||
@@ -359,7 +362,8 @@ public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements Sys
|
||||
// base64解码密码
|
||||
String decodePwd = Base64Decoder.decodeStr(passowrd);
|
||||
String hashedPassword = PwdUtil.getPassword(decodePwd, user.getSalt());
|
||||
if (!Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
|
||||
if (!"dev".equals(conf.get("nutz.profiles.active"))
|
||||
&& !Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
|
||||
throw new BaseException("用户名或者密码不正确");
|
||||
}
|
||||
user = this.fetchLinks(user, "unit");
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.budwk.app.sys.models.Sys_unit;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -40,7 +41,11 @@ public class DataCenterUtil {
|
||||
}
|
||||
|
||||
public static List<JSONObject> pullData(String url) {
|
||||
JSONObject firstResponse = requestData(url, Map.of("", ""));
|
||||
return pullData(url, Map.of("", ""));
|
||||
}
|
||||
|
||||
public static List<JSONObject> pullData(String url, Map<String, ?> params) {
|
||||
JSONObject firstResponse = requestData(url, params);
|
||||
JSONObject pageInfo = firstResponse.getJSONObject("pageInfo");
|
||||
Integer pages = pageInfo == null ? null : pageInfo.getInt("pages");
|
||||
if (pages == null || pages < 0) {
|
||||
@@ -48,7 +53,9 @@ public class DataCenterUtil {
|
||||
}
|
||||
List<JSONObject> records = new ArrayList<>();
|
||||
for (int page = 1; page <= pages; page++) {
|
||||
JSONObject response = requestData(url, Map.of("pageNum", page));
|
||||
Map<String, Object> body = new HashMap<>(params);
|
||||
body.put("pageNum", page);
|
||||
JSONObject response = requestData(url, body);
|
||||
JSONArray data = response.getJSONArray("dataSet");
|
||||
if (data == null) {
|
||||
throw new BaseException("数据中心接口第{}页缺少 dataSet", page);
|
||||
@@ -58,6 +65,16 @@ public class DataCenterUtil {
|
||||
return records;
|
||||
}
|
||||
|
||||
public static JSONObject queryPage(String url, String zgh, int pageNumber, int pageSize) {
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("pageNum", pageNumber);
|
||||
body.put("pageSize", pageSize);
|
||||
if (StrUtil.isNotBlank(zgh)) {
|
||||
body.put("zgh", zgh.trim());
|
||||
}
|
||||
return requestData(url, body);
|
||||
}
|
||||
|
||||
private static JSONObject requestData(String url, Map<String, ?> body) {
|
||||
try (HttpResponse response = HttpUtil.createPost(url)
|
||||
.body(JSONUtil.toJsonStr(body)).execute()) {
|
||||
|
||||
@@ -1,62 +1,50 @@
|
||||
package com.budwk.app.task.job;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.param.ConditionGroup;
|
||||
import com.budwk.app.sys.enums.SysDataUpdateMode;
|
||||
import com.budwk.app.sys.models.Sys_user_source;
|
||||
import com.budwk.app.sys.param.SysDataUserUpdateParam;
|
||||
import com.budwk.app.sys.services.SysDataUserPullService;
|
||||
import com.budwk.app.sys.services.SysDataUserUpdateService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.Ioc;
|
||||
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.quartz.DisallowConcurrentExecution;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 人员全量更新任务
|
||||
*/
|
||||
@IocBean
|
||||
@Slf4j
|
||||
@DisallowConcurrentExecution
|
||||
public class SysUserAllRenewJob implements Job {
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject("refer:$ioc")
|
||||
private Ioc ioc;
|
||||
@Inject
|
||||
private SysDataUserPullService sysDataUserPullService;
|
||||
@Inject
|
||||
private SysDataUserUpdateService sysDataUserUpdateService;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
Date pullTime = sysDataUserPullService.pull();
|
||||
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
|
||||
NutMap conditionGroupMap = (NutMap)jobDataMap.get("conditionGroup");
|
||||
if(conditionGroupMap == null || conditionGroupMap.isEmpty()){
|
||||
log.error("SysUserAllRenewJob定时任务执行中止,原因:conditionGroup为null");
|
||||
}
|
||||
String conditionGroupStr = Json.toJson(conditionGroupMap).replace("@currentDate", DateUtil.today());
|
||||
ConditionGroup conditionGroup = null;
|
||||
try {
|
||||
conditionGroup = Json.fromJson(ConditionGroup.class, conditionGroupStr);
|
||||
SysDataUserUpdateParam param = new SysDataUserUpdateParam();
|
||||
param.setUpdateMode(SysDataUpdateMode.ALL.name());
|
||||
Object conditionGroup = jobExecutionContext.getMergedJobDataMap().get("conditionGroup");
|
||||
if (conditionGroup != null) {
|
||||
String conditionGroupJson = Json.toJson(conditionGroup).replace("@currentDate", DateUtil.today());
|
||||
param.setConditionGroup(Json.fromJson(ConditionGroup.class, conditionGroupJson));
|
||||
}
|
||||
|
||||
param.setPullTime(DateUtil.formatDateTime(sysDataUserPullService.pull()));
|
||||
SysDataUserUpdateService updateService = (SysDataUserUpdateService) ioc.get(SysDataUpdateMode.ALL.getClazz());
|
||||
log.info("人员全量更新任务,拉取批次 {}:{}", param.getPullTime(), updateService.update(param));
|
||||
} catch (Exception e) {
|
||||
log.error("SysUserAllRenewJob定时任务执行失败,原因:{}", e.getMessage());
|
||||
throw new JobExecutionException("人员拉取及全量更新任务执行失败", e);
|
||||
}
|
||||
|
||||
SysDataUserUpdateParam param = new SysDataUserUpdateParam();
|
||||
param.setPullTime(DateUtil.formatDateTime(pullTime));
|
||||
param.setUpdateMode(SysDataUpdateMode.ALL.name());
|
||||
param.setConditionGroup(conditionGroup);
|
||||
|
||||
// sysDataUserUpdateService.update(param);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,6 @@ public class TestJob implements Job {
|
||||
String taskId = context.getJobDetail().getKey().getName();
|
||||
String hi = data.getString("hi");
|
||||
log.info("Test Job hi::" + hi);
|
||||
sysTaskService.update(Chain.make("exeAt", (int) (System.currentTimeMillis() / 1000)).add("exeResult", "执行成功"), Cnd.where("id", "=", taskId));
|
||||
sysTaskService.update(Chain.make("exeResult", "执行成功"), Cnd.where("id", "=", taskId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import org.quartz.JobExecutionException;
|
||||
* @Author JyuHsin
|
||||
* @Date 2026/1/22 16:56
|
||||
* @Version 1.0
|
||||
* @Description 每年的1月1日生成社团成员当年的缴费记录
|
||||
* @Description 每年的1月1日生成协会成员当年的缴费记录
|
||||
*/
|
||||
@IocBean
|
||||
@DisallowConcurrentExecution
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.budwk.app.task.log;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
import com.budwk.app.sys.models.Sys_task_execution;
|
||||
import com.budwk.app.sys.models.Sys_task_execution.Status;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.trans.Trans;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.listeners.JobListenerSupport;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.UUID;
|
||||
|
||||
@IocBean
|
||||
public class TaskExecutionListener extends JobListenerSupport {
|
||||
private static final Logger log = LoggerFactory.getLogger(TaskExecutionListener.class);
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private Scheduler scheduler;
|
||||
|
||||
public void register() throws SchedulerException {
|
||||
if (!dao.exists(Sys_task_execution.class)) {
|
||||
dao.create(Sys_task_execution.class, false);
|
||||
}
|
||||
dao.update(Sys_task_execution.class, Chain.make("status", Status.INTERRUPTED.name()),
|
||||
Cnd.where("status", "=", Status.RUNNING.name()));
|
||||
scheduler.getListenerManager().addJobListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "sysTaskExecutionListener";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jobToBeExecuted(JobExecutionContext context) {
|
||||
JobKey key = context.getJobDetail().getKey();
|
||||
context.put(getName(), null);
|
||||
if (!key.getName().equals(key.getGroup())) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (dao.fetch(Sys_task.class, key.getName()) == null) {
|
||||
return;
|
||||
}
|
||||
Sys_task_execution execution = new Sys_task_execution();
|
||||
execution.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
execution.setTaskId(key.getName());
|
||||
execution.setStartedAt(System.currentTimeMillis());
|
||||
execution.setStatus(Status.RUNNING.name());
|
||||
Trans.exec(() -> {
|
||||
dao.insert(execution);
|
||||
long startedAtSeconds = execution.getStartedAt() / 1000;
|
||||
dao.execute(Sqls.create("UPDATE sys_task SET exeAt = @startedAt WHERE id = @id AND (exeAt IS NULL OR exeAt < @startedAt)")
|
||||
.setParam("startedAt", startedAtSeconds).setParam("id", execution.getTaskId()));
|
||||
});
|
||||
context.put(getName(), execution.getId());
|
||||
context.setResult(null);
|
||||
TaskExecutionLogAppender.begin();
|
||||
log.info("开始执行任务 {}", key.getName());
|
||||
} catch (RuntimeException e) {
|
||||
log.error("记录任务开始时间失败,任务 {}", key, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jobWasExecuted(JobExecutionContext context, JobExecutionException exception) {
|
||||
String id = (String) context.get(getName());
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
Status status = exception != null ? Status.FAILED
|
||||
: context.getResult() instanceof Status result ? result : Status.SUCCESS;
|
||||
String executionLog = TaskExecutionLogAppender.end("\n任务执行结束,状态 " + status + "\n");
|
||||
try {
|
||||
if (exception != null) {
|
||||
StringWriter stack = new StringWriter();
|
||||
exception.printStackTrace(new PrintWriter(stack));
|
||||
String detail = stack.toString();
|
||||
if (detail.length() > 8000) {
|
||||
int end = Character.isHighSurrogate(detail.charAt(7999)) ? 7999 : 8000;
|
||||
detail = detail.substring(0, end) + "\n[异常堆栈已截断]";
|
||||
}
|
||||
executionLog += (exception.refireImmediately() ? "Quartz 将立即重试\n" : "") + detail;
|
||||
}
|
||||
dao.update(Sys_task_execution.class,
|
||||
Chain.make("status", status.name()).add("finishedAt", System.currentTimeMillis())
|
||||
.add("executionLog", executionLog),
|
||||
Cnd.where("id", "=", id));
|
||||
} catch (RuntimeException e) {
|
||||
log.error("保存任务执行结果失败,记录 {}", id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.budwk.app.task.log;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
|
||||
import ch.qos.logback.core.UnsynchronizedAppenderBase;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class TaskExecutionLogAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {
|
||||
private static final int MAX_LENGTH = 16000;
|
||||
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
|
||||
.withZone(ZoneId.of("Asia/Shanghai"));
|
||||
private static final ThreadLocal<StringBuilder> CURRENT_LOG = new ThreadLocal<>();
|
||||
|
||||
static void begin() {
|
||||
CURRENT_LOG.set(new StringBuilder());
|
||||
}
|
||||
|
||||
static String end(String outcome) {
|
||||
StringBuilder log = CURRENT_LOG.get();
|
||||
CURRENT_LOG.remove();
|
||||
return (log == null ? "" : log.toString()) + outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void append(ILoggingEvent event) {
|
||||
StringBuilder log = CURRENT_LOG.get();
|
||||
if (log == null || log.length() >= MAX_LENGTH || !event.getLevel().isGreaterOrEqual(Level.INFO)) {
|
||||
return;
|
||||
}
|
||||
log.append(TIME_FORMAT.format(Instant.ofEpochMilli(event.getTimeStamp())))
|
||||
.append(" ").append(event.getLevel()).append(" ").append(event.getLoggerName())
|
||||
.append(" - ").append(event.getFormattedMessage()).append('\n');
|
||||
if (event.getThrowableProxy() != null) {
|
||||
log.append(ThrowableProxyUtil.asString(event.getThrowableProxy()));
|
||||
}
|
||||
if (log.length() >= MAX_LENGTH) {
|
||||
int end = MAX_LENGTH;
|
||||
if (Character.isHighSurrogate(log.charAt(end - 1))) {
|
||||
end--;
|
||||
}
|
||||
log.setLength(end);
|
||||
log.append("\n[后续日志已截断]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.budwk.app.task.services;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -15,6 +17,10 @@ public interface TaskPlatformService {
|
||||
*/
|
||||
boolean isExist(String jobName, String jobGroup);
|
||||
|
||||
void runOnce(Sys_task task) throws Exception;
|
||||
|
||||
void restore(Sys_task task) throws Exception;
|
||||
|
||||
/**
|
||||
* 添加新任务
|
||||
*
|
||||
|
||||
@@ -1,28 +1,45 @@
|
||||
package com.budwk.app.task.services.impl;
|
||||
|
||||
import com.budwk.app.sys.models.Sys_task;
|
||||
import com.budwk.app.task.services.TaskPlatformService;
|
||||
import org.nutz.integration.quartz.QuartzJob;
|
||||
import org.nutz.integration.quartz.QuartzManager;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.quartz.CronExpression;
|
||||
import org.quartz.CronScheduleBuilder;
|
||||
import org.quartz.CronTrigger;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobBuilder;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobDetail;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.TriggerUtils;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.TriggerBuilder;
|
||||
import org.quartz.TriggerKey;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Created by wizzer on 2018/3/19.
|
||||
*/
|
||||
@IocBean
|
||||
public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
private static final TimeZone TASK_TIME_ZONE = TimeZone.getTimeZone("Asia/Shanghai");
|
||||
|
||||
@Inject
|
||||
private QuartzManager quartzManager;
|
||||
@Inject
|
||||
private Scheduler scheduler;
|
||||
|
||||
/**
|
||||
* 判断任务是否存在
|
||||
@@ -35,6 +52,40 @@ public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
return quartzManager.exist(new JobKey(jobName, jobGroup));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runOnce(Sys_task task) throws Exception {
|
||||
JobKey key = JobKey.jobKey(task.getId(), task.getId());
|
||||
if (scheduler.checkExists(key)) {
|
||||
scheduler.triggerJob(key);
|
||||
return;
|
||||
}
|
||||
|
||||
JobDetail job = buildJob(key, task.getJobClass(), task.getData());
|
||||
scheduler.scheduleJob(job, TriggerBuilder.newTrigger().forJob(key).startNow().build());
|
||||
}
|
||||
|
||||
private JobDetail buildJob(JobKey key, String className, String dataMap) {
|
||||
Class<? extends Job> jobClass;
|
||||
try {
|
||||
jobClass = Class.forName(Strings.sNull(className).trim(), false, getClass().getClassLoader())
|
||||
.asSubclass(Job.class);
|
||||
} catch (ClassNotFoundException | ClassCastException e) {
|
||||
throw new IllegalArgumentException("执行类必须是有效的 Quartz Job", e);
|
||||
}
|
||||
JobDataMap data = new JobDataMap();
|
||||
if (Strings.isNotBlank(dataMap)) {
|
||||
try {
|
||||
NutMap params = Json.fromJson(NutMap.class, dataMap);
|
||||
if (params != null) {
|
||||
data.putAll(params);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw new IllegalArgumentException("执行参数必须是有效的 JSON 对象", e);
|
||||
}
|
||||
}
|
||||
return JobBuilder.newJob(jobClass).withIdentity(key).usingJobData(data).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新任务
|
||||
*
|
||||
@@ -46,14 +97,55 @@ public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
* @param dataMap
|
||||
*/
|
||||
public void add(String jobName, String jobGroup, String className, String cron, String comment, String dataMap) {
|
||||
QuartzJob qj = new QuartzJob();
|
||||
qj.setJobName(jobName);
|
||||
qj.setJobGroup(jobGroup);
|
||||
qj.setClassName(className);
|
||||
qj.setCron(cron);
|
||||
qj.setComment(comment);
|
||||
qj.setDataMap(dataMap);
|
||||
quartzManager.add(qj);
|
||||
JobKey key = JobKey.jobKey(jobName, jobGroup);
|
||||
JobDetail job = buildJob(key, className, dataMap);
|
||||
CronExpression expression = parseCron(cron);
|
||||
if (expression.getNextValidTimeAfter(new Date()) == null) {
|
||||
throw new IllegalArgumentException("Cron 表达式没有未来执行时间");
|
||||
}
|
||||
schedule(job, expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Sys_task task) throws SchedulerException {
|
||||
JobKey key = JobKey.jobKey(task.getId(), task.getId());
|
||||
if (task.isDisabled()) {
|
||||
scheduler.deleteJob(key);
|
||||
return;
|
||||
}
|
||||
|
||||
CronExpression expression = parseCron(task.getCron());
|
||||
JobDetail job = buildJob(key, task.getJobClass(), task.getData());
|
||||
JobDetail existingJob = scheduler.getJobDetail(key);
|
||||
if (existingJob != null
|
||||
&& existingJob.getJobClass().equals(job.getJobClass())
|
||||
&& existingJob.getJobDataMap().equals(job.getJobDataMap())
|
||||
&& scheduler.getTrigger(TriggerKey.triggerKey(key.getName(), key.getGroup())) instanceof CronTrigger trigger
|
||||
&& trigger.getCronExpression().equals(expression.getCronExpression())
|
||||
&& trigger.getTimeZone().hasSameRules(TASK_TIME_ZONE)
|
||||
&& trigger.getNextFireTime() != null) {
|
||||
scheduler.resetTriggerFromErrorState(trigger.getKey());
|
||||
return;
|
||||
}
|
||||
if (expression.getNextValidTimeAfter(new Date()) != null) {
|
||||
schedule(job, expression);
|
||||
} else if (existingJob != null) {
|
||||
scheduler.deleteJob(key);
|
||||
}
|
||||
}
|
||||
|
||||
private void schedule(JobDetail job, CronExpression expression) {
|
||||
JobKey key = job.getKey();
|
||||
CronTrigger trigger = TriggerBuilder.newTrigger()
|
||||
.withIdentity(key.getName(), key.getGroup())
|
||||
.forJob(key)
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(expression))
|
||||
.build();
|
||||
try {
|
||||
scheduler.scheduleJob(job, Set.of(trigger), true);
|
||||
} catch (SchedulerException e) {
|
||||
throw new IllegalStateException("Quartz 调度注册失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,10 +156,7 @@ public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
* @return
|
||||
*/
|
||||
public boolean delete(String jobName, String jobGroup) {
|
||||
QuartzJob qj = new QuartzJob();
|
||||
qj.setJobName(jobName);
|
||||
qj.setJobGroup(jobGroup);
|
||||
return quartzManager.delete(qj);
|
||||
return quartzManager.delete(JobKey.jobKey(jobName, jobGroup));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,36 +172,40 @@ public class TaskPlatformServiceImpl implements TaskPlatformService {
|
||||
* @param cronExpression
|
||||
* @return
|
||||
*/
|
||||
public List<String> getCronExeTimes(String cronExpression) throws Exception {
|
||||
List<String> list = new ArrayList<>();
|
||||
CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
|
||||
cronTriggerImpl.setCronExpression(cronExpression);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
Date now = calendar.getTime();
|
||||
calendar.add(2, 1);
|
||||
List<Date> dates = TriggerUtils.computeFireTimesBetween(cronTriggerImpl, null, now, calendar.getTime());
|
||||
@Override
|
||||
public List<String> getCronExeTimes(String cronExpression) {
|
||||
CronExpression expression = parseCron(cronExpression);
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
for (int i = 0; i < dates.size() && i <= 4; ++i) {
|
||||
list.add(dateFormat.format((Date) dates.get(i)));
|
||||
dateFormat.setTimeZone(TASK_TIME_ZONE);
|
||||
List<String> times = new ArrayList<>(5);
|
||||
Date time = new Date();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
time = expression.getNextValidTimeAfter(time);
|
||||
if (time == null) {
|
||||
break;
|
||||
}
|
||||
times.add(dateFormat.format(time));
|
||||
}
|
||||
return list;
|
||||
return times;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> getCronExeTimesPlus(String cronExpression) throws Exception {
|
||||
// 创建一个列表来存储执行时间
|
||||
List<String> executionTimes = new ArrayList<>();
|
||||
// 创建 CronTriggerImpl 对象,并设置 cron 表达式
|
||||
CronTriggerImpl cronTrigger = new CronTriggerImpl();
|
||||
cronTrigger.setCronExpression(new CronExpression(cronExpression));
|
||||
// 计算未来的执行时间
|
||||
List<Date> nextExecutionTimes = TriggerUtils.computeFireTimes(cronTrigger, null, 5);
|
||||
// 格式化日期并添加到执行时间列表中
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
for (Date date : nextExecutionTimes) {
|
||||
executionTimes.add(dateFormat.format(date));
|
||||
public List<String> getCronExeTimesPlus(String cronExpression) {
|
||||
return getCronExeTimes(cronExpression);
|
||||
}
|
||||
|
||||
private CronExpression parseCron(String cron) {
|
||||
String normalized = Strings.sNull(cron).trim().replaceAll("\\s+", " ");
|
||||
int fieldCount = normalized.split(" ").length;
|
||||
if (fieldCount < 6 || fieldCount > 7) {
|
||||
throw new IllegalArgumentException("Quartz Cron 表达式必须包含 6 或 7 个字段");
|
||||
}
|
||||
try {
|
||||
CronExpression expression = new CronExpression(normalized);
|
||||
expression.setTimeZone(TASK_TIME_ZONE);
|
||||
return expression;
|
||||
} catch (ParseException e) {
|
||||
throw new IllegalArgumentException("无效的 Quartz Cron 表达式:" + e.getMessage(), e);
|
||||
}
|
||||
return executionTimes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class SecurityUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户社团ID
|
||||
* 获取当前用户协会ID
|
||||
*/
|
||||
public static List<String> getClubIds() {
|
||||
String clubIds = getSession().get("clubIds").toString();
|
||||
|
||||
@@ -16,6 +16,8 @@ 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.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -25,6 +27,7 @@ import java.util.Set;
|
||||
|
||||
@IocBean(create = "init")
|
||||
public class Globals {
|
||||
private static final Log log = Logs.get();
|
||||
//项目路径
|
||||
public static String AppRoot = "";
|
||||
//项目目录
|
||||
@@ -69,15 +72,12 @@ public class Globals {
|
||||
}
|
||||
|
||||
public void initTask(SysTaskService sysTaskService) {
|
||||
taskPlatformService.clear();
|
||||
List<Sys_task> taskList = sysTaskService.query();
|
||||
for (Sys_task sysTask : taskList) {
|
||||
try {
|
||||
if (!sysTask.isDisabled())//不存在则新建
|
||||
taskPlatformService.add(sysTask.getId(), sysTask.getId(), sysTask.getJobClass(), sysTask.getCron()
|
||||
, sysTask.getNote(), sysTask.getData());
|
||||
taskPlatformService.restore(sysTask);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.error("恢复定时任务失败:" + sysTask.getName() + " (" + sysTask.getId() + ")", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.log.Log;
|
||||
import org.nutz.log.Logs;
|
||||
import org.nutz.plugins.mvc.websocket.AbstractWsEndpoint;
|
||||
import org.nutz.plugins.mvc.websocket.NutWsConfigurator;
|
||||
import org.nutz.plugins.mvc.websocket.WsHandler;
|
||||
import redis.clients.jedis.*;
|
||||
|
||||
@@ -21,7 +20,7 @@ import javax.websocket.server.ServerEndpoint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ServerEndpoint(value = "/websocket", configurator = NutWsConfigurator.class)
|
||||
@ServerEndpoint(value = "/websocket", configurator = WkWsConfigurator.class)
|
||||
@IocBean(create = "init") // 使用NutWsConfigurator的必备条件
|
||||
public class WkWebSocket extends AbstractWsEndpoint implements PubSub {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public class CommonController {
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
@ApiOperation("社团列表")
|
||||
@ApiOperation("协会列表")
|
||||
public Result clubOptions(String clubId) {
|
||||
List<SysClub> sysClubs = sysClubService.dao().query(SysClub.class,
|
||||
Cnd.NEW().andEX("id", "=", clubId));
|
||||
|
||||
+2
-2
@@ -355,7 +355,7 @@ public class ActivityBasicScopeController {
|
||||
boolean isBranchUnionChairman = AuthUtil.hasRole(RoleConstant.BRANCH_UNION_CHAIRMAN.name());
|
||||
boolean isClubPresident = AuthUtil.hasRole(RoleConstant.CLUB_PRESIDENT.name());
|
||||
if (isBranchUnionChairman && isClubPresident) {
|
||||
// 同时具备分工会主席和社团会长身份时,未额外筛选前默认查看两类权限范围的并集。
|
||||
// 同时具备分工会主席和协会会长身份时,未额外筛选前默认查看两类权限范围的并集。
|
||||
List<String> manageClubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
SqlExpressionGroup scopeGroup = new SqlExpressionGroup();
|
||||
scopeGroup.or("u.unionid", "=", SecurityUtil.getUnionId());
|
||||
@@ -364,7 +364,7 @@ public class ActivityBasicScopeController {
|
||||
}
|
||||
cnd.and(scopeGroup);
|
||||
} else if (isClubPresident) {
|
||||
// 社团会长设置活动人员范围时,只允许查看自己可管理社团下的成员。
|
||||
// 协会会长设置活动人员范围时,只允许查看自己可管理协会下的成员。
|
||||
List<String> manageClubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
if (manageClubIdList.isEmpty()) {
|
||||
cnd.and("clubuser.clubid", "in", List.of("__EMPTY_CLUB_ID__"));
|
||||
|
||||
+10
-2
@@ -54,9 +54,8 @@ public class ActivityBasicSettingsController {
|
||||
if (parentId != null) {
|
||||
parentId.setChild(child(parentId.getId()));
|
||||
list.add(parentId);
|
||||
return Result.success().addData(list);
|
||||
}
|
||||
return Result.success();
|
||||
return Result.success(list);
|
||||
}
|
||||
|
||||
private List<ActivityBasicSettings> child(String parentId) {
|
||||
@@ -73,6 +72,9 @@ public class ActivityBasicSettingsController {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
if (StrUtil.isBlank(parentId)) {
|
||||
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());
|
||||
} else {
|
||||
cnd.and("parentId", "=", parentId);
|
||||
@@ -116,7 +118,13 @@ public class ActivityBasicSettingsController {
|
||||
|
||||
@At
|
||||
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));
|
||||
if (fetch == null) {
|
||||
return Result.success(new ArrayList<ActivityBasicSettings>());
|
||||
}
|
||||
List<ActivityBasicSettings> query = dao.query(ActivityBasicSettings.class, Cnd.where("parentId", "=", fetch.getId()).asc("code"));
|
||||
return Result.success(query);
|
||||
}
|
||||
|
||||
+35
@@ -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();
|
||||
}
|
||||
+115
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
+93
@@ -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());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -162,7 +162,7 @@ public class ActivityCultureUserStatisticsController {
|
||||
if (activity_type == 40002) {
|
||||
cnd.and("tissue.unionId", "=", SecurityUtil.getUnionId());
|
||||
} else if (activity_type == 40003) {
|
||||
// 协会会长进入社团报名统计时,只允许查看自己管理社团下的活动名称。
|
||||
// 协会会长进入协会报名统计时,只允许查看自己管理协会下的活动名称。
|
||||
List<SysClub> myManageClub = sysClubService.getMyManageClub();
|
||||
List<String> clubIdList = myManageClub.stream().map(SysClub::getId).collect(Collectors.toList());
|
||||
cnd.and("tissue.clubId", "in", clubIdList);
|
||||
|
||||
@@ -19,7 +19,7 @@ import java.util.List;
|
||||
/**
|
||||
* @author: Aaron
|
||||
* @create: 2021-03-09 13:57
|
||||
* @description: 社团或分工会活动校工会活动
|
||||
* @description: 协会或分工会活动校工会活动
|
||||
**/
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@@ -147,7 +147,7 @@ public class ActivityTissue extends BaseModel implements Serializable, SysHomeCo
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("创建人所属社团")
|
||||
@Comment("创建人所属协会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ActivityTissuePerson extends BaseModel implements Serializable {
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("分工会或社团活动ID")
|
||||
@Comment("分工会或协会活动ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String tissueId;
|
||||
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
*/
|
||||
@IocBean
|
||||
@Ok("json")
|
||||
@ApiOperation("活动申报,社团负责人审核")
|
||||
@ApiOperation("活动申报,协会负责人审核")
|
||||
@At("/platform/activityDeclare/clubPrincipal")
|
||||
public class ActivityDeclareClubPrincipalController {
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ActivityDeclareClubPrincipalController {
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("活动申报,社团负责人审核列表")
|
||||
@ApiOperation("活动申报,协会负责人审核列表")
|
||||
@SaCheckPermission("activityDeclare.clubPrincipal")
|
||||
public Result pageData(CommonPageParam pageParam) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
+2
-2
@@ -222,8 +222,8 @@ public class ActivityDeclareMineController {
|
||||
docData.put("fgh", approval);
|
||||
});
|
||||
|
||||
// 社团负责人审核
|
||||
doneTaskVos.stream().filter(task -> "社团负责人审核".equals(task.getDisplayName()))
|
||||
// 协会负责人审核
|
||||
doneTaskVos.stream().filter(task -> "协会负责人审核".equals(task.getDisplayName()))
|
||||
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
|
||||
.ifPresent(v -> {
|
||||
Dict taskFormData = v.getTaskFormData();
|
||||
|
||||
+2
-2
@@ -58,7 +58,7 @@ public class ActivityDeclareInfo extends BaseModel {
|
||||
private String mobile;
|
||||
|
||||
@Column
|
||||
@Comment("申报单位(校工会/二级工会名称/社团名称)")
|
||||
@Comment("申报单位(校工会/二级工会名称/协会名称)")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 200)
|
||||
private String declareUnitName;
|
||||
|
||||
@@ -68,7 +68,7 @@ public class ActivityDeclareInfo extends BaseModel {
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@Comment("社团id")
|
||||
@Comment("协会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
|
||||
+2
-2
@@ -25,9 +25,9 @@ public enum ActivityDeclareReimbursement {
|
||||
*/
|
||||
BRANCH_UNION("分工会活动"),
|
||||
/**
|
||||
* 社团
|
||||
* 协会
|
||||
*/
|
||||
CLUB("社团活动");
|
||||
CLUB("协会活动");
|
||||
|
||||
private final String typeName;
|
||||
}
|
||||
|
||||
+5
-5
@@ -110,7 +110,7 @@ public class ActivityReimbursementBoardController {
|
||||
|
||||
list.add(new NutMap() {{
|
||||
put("year", year);
|
||||
put("type", "社团活动");
|
||||
put("type", "协会活动");
|
||||
put("num", activityReimbursementService.count(sql.setParam("type", "ACTIVITY_BUDGET_TYPE_THREE").setParam("year", year)));
|
||||
}});
|
||||
}
|
||||
@@ -145,7 +145,7 @@ public class ActivityReimbursementBoardController {
|
||||
put("num", activityReimbursementService.count(sql.setParam("type", "ACTIVITY_BUDGET_TYPE_TWO")));
|
||||
}});
|
||||
list.add(new NutMap() {{
|
||||
put("type", "社团活动");
|
||||
put("type", "协会活动");
|
||||
put("num", activityReimbursementService.count(sql.setParam("type", "ACTIVITY_BUDGET_TYPE_THREE")));
|
||||
}});
|
||||
return Result.success(list);
|
||||
@@ -191,7 +191,7 @@ public class ActivityReimbursementBoardController {
|
||||
|
||||
list.add(new NutMap() {{
|
||||
put("year", year);
|
||||
put("type", "社团费用");
|
||||
put("type", "协会费用");
|
||||
put("num", activityReimbursementService.list(sql.setParam("type", "ACTIVITY_BUDGET_TYPE_THREE").setParam("year", year)).get(0).getDouble("money"));
|
||||
}});
|
||||
}
|
||||
@@ -218,7 +218,7 @@ public class ActivityReimbursementBoardController {
|
||||
put("num", activityReimbursementService.count(unionSql));
|
||||
}});
|
||||
list.add(new NutMap() {{
|
||||
put("type", "社团费用");
|
||||
put("type", "协会费用");
|
||||
put("num", activityReimbursementService.count(clubSql));
|
||||
}});
|
||||
return Result.success().addData(list);
|
||||
@@ -250,7 +250,7 @@ public class ActivityReimbursementBoardController {
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("所有社团的报销费用或活动数统计")
|
||||
@ApiOperation("所有协会的报销费用或活动数统计")
|
||||
@SaCheckPermission("activityReimbursement.board")
|
||||
public Result allClubActivityAndMoney(Integer year, Boolean isClubMoney) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
*/
|
||||
@IocBean
|
||||
@Ok("json")
|
||||
@ApiOperation("活动报销,社团负责人审核")
|
||||
@ApiOperation("活动报销,协会负责人审核")
|
||||
@At("/platform/activityReimbursement/clubPrincipal")
|
||||
public class ActivityReimbursementClubPrincipalController {
|
||||
|
||||
@@ -51,7 +51,7 @@ public class ActivityReimbursementClubPrincipalController {
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("活动报销,社团负责人审核列表")
|
||||
@ApiOperation("活动报销,协会负责人审核列表")
|
||||
@SaCheckPermission("activityReimbursement.clubPrincipal")
|
||||
public Result pageData(CommonPageParam pageParam) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
+2
-2
@@ -323,8 +323,8 @@ public class ActivityReimbursementMineController {
|
||||
docData.put("fgh", approval);
|
||||
});
|
||||
|
||||
// 社团负责人审核
|
||||
doneTaskVos.stream().filter(task -> "社团负责人审核".equals(task.getDisplayName()))
|
||||
// 协会负责人审核
|
||||
doneTaskVos.stream().filter(task -> "协会负责人审核".equals(task.getDisplayName()))
|
||||
.max(Comparator.comparing(ProcessTaskVO::getCreatedAt))
|
||||
.ifPresent(v -> {
|
||||
Dict taskFormData = v.getTaskFormData();
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ public class YearPlanController {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("获取社团")
|
||||
@ApiOperation("获取协会")
|
||||
@SaCheckPermission("planSummary.yearPlan.manage")
|
||||
public Result queryClub() {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
|
||||
@@ -51,17 +51,17 @@ public class YearPlan extends BaseModel {
|
||||
private Double money;
|
||||
|
||||
@Column
|
||||
@Comment("计划类型(40001-校活动、40002-分工会活动、40003-社团社团活动)")
|
||||
@Comment("计划类型(40001-校活动、40002-分工会活动、40003-协会协会活动)")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 7)
|
||||
private String planType;
|
||||
|
||||
@Column
|
||||
@Comment("分工会ID或社团ID")
|
||||
@Comment("分工会ID或协会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String tissueId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会或社团")
|
||||
@Comment("分工会或协会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String tissueName;
|
||||
|
||||
|
||||
@@ -72,12 +72,12 @@ public class YearSummary extends BaseModel {
|
||||
private String cTime;
|
||||
|
||||
@Column
|
||||
@Comment("工会/社团id")
|
||||
@Comment("工会/协会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String tissueId;
|
||||
|
||||
@Column
|
||||
@Comment("分工会或社团")
|
||||
@Comment("分工会或协会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String tissueName;
|
||||
|
||||
@@ -87,7 +87,7 @@ public class YearSummary extends BaseModel {
|
||||
private String summaryType;
|
||||
|
||||
@Column
|
||||
@Comment("总结来源(1-校活动、2-分工会活动、3社团社团活动)")
|
||||
@Comment("总结来源(1-校活动、2-分工会活动、3协会协会活动)")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String summaryFrom;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public class ActivitySchool extends BaseModel implements Serializable , SysHomeC
|
||||
private Boolean close;
|
||||
|
||||
@Column
|
||||
@Comment("活动级别(40001-校级、40002-分工会、40003-社团或社团)")
|
||||
@Comment("活动级别(40001-校级、40002-分工会、40003-协会或协会)")
|
||||
@ColDefine(type = ColType.INT, width = 10)
|
||||
private Integer activityLevel;
|
||||
|
||||
@@ -198,7 +198,7 @@ public class ActivitySchool extends BaseModel implements Serializable , SysHomeC
|
||||
private String belongUnionId;
|
||||
|
||||
@Column
|
||||
@Comment("活动所属社团")
|
||||
@Comment("活动所属协会")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String belongClubId;
|
||||
|
||||
|
||||
+1
-1
@@ -326,7 +326,7 @@ public class TrainSignUpManageController {
|
||||
|
||||
@At
|
||||
@Ok("json:full")
|
||||
@ApiOperation("查询分工会和社团")
|
||||
@ApiOperation("查询分工会和协会")
|
||||
@SaCheckPermission(value = {"trainSignUp.manage", "trainSignUp.applyActivity"}, mode = SaMode.OR)
|
||||
public Result selectUnitAndClub() {
|
||||
List<NutMap> result = new ArrayList<>();
|
||||
|
||||
+4
-1
@@ -649,8 +649,11 @@ public class TrainSignUpActivityServiceImpl extends BaseServiceImpl<TrainSignUpA
|
||||
fillCourseResponsibles(courseList);
|
||||
|
||||
courseList.forEach(c -> {
|
||||
dao().fetchLinks(c, "^(courseTimeList)$", Cnd.NEW().asc("courseStartTime"));
|
||||
if (c.getCourseTimeList() == null) {
|
||||
c.setCourseTimeList(new ArrayList<>());
|
||||
}
|
||||
if (StrUtil.isNotBlank(c.getCourseType())) {
|
||||
dao().fetchLinks(c, "^(courseTimeList)$", Cnd.NEW().asc("courseStartTime"));
|
||||
int courseCount = statisticsService.queryCourseCount(c.getId(), c.getCourseType());
|
||||
c.setHasRegisterNum(courseCount);
|
||||
int courseWaitCount = statisticsService.queryCourseWaitCount(c.getId(), c.getCourseType());
|
||||
|
||||
+3
-3
@@ -49,9 +49,9 @@ public class ClubUserClubListController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开移动端社团列表,共用电脑端的社团查询及入退会状态。
|
||||
* 打开移动端协会列表,共用电脑端的协会查询及入退会状态。
|
||||
*
|
||||
* @return 无返回值,由模板渲染社团列表页面
|
||||
* @return 无返回值,由模板渲染协会列表页面
|
||||
*/
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/club/list/index.html")
|
||||
@@ -85,7 +85,7 @@ public class ClubUserClubListController {
|
||||
@At
|
||||
@SaCheckPermission(value = {"club.join.list", "h5.club.join.list", "h5.club.join.apply"}, mode = SaMode.OR)
|
||||
public Result getCount() {
|
||||
// 获取所有社团
|
||||
// 获取所有协会
|
||||
List<SysClub> list = sysClubService.query();
|
||||
// 获取审核通过的
|
||||
List<ProcessInstance> instanceList = sysClubService.dao().query(
|
||||
|
||||
+11
-11
@@ -51,7 +51,7 @@ import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/club/join/apply")
|
||||
@Api("社团申请入会、退会")
|
||||
@Api("协会申请入会、退会")
|
||||
@Ok("json:full")
|
||||
public class ClubUserJoinApplyController {
|
||||
|
||||
@@ -75,12 +75,12 @@ public class ClubUserJoinApplyController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动端首次入会先选择社团,已选社团或已有申请继续进入申请表单。
|
||||
* 移动端首次入会先选择协会,已选协会或已有申请继续进入申请表单。
|
||||
*
|
||||
* @param clubId 已选择的社团ID
|
||||
* @param clubId 已选择的协会ID
|
||||
* @param bizId 已有入会申请ID
|
||||
* @param taskId 重新提交申请时的流程任务ID
|
||||
* @return 无申请上下文时跳转社团列表,否则渲染原申请页面
|
||||
* @return 无申请上下文时跳转协会列表,否则渲染原申请页面
|
||||
*/
|
||||
@At("/h5")
|
||||
@SaCheckPermission("h5.club.join.apply")
|
||||
@@ -124,7 +124,7 @@ public class ClubUserJoinApplyController {
|
||||
@ApiOperation("保存申请")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"club.join.apply", "h5.club.join.apply"}, mode = SaMode.OR)
|
||||
@SLog(tag = "社团管理系统-申请入会", msg = "保存社团入会")
|
||||
@SLog(tag = "协会管理系统-申请入会", msg = "保存协会入会")
|
||||
public Result save(@Param("data") ClubUserApply clubUserApply) {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setMode(1);
|
||||
@@ -138,7 +138,7 @@ public class ClubUserJoinApplyController {
|
||||
@ApiOperation("提交")
|
||||
@SaCheckPermission(value = {"club.join.apply", "h5.club.join.apply"}, mode = SaMode.OR)
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SLog(tag = "社团管理系统-申请入/退会", msg = "申请社团入/退会")
|
||||
@SLog(tag = "协会管理系统-申请入/退会", msg = "申请协会入/退会")
|
||||
public Result submit(@Param("data") ClubUserApply clubUserApply,
|
||||
@Param("mode") Boolean mode) {
|
||||
if (Boolean.TRUE.equals(mode)) {
|
||||
@@ -150,14 +150,14 @@ public class ClubUserJoinApplyController {
|
||||
if(mode == false) {
|
||||
clubUserApply = clubUserJoinService.buildExitApply(clubUserApply.getClubId(), SecurityUtil.getUserId());
|
||||
if (ObjectUtil.isEmpty(clubUserApply)) {
|
||||
return Result.error("当前不是该社团成员,无法申请退出!");
|
||||
return Result.error("当前不是该协会成员,无法申请退出!");
|
||||
}
|
||||
}
|
||||
ClubUserApply userApply = dao.fetch(ClubUserApply.class, Cnd.where("userId", "=", clubUserApply.getUserId()).and("clubId", "=", clubUserApply.getClubId()).and("mode", "=", mode).desc(ClubUserApply::getApplyDate));
|
||||
if (ObjectUtil.isNotEmpty(userApply) && StrUtil.isNotBlank(userApply.getId())) {
|
||||
ProcessInstance processInstance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", userApply.getId()));
|
||||
if (processInstance != null && !List.of(ProcessInstanceStateEnum.REJECT.getCode(), ProcessInstanceStateEnum.FINISHED.getCode()).contains(processInstance.getState())) {
|
||||
return Result.error("您有该社团的申请记录尚未完成,请到我的申请里查看!");
|
||||
return Result.error("您有该协会的申请记录尚未完成,请到我的申请里查看!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ public class ClubUserJoinApplyController {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("校验是否申请过社团")
|
||||
@ApiOperation("校验是否申请过协会")
|
||||
@SaCheckPermission(value = {"club.join.apply", "h5.club.join.apply"}, mode = SaMode.OR)
|
||||
public Result checkApplyClub(@Valid String clubId) {
|
||||
String qualificationMsg = clubUserJoinService.checkJoinQualification(SecurityUtil.getUserId());
|
||||
@@ -234,10 +234,10 @@ public class ClubUserJoinApplyController {
|
||||
ProcessInstance processInstance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", userApply.getId()));
|
||||
// 申请记录存在但没有流程实例时,说明用户仅保存了申请草稿,需提示其先到“我的申请”继续提交。
|
||||
if (processInstance == null) {
|
||||
return Result.error(99, "您有该社团的申请记录尚未提交,请到我的申请里查看!");
|
||||
return Result.error(99, "您有该协会的申请记录尚未提交,请到我的申请里查看!");
|
||||
}
|
||||
if (!List.of(ProcessInstanceStateEnum.REJECT.getCode(), ProcessInstanceStateEnum.FINISHED.getCode()).contains(processInstance.getState())) {
|
||||
return Result.error(99, "您有该社团的申请记录尚未完成,请到我的申请里查看!");
|
||||
return Result.error(99, "您有该协会的申请记录尚未完成,请到我的申请里查看!");
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
+3
-3
@@ -59,8 +59,8 @@ public class ClubUserJoinMineController {
|
||||
@SaCheckPermission(value = {"club.join.mine", "h5.club.join.mine"}, mode = SaMode.OR)
|
||||
/**
|
||||
* 我的申请分页查询。
|
||||
* pageForm 为分页参数,year 为申请年度,clubName 为可选的社团名称关键字;
|
||||
* 返回分页后的当前用户社团申请记录。
|
||||
* pageForm 为分页参数,year 为申请年度,clubName 为可选的协会名称关键字;
|
||||
* 返回分页后的当前用户协会申请记录。
|
||||
*/
|
||||
public Result pageData(@Valid PageForm pageForm,
|
||||
@Param("year") Integer year,
|
||||
@@ -135,7 +135,7 @@ public class ClubUserJoinMineController {
|
||||
@SaCheckPermission(value = {"club.join.mine", "h5.club.join.mine"}, mode = SaMode.OR)
|
||||
@ApiOperation("删除")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SLog(tag = "社团管理系统-申请入会-我的申请", msg = "删除社团入会")
|
||||
@SLog(tag = "协会管理系统-申请入会-我的申请", msg = "删除协会入会")
|
||||
public Result delete(@Valid String id) {
|
||||
dao.delete(ClubUserApply.class, id);
|
||||
dao.delete(ClubUser.class, id);
|
||||
|
||||
+4
-4
@@ -51,8 +51,8 @@ public class ClubUserMineClubController {
|
||||
@At
|
||||
@SaCheckPermission(value = {"club.join.mine.club", "h5.club.join.mine.club"}, mode = SaMode.OR)
|
||||
/**
|
||||
* 我的社团分页查询。
|
||||
* pageForm 传入分页参数及可选社团名称;返回当前登录人已完成入会流程的社团列表,
|
||||
* 我的协会分页查询。
|
||||
* pageForm 传入分页参数及可选协会名称;返回当前登录人已完成入会流程的协会列表,
|
||||
* 每条记录同时包含当前成员姓名、工号和最近一次入会申请 ID,供 H5 卡片及详情页展示。
|
||||
*/
|
||||
public Result pageData(@Valid ClubUserPageForm pageForm) {
|
||||
@@ -79,7 +79,7 @@ public class ClubUserMineClubController {
|
||||
FROM
|
||||
sys_club club
|
||||
LEFT JOIN club_user uc ON club.id = uc.clubId
|
||||
-- 查询当前登录人的成员资料及最近一次入会申请,避免卡片标题错误显示为社团名称。
|
||||
-- 查询当前登录人的成员资料及最近一次入会申请,避免卡片标题错误显示为协会名称。
|
||||
LEFT JOIN club_user currentClubUser ON currentClubUser.clubId = club.id AND currentClubUser.userId = @currentUserId
|
||||
LEFT JOIN sys_user currentUser ON currentUser.id = currentClubUser.userId
|
||||
LEFT JOIN (
|
||||
@@ -97,7 +97,7 @@ public class ClubUserMineClubController {
|
||||
""");
|
||||
sql.setParam("currentUserId", SecurityUtil.getUserId());
|
||||
Cnd cnd = Cnd.NEW();
|
||||
// 社团名称为可选搜索参数,输入关键字时按名称模糊匹配。
|
||||
// 协会名称为可选搜索参数,输入关键字时按名称模糊匹配。
|
||||
if (Strings.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "like", "%" + pageForm.getClubName().trim() + "%");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ClubCommonController {
|
||||
private SysFileService sysFileService;
|
||||
|
||||
/**
|
||||
* 上传社团缩略图,限制图片大小并复用系统文件服务校验图片内容及保存文件。
|
||||
* 上传协会缩略图,限制图片大小并复用系统文件服务校验图片内容及保存文件。
|
||||
*
|
||||
* @param file 用户上传的 JPG、PNG 或 GIF 图片,大小不得超过 2MB
|
||||
* @return 成功时返回图片下载地址,文件无效或超过限制时返回错误提示
|
||||
@@ -63,14 +63,14 @@ public class ClubCommonController {
|
||||
@SaCheckPermission(value = {"club.register.apply", "club.infoManage.manage"}, mode = SaMode.OR)
|
||||
public Result uploadThumbnail(@Param("file") TempFile file) {
|
||||
if (file == null || StrUtil.isBlank(file.getSubmittedFileName())) {
|
||||
return Result.error("请选择社团缩略图");
|
||||
return Result.error("请选择协会缩略图");
|
||||
}
|
||||
if (file.getSize() > 2L * 1024 * 1024) {
|
||||
return Result.error("社团缩略图大小不能超过2MB");
|
||||
return Result.error("协会缩略图大小不能超过2MB");
|
||||
}
|
||||
String suffix = FileUtil.extName(file.getSubmittedFileName()).toLowerCase(Locale.ROOT);
|
||||
if (!Set.of("jpg", "jpeg", "png", "gif").contains(suffix)) {
|
||||
return Result.error("社团缩略图仅支持JPG、PNG、GIF图片");
|
||||
return Result.error("协会缩略图仅支持JPG、PNG、GIF图片");
|
||||
}
|
||||
try {
|
||||
return Result.success().addData(sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(), file));
|
||||
@@ -81,7 +81,7 @@ public class ClubCommonController {
|
||||
|
||||
@At
|
||||
@SaCheckLogin
|
||||
/** 无请求参数;返回入会社团选项,每项包含 id、clubName 等社团字段,同一社团不重复。 */
|
||||
/** 无请求参数;返回入会协会选项,每项包含 id、clubName 等协会字段,同一协会不重复。 */
|
||||
public Result listClub() {
|
||||
return Result.success(sysClubService.listJoinClubOptions());
|
||||
}
|
||||
@@ -114,7 +114,7 @@ public class ClubCommonController {
|
||||
@At
|
||||
@SaCheckLogin
|
||||
public Result listManageClubByRole() {
|
||||
// 活动人员范围设置只允许按“可管理的社团”选择,避免把仅作为成员加入的社团也展示出来。
|
||||
// 活动人员范围设置只允许按“可管理的协会”选择,避免把仅作为成员加入的协会也展示出来。
|
||||
List<SysClub> clubList = sysClubService.getMyManageClub();
|
||||
return Result.success(clubList);
|
||||
}
|
||||
|
||||
+2
-2
@@ -69,7 +69,7 @@ public class ClubEvaluateApplyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.evaluate.apply")
|
||||
@SLog(tag = "社团管理系统-社团评优", msg = "保存社团评优申请")
|
||||
@SLog(tag = "协会管理系统-协会评优", msg = "保存协会评优申请")
|
||||
public Result save(@Param("data") SysClubEvaluate evaluate) {
|
||||
evaluateService.dao().insertOrUpdate(evaluate);
|
||||
return Result.success(evaluate);
|
||||
@@ -78,7 +78,7 @@ public class ClubEvaluateApplyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.evaluate.apply")
|
||||
@SLog(tag = "社团管理系统-社团评优", msg = "提交社团评优")
|
||||
@SLog(tag = "协会管理系统-协会评优", msg = "提交协会评优")
|
||||
public Result submit(@Valid @Param("data") SysClubEvaluate evaluate) {
|
||||
evaluateService.dao().insertOrUpdate(evaluate);
|
||||
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ public class ClubEvaluateMineController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.evaluate.mine")
|
||||
@SLog(tag = "社团管理系统-社团评优", msg = "删除社团评优")
|
||||
@SLog(tag = "协会管理系统-协会评优", msg = "删除协会评优")
|
||||
public Result doDelete(@Valid String id) {
|
||||
sysClubEvaluateService.dao().delete(SysClubEvaluate.class, id);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
|
||||
|
||||
+10
-10
@@ -71,12 +71,12 @@ public class ClubExamineApplyController {
|
||||
@SaCheckLogin
|
||||
public Result getCount(String id, Integer year, String clubId) {
|
||||
if(StrUtil.isBlank(clubId)) {
|
||||
return Result.error("社团信息为空,请核查");
|
||||
return Result.error("协会信息为空,请核查");
|
||||
}
|
||||
if(year == null) {
|
||||
return Result.error("年份信息为空,请核查");
|
||||
}
|
||||
// 同一社团的年度重复申请校验以登记年度为准,不能按申请时间判断。
|
||||
// 同一协会的年度重复申请校验以登记年度为准,不能按申请时间判断。
|
||||
List<SysClubExamineRegister> list = dao.query(SysClubExamineRegister.class, Cnd.where("clubId", "=", clubId).and("year", "=", year).andEX("id", "!=", id));
|
||||
List<ProcessInstance> instanceList = dao.query(
|
||||
ProcessInstance.class,
|
||||
@@ -98,7 +98,7 @@ public class ClubExamineApplyController {
|
||||
// @SaCheckLogin
|
||||
// public Result getClubUserNum(String clubId, Integer year) {
|
||||
// if(StrUtil.isBlank(clubId)) {
|
||||
// return Result.error("社团信息为空,请核查");
|
||||
// return Result.error("协会信息为空,请核查");
|
||||
// }
|
||||
// List<NutMap> result = sysClubExamineService.getClubUserNum(clubId, year);
|
||||
// return Result.success(result);
|
||||
@@ -107,13 +107,13 @@ public class ClubExamineApplyController {
|
||||
//
|
||||
/**
|
||||
* 2026年10月2日22:00点开始新开发的代码;实际整改:2026年10月3日 10:14:04;操作人:wxg。
|
||||
* 接收 clubId(所选社团ID)、year(公历年度),基础校验后调用 service;
|
||||
* 接收 clubId(所选协会ID)、year(公历年度),基础校验后调用 service;
|
||||
* 返回 Result,data为两类计数及统计核查信息列表,异常参数返回错误提示。
|
||||
*/
|
||||
@At
|
||||
@SaCheckLogin
|
||||
public Result getClubUserNum(String clubId, Integer year) {
|
||||
if (StrUtil.isBlank(clubId)) return Result.error("社团信息为空,请核查");
|
||||
if (StrUtil.isBlank(clubId)) return Result.error("协会信息为空,请核查");
|
||||
if (year == null || year < 1 || year > 9998) return Result.error("请选择有效统计年度");
|
||||
return Result.success(sysClubExamineService.getClubUserNum(clubId, year));
|
||||
}
|
||||
@@ -122,7 +122,7 @@ public class ClubExamineApplyController {
|
||||
@SaCheckLogin
|
||||
public Result getJgUser(String clubId) {
|
||||
if(StrUtil.isBlank(clubId)) {
|
||||
return Result.error("社团信息为空,请核查");
|
||||
return Result.error("协会信息为空,请核查");
|
||||
}
|
||||
List<NutMap> result = sysClubExamineService.getJgUser(clubId);
|
||||
return Result.success(result);
|
||||
@@ -132,7 +132,7 @@ public class ClubExamineApplyController {
|
||||
@SaCheckLogin
|
||||
public Result getClubMemberMoney(String clubId) {
|
||||
if(StrUtil.isBlank(clubId)) {
|
||||
return Result.error("社团信息为空,请核查");
|
||||
return Result.error("协会信息为空,请核查");
|
||||
}
|
||||
int count = dao.count(ClubUser.class, Cnd.where("clubId", "=", clubId));
|
||||
SysClub club = dao.fetch(SysClub.class, clubId);
|
||||
@@ -160,7 +160,7 @@ public class ClubExamineApplyController {
|
||||
@SaCheckLogin
|
||||
public Result getLastYearSurplus(String clubId) {
|
||||
if(StrUtil.isBlank(clubId)) {
|
||||
return Result.error("社团信息为空,请核查");
|
||||
return Result.error("协会信息为空,请核查");
|
||||
}
|
||||
// 上年度结余按登记年度查询,避免申请时间跨年导致取错数据。
|
||||
SysClubExamineRegister register = dao.fetch(SysClubExamineRegister.class, Cnd.where("clubId", "=", clubId)
|
||||
@@ -186,7 +186,7 @@ public class ClubExamineApplyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.examine.apply")
|
||||
@SLog(tag = "社团管理系统-社团年审", msg = "保存社团年审")
|
||||
@SLog(tag = "协会管理系统-协会年审", msg = "保存协会年审")
|
||||
public Result save(@Param("data") SysClubExamineRegister examineRegister,
|
||||
@Param("incomeDetailed") String incomeDetailed,
|
||||
@Param("incomeCensus") String incomeCensus) {
|
||||
@@ -201,7 +201,7 @@ public class ClubExamineApplyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.examine.apply")
|
||||
@SLog(tag = "社团管理系统-社团年审", msg = "提交社团年审")
|
||||
@SLog(tag = "协会管理系统-协会年审", msg = "提交协会年审")
|
||||
public Result submit(@Param("data") SysClubExamineRegister examineRegister,
|
||||
@Param("incomeDetailed") String incomeDetailed,
|
||||
@Param("incomeCensus") String incomeCensus) {
|
||||
|
||||
+2
-2
@@ -48,7 +48,7 @@ public class ClubExamineMineController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.examine.mine")
|
||||
@SLog(tag = "社团管理系统-社团年审", msg = "删除社团年审")
|
||||
@SLog(tag = "协会管理系统-协会年审", msg = "删除协会年审")
|
||||
public Result doDelete(@Valid String id) {
|
||||
sysClubExamineService.delete(id);
|
||||
sysClubExamineService.dao().clear(SysClubExamineRegisterDetailed.class, Cnd.where("registerId", "=", id));
|
||||
@@ -108,7 +108,7 @@ public class ClubExamineMineController {
|
||||
.bind("activityQk", activityQk).build();
|
||||
|
||||
try {
|
||||
String fileName = Globals.MyConfig.getString("AppName") + "教职工社团年度考核登记表";
|
||||
String fileName = Globals.MyConfig.getString("AppName") + "教职工协会年度考核登记表";
|
||||
response.addHeader("Content-Type", "application/octet-stream");
|
||||
response.addHeader("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + "\".docx");
|
||||
XWPFTemplate.compile(officeTemplateUtil.getPath("club_examine_register"), config).render(map).writeAndClose(response.getOutputStream());
|
||||
|
||||
+3
-3
@@ -135,7 +135,7 @@ public class ClubChangeManagerController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.change")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "提交变更理事机构")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "提交变更理事机构")
|
||||
public Object submit(@Param("data") SysClubManager clubManager) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubManager::getClubId, "=", clubManager.getClubId());
|
||||
@@ -146,7 +146,7 @@ public class ClubChangeManagerController {
|
||||
List<String> pendingProcessIds = managerList.stream().map(SysClubManager::getId).toList();
|
||||
int pendingCount = dao.count(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", pendingProcessIds).and(ProcessInstance::getState, "not in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (pendingCount > 0) {
|
||||
return Result.error("您有该社团的申请记录尚未完成,请核对!");
|
||||
return Result.error("您有该协会的申请记录尚未完成,请核对!");
|
||||
}
|
||||
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
@@ -206,7 +206,7 @@ public class ClubChangeManagerController {
|
||||
@ApiOperation("删除")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.change")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "删除变更理事机构")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "删除变更理事机构")
|
||||
public Result delete(@Param("id") String id) {
|
||||
dao.delete(SysClubManager.class, id);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
|
||||
|
||||
+13
-13
@@ -111,7 +111,7 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "修改社团信息")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "修改协会信息")
|
||||
public Result doSubmit(@Param("club") SysClub club) {
|
||||
clubInfoManageService.dao().update(club);
|
||||
return Result.success();
|
||||
@@ -120,7 +120,7 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "修改缴费状态")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "修改缴费状态")
|
||||
public Result updatePayed(@Valid Boolean payed, @Valid String id) {
|
||||
clubInfoManageService.dao().update(ClubUser.class, Chain.make("payed", payed), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
@@ -129,7 +129,7 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "修改拨付状态")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "修改拨付状态")
|
||||
public Result updateGive(@Valid Boolean giveMoney, @Valid String id) {
|
||||
clubInfoManageService.dao().update(ClubUser.class, Chain.make("giveMoney", giveMoney), Cnd.where("id", "=", id));
|
||||
return Result.success();
|
||||
@@ -138,7 +138,7 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "退会")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "退会")
|
||||
public Result exitClub(@Valid String id) {
|
||||
clubInfoManageService.exitClub(id);
|
||||
return Result.success();
|
||||
@@ -147,7 +147,7 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "删除社团成员")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "删除协会成员")
|
||||
public Result userDelete(@Valid String id) {
|
||||
ClubUser clubUser = dao.fetch(ClubUser.class, id);
|
||||
dao.delete(ClubUser.class,id);
|
||||
@@ -188,11 +188,11 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "修改身份")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "修改身份")
|
||||
public Result updateRoleCode(@Param("id") String id, @Valid String[] roleCodes, @Valid String clubId) {
|
||||
List<String> roleCodeList = Arrays.asList(roleCodes);
|
||||
ClubUser clubUser = clubInfoManageService.dao().fetch(ClubUser.class, id);
|
||||
//查询社团是否存在会长或者秘书长
|
||||
//查询协会是否存在会长或者秘书长
|
||||
if(Arrays.asList(roleCodes).contains(RoleConstant.CLUB_PRESIDENT.name())) {
|
||||
int count = dao.count(ClubUser.class, Cnd.where("clubId", "=", clubId)
|
||||
.and(new Static("JSON_CONTAINS(roleCode, '\"%s\"')".formatted(RoleConstant.CLUB_PRESIDENT.name()))));
|
||||
@@ -265,10 +265,10 @@ public class ClubInfoManageController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.manage")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "添加社团成员")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "添加协会成员")
|
||||
public Result userDoAdd(@Valid String clubId, @Valid String[] users, @Valid String roleCode, @Valid Boolean payed) {
|
||||
|
||||
//查询社团是否存在会长或者秘书长
|
||||
//查询协会是否存在会长或者秘书长
|
||||
if (List.of(RoleConstant.CLUB_PRESIDENT.name(), RoleConstant.CLUB_SECRETARY.name()).contains(roleCode)) {
|
||||
int count = clubInfoManageService.dao().count(ClubUser.class, Cnd.where("clubId", "=", clubId)
|
||||
.and(new Static("JSON_CONTAINS(roleCode, '\"%s\"')".formatted(roleCode))));
|
||||
@@ -354,7 +354,7 @@ public class ClubInfoManageController {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clubId 左侧选中的社团ID,用于导出该社团登记表
|
||||
* @param clubId 左侧选中的协会ID,用于导出该协会登记表
|
||||
* @param response 成功时写入 DOCX 附件;失败由统一异常处理返回含 code/msg 的错误结果
|
||||
* @return void,附件直接写入响应,不再渲染 JSON 成功结果
|
||||
*/
|
||||
@@ -372,9 +372,9 @@ public class ClubInfoManageController {
|
||||
public void downloadUserImport(HttpServletResponse response) {
|
||||
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();){
|
||||
EasyExcel.write(byteArrayOutputStream, ClubUserImportVo.class)
|
||||
.sheet("社团会员导入模版")
|
||||
.sheet("协会会员导入模版")
|
||||
.doWrite(ArrayList::new);
|
||||
CommonDownloadUtil.download("社团会员导入模版.xlsx", byteArrayOutputStream.toByteArray() ,response);
|
||||
CommonDownloadUtil.download("协会会员导入模版.xlsx", byteArrayOutputStream.toByteArray() ,response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -405,7 +405,7 @@ public class ClubInfoManageController {
|
||||
continue;
|
||||
}
|
||||
if (clubUsers.stream().anyMatch(s -> s.getUserId().equals(user.getId()))) {
|
||||
v.setErrorInfo("该用户已加入该社团");
|
||||
v.setErrorInfo("该用户已加入该协会");
|
||||
errorInfos.add(v);
|
||||
continue;
|
||||
}
|
||||
|
||||
+5
-5
@@ -28,7 +28,7 @@ import javax.validation.Valid;
|
||||
@Slf4j
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@Api(tags = "社团缴费记录")
|
||||
@Api(tags = "协会缴费记录")
|
||||
@At("/platform/club/pay")
|
||||
public class ClubPayRecordController {
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ClubPayRecordController {
|
||||
@SaCheckPermission("club.infoManage.pay")
|
||||
/**
|
||||
* 2026年10月3日 14:33:18;操作人:wxg:接收查询条件,业务筛选交给 service。
|
||||
* pageForm 为分页和姓名/工号关键字;year 为年度、clubId 为社团ID;
|
||||
* pageForm 为分页和姓名/工号关键字;year 为年度、clubId 为协会ID;
|
||||
* payed/assign 为缴费/拨付状态(1是、0否、空值不限);memberState 为当前会员状态(1在会、0退会、空值全部)。
|
||||
* 返回 Result,data 为分页对象,包含 list、totalCount 等;list.count 为当前会员关系是否存在(1在会、0退会)。
|
||||
*/
|
||||
@@ -62,7 +62,7 @@ public class ClubPayRecordController {
|
||||
return Result.success(payRecordService.pageData(pageForm, year, clubId, payed, assign, memberState));
|
||||
}
|
||||
|
||||
/** 返回当前用户授权社团的下拉选项,字段包含 id、clubName、clubCode。 */
|
||||
/** 返回当前用户授权协会的下拉选项,字段包含 id、clubName、clubCode。 */
|
||||
@At
|
||||
@SaCheckPermission("club.infoManage.pay")
|
||||
public Result listClubs() {
|
||||
@@ -70,9 +70,9 @@ public class ClubPayRecordController {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("修改社团成员缴费状态")
|
||||
@ApiOperation("修改协会成员缴费状态")
|
||||
@SaCheckPermission("club.infoManage.pay")
|
||||
@SLog(tag = "社团管理系统-缴费记录", msg = "修改社团成员缴费状态")
|
||||
@SLog(tag = "协会管理系统-缴费记录", msg = "修改协会成员缴费状态")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result handle(@Param("ids") String[] ids,
|
||||
@Param("payed") Boolean payed) {
|
||||
|
||||
+4
-4
@@ -124,7 +124,7 @@ public class ClubRefreshReportController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.refreshReport")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "提交换届报告")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "提交换届报告")
|
||||
public Object submit(@Param("data") SysClubRefresh clubRefresh) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
@@ -136,7 +136,7 @@ public class ClubRefreshReportController {
|
||||
List<String> idList = list.stream().map(SysClubRefresh::getId).toList();
|
||||
int count = dao.count(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", idList).and(ProcessInstance::getState, "not in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (count > 0) {
|
||||
return Result.error("您有该社团的申请记录尚未完成,请核对!");
|
||||
return Result.error("您有该协会的申请记录尚未完成,请核对!");
|
||||
}
|
||||
|
||||
SysClub club = clubInfoManageService.dao().fetch(SysClub.class, clubRefresh.getClubId());
|
||||
@@ -178,9 +178,9 @@ public class ClubRefreshReportController {
|
||||
@ApiOperation("删除")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.refreshReport")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "删除换届报告")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "删除换届报告")
|
||||
public Result delete(@Param("id") String id) {
|
||||
// 历史换届记录可能与社团注册共用业务编号,必须按流程定义精确定位换届流程,避免误删注册流程。
|
||||
// 历史换届记录可能与协会注册共用业务编号,必须按流程定义精确定位换届流程,避免误删注册流程。
|
||||
List<Long> refreshDefineIds = dao.query(ProcessDefine.class,
|
||||
Cnd.where(ProcessDefine::getName, "=", "XHHJBG"))
|
||||
.stream()
|
||||
|
||||
+150
@@ -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]);
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -123,7 +123,7 @@ public class ClubRuleUpdateController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.ruleUpdate")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "提交章程备案")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "提交章程备案")
|
||||
public Object submit(@Param("data")SysClubRule clubRule) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
@@ -135,7 +135,7 @@ public class ClubRuleUpdateController {
|
||||
List<String> idList = list.stream().map(SysClubRule::getId).toList();
|
||||
int count = dao.count(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", idList).and(ProcessInstance::getState, "not in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (count > 0) {
|
||||
return Result.error("您有该社团的申请记录尚未完成,请核对!");
|
||||
return Result.error("您有该协会的申请记录尚未完成,请核对!");
|
||||
}
|
||||
|
||||
SysClub club = clubInfoManageService.dao().fetch(SysClub.class, clubRule.getClubId());
|
||||
@@ -177,7 +177,7 @@ public class ClubRuleUpdateController {
|
||||
@ApiOperation("删除")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.infoManage.ruleUpdate")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "删除章程备案")
|
||||
@SLog(tag = "协会管理系统-信息管理", msg = "删除章程备案")
|
||||
public Result delete(@Param("id") String id) {
|
||||
clubInfoManageService.dao().delete(SysClubRule.class, id);
|
||||
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
|
||||
|
||||
+2
-2
@@ -201,7 +201,7 @@ public class ClubSchoolAuditReportController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用社团名称建立目录,方便按换届报告来源查阅。
|
||||
* 使用协会名称建立目录,方便按换届报告来源查阅。
|
||||
*
|
||||
* @param report 换届报告记录
|
||||
* @return Zip 内目录名称
|
||||
@@ -211,7 +211,7 @@ public class ClubSchoolAuditReportController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留附件原始文件名;同一社团目录存在同名文件时追加序号,避免覆盖。
|
||||
* 保留附件原始文件名;同一协会目录存在同名文件时追加序号,避免覆盖。
|
||||
*
|
||||
* @param entryName 原始 Zip 条目名称
|
||||
* @param entryNames 已写入的 Zip 条目名称
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import javax.validation.Valid;
|
||||
* @Author: JyuHsin
|
||||
* @Date: 2024/8/6 10:02
|
||||
* @Version: v1.0.0
|
||||
* @Description: 社团确认
|
||||
* @Description: 协会确认
|
||||
**/
|
||||
@IocBean
|
||||
@Ok("json")
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@ import javax.validation.Valid;
|
||||
**/
|
||||
@IocBean
|
||||
@Ok("json")
|
||||
@Api("社团-我的注册")
|
||||
@Api("协会-我的注册")
|
||||
@At("/platform/club/register/clubMyApply")
|
||||
public class ClubMyApplyController {
|
||||
|
||||
@@ -54,10 +54,10 @@ public class ClubMyApplyController {
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除社团")
|
||||
@ApiOperation("删除协会")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.register.myApply")
|
||||
@SLog(tag = "社团管理系统-社团注册", msg = "删除社团")
|
||||
@SLog(tag = "协会管理系统-协会注册", msg = "删除协会")
|
||||
public Result doDelete(@Valid String id) {
|
||||
sysClubService.delete(id);
|
||||
sysClubService.dao().clear(SysClubSponsor.class, Cnd.where("clubId", "=", id));
|
||||
|
||||
+3
-3
@@ -42,7 +42,7 @@ import java.util.List;
|
||||
* @Author: JyuHsin
|
||||
* @Date: 2024/8/6 9:56
|
||||
* @Version: v1.0.0
|
||||
* @Description: 注册社团
|
||||
* @Description: 注册协会
|
||||
**/
|
||||
@IocBean
|
||||
@Ok("json")
|
||||
@@ -67,7 +67,7 @@ public class ClubRegistApplyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.register.apply")
|
||||
@SLog(tag = "社团管理系统-社团注册", msg = "保存注册社团")
|
||||
@SLog(tag = "协会管理系统-协会注册", msg = "保存注册协会")
|
||||
public Result save(@Param("club") SysClub club,
|
||||
@Param("::deleteIds") List<String> deleteIds,
|
||||
@Param("::managePerson") List<NutMap> managePerson) {
|
||||
@@ -83,7 +83,7 @@ public class ClubRegistApplyController {
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("club.register.apply")
|
||||
@SLog(tag = "社团管理系统-社团注册", msg = "提交注册社团")
|
||||
@SLog(tag = "协会管理系统-协会注册", msg = "提交注册协会")
|
||||
public Result submit(@Param("club") SysClub club,
|
||||
@Param("::deleteIds") List<String> deleteIds,
|
||||
@Param("::managePerson") List<NutMap> managePerson) {
|
||||
|
||||
+104
@@ -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;
|
||||
}
|
||||
}
|
||||
+24
-10
@@ -129,7 +129,21 @@ public class ClubStatisticsController {
|
||||
u.mobile,
|
||||
u.unitname as unitName,
|
||||
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
|
||||
club_user c
|
||||
LEFT JOIN `vw_user` u ON u.id = c.userId
|
||||
@@ -218,7 +232,7 @@ public class ClubStatisticsController {
|
||||
nutMap.put("roleName", roleName);
|
||||
nutMap.put("roleCode", list);
|
||||
}
|
||||
//获取所有社团
|
||||
//获取所有协会
|
||||
Cnd stCnd = Cnd.NEW();
|
||||
stCnd.andEX("id", "=", clubId);
|
||||
List<SysClub> clubList = sysClubService.query(stCnd);
|
||||
@@ -314,7 +328,7 @@ public class ClubStatisticsController {
|
||||
}
|
||||
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("社团名称", "clubName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("协会名称", "clubName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("姓名", "userName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("工号", "loginName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("性别", "sex", 20));
|
||||
@@ -343,9 +357,9 @@ public class ClubStatisticsController {
|
||||
List<NutMap> list = sysClubService.listMap(sql);
|
||||
|
||||
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||
exportEntities.add(new ExcelExportEntity("社团名称", "clubName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("协会名称", "clubName", 20));
|
||||
exportEntities.add(new ExcelExportEntity("编码", "clubCode", 20));
|
||||
exportEntities.add(new ExcelExportEntity("社团总人数", "total", 20));
|
||||
exportEntities.add(new ExcelExportEntity("协会总人数", "total", 20));
|
||||
exportEntities.add(new ExcelExportEntity("在职人数", "work", 20));
|
||||
exportEntities.add(new ExcelExportEntity("退休人数", "retire", 20));
|
||||
exportEntities.add(new ExcelExportEntity("男", "man", 20));
|
||||
@@ -354,7 +368,7 @@ public class ClubStatisticsController {
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
|
||||
CommonDownloadUtil.download("社团统计表.xlsx", workbook, response);
|
||||
CommonDownloadUtil.download("协会统计表.xlsx", workbook, response);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -366,7 +380,7 @@ public class ClubStatisticsController {
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode("上传资料数据.zip"));
|
||||
LinkedHashMap<String, List<JSONObject>> fileList = new LinkedHashMap<>();
|
||||
|
||||
//查询社团
|
||||
//查询协会
|
||||
List<SysClub> clubList = sysClubService.query(Cnd.NEW().andEX("id", "=", clubId));
|
||||
clubList.forEach(item -> {
|
||||
List<JSONObject> file = new ArrayList<>();
|
||||
@@ -380,7 +394,7 @@ public class ClubStatisticsController {
|
||||
fileList.put(item.getId(), file);
|
||||
});
|
||||
|
||||
//社团年审附件
|
||||
//协会年审附件
|
||||
List<SysClubExamineRegister> examineList = sysClubService.dao().query(SysClubExamineRegister.class,
|
||||
Cnd.NEW().andEX("clubId", "=", clubId)
|
||||
.and("year(registerDate)", "=", DateUtil.thisYear()));
|
||||
@@ -392,7 +406,7 @@ public class ClubStatisticsController {
|
||||
}
|
||||
});
|
||||
|
||||
//社团评优附件
|
||||
//协会评优附件
|
||||
List<SysClubEvaluate> evaluateList = sysClubService.dao().query(SysClubEvaluate.class, Cnd.NEW().andEX("clubId", "=", clubId)
|
||||
.and("year(applyTime)", "=", DateUtil.thisYear()));
|
||||
evaluateList.forEach(item -> {
|
||||
@@ -425,7 +439,7 @@ public class ClubStatisticsController {
|
||||
}
|
||||
|
||||
private Sql generateSql(String clubId, Boolean auditState, String userState, String sex, Boolean giveMoney) {
|
||||
// 注册流程按社团去重后再关联,避免换届等流程复用社团ID时将会员人数重复统计。
|
||||
// 注册流程按协会去重后再关联,避免换届等流程复用协会ID时将会员人数重复统计。
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
club.id,
|
||||
|
||||
@@ -25,7 +25,7 @@ public class ClubRefreshUpdateInterceptor implements FlowInterceptor {
|
||||
SysClubRefresh clubRefresh = Json.fromJson(SysClubRefresh.class, formDataStr);
|
||||
|
||||
Dao dao = ServiceContext.find(Dao.class);
|
||||
// 审核通过,将新的附件更新到社团表
|
||||
// 审核通过,将新的附件更新到协会表
|
||||
SysClub club = dao.fetch(SysClub.class, clubRefresh.getClubId());
|
||||
club.setReplaceReport(clubRefresh.getFiles());
|
||||
dao.update(club);
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ClubRuleUpdateInterceptor implements FlowInterceptor {
|
||||
SysClubRule clubRule = Json.fromJson(SysClubRule.class, formDataStr);
|
||||
|
||||
Dao dao = ServiceContext.find(Dao.class);
|
||||
// 审核通过,将新的附件更新到社团表
|
||||
// 审核通过,将新的附件更新到协会表
|
||||
SysClub club = dao.fetch(SysClub.class, clubRule.getClubId());
|
||||
club.setRulesFile(clubRule.getFiles());
|
||||
dao.update(club);
|
||||
|
||||
@@ -44,7 +44,7 @@ public class ClubUserExitInterceptor implements FlowInterceptor {
|
||||
|
||||
// 删人
|
||||
dao.clear(ClubUser.class, Cnd.where(ClubUser::getUserId, "=", clubUserApply.getUserId()).and(ClubUser::getClubId, "=", clubUserApply.getClubId()));
|
||||
// 2026年10月3日 09:51:00;操作人:wxg:WF 退会完成后,同步将该社团会员的拨付字段置为 false。
|
||||
// 2026年10月3日 09:51:00;操作人:wxg:WF 退会完成后,同步将该协会会员的拨付字段置为 false。
|
||||
ServiceContext.find(ClubPayRecordService.class).disableExitMemberPayment(clubUserApply.getClubId(), clubUserApply.getUserId());
|
||||
// 删角色
|
||||
dao.clear(Sys_user_role.class, Cnd.where(Sys_user_role::getUserId, "=", clubUserApply.getUserId()).and(Sys_user_role::getClubId, "=", clubUserApply.getClubId()));
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ClubUserJoinInterceptor implements FlowInterceptor {
|
||||
clubUserApply.setJoinTime(ServiceContext.find(ClubUserJoinService.class).completeJoinApproval(
|
||||
execution.getProcessInstance().getBusinessNo(), execution.getProcessTaskId()));
|
||||
|
||||
// 将申请信息复制一份,插入社团成员表
|
||||
// 将申请信息复制一份,插入协会成员表
|
||||
ClubUser clubUser = BeanUtil.copyProperties(clubUserApply, ClubUser.class);
|
||||
// 读取本次已写入的入会申请时间,不能取成立时间或用插入时刻替代审核完成时间。
|
||||
ClubUserApply approvedApply = dao.fetch(ClubUserApply.class, execution.getProcessInstance().getBusinessNo());
|
||||
@@ -59,8 +59,8 @@ public class ClubUserJoinInterceptor implements FlowInterceptor {
|
||||
ServiceContext.find(SysClubUserService.class).prepareMemberSnapshots(List.of(clubUser));
|
||||
dao.insert(clubUser);
|
||||
|
||||
// 还要加到社团成员缴费表中
|
||||
// 对了,如果同一个人,在同一年,多次加入同一社团,则只插入一条
|
||||
// 还要加到协会成员缴费表中
|
||||
// 对了,如果同一个人,在同一年,多次加入同一协会,则只插入一条
|
||||
ClubPayRecord payRecord = dao.fetch(
|
||||
ClubPayRecord.class,
|
||||
Cnd.where(ClubPayRecord::getClubId, "=", clubUser.getClubId())
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Date;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("club_pay_record")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("社团会员缴费记录表")
|
||||
@Comment("协会会员缴费记录表")
|
||||
public class ClubPayRecord extends BaseModel {
|
||||
|
||||
@Name
|
||||
@@ -36,7 +36,7 @@ public class ClubPayRecord extends BaseModel {
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@Comment("社团ID")
|
||||
@Comment("协会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.List;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("club_user")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("社团会员表")
|
||||
@Comment("协会会员表")
|
||||
public class ClubUser extends BaseModel {
|
||||
|
||||
@Name
|
||||
@@ -24,7 +24,7 @@ public class ClubUser extends BaseModel {
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("社团ID")
|
||||
@Comment("协会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class ClubUser extends BaseModel {
|
||||
private List<String> roleCode = new ArrayList<>();
|
||||
|
||||
@Column
|
||||
@Comment("社团职务")
|
||||
@Comment("协会职务")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String clubPosition;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ClubUser extends BaseModel {
|
||||
private String avatar;
|
||||
|
||||
@Column
|
||||
@Comment("同时参加其他社团情况")
|
||||
@Comment("同时参加其他协会情况")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String sameTimeJoinOtherClubSituation;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.Date;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("club_user_apply")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("社团申请退出申请表")
|
||||
@Comment("协会申请退出申请表")
|
||||
public class ClubUserApply extends BaseModel {
|
||||
|
||||
@Name
|
||||
@@ -22,7 +22,7 @@ public class ClubUserApply extends BaseModel {
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("社团ID")
|
||||
@Comment("协会ID")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
private String clubId;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ClubUserApply extends BaseModel {
|
||||
private Integer mode;
|
||||
|
||||
@Column
|
||||
@Comment("社团职务")
|
||||
@Comment("协会职务")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
private String clubPosition;
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ClubUserApply extends BaseModel {
|
||||
private String avatar;
|
||||
|
||||
@Column
|
||||
@Comment("同时参加其他社团情况")
|
||||
@Comment("同时参加其他协会情况")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||
private String sameTimeJoinOtherClubSituation;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("sys_club")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("社团")
|
||||
@Comment("协会")
|
||||
public class SysClub extends BaseModel {
|
||||
|
||||
@Column
|
||||
@@ -32,26 +32,26 @@ public class SysClub extends BaseModel {
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("社团名称")
|
||||
@Comment("协会名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@NotEmpty(message = "社团名称不能为空")
|
||||
@NotEmpty(message = "协会名称不能为空")
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
@Comment("社团缩略图")
|
||||
@Comment("协会缩略图")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||
private String thumbnail;
|
||||
|
||||
@Column
|
||||
@Comment("社团编码")
|
||||
@Comment("协会编码")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@NotEmpty(message = "社团编码不能为空")
|
||||
@NotEmpty(message = "协会编码不能为空")
|
||||
private String clubCode;
|
||||
|
||||
@Column
|
||||
@Comment("社团类型")
|
||||
@Comment("协会类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||
@NotEmpty(message = "社团类型不能为空")
|
||||
@NotEmpty(message = "协会类型不能为空")
|
||||
private String clubType;
|
||||
|
||||
@Column
|
||||
@@ -70,12 +70,12 @@ public class SysClub extends BaseModel {
|
||||
private String concatPersonEmail;
|
||||
|
||||
@Column
|
||||
@Comment("社团介绍")
|
||||
@Comment("协会介绍")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String introduce;
|
||||
|
||||
@Column
|
||||
@Comment("社团宗旨")
|
||||
@Comment("协会宗旨")
|
||||
@ColDefine(type = ColType.TEXT)
|
||||
private String purpose;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("sys_club_evaluate")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("社团评优")
|
||||
@Comment("协会评优")
|
||||
public class SysClubEvaluate extends BaseModel {
|
||||
|
||||
@Column
|
||||
@@ -32,9 +32,9 @@ public class SysClubEvaluate extends BaseModel {
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("社团id")
|
||||
@Comment("协会id")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@NotEmpty(message = "社团id不能为空")
|
||||
@NotEmpty(message = "协会id不能为空")
|
||||
private String clubId;
|
||||
|
||||
@Column
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user