This commit is contained in:
2026-08-20 10:55:04 +08:00
parent c6609dcb0b
commit 34fe53caf9
14 changed files with 219 additions and 582 deletions
@@ -51,11 +51,6 @@ public class Sys_user_history extends Sys_user {
@Comment("变更原因")
private String changeReason;
@Column
@ColDefine(type = ColType.VARCHAR, customType = "text")
@Comment("备注")
private String remark;
@Column
@Comment("会员变更表记录id")
@ColDefine(type = ColType.VARCHAR, width = 32)
@@ -22,11 +22,12 @@ import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
import com.budwk.app.zhgh.staffmanage.sourcechange.service.PendingUserHistoryService;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
@@ -51,6 +52,10 @@ import java.util.stream.Collectors;
@IocBean
public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService {
private static final int BATCH_SIZE = 500;
/** 不需要人工确认。 */
private static final int PENDING_CONFIRM_STATUS_NONE = 0;
/** 数据源缺失,等待人工确认。 */
private static final int PENDING_CONFIRM_STATUS_PENDING = 1;
@Inject
private Dao dao;
@@ -62,8 +67,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
private SysUserService sysUserService;
@Inject
private ThreadPoolTaskExecutor executorService;
@Inject
private PendingUserHistoryService pendingUserHistoryService;
private static Map<String, String> unitIdNameMap;
@@ -177,7 +180,7 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
* 全量更新已有用户时置空,避免 updateIgnoreNull 把已迁移的基金会员标识覆盖为非会员。
*/
u.setAidFundMember(null);
u.setPersonType(null);
needDoUpdateList.add(u);
}
@@ -292,12 +295,6 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
return "更新失败: " + e.getMessage();
}
/*
* 用户及普通变更记录完成后,再以本次完整源数据校正待确认人员。
* 该步骤仅存在于 ALL 实现中,增量更新不会误判未包含在增量数据中的系统用户。
*/
int pendingConfirmCount = pendingUserHistoryService.reconcile(sysUsers, sources);
/* // 4. 异步添加会员角色 - 不等待完成
if (Lang.isNotEmpty(addMemberUserIds)) {
executorService.execute(() -> {
@@ -355,14 +352,63 @@ public class SysDataUserAllUpdateServiceImpl implements SysDataUserUpdateService
RoleEventPublisher.broadcast(new RoleEventMsg(unitId, RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER.name(), RoleEventMsg.RENEW_ROLE));
}
/*
* 所有异步用户更新完成后再校正待确认状态,避免主事务提前锁定 sys_user,
* 导致异步更新线程等待主事务释放行锁而形成相互等待。
*/
reconcilePendingConfirmStatus(updateParam.getPullTime());
long endTime = System.currentTimeMillis();
log.info("全量更新用户数据完成,耗时: {} 毫秒", (endTime - startTime));
if (needInitUserList.isEmpty() && histories.isEmpty() && pendingConfirmCount == 0) {
if (needInitUserList.isEmpty() && histories.isEmpty()) {
return "本次没有可更新的数据。";
}
return "更新完成: 新增用户 " + needInitUserList.size() + " 个, 有效变更 " + histories.size()
+ ", 新增待确认人员 " + pendingConfirmCount + "";
+ "";
}
/**
* 根据指定批次的完整数据源校正系统用户待确认状态。
* 已人工确认且仍未重新出现的人员保持已确认状态,避免每次全量更新重复转为待确认。
*
* @param pullTime 本次全量数据的拉取时间
*/
private void reconcilePendingConfirmStatus(String pullTime) {
Sql resetStatusSql = Sqls.create("""
UPDATE sys_user userInfo
SET userInfo.pendingConfirmStatus = @noneStatus
WHERE userInfo.personType IN ('教职工', '劳务派遣人员')
AND userInfo.pendingConfirmStatus <> @noneStatus
AND EXISTS (
SELECT 1
FROM sys_user_source sourceInfo
WHERE sourceInfo.pullTime = @pullTime
AND sourceInfo.loginname = userInfo.loginname
AND sourceInfo.personType IN ('教职工', '劳务派遣人员')
)
""");
resetStatusSql.setParam("noneStatus", PENDING_CONFIRM_STATUS_NONE);
resetStatusSql.setParam("pullTime", pullTime);
dao.execute(resetStatusSql);
Sql pendingStatusSql = Sqls.create("""
UPDATE sys_user userInfo
SET userInfo.pendingConfirmStatus = @pendingStatus
WHERE userInfo.personType IN ('教职工', '劳务派遣人员')
AND IFNULL(userInfo.pendingConfirmStatus, @noneStatus) = @noneStatus
AND NOT EXISTS (
SELECT 1
FROM sys_user_source sourceInfo
WHERE sourceInfo.pullTime = @pullTime
AND sourceInfo.loginname = userInfo.loginname
AND sourceInfo.personType IN ('教职工', '劳务派遣人员')
)
""");
pendingStatusSql.setParam("pendingStatus", PENDING_CONFIRM_STATUS_PENDING);
pendingStatusSql.setParam("noneStatus", PENDING_CONFIRM_STATUS_NONE);
pendingStatusSql.setParam("pullTime", pullTime);
dao.execute(pendingStatusSql);
}
/**
@@ -17,7 +17,6 @@ import lombok.Getter;
public enum MemberChangeType {
//变更类型
PENDING_CONFIRM("PENDING_CONFIRM", "待确认"),
NEW("NEW", "新入职"),
RESTORE("RESTORE", "入会"),
WITHDRAWAL("WITHDRAWAL", "退会"),
@@ -156,7 +156,12 @@ public class MemberChangeApplyController {
* @return
*/
@At
@SaCheckPermission(value = {"member.change.branchUnion.audit","member.change.schoolUnion.audit", "member.change.unionGroup.audit"}, mode = SaMode.OR)
@SaCheckPermission(value = {
"member.change.branchUnion.audit",
"member.change.schoolUnion.audit",
"member.change.unionGroup.audit",
"staff.sourcechange.pending"
}, mode = SaMode.OR)
public Result getUserByIdForMemberChange(String userId){
View_user user = dao.fetch(View_user.class, Cnd.where("id", "=", userId));
NutMap nutMap = Lang.obj2nutmap(user);
@@ -36,6 +36,7 @@ import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
import com.budwk.app.zhgh.staffmanage.member.models.MemberChangeRecord;
import com.budwk.app.zhgh.staffmanage.member.param.pageform.MemberManagePageForm;
import com.budwk.app.zhgh.staffmanage.member.service.MemberCommonService;
import com.budwk.app.zhgh.staffmanage.sourcechange.service.PendingConfirmUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@@ -79,6 +80,8 @@ public class MemberChangeManageController {
private CommonService commonService;
@Inject
private MemberCommonService memberCommonService;
@Inject
private PendingConfirmUserService pendingConfirmUserService;
@At("")
@Ok("beetl:/platform/zhgh/staffmanage/member/change/manage/index.html")
@@ -101,7 +104,11 @@ public class MemberChangeManageController {
@RepeatSubmit
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "会员高级管理-会员变更", msg = "分工会/校工会会员管理员提交变更")
@SaCheckPermission(value = {"member.change.mange", "staff.member.change.mange"}, mode = SaMode.OR)
@SaCheckPermission(value = {
"member.change.mange",
"staff.member.change.mange",
"staff.sourcechange.pending"
}, mode = SaMode.OR)
public Result doSubmitChange(MemberChangeRecord record){
// 检验是否有变更
if (Lang.isEmpty(record)) {
@@ -162,6 +169,8 @@ public class MemberChangeManageController {
if (schoolRoleBool) {
memberCommonService.compareChangeInfoAndUpdateMember(record);
}
// 待确认人员完成变更提交后转为已确认;普通人员调用时不会产生状态变化。
pendingConfirmUserService.markConfirmed(record.getUserId());
return Result.success();
}
@@ -171,8 +180,7 @@ public class MemberChangeManageController {
@SaCheckPermission(value = {
"member.change.mange",
"staff.member.change.mange",
"staff.sourcechange.manage",
"staff.sourcechange.pending"
"staff.sourcechange.manage"
}, mode = SaMode.OR)
public Result getAllChangeMemberInfo(String userId){
List<NutMap> mapList = memberCommonService.getAllChangeInfo(userId);
@@ -441,12 +441,8 @@ public class MemberManageServiceImpl extends BaseServiceImpl<Sys_user> implement
MemberChangeRecord record = dao().fetch(MemberChangeRecord.class, Cnd.where("userId", "=", userId).desc("applyDateTime"));
/*
* 待确认人员来自全量数据差异校正,没有常规的字段前后值 changeInfos。
* 此处保留该人员的全部历史,再在组装时间线时仅接纳普通变更或待确认记录。
*/
List<Sys_user_history> historyList = dao().query(Sys_user_history.class,
Cnd.where("loginname", "=", loginName).desc("changeTime"));
List<Sys_user_history> historyList = dao().query(Sys_user_history.class, Cnd.where("loginname", "=", loginName)
.and("changeInfos", "is not", null).desc("changeTime"));
List<String> recordList = historyList.stream().map(Sys_user_history::getRecordId).toList();
@@ -459,25 +455,11 @@ public class MemberManageServiceImpl extends BaseServiceImpl<Sys_user> implement
resultMapList.add(map);
}
for (Sys_user_history history : historyList) {
boolean pendingConfirm = Lang.isNotEmpty(history.getChangeTypes())
&& history.getChangeTypes().contains(MemberChangeType.PENDING_CONFIRM.name());
if (Lang.isEmpty(history.getChangeInfos()) && !pendingConfirm) {
continue;
}
NutMap map = NutMap.NEW();
List<NutMap> changeInfos = history.getChangeInfos();
if (pendingConfirm) {
// 待确认记录没有人工异动表,使用差异校正原因构造可阅读的变更说明。
changeInfos = List.of(NutMap.NEW()
.setv("field", "pendingConfirm")
.setv("fieldName", "人员状态")
.setv("sourceValue", "系统用户中存在")
.setv("newValue", StrUtil.blankToDefault(history.getChangeReason(), "本次全量人员数据中不存在")));
}
map.put("changeInfos", changeInfos);
map.put("timestamp", DateUtil.format(history.getChangeTime(), "yyyy-MM-dd HH:mm:ss"));
String changeOriginName = MemberChangeOrigin.valueOf(MemberChangeOrigin.class, history.getChangeOrigin()).changeOriginName;
map.put("changeOriginName", pendingConfirm ? changeOriginName + "(待确认)" : changeOriginName);
map.put("changeOriginName", MemberChangeOrigin.valueOf(MemberChangeOrigin.class, history.getChangeOrigin()).changeOriginName);
resultMapList.add(map);
}
return resultMapList;
@@ -1,71 +0,0 @@
package com.budwk.app.zhgh.staffmanage.sourcechange.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.staffmanage.sourcechange.param.PendingUserConfirmParam;
import com.budwk.app.zhgh.staffmanage.sourcechange.param.SourceChangePageForm;
import com.budwk.app.zhgh.staffmanage.sourcechange.service.PendingUserHistoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.validation.Valid;
/**
* 待确认人员记录页面及接口。
*/
@IocBean
@At("/platform/sourcechange/pending")
@Ok("json")
@Api(tags = "待确认人员记录")
public class PendingSourceChangeController {
@Inject
private PendingUserHistoryService pendingUserHistoryService;
/**
* 打开待确认人员记录页面。
*/
@At("")
@Ok("beetl:/platform/zhgh/staffmanage/sourcechange/pending/index.html")
@SaCheckPermission("staff.sourcechange.pending")
public void index() {
}
/**
* 分页查询当前仍需人工确认的人员记录。
*
* @param pageForm 变更记录通用查询条件
* @return 分页结果
*/
@At
@ApiOperation("分页查询待确认人员")
@SaCheckPermission("staff.sourcechange.pending")
public Result pageData(SourceChangePageForm pageForm) {
return Result.success(pendingUserHistoryService.listPage(pageForm));
}
/**
* 将待确认人员记录确认成最终异动类型。
*
* @param confirmParam 异动类型及备注
* @return 处理结果
*/
@At
@ApiOperation("确认待确认人员")
@SLog(tag = "待确认人员记录", msg = "确认人员")
@SaCheckPermission("staff.sourcechange.pending")
public Result confirm(@Valid @Param("data") PendingUserConfirmParam confirmParam) {
try {
pendingUserHistoryService.confirm(confirmParam);
return Result.success();
} catch (IllegalArgumentException | IllegalStateException e) {
return Result.error(e.getMessage());
}
}
}
@@ -1,28 +0,0 @@
package com.budwk.app.zhgh.staffmanage.sourcechange.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 待确认人员确认参数。
*/
@Data
@ApiModel("待确认人员确认参数")
public class PendingUserConfirmParam {
@NotBlank(message = "待确认记录不能为空")
@ApiModelProperty("sys_user_history 记录ID")
private String id;
@NotBlank(message = "请选择异动类型")
@ApiModelProperty("最终异动类型")
private String changeType;
@Size(max = 1000, message = "备注不能超过1000个字符")
@ApiModelProperty("确认备注")
private String remark;
}
@@ -1,39 +0,0 @@
package com.budwk.app.zhgh.staffmanage.sourcechange.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.models.Sys_user_source;
import com.budwk.app.zhgh.staffmanage.sourcechange.param.PendingUserConfirmParam;
import com.budwk.app.zhgh.staffmanage.sourcechange.param.SourceChangePageForm;
import java.util.List;
/**
* 待确认人员历史记录业务服务。
*/
public interface PendingUserHistoryService {
/**
* 根据变更记录页面的查询条件分页查询待确认人员。
*
* @param pageForm 查询及分页参数
* @return 待确认人员分页数据
*/
Pagination listPage(SourceChangePageForm pageForm);
/**
* 将待确认记录更新为人工选择的最终异动类型并保存备注。
*
* @param confirmParam 确认参数
*/
void confirm(PendingUserConfirmParam confirmParam);
/**
* 依据本次全量源数据校正待确认记录:缺失人员补充记录,重新出现人员删除待确认记录。
*
* @param systemUsers 更新开始时系统中已有的用户
* @param sourceUsers 本次全量拉取的用户
* @return 本次新增的待确认记录数量
*/
int reconcile(List<Sys_user> systemUsers, List<Sys_user_source> sourceUsers);
}
@@ -1,197 +0,0 @@
package com.budwk.app.zhgh.staffmanage.sourcechange.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.models.Sys_user_history;
import com.budwk.app.sys.models.Sys_user_source;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeOrigin;
import com.budwk.app.zhgh.staffmanage.member.constant.MemberChangeType;
import com.budwk.app.zhgh.staffmanage.sourcechange.param.PendingUserConfirmParam;
import com.budwk.app.zhgh.staffmanage.sourcechange.param.SourceChangePageForm;
import com.budwk.app.zhgh.staffmanage.sourcechange.service.PendingUserHistoryService;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.random.R;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 待确认人员历史记录业务实现。
*/
@IocBean
public class PendingUserHistoryServiceImpl implements PendingUserHistoryService {
private static final int BATCH_SIZE = 500;
@Inject
private Dao dao;
@Inject
private SysUserService sysUserService;
/**
* 查询待确认人员,查询字段与人员变更记录页面保持一致,但未选择日期时查询全部待确认数据。
*/
@Override
public Pagination listPage(SourceChangePageForm pageForm) {
Sql sql = Sqls.create("""
SELECT
his.id,
his.loginname,
his.username,
COALESCE(u.sex, his.sex) AS sex,
COALESCE(u.unitName, his.unitName) AS unitName,
COALESCE(u.unionName, his.unionName) AS unionName,
his.userState,
his.personType,
his.preparedBy,
his.changeTime,
his.changeTypes,
his.changeOrigin,
his.remark,
u.id AS userId
FROM sys_user_history his
LEFT JOIN vw_user u ON his.loginname = u.loginname
$condition
""");
Cnd cnd = Cnd.NEW();
// 待确认页面固定限定待确认类型,避免已处理记录继续出现在列表中。
cnd.and(new Static("JSON_CONTAINS(his.changeTypes, JSON_QUOTE('" + MemberChangeType.PENDING_CONFIRM.name() + "'), '$')"));
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup keywordGroup = new SqlExpressionGroup();
keywordGroup.orLike("his.username", pageForm.getSearchKeyword());
keywordGroup.orLike("his.loginname", pageForm.getSearchKeyword());
cnd.and(keywordGroup);
}
cnd.andEX("u.unionId", "=", pageForm.getUnionId());
cnd.andEX("u.unitId", "=", pageForm.getUnitId());
cnd.andEX("u.sex", "=", pageForm.getSex());
cnd.andEX("his.personType", "=", pageForm.getPersonType());
cnd.andEX("his.preparedBy", "=", pageForm.getPreparedBy());
cnd.andEX("his.userState", "=", pageForm.getUserState());
cnd.andEX("his.changeOrigin", "=", pageForm.getChangeOrigin());
// 日期范围使用参数化条件,结束日期按次日零点前处理,包含所选结束日期的全部数据。
if (StrUtil.isAllNotBlank(pageForm.getChangeDateBefore(), pageForm.getChangeDateEnd())) {
Date startDate = DateUtil.parseDate(pageForm.getChangeDateBefore());
Date endDateExclusive = DateUtil.offsetDay(DateUtil.parseDate(pageForm.getChangeDateEnd()), 1);
cnd.and("his.changeTime", ">=", startDate);
cnd.and("his.changeTime", "<", endDateExclusive);
}
if (StrUtil.isAllNotBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
} else {
cnd.desc("his.changeTime");
}
sql.setCondition(cnd);
return sysUserService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
/**
* 确认待确认人员记录,异动类型只允许选择已定义且非待确认的最终类型。
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void confirm(PendingUserConfirmParam confirmParam) {
MemberChangeType selectedType;
try {
selectedType = MemberChangeType.valueOf(confirmParam.getChangeType());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("异动类型不存在");
}
if (MemberChangeType.PENDING_CONFIRM == selectedType) {
throw new IllegalArgumentException("请选择最终异动类型");
}
// 更新条件同时校验记录仍处于待确认状态,防止重复确认覆盖已经处理的数据。
Cnd cnd = Cnd.where("id", "=", confirmParam.getId())
.and(new Static("JSON_CONTAINS(changeTypes, JSON_QUOTE('" + MemberChangeType.PENDING_CONFIRM.name() + "'), '$')"));
Chain chain = Chain.make("changeTypes", Json.toJson(List.of(selectedType.name())))
.add("remark", StrUtil.trim(confirmParam.getRemark()));
int updated = dao.update(Sys_user_history.class, chain, cnd);
if (updated == 0) {
throw new IllegalStateException("待确认记录不存在或已被处理");
}
}
/**
* 根据本次全量源数据双向校正待确认历史:源数据重新出现则删除,源数据缺失则幂等新增。
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public int reconcile(List<Sys_user> systemUsers, List<Sys_user_source> sourceUsers) {
Set<String> sourceLoginNames = sourceUsers.stream()
.map(Sys_user_source::getLoginname)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toSet());
List<Sys_user_history> pendingHistories = dao.query(Sys_user_history.class, pendingCondition());
// 已重新出现在完整源数据中的人员不再需要人工确认,仅删除尚未处理的待确认记录。
List<String> recoveredPendingIds = pendingHistories.stream()
.filter(history -> sourceLoginNames.contains(history.getLoginname()))
.map(Sys_user_history::getId)
.toList();
for (List<String> idBatch : ListUtil.split(recoveredPendingIds, BATCH_SIZE)) {
dao.clear(Sys_user_history.class, Cnd.where("id", "in", idBatch));
}
Set<String> existingPendingLoginNames = pendingHistories.stream()
.filter(history -> !sourceLoginNames.contains(history.getLoginname()))
.map(Sys_user_history::getLoginname)
.filter(StrUtil::isNotBlank)
.collect(Collectors.toCollection(HashSet::new));
List<Sys_user_history> historiesToInsert = new ArrayList<>();
// 同一工号最多保留一条待确认记录,重复执行全部更新不会重复生成数据。
for (Sys_user user : systemUsers) {
String loginname = user.getLoginname();
if (StrUtil.isBlank(loginname)
|| sourceLoginNames.contains(loginname)
|| !existingPendingLoginNames.add(loginname)) {
continue;
}
Sys_user_history history = new Sys_user_history();
BeanUtil.copyProperties(user, history);
history.setId(R.UU32());
history.setChangeTime(DateUtil.date());
history.setChangeTypes(List.of(MemberChangeType.PENDING_CONFIRM.name()));
history.setChangeOrigin(MemberChangeOrigin.SYSTEM.name());
history.setChangeReason("全量人员数据中不存在");
historiesToInsert.add(history);
}
for (List<Sys_user_history> historyBatch : ListUtil.split(historiesToInsert, BATCH_SIZE)) {
dao.fastInsert(historyBatch);
}
return historiesToInsert.size();
}
/**
* 构造待确认 JSON 类型条件,供查询及差异校正统一使用。
*/
private Cnd pendingCondition() {
return Cnd.where(new Static("JSON_CONTAINS(changeTypes, JSON_QUOTE('" + MemberChangeType.PENDING_CONFIRM.name() + "'), '$')"));
}
}