feat: 优化批量导入人员角色

This commit is contained in:
2026-10-28 15:21:27 +08:00
parent 919f8c9dec
commit a09cd7b8fd
5 changed files with 338 additions and 68 deletions
@@ -8,7 +8,10 @@ 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;
@@ -17,6 +20,9 @@ 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;
@@ -26,9 +32,15 @@ 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
@@ -45,6 +57,10 @@ public class SysUnionCadreImportController {
private SysDictService sysDictService;
@Inject
private SysUnionController sysUnionController;
@Inject
private SysRoleService sysRoleService;
@Inject
private SysUserService sysUserService;
@SuppressWarnings("unchecked")
private List<NutMap> roleOptions() {
@@ -72,7 +88,7 @@ public class SysUnionCadreImportController {
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"));
@@ -145,101 +161,271 @@ public class SysUnionCadreImportController {
if (rows.isEmpty()) {
return Result.error("文件中没有需要导入的数据");
}
List<String> roleCodes = roleOptions().stream().map(item -> item.getString("code")).toList();
List<String> terms = sysDictService.getSubListByCode("TEACHER_CONGRESS_J").stream()
.map(Sys_dict::getCode).toList();
int success = 0;
int skipped = 0;
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) {
try {
importRow(row, roleCodes, terms);
} catch (Exception e) {
log.error("导入分工会干部失败,行号:{}", row.getInt("rowNumber"), e);
outcome(row, "失败", "保存失败,请检查该行数据或联系管理员");
}
if ("成功".equals(row.getString("status"))) {
success++;
} else if ("跳过".equals(row.getString("status"))) {
skipped++;
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 void importRow(NutMap row, List<String> roleCodes, List<String> terms) {
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");
if (StrUtil.isBlank(unionCode) || StrUtil.isBlank(loginname) || StrUtil.isBlank(roleCode)) {
outcome(row, "失败", "工会编码、工号、角色编码不能为空");
return;
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 + "】不在允许导入的分工会干部角色范围内,请参照角色对照表");
}
List<Sys_union> unions = dao.query(Sys_union.class, Cnd.where("unionCode", "=", unionCode));
List<View_user> users = dao.query(View_user.class, Cnd.where("loginname", "=", loginname));
List<Sys_role> roles = dao.query(Sys_role.class, Cnd.where("code", "=", roleCode));
if (unions.size() != 1 || users.size() != 1 || roles.size() != 1 || !roleCodes.contains(roleCode)) {
outcome(row, "失败", "工会、工号或分工会角色编码不存在或不唯一,请按模板对照表填写");
return;
if (!errors.isEmpty()) {
outcome(row, "失败", String.join(";", errors));
return null;
}
Sys_union union = unions.get(0);
View_user user = users.get(0);
Sys_role role = roles.get(0);
boolean secretary = RoleConstant.UNIT_PARTY_SECRETARY.name().equals(roleCode);
Cnd existing = Cnd.where("userId", "=", user.getId()).and("roleId", "=", role.getId());
if (secretary) {
existing.and("unionId", "=", union.getId());
}
if (dao.count(Sys_user_role.class, existing) > 0) {
outcome(row, "跳过", "已分配该角色,保留原有记录(含禁用关系)");
return;
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())) {
outcome(row, "失败", "所选人员不属于该分工会");
return;
errors.add("工号【" + loginname + "】所属工会为【" + StrUtil.blankToDefault(user.getUnionName(), "未分配工会")
+ "】,与填写的工会【" + union.getName() + "(" + unionCode + ")】不一致");
}
if (StrUtil.isNotBlank(j) && !terms.contains(j)) {
outcome(row, "失败", "届次编码不存在,请参照届次对照表或留空");
return;
errors.add("届次编码【" + j + "】不存在,请参照届次对照表或留空");
}
if (dao.count(Sys_union_cadre.class, Cnd.where("userId", "=", user.getId())
.and("roleCode", "=", roleCode).and("unionId", "=", union.getId()).and("isServing", "=", true)) > 0) {
outcome(row, "跳过", "已有在任或待审核干部记录,请通过原记录处理");
return;
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 = Arrays.stream(unitCodes.split("[,,]"))
.map(String::trim).filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
List<String> codes = splitUnitCodes(unitCodes);
if (codes.isEmpty()) {
outcome(row, "失败", "二级党委书记必须填写所属单位编码");
return;
errors.add("角色【二级党委书记】必须填写所属单位编码,请参照所属单位对照表");
}
for (String code : codes) {
List<Sys_unit> units = dao.query(Sys_unit.class, Cnd.where("unitcode", "=", code)
.and("unionId", "=", union.getId()).and("unitLevel", "=", 2));
if (units.size() != 1) {
outcome(row, "失败", "所属单位编码不存在、不唯一或不是该分工会的二级单位:" + code);
return;
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());
}
unitIds.add(units.get(0).getId());
}
} else if (StrUtil.isNotBlank(unitCodes)) {
outcome(row, "失败", "普通干部角色的所属单位编码应留空");
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;
}
// 经由注入的原控制器代理调用,保留单行事务、直接授权及缓存清理逻辑。
Result result = secretary
? sysUnionController.insertBranchUnionPartySecretaryRole(user.getId(), union.getId(), unitIds.toArray(new String[0]), j)
: sysUnionController.insertBranchUnionUserRole(user.getId(), roleCode, union.getId(), j);
if (result.isSuccess()) {
outcome(row, "成功", "添加成功");
} else if ("请勿重复添加".equals(result.getMsg()) || "该人员已设置二级党委书记,请先删除后再重新设置".equals(result.getMsg())) {
outcome(row, "跳过", result.getMsg());
} else {
outcome(row, "失败", result.getMsg());
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;
}
}
@@ -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);
}
@@ -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;
}
}
+2 -2
View File
@@ -42,8 +42,8 @@ sdk:
client-call-back-url: /platform/sso/login
validation-type: cas
minio:
accessKey: o1MwuzixNqAXh5zqEfMH
secretKey: RVnZum91JmGO79qtzWy2gKMBsF6OxAaibGrr7ets
accessKey: minioadmin
secretKey: Minio@123#admin
endPoint: http://localhost:9000
bucket: zjnu
@@ -71,7 +71,7 @@ const branchUnionManage = {
<div class="el-upload__text" v-if="cadreImportLoading">正在导入,请稍候…</div>
<div class="el-upload__text" v-else>将文件拖到此处,或<em>点击选择文件</em></div>
</el-upload>
<div class="union-cadre-import-note">选择文件后点击“开始导入”。逐行保存,一行失败不影响其他行。</div>
<div class="union-cadre-import-note">选择文件后点击“开始导入”。批量校验并保存,失败行显示具体原因,其他有效行继续导入。</div>
</section>
</div>
<section v-if="cadreImportResult" class="union-cadre-import-results">