diff --git a/src/main/java/io/v/nutz/zhgh/data/service/impl/SourceUserServiceImpl.java b/src/main/java/io/v/nutz/zhgh/data/service/impl/SourceUserServiceImpl.java index cd4fffb..075193f 100644 --- a/src/main/java/io/v/nutz/zhgh/data/service/impl/SourceUserServiceImpl.java +++ b/src/main/java/io/v/nutz/zhgh/data/service/impl/SourceUserServiceImpl.java @@ -20,6 +20,7 @@ import io.v.nutz.zhgh.data.model.UserSource; import io.v.nutz.zhgh.data.service.HistoryUserService; import io.v.nutz.zhgh.data.service.SourceUserService; import io.v.nutz.base.lang.Enum; +import io.v.nutz.zhgh.member.MemberMode; import io.v.nutz.zhgh.member.UserMode; import io.v.nutz.base.service.AsyncService; import io.v.nutz.base.service.impl.ViServiceImpl; @@ -67,6 +68,9 @@ import java.util.stream.Collectors; @CacheDefaults(cacheName = "user_source") @Slf4j public class SourceUserServiceImpl extends ViServiceImpl implements SourceUserService { + private static final String CONTRACT_PERSON_TYPE = "合同制"; + private static final String NON_CONTRACT_PERSON_TYPE = "非合同制"; + public SourceUserServiceImpl(Dao dao) { super(dao); } @@ -96,9 +100,25 @@ public class SourceUserServiceImpl extends ViServiceImpl implements public void pullSourceData(Boolean isIncrement) { Date now = new Date(); List users = SourceData.users(); + // 正式用户已明确标记为非合同制时,不能因数据中心人员类型为空而被改为合同制或自动入会。 + Set nonContractLoginNames = sysUserService.query(Cnd.where("personType", "=", NON_CONTRACT_PERSON_TYPE)) + .stream() + .map(Sys_user::getLoginname) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toSet()); asyncService.exe2(users, (user) -> { user.setPullTime(now); UserMode.initUser(user); + // 数据中心人员类型为空且工号以 18 开头时,仅非“非合同制”人员按合同制会员处理。 + if (isContractMemberCandidate(user)) { + if (nonContractLoginNames.contains(user.getLoginname())) { + // 使用 null 避免后续 updateIgnoreNull 将正式用户已有的“非合同制”覆盖为空字符串。 + user.setPersonType(null); + } else { + user.setPersonType(CONTRACT_PERSON_TYPE); + user.setMember(MemberMode.NORMAL.getCode()); + } + } }); dao().insert(users); } @@ -149,6 +169,8 @@ public class SourceUserServiceImpl extends ViServiceImpl implements List unitChangeUserList = new CopyOnWriteArrayList<>(); // 删除博士后出站的会员和福利会员角色 List deleteLeavingStationUserIdList = new CopyOnWriteArrayList<>(); + // 拉取时识别出的合同制人员,在正式用户保存后统一补充会员字段及会员角色。 + List addContractMemberUserIdList = new CopyOnWriteArrayList<>(); // 创建一个固定大小的线程池 可以根据服务器性能调整线程池大小 @@ -171,9 +193,11 @@ public class SourceUserServiceImpl extends ViServiceImpl implements continue; } + boolean shouldAddContractMember = isPulledContractMember(source); source.setMember(null); source.setWelfareMember(null); Sys_user user = userMap.get(source.getLoginname()); + Sys_user systemUser = user; UserChangeType changeType = getChangeType(source, user); @@ -214,12 +238,14 @@ public class SourceUserServiceImpl extends ViServiceImpl implements unitChangeUserList.add(u); } + boolean includedInUpdate = user == null; switch (sourceType) { case "all" -> { //复制属性到一个新的user对象 u.setId(user == null ? source.getId() : user.getId()); if (user != null) { needDoUpdateList.add(u); + includedInUpdate = true; } } case "add" -> { @@ -234,6 +260,7 @@ public class SourceUserServiceImpl extends ViServiceImpl implements } if (Strings.isNotBlank(finalUserPartMap.get(u.getLoginname())) && user != null) { needDoUpdateList.add(u); + includedInUpdate = true; } } } @@ -256,6 +283,12 @@ public class SourceUserServiceImpl extends ViServiceImpl implements histories.add(createUserHistory(user, changeTypes)); } + // 仅对本次实际新增或更新、且尚未入会的人员执行会员初始化,避免重复覆盖原入会时间。 + if (shouldAddContractMember && includedInUpdate + && !ObjectUtil.equal(systemUser != null ? systemUser.getMember() : null, MemberMode.NORMAL.getCode())) { + addContractMemberUserIdList.add(systemUser == null ? u.getId() : systemUser.getId()); + } + } }, Executors.newFixedThreadPool(numberOfThreads)); futures.add(future); @@ -277,6 +310,10 @@ public class SourceUserServiceImpl extends ViServiceImpl implements massUpdatesAsync(needDoUpdateList, false, null); } + if (Lang.isNotEmpty(addContractMemberUserIdList)) { + UserMode.addMemberRole(addContractMemberUserIdList.toArray(new String[0])); + } + if (Lang.isNotEmpty(deleteLeavingStationUserIdList)) { dao().clear(Sys_user_role.class, Cnd.where("userId", "in", deleteLeavingStationUserIdList).and("roleId", "=", Roles.MEMBER)); dao().update(Sys_user.class, Chain.make("member", 0).add("welfareMember", 0), Cnd.where("id", "in", deleteLeavingStationUserIdList)); @@ -377,6 +414,33 @@ public class SourceUserServiceImpl extends ViServiceImpl implements dao().clear(UserSource.class, Cnd.where("DATE(pullTime)", "<", formatAgoWeekDate)); } + /** + * 判断数据中心人员是否需要按合同制会员初始化。 + * + * @param user 数据中心返回的人员;工号需以 18 开头且人员类型为空 + * @return true 表示需要补充“合同制”人员类型并设置为会员 + */ + private boolean isContractMemberCandidate(Sys_user user) { + return user != null + && user.getLoginname() != null + && user.getLoginname().startsWith("18") + && StrUtil.isBlank(user.getPersonType()); + } + + /** + * 判断暂存人员是否为拉取阶段标记的合同制会员。 + * + * @param source 人员拉取暂存数据 + * @return true 表示人员类型及会员标记均符合自动入会条件 + */ + private boolean isPulledContractMember(UserSource source) { + return source != null + && source.getLoginname() != null + && source.getLoginname().startsWith("18") + && CONTRACT_PERSON_TYPE.equals(source.getPersonType()) + && ObjectUtil.equal(source.getMember(), MemberMode.NORMAL.getCode()); + } + private UserChangeType getChangeType(Sys_user source, Sys_user user) { //新入职 if (user == null) { diff --git a/src/main/java/io/v/nutz/zhgh/member/controller/info/MemberGroupInfoController.java b/src/main/java/io/v/nutz/zhgh/member/controller/info/MemberGroupInfoController.java index 9786a6a..41b8918 100644 --- a/src/main/java/io/v/nutz/zhgh/member/controller/info/MemberGroupInfoController.java +++ b/src/main/java/io/v/nutz/zhgh/member/controller/info/MemberGroupInfoController.java @@ -2,6 +2,7 @@ package io.v.nutz.zhgh.member.controller.info; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; import cn.hutool.core.util.StrUtil; import io.v.nutz.base.annontation.ViReturn; @@ -153,16 +154,15 @@ public class MemberGroupInfoController { cnd.where().andLike("jobTitle", jobTitle); } - if (!ShiroUtil.hasAnyRoles("sysadmin,H03,A06")) { - if (ShiroUtil.hasRole("H04")) { - cnd.and("unionId", "=", Vi.getUnionId()); - } else if (ShiroUtil.hasRole("ghxzzz")) { - cnd.and("unionId", "=", Vi.getUnionId()); - SqlExpressionGroup seg = new SqlExpressionGroup(); - seg.or("unionGroupId", "in", io.v.nutz.web.commons.utils.ShiroUtil.getUnionGroupIds()); - seg.or("unionGroupId", "is", null); - cnd.and(seg); - } + // 分工会主席可能同时具有校会员管理员角色,除系统管理员和校级管理员外,必须优先限制为当前分工会。 + if (ShiroUtil.hasRole("H04") && !ShiroUtil.hasAnyRoles("sysadmin,A06")) { + cnd.and("unionId", "=", Vi.getUnionId()); + } else if (!ShiroUtil.hasAnyRoles("sysadmin,H03,A06") && ShiroUtil.hasRole("ghxzzz")) { + cnd.and("unionId", "=", Vi.getUnionId()); + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("unionGroupId", "in", io.v.nutz.web.commons.utils.ShiroUtil.getUnionGroupIds()); + seg.or("unionGroupId", "is", null); + cnd.and(seg); } @@ -249,7 +249,7 @@ public class MemberGroupInfoController { @Param(value = "memberSearchName", required = false) String memberSearchName, @Param(value = "memberSearchKeyWord", required = false) String memberSearchKeyWord) { try { - ViTool.excelResponse(response, "会员名单.xls"); + ViTool.excelResponse(response, "会员名单.xlsx"); List dataList = memberService.listMap(dataSql(pageForm, unionId, unitId, threeUnitId, unionGroupId, Json.fromJsonAsArray(String.class, personTypes), Json.fromJsonAsArray(String.class, userStates), campus, sex, memberStatus, position, jobTitle, memberSearchName, memberSearchKeyWord)); List entityList = new ArrayList<>(); ExcelExportEntity no = new ExcelExportEntity("序号", "no", 10); @@ -260,7 +260,9 @@ public class MemberGroupInfoController { propMap.forEach((k, v) -> { entityList.add(new ExcelExportEntity(v, k, 20)); }); - Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, dataList); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, dataList); workbook.write(response.getOutputStream()); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/resources/views/platform/member/info/GroupInfo.html b/src/main/resources/views/platform/member/info/GroupInfo.html index 7e0b992..d69e8d5 100644 --- a/src/main/resources/views/platform/member/info/GroupInfo.html +++ b/src/main/resources/views/platform/member/info/GroupInfo.html @@ -560,7 +560,12 @@ layout("/layouts/platform.html"){ }, async created() { this.pageData(); - if ("${@shiro.hasRole('sysadmin')||@shiro.hasRole('A06')||@shiro.hasRole('H03')}" === 'true') { + // 分工会主席可能兼具 H03 角色,需优先按当前分工会加载查询选项。 + if ("${@shiro.hasRole('H04')&&!(@shiro.hasRole('sysadmin')||@shiro.hasRole('A06'))}" === 'true') { + this.unions = await getUnions(null, true) + this.$set(this.pageForm, 'unionId', this.unions ? this.unions[0].id : null) + this.flushUnits() + } else if ("${@shiro.hasRole('sysadmin')||@shiro.hasRole('A06')||@shiro.hasRole('H03')}" === 'true') { this.unions = await getUnions(null, false) } else { this.unions = await getUnions(null, true) @@ -574,4 +579,4 @@ layout("/layouts/platform.html"){ \ No newline at end of file +#-->