This commit is contained in:
2026-06-11 10:06:33 +08:00
195 changed files with 18529 additions and 777 deletions

View File

@@ -61,6 +61,11 @@ public interface ISysImChatService {
* @return 消息VO发送失败返回 null
*/
SysImMessageVO sendSystemSingleMessage(String fromUserId, String toUserId, Integer tenantId, String content, String msgType);
/**
* 审批待办卡片:从「工作通知」公众号推送给处理人。
*/
SysImMessageVO sendApprovalHandlerMessage(String toUserId, Integer tenantId, String content, String msgType);
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流设计】系统单聊消息(绕过同部门校验,供审批等系统通知场景)-----

View File

@@ -36,6 +36,7 @@ import org.jeecg.modules.system.mapper.SysUserTenantMapper;
import org.jeecg.modules.system.service.ISysPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
@@ -64,6 +65,13 @@ public class SysImChatServiceImpl implements ISysImChatService {
private static final String MSG_IMAGE_PREVIEW = "[图片]";
private static final String MSG_BIZ_RECORD_PREVIEW = "[业务数据]";
private static final String IM_RECORD_QUERY_KEY = "imRecordId";
/** IM 工作通知公众号账号(审批等系统消息统一从此账号推送) */
private static final String WORK_NOTIFY_USERNAME = "im_work_notify";
private static final String WORK_NOTIFY_REALNAME = "工作通知";
private static final String WORK_NOTIFY_USER_ID = "1995000000000000999";
private static final String CONTACT_TYPE_WORK_NOTIFY = "work_notify";
private static final String CONTACT_TYPE_USER = "user";
private volatile String workNotifyUserIdCache;
@Autowired
private ISysPermissionService sysPermissionService;
@@ -107,7 +115,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
if (conversation != null) {
return buildConversationVo(conversation, userId, targetUserId);
}
validateTenantChat(userId, tenantId, orgCode, targetUserId);
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】工作通知公众号会话免同部门校验-----------
if (!isWorkNotifyUser(targetUserId)) {
validateTenantChat(userId, tenantId, orgCode, targetUserId);
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】工作通知公众号会话免同部门校验-----------
//update-end---author:cursor ---date:20260528 for【IM聊天-OA】已有会话快速打开-----------
conversation = new SysImConversation();
conversation.setConvType(CONV_TYPE_SINGLE);
@@ -439,6 +451,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
throw new JeecgBootException("消息内容不能为空");
}
assertMember(userId, dto.getConversationId());
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】工作通知公众号只读,禁止用户发消息-----------
if (isWorkNotifyConversation(dto.getConversationId())) {
throw new JeecgBootException("工作通知为系统消息通道,不支持发送消息");
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】工作通知公众号只读,禁止用户发消息-----------
Date now = new Date();
SysImMessage message = new SysImMessage();
message.setConversationId(dto.getConversationId());
@@ -480,8 +497,8 @@ public class SysImChatServiceImpl implements ISysImChatService {
if (oConvertUtils.isEmpty(fromUserId) || oConvertUtils.isEmpty(toUserId) || oConvertUtils.isEmpty(content)) {
return null;
}
// 不给自己发送
if (fromUserId.equals(toUserId)) {
log.warn("IM系统消息跳过收发为同一人 toUserId={}", toUserId);
return null;
}
Integer tenant = tenantId == null ? 0 : tenantId;
@@ -500,8 +517,17 @@ public class SysImChatServiceImpl implements ISysImChatService {
conversation.setCreateTime(now);
conversation.setUpdateTime(now);
conversationMapper.insert(conversation);
createMember(conversation.getId(), fromUserId, now);
createMember(conversation.getId(), toUserId, now);
ensureMember(conversation.getId(), fromUserId, now);
if (!fromUserId.equals(toUserId)) {
ensureMember(conversation.getId(), toUserId, now);
}
} else {
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】已有会话补全缺失成员-----------
ensureMember(conversation.getId(), fromUserId, now);
if (!fromUserId.equals(toUserId)) {
ensureMember(conversation.getId(), toUserId, now);
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】已有会话补全缺失成员-----------
}
// 写入消息
SysImMessage message = new SysImMessage();
@@ -522,6 +548,22 @@ public class SysImChatServiceImpl implements ISysImChatService {
pushChatMessage(conversation.getId(), fromUserId, messageVo, conversation.getConvType());
return messageVo;
}
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】审批待办统一由系统账号发给处理人-----------
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public SysImMessageVO sendApprovalHandlerMessage(String toUserId, Integer tenantId, String content, String msgType) {
if (oConvertUtils.isEmpty(toUserId) || oConvertUtils.isEmpty(content)) {
return null;
}
String fromUserId = ensureWorkNotifyUserId();
if (fromUserId.equals(toUserId)) {
log.warn("审批待办IM发送失败接收人不能是工作通知公众号 toUserId={}", toUserId);
return null;
}
return sendSystemSingleMessage(fromUserId, toUserId, tenantId, content, msgType);
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】审批待办统一由系统账号发给处理人-----------
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流设计】系统单聊消息(绕过同部门校验)-----
//update-begin---author:cursor ---date:20260528 for【IM聊天-OA】标记已读-----------
@@ -541,13 +583,19 @@ public class SysImChatServiceImpl implements ISysImChatService {
//update-begin---author:cursor ---date:20260528 for【IM聊天-OA】本部门成员列表含会话摘要-----------
@Override
public List<SysImContactVO> listDeptMembers(String userId, Integer tenantId, String orgCode, String keyword) {
List<SysImContactVO> result = new ArrayList<>();
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】同事列表置顶工作通知公众号-----------
if (matchWorkNotifyKeyword(keyword)) {
result.add(buildWorkNotifyContact(userId, tenantId));
}
String workNotifyId = ensureWorkNotifyUserId();
String resolvedOrgCode = resolveOrgCode(userId, tenantId, orgCode);
if (oConvertUtils.isEmpty(resolvedOrgCode)) {
throw new JeecgBootException("未获取到当前部门,请切换部门后重试");
return result;
}
List<SysUser> users = userDepartMapper.querySameDepartUserList(resolvedOrgCode, userId, tenantId, keyword);
if (users == null || users.isEmpty()) {
return Collections.emptyList();
return result;
}
Map<String, SysImConversationVO> convMap = new HashMap<>(16);
if (tenantId != null && tenantId > 0) {
@@ -557,20 +605,26 @@ public class SysImChatServiceImpl implements ISysImChatService {
}
}
}
List<SysImContactVO> result = users.stream().map(user -> {
SysImContactVO vo = toContactVo(user);
SysImConversationVO conv = convMap.get(user.getId());
if (conv != null) {
vo.setConversationId(conv.getConversationId());
vo.setLastContent(conv.getLastContent());
vo.setLastTime(conv.getLastTime());
vo.setUnreadCount(conv.getUnreadCount());
}
return vo;
}).collect(Collectors.toList());
result.sort(Comparator
List<SysImContactVO> colleagues = users.stream()
.filter(user -> !workNotifyId.equals(user.getId()) && !WORK_NOTIFY_USERNAME.equals(user.getUsername()))
.map(user -> {
SysImContactVO vo = toContactVo(user);
vo.setContactType(CONTACT_TYPE_USER);
SysImConversationVO conv = convMap.get(user.getId());
if (conv != null) {
vo.setConversationId(conv.getConversationId());
vo.setLastContent(conv.getLastContent());
vo.setLastTime(conv.getLastTime());
vo.setUnreadCount(conv.getUnreadCount());
}
return vo;
})
.collect(Collectors.toList());
colleagues.sort(Comparator
.comparing(SysImContactVO::getLastTime, Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(item -> oConvertUtils.getString(item.getRealname(), item.getUsername())));
result.addAll(colleagues);
//update-end---author:GHT ---date:20260610 for【IM审批通用化】同事列表置顶工作通知公众号-----------
return result;
}
//update-end---author:cursor ---date:20260528 for【IM聊天-OA】本部门成员列表含会话摘要-----------
@@ -583,9 +637,111 @@ public class SysImChatServiceImpl implements ISysImChatService {
vo.setAvatar(user.getAvatar());
vo.setOrgCodeTxt(user.getOrgCodeTxt());
vo.setUnreadCount(0);
vo.setContactType(CONTACT_TYPE_USER);
return vo;
}
private SysImContactVO buildWorkNotifyContact(String userId, Integer tenantId) {
String workNotifyId = ensureWorkNotifyUserId();
SysImContactVO vo = new SysImContactVO();
vo.setId(workNotifyId);
vo.setUsername(WORK_NOTIFY_USERNAME);
vo.setRealname(WORK_NOTIFY_REALNAME);
vo.setUnreadCount(0);
vo.setContactType(CONTACT_TYPE_WORK_NOTIFY);
if (tenantId != null && tenantId > 0) {
SysImConversationVO conv = findSingleConversationSummary(userId, tenantId, workNotifyId);
if (conv != null) {
vo.setConversationId(conv.getConversationId());
vo.setLastContent(conv.getLastContent());
vo.setLastTime(conv.getLastTime());
vo.setUnreadCount(conv.getUnreadCount());
}
}
return vo;
}
private SysImConversationVO findSingleConversationSummary(String userId, Integer tenantId, String targetUserId) {
String pairKey = buildPairKey(userId, targetUserId);
SysImConversation conversation = conversationMapper.selectOne(new LambdaQueryWrapper<SysImConversation>()
.eq(SysImConversation::getTenantId, tenantId)
.eq(SysImConversation::getUserPairKey, pairKey));
if (conversation == null) {
return null;
}
SysImConversationMember member = getMember(userId, conversation.getId());
SysImConversationVO vo = buildConversationVo(conversation, userId, targetUserId);
vo.setUnreadCount(member == null ? 0 : member.getUnreadCount());
return vo;
}
private boolean matchWorkNotifyKeyword(String keyword) {
if (oConvertUtils.isEmpty(keyword)) {
return true;
}
String key = keyword.trim().toLowerCase();
return WORK_NOTIFY_REALNAME.contains(keyword.trim())
|| WORK_NOTIFY_REALNAME.toLowerCase().contains(key)
|| WORK_NOTIFY_USERNAME.contains(key)
|| key.contains("工作")
|| key.contains("通知");
}
private String ensureWorkNotifyUserId() {
if (oConvertUtils.isNotEmpty(workNotifyUserIdCache)) {
return workNotifyUserIdCache;
}
synchronized (this) {
if (oConvertUtils.isNotEmpty(workNotifyUserIdCache)) {
return workNotifyUserIdCache;
}
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getUsername, WORK_NOTIFY_USERNAME)
.eq(SysUser::getDelFlag, 0)
.last("LIMIT 1"));
if (user == null) {
user = userMapper.selectById(WORK_NOTIFY_USER_ID);
}
if (user == null) {
user = createWorkNotifyUser();
}
workNotifyUserIdCache = user.getId();
return workNotifyUserIdCache;
}
}
private SysUser createWorkNotifyUser() {
SysUser user = new SysUser();
user.setId(WORK_NOTIFY_USER_ID);
user.setUsername(WORK_NOTIFY_USERNAME);
user.setRealname(WORK_NOTIFY_REALNAME);
user.setPassword("disabled");
user.setSalt("");
user.setStatus(2);
user.setDelFlag(0);
user.setCreateBy("system");
user.setCreateTime(new Date());
userMapper.insert(user);
return user;
}
private boolean isWorkNotifyUser(String userId) {
return oConvertUtils.isNotEmpty(userId) && userId.equals(ensureWorkNotifyUserId());
}
private boolean isWorkNotifyConversation(String conversationId) {
if (oConvertUtils.isEmpty(conversationId)) {
return false;
}
SysImConversation conversation = conversationMapper.selectById(conversationId);
if (conversation == null || !CONV_TYPE_SINGLE.equals(conversation.getConvType())) {
return false;
}
String workNotifyId = ensureWorkNotifyUserId();
String pairKey = conversation.getUserPairKey();
return oConvertUtils.isNotEmpty(pairKey) && pairKey.contains(workNotifyId);
}
private String resolveOrgCode(String userId, Integer tenantId, String orgCode) {
if (oConvertUtils.isNotEmpty(orgCode)) {
return orgCode;
@@ -610,6 +766,17 @@ public class SysImChatServiceImpl implements ISysImChatService {
}
private void createMember(String conversationId, String userId, Date now) {
ensureMember(conversationId, userId, now);
}
/** 幂等创建会话成员,避免 uk_im_member 重复插入 */
private void ensureMember(String conversationId, String userId, Date now) {
if (oConvertUtils.isEmpty(conversationId) || oConvertUtils.isEmpty(userId)) {
return;
}
if (getMember(userId, conversationId) != null) {
return;
}
SysImConversationMember member = new SysImConversationMember();
member.setConversationId(conversationId);
member.setUserId(userId);
@@ -742,7 +909,11 @@ public class SysImChatServiceImpl implements ISysImChatService {
sender = userMapper.selectById(message.getSenderId());
}
if (sender != null) {
vo.setSenderName(sender.getRealname());
if (WORK_NOTIFY_USERNAME.equals(sender.getUsername())) {
vo.setSenderName(WORK_NOTIFY_REALNAME);
} else {
vo.setSenderName(sender.getRealname());
}
vo.setSenderAvatar(sender.getAvatar());
}
return vo;

View File

@@ -28,4 +28,6 @@ public class SysImContactVO {
private java.util.Date lastTime;
@Schema(description = "未读数")
private Integer unreadCount;
@Schema(description = "联系人类型 user=同事 work_notify=工作通知公众号")
private String contactType;
}

View File

@@ -18,6 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.modules.print.vo.PrintBizFieldItemVO;
import org.jeecgframework.poi.excel.annotation.Excel;
@@ -46,6 +47,7 @@ public final class PrintBizEntityFieldIntrospector {
PrintBizFieldItemVO vo =
new PrintBizFieldItemVO(name, resolveLabel(f), "");
fillJavaJdbcSimple(vo, f.getType());
fillDictMeta(vo, f);
ordered.putIfAbsent(name, vo);
}
c = c.getSuperclass();
@@ -223,6 +225,69 @@ public final class PrintBizEntityFieldIntrospector {
return f.getName();
}
//update-begin---author:GHT ---date:2026-06-10 for【钉钉审批模板绑定】扫描@Dict并补全字典元数据-----------
/** 扫描 @Dict 注解,供绑定页选择「原值/显示文本」 */
public static void fillDictMeta(PrintBizFieldItemVO vo, Field f) {
if (vo == null || f == null) {
return;
}
Dict dict = f.getAnnotation(Dict.class);
if (dict == null) {
vo.setTranslateKind("NONE");
return;
}
if (StringUtils.isNotBlank(dict.dictTable())) {
vo.setTranslateKind("TABLE");
vo.setDictTable(dict.dictTable().trim());
vo.setDictText(StringUtils.isNotBlank(dict.dicText()) ? dict.dicText().trim() : "");
vo.setDictCodeField(StringUtils.isNotBlank(dict.dicCode()) ? dict.dicCode().trim() : "id");
} else if (StringUtils.isNotBlank(dict.dicCode())) {
vo.setTranslateKind("DICT");
vo.setDictCode(dict.dicCode().trim());
} else {
vo.setTranslateKind("NONE");
}
}
/** 按字段名在实体类上补全字典元数据catalog 缓存字段可能缺 translateKind */
public static void enrichDictMeta(List<PrintBizFieldItemVO> fields, Class<?> clazz, String fieldKeyPrefix) {
if (fields == null || fields.isEmpty() || clazz == null) {
return;
}
String prefix = StringUtils.isBlank(fieldKeyPrefix) ? "" : fieldKeyPrefix.trim();
if (StringUtils.isNotBlank(prefix) && !prefix.endsWith(".")) {
prefix = prefix + ".";
}
Map<String, Field> fieldMap = new LinkedHashMap<>();
Class<?> c = clazz;
while (c != null && c != Object.class) {
for (Field f : c.getDeclaredFields()) {
fieldMap.putIfAbsent(f.getName(), f);
}
c = c.getSuperclass();
}
for (PrintBizFieldItemVO vo : fields) {
if (vo == null || StringUtils.isBlank(vo.getFieldKey())) {
continue;
}
String key = vo.getFieldKey();
if (StringUtils.isNotBlank(prefix) && key.startsWith(prefix)) {
key = key.substring(prefix.length());
}
int dot = key.indexOf('.');
if (dot >= 0) {
key = key.substring(dot + 1);
}
Field f = fieldMap.get(key);
if (f != null) {
fillDictMeta(vo, f);
} else if (StringUtils.isBlank(vo.getTranslateKind())) {
vo.setTranslateKind("NONE");
}
}
}
//update-end---author:GHT ---date:2026-06-10 for【钉钉审批模板绑定】扫描@Dict并补全字典元数据-----------
/** 按全限定类名加载 Class失败返回 null */
public static Class<?> tryLoadClass(String entityClassFqn) {
if (StringUtils.isBlank(entityClassFqn)) {

View File

@@ -35,6 +35,24 @@ public class PrintBizFieldItemVO implements Serializable {
@Schema(description = "简化种类,便于前端格式化")
private String simpleKind;
//update-begin---author:GHT ---date:2026-06-10 for【钉钉审批模板绑定】字段元数据支持字典/表字典-----------
/** 取值翻译类型NONE=普通字段DICT=字典TABLE=表字典(部门/用户等) */
@Schema(description = "取值翻译类型NONE/DICT/TABLE")
private String translateKind;
@Schema(description = "字典编码(dicCode)translateKind=DICT 时有效")
private String dictCode;
@Schema(description = "字典表名translateKind=TABLE 时有效")
private String dictTable;
@Schema(description = "字典表文本列translateKind=TABLE 时有效")
private String dictText;
@Schema(description = "字典表编码列translateKind=TABLE 时有效")
private String dictCodeField;
//update-end---author:GHT ---date:2026-06-10 for【钉钉审批模板绑定】字段元数据支持字典/表字典-----------
/** 兼容旧三参构造(类型字段为空) */
public PrintBizFieldItemVO(String fieldKey, String label, String description) {
this.fieldKey = fieldKey;
@@ -53,6 +71,13 @@ public class PrintBizFieldItemVO implements Serializable {
o.setJavaType(src.getJavaType());
o.setJdbcType(src.getJdbcType());
o.setSimpleKind(src.getSimpleKind());
//update-begin---author:GHT ---date:2026-06-10 for【钉钉审批模板绑定】复制字段时保留字典元数据-----------
o.setTranslateKind(src.getTranslateKind());
o.setDictCode(src.getDictCode());
o.setDictTable(src.getDictTable());
o.setDictText(src.getDictText());
o.setDictCodeField(src.getDictCodeField());
//update-end---author:GHT ---date:2026-06-10 for【钉钉审批模板绑定】复制字段时保留字典元数据-----------
}
return o;
}

View File

@@ -56,6 +56,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.*;
//update-begin---author:GHT ---date:2026-06-08 for【XSLMES-20260608】同步钉钉ID功能-----------
import com.jeecg.dingtalk.api.core.response.Response;
import com.jeecg.dingtalk.api.user.JdtUserAPI;
import org.jeecg.modules.system.service.impl.ThirdAppDingtalkServiceImpl;
//update-end---author:GHT ---date:2026-06-08 for【XSLMES-20260608】同步钉钉ID功能-----------
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
@@ -125,6 +130,11 @@ public class SysUserController {
@Autowired(required = false)
private SimpMessagingTemplate simpMessagingTemplate;
//update-begin---author:GHT ---date:2026-06-08 for【XSLMES-20260608】注入钉钉服务用于同步钉钉ID-----------
@Autowired(required = false)
private ThirdAppDingtalkServiceImpl thirdAppDingtalkService;
//update-end---author:GHT ---date:2026-06-08 for【XSLMES-20260608】注入钉钉服务用于同步钉钉ID-----------
private void notifyScadaUserChanged(String action, String userId) {
try {
JSONObject payload = new JSONObject();
@@ -2246,6 +2256,60 @@ public class SysUserController {
* yes_{URL编码后的默认密码} -> 用户当前密码为默认初始密码,前端需弹出强制修改提示
* no -> 用户密码不是默认密码,或未开启默认密码检测开关
*/
//update-begin---author:GHT ---date:2026-06-08 for【XSLMES-20260608】批量同步钉钉用户ID接口-----------
/**
* 批量同步钉钉ID根据用户手机号查询钉钉userId并回写到sys_user.ding_user_id。
* 匹配不到的用户只做提示,不影响其他用户继续匹配。
*/
@Operation(summary = "同步钉钉用户ID")
@PostMapping("/syncDingUserId")
public Result<JSONObject> syncDingUserId() {
if (thirdAppDingtalkService == null) {
return Result.error("钉钉集成未配置,无法同步");
}
String accessToken = thirdAppDingtalkService.getAccessTokenForBackground();
if (oConvertUtils.isEmpty(accessToken)) {
return Result.error("获取钉钉 AccessToken 失败,请检查钉钉应用配置");
}
// 查询所有有手机号的用户
List<SysUser> users = sysUserService.list(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysUser>()
.isNotNull(SysUser::getPhone)
.ne(SysUser::getPhone, "")
.eq(SysUser::getDelFlag, 0)
);
int successCount = 0;
int failCount = 0;
List<String> failDetails = new ArrayList<>();
for (SysUser user : users) {
try {
Response<String> resp = JdtUserAPI.getUseridByMobile(user.getPhone(), accessToken);
if (resp != null && resp.isSuccess() && oConvertUtils.isNotEmpty(resp.getResult())) {
sysUserService.lambdaUpdate()
.eq(SysUser::getId, user.getId())
.set(SysUser::getDingUserId, resp.getResult())
.update();
successCount++;
} else {
failCount++;
failDetails.add(user.getRealname() + "(" + user.getPhone() + ")");
log.info("[syncDingUserId] 手机号未匹配到钉钉用户 realname={} phone={}", user.getRealname(), user.getPhone());
}
} catch (Exception e) {
failCount++;
failDetails.add(user.getRealname() + "(" + user.getPhone() + ")");
log.warn("[syncDingUserId] 查询钉钉ID异常 realname={} phone={}", user.getRealname(), user.getPhone(), e);
}
}
JSONObject result = new JSONObject();
result.put("successCount", successCount);
result.put("failCount", failCount);
result.put("failDetails", failDetails);
String msg = "同步完成:成功 " + successCount + " 人,未匹配 " + failCount + "";
return Result.OK(msg, result);
}
//update-end---author:GHT ---date:2026-06-08 for【XSLMES-20260608】批量同步钉钉用户ID接口-----------
@GetMapping("/verifyIzDefaultPwd")
public Result<String> verifyIzDefaultPwd() throws UnsupportedEncodingException {
// 未配置 Firewall 或已关闭默认密码检测开关 (enableDefaultPwdCheck=false) 时,直接返回 "no" 表示无需提示

View File

@@ -32,8 +32,12 @@ import org.springframework.web.bind.annotation.*;
import jakarta.servlet.http.HttpServletRequest;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

View File

@@ -72,6 +72,17 @@ public class SysThirdAppConfig {
private Integer streamEnabled;
//update-end---author:GHT ---date:20260604 for【钉钉Stream回调】Stream事件推送主配置标识-----
//update-begin---author:GHT ---date:20260609 for【钉钉Stream开发】第三方配置页Stream接收节点可视化-----------
@Schema(description = "是否限制仅指定节点接收Stream(0-否,1-是)")
private Integer streamReceiverEnabled;
@Schema(description = "允许接收Stream的IP白名单逗号分隔")
private String streamDesignatedIps;
@Schema(description = "允许接收Stream的主机名白名单逗号分隔")
private String streamDesignatedHosts;
@Schema(description = "Stream集群Redis选主(0-否,1-是)")
private Integer streamClusterMode;
//update-end---author:GHT ---date:20260609 for【钉钉Stream开发】第三方配置页Stream接收节点可视化-----------
/**创建日期*/
@Excel(name = "创建日期", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")

View File

@@ -272,4 +272,11 @@ public class SysUser implements Serializable {
*/
@TableField(exist = false)
private String belongDepIds;
//update-begin---author:GHT ---date:2026-06-08 for【XSLMES-20260608】新增钉钉用户ID字段支持同步钉钉ID功能-----------
/**
* 钉钉用户ID
*/
private String dingUserId;
//update-end---author:GHT ---date:2026-06-08 for【XSLMES-20260608】新增钉钉用户ID字段支持同步钉钉ID功能-----------
}

View File

@@ -1228,6 +1228,29 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
}
//update-end---author:GHT ---date:20260604 for【钉钉Stream回调】获取钉钉应用凭证Stream模式专用-----
//update-begin---author:GHT ---date:20260609 for【钉钉Stream开发】获取Stream主配置含节点白名单-----------
/**
* 获取 Stream 主配置记录stream_enabled=1 优先)。
*/
public SysThirdAppConfig getStreamMasterConfig() {
java.util.List<SysThirdAppConfig> all = configMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SysThirdAppConfig>()
.eq(SysThirdAppConfig::getThirdType, THIRD_TYPE)
.eq(SysThirdAppConfig::getStatus, 1)
.orderByDesc(SysThirdAppConfig::getStreamEnabled)
.orderByDesc(SysThirdAppConfig::getTenantId));
if (all == null || all.isEmpty()) {
return null;
}
for (SysThirdAppConfig c : all) {
if (c.getStreamEnabled() != null && c.getStreamEnabled() == 1) {
return c;
}
}
return all.get(0);
}
//update-end---author:GHT ---date:20260609 for【钉钉Stream开发】获取Stream主配置含节点白名单-----------
//update-begin---author:GHT ---date:20260604 for【钉钉Stream回调】后台线程专用AccessToken绕过租户检查-----
/**
* 后台线程专用:获取钉钉 AccessToken不依赖 TenantContext。

View File

@@ -34,6 +34,12 @@
<artifactId>jeecg-module-xslmes</artifactId>
<version>${jeecgboot.version}</version>
</dependency>
<!-- 钉钉 Stream SDK显式声明确保 IDE 调试运行时 classpath 包含 dingtalk-stream GHT 20260605 -->
<dependency>
<groupId>com.dingtalk.open</groupId>
<artifactId>dingtalk-stream</artifactId>
<version>1.3.12</version>
</dependency>
<dependency>
<groupId>org.jeecgframework.boot3</groupId>
<artifactId>jeecg-module-device-sync</artifactId>

View File

@@ -0,0 +1,21 @@
# 复制为 application-dev-local.yml同目录仅本机生效勿提交 Git
# 作用:只有你这台电脑接收钉钉 Stream 回调与补偿扫描,其他共用 dev 库的机器不会抢消息
#
# 1. 复制application-dev-local.yml.example -> application-dev-local.yml
# 2. 查本机 IPPowerShell: ipconfig看 IPv4 地址)
# 3. 将 designated-ips 改成你的 IP推荐比主机名稳定
# 4. 重启 JeecgBoot
#
# 启动后若未匹配,日志会打印 localIps=... 便于核对
jeecg:
xslmes:
dingtalk:
stream:
receiver-enabled: true
# 推荐:仅 IP 白名单(二选一或同时配置,满足其一即可)
designated-ips:
- 192.168.1.100
# 可选主机名白名单hostname 命令查看)
# designated-hosts:
# - LAPTOP-9LEM1NNJ

View File

@@ -20,6 +20,9 @@ management:
include: metrics,httpexchanges,jeecghttptrace
spring:
config:
# 开发者本机覆盖配置(不提交 Git用于指定仅本机接收钉钉 Stream 回调
import: optional:classpath:application-dev-local.yml
# main:
# # 启动加速 (建议开发环境开启后flyway自动升级失效)
# lazy-initialization: true
@@ -211,6 +214,20 @@ mybatis-plus:
minidao:
base-package: org.jeecg.modules.jmreport.*,org.jeecg.modules.drag.*
jeecg:
xslmes:
dingtalk:
stream:
# 共享 dev 默认关闭;仅本机在 application-dev-local.yml 开启(见 application-dev-local.yml.example
receiver-enabled: false
# 白名单二选一或同时配置(满足其一即可);推荐 designated-ips比主机名稳定
designated-hosts: []
designated-ips: []
# 多实例部署务必 trueRedis 选主,仅 Leader 建 Stream 长连接
cluster-mode: true
leader-renew-interval-ms: 10000
follower-retry-interval-ms: 15000
health-log-interval-ms: 60000
idle-warn-seconds: 1800
# 自定义资源请求前缀js、css等解决nginx转发问题
custom-resource-prefix-path:
# AI集成

View File

@@ -0,0 +1,115 @@
-- 审核集成 Phase0新建4张集成表 + 扩展审批台账
-- author: GHT date: 2026-06-05
SET NAMES utf8mb4;
-- 单据注册中心
CREATE TABLE IF NOT EXISTS `mes_xsl_biz_doc_registry` (
`id` varchar(32) NOT NULL COMMENT '主键',
`doc_code` varchar(64) NOT NULL COMMENT '业务编码 formula_spec',
`table_name` varchar(128) NOT NULL COMMENT '物理表名',
`display_name` varchar(128) DEFAULT NULL COMMENT '中文名',
`enabled` tinyint DEFAULT 1 COMMENT '启用 0否 1是',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`del_flag` int DEFAULT 0 COMMENT '逻辑删除',
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
`sys_org_code` varchar(64) DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_biz_doc_code_tenant` (`doc_code`, `tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES单据注册中心';
-- 预置常用单据
INSERT IGNORE INTO `mes_xsl_biz_doc_registry`
(`id`, `doc_code`, `table_name`, `display_name`, `enabled`, `del_flag`, `tenant_id`, `create_by`, `create_time`)
VALUES
(REPLACE(UUID(),'-',''), 'formula_spec', 'mes_xsl_formula_spec', '配合示方', 1, 0, 0, 'admin', NOW()),
(REPLACE(UUID(),'-',''), 'mixing_spec', 'mes_xsl_mixing_spec', '密炼示方', 1, 0, 0, 'admin', NOW()),
(REPLACE(UUID(),'-',''), 'mixer_ps_compile', 'mes_xsl_mixer_ps_compile', '密炼PS编制', 1, 0, 0, 'admin', NOW()),
(REPLACE(UUID(),'-',''), 'rubber_quick_test_std', 'mes_xsl_rubber_quick_test_std', '快检实验标准', 1, 0, 0, 'admin', NOW()),
(REPLACE(UUID(),'-',''), 'raw_material_entry', 'mes_xsl_raw_material_entry', '原料入场记录', 1, 0, 0, 'admin', NOW());
-- 集成方案
CREATE TABLE IF NOT EXISTS `mes_xsl_integration_plan` (
`id` varchar(32) NOT NULL COMMENT '主键',
`plan_code` varchar(64) NOT NULL COMMENT '方案编码唯一',
`plan_name` varchar(128) NOT NULL COMMENT '方案名称',
`source_table` varchar(128) NOT NULL COMMENT '源单表名',
`trigger_phase` varchar(20) NOT NULL COMMENT '触发时机 onApprove/onReject/onNodeApprove',
`exec_mode` varchar(10) DEFAULT 'async' COMMENT '执行模式 sync同步/async异步提交后',
`match_condition` varchar(500) DEFAULT NULL COMMENT '匹配条件=无条件',
`status` varchar(1) DEFAULT '0' COMMENT '0草稿 1已发布 2已停用',
`remark` varchar(500) DEFAULT NULL,
`del_flag` int DEFAULT 0,
`tenant_id` int DEFAULT NULL,
`sys_org_code` varchar(64) DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_int_plan_table_phase` (`source_table`, `trigger_phase`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审核集成方案';
-- 集成动作
CREATE TABLE IF NOT EXISTS `mes_xsl_integration_action` (
`id` varchar(32) NOT NULL COMMENT '主键',
`plan_id` varchar(32) NOT NULL COMMENT '所属方案ID',
`action_name` varchar(128) NOT NULL COMMENT '动作名称',
`action_type` varchar(30) NOT NULL DEFAULT 'SQL_UPDATE' COMMENT '动作类型 Phase0仅SQL_UPDATE',
`sql_template` text DEFAULT NULL COMMENT 'SQL_UPDATE模板支持#{source.xxx}变量',
`exec_order` int DEFAULT 0 COMMENT '执行顺序升序',
`on_fail` varchar(10) DEFAULT 'stop' COMMENT '失败策略 stop终止/continue继续',
`idempotent_key` varchar(200) DEFAULT NULL COMMENT '幂等键表达式=record_id+action_id',
`enabled` tinyint DEFAULT 1 COMMENT '启用',
`remark` varchar(500) DEFAULT NULL,
`del_flag` int DEFAULT 0,
`create_by` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_int_action_plan` (`plan_id`, `exec_order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审核集成动作';
-- 集成执行日志
CREATE TABLE IF NOT EXISTS `mes_xsl_integration_log` (
`id` varchar(32) NOT NULL COMMENT '主键',
`record_id` varchar(32) DEFAULT NULL COMMENT '审批台账ID',
`plan_id` varchar(32) DEFAULT NULL COMMENT '方案ID',
`action_id` varchar(32) DEFAULT NULL COMMENT '动作ID',
`idempotent_key` varchar(200) DEFAULT NULL COMMENT '幂等键',
`status` varchar(10) DEFAULT NULL COMMENT 'success/failed/skipped',
`source_biz_id` varchar(64) DEFAULT NULL COMMENT '源单ID',
`source_biz_table` varchar(128) DEFAULT NULL COMMENT '源单表名',
`error_message` text DEFAULT NULL COMMENT '错误信息',
`retry_count` int DEFAULT 0 COMMENT '重试次数',
`exec_time_ms` bigint DEFAULT NULL COMMENT '耗时ms',
`request_snapshot` text DEFAULT NULL COMMENT '执行前变量快照',
`response_snapshot` text DEFAULT NULL COMMENT '执行结果快照',
`create_by` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_intlog_record` (`record_id`),
KEY `idx_intlog_idempotent` (`idempotent_key`(191)),
KEY `idx_intlog_plan_action` (`plan_id`, `action_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审核集成执行日志';
-- 扩展 mes_xsl_approval_record幂等列已存在则跳过避免重复执行报 1060
SET @db = DATABASE();
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_approval_record' AND COLUMN_NAME = 'integration_status') = 0,
'ALTER TABLE `mes_xsl_approval_record` ADD COLUMN `integration_status` varchar(2) DEFAULT ''0'' COMMENT ''编排状态 0未执行 1成功 2部分失败 3失败'' AFTER `finish_time`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_approval_record' AND COLUMN_NAME = 'integration_remark') = 0,
'ALTER TABLE `mes_xsl_approval_record` ADD COLUMN `integration_remark` varchar(500) DEFAULT NULL COMMENT ''编排摘要/错误信息'' AFTER `integration_status`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

View File

@@ -0,0 +1,74 @@
-- 审核集成 Phase0字典数据
-- author: GHT date: 2026-06-05
SET NAMES utf8mb4;
-- 集成动作类型
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000360','集成动作类型','mes_xsl_integration_action_type','审核集成动作类型',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000361','1995000000000000360','SQL更新','SQL_UPDATE','执行UPDATE/INSERT SQL',1,1,'admin',NOW()),
('1995000000000000362','1995000000000000360','更新单据','UPDATE_DOC','结构化更新目标单据Phase1',2,1,'admin',NOW()),
('1995000000000000363','1995000000000000360','生成单据','CREATE_DOC','生成目标主+子表Phase1',3,1,'admin',NOW()),
('1995000000000000364','1995000000000000360','调用接口','CALL_API','HTTP调用业务接口Phase2',4,1,'admin',NOW()),
('1995000000000000365','1995000000000000360','调用Handler','CALL_HANDLER','Spring Bean处理Phase2',5,1,'admin',NOW());
-- 集成触发时机
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000366','集成触发时机','mes_xsl_integration_trigger_phase','审核集成方案触发时机',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000367','1995000000000000366','审批通过','onApprove','整个流程最终通过时触发',1,1,'admin',NOW()),
('1995000000000000368','1995000000000000366','审批驳回','onReject','任一节点驳回时触发',2,1,'admin',NOW()),
('1995000000000000369','1995000000000000366','节点通过','onNodeApprove','单个节点通过中间态时触发',3,1,'admin',NOW());
-- 集成方案状态
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000370','集成方案状态','mes_xsl_integration_plan_status','审核集成方案状态',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000371','1995000000000000370','草稿','0','未发布不生效',1,1,'admin',NOW()),
('1995000000000000372','1995000000000000370','已发布','1','生效中',2,1,'admin',NOW()),
('1995000000000000373','1995000000000000370','已停用','2','已停用',3,1,'admin',NOW());
-- 集成执行日志状态
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000374','集成执行状态','mes_xsl_integration_log_status','审核集成执行日志状态',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000375','1995000000000000374','成功','success','执行成功',1,1,'admin',NOW()),
('1995000000000000376','1995000000000000374','失败','failed','执行失败',2,1,'admin',NOW()),
('1995000000000000377','1995000000000000374','已跳过','skipped','幂等命中跳过',3,1,'admin',NOW());
-- 集成执行模式
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000378','集成执行模式','mes_xsl_integration_exec_mode','审批后编排执行模式',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000379','1995000000000000378','异步推荐','async','事务提交后异步执行审批不因编排失败回滚',1,1,'admin',NOW()),
('1995000000000000380','1995000000000000378','同步','sync','与审批同事务编排失败回滚审批',2,1,'admin',NOW());
-- 编排执行状态台账扩展字段
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000381','编排执行状态','mes_xsl_integration_orch_status','审批台账的编排执行状态',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000382','1995000000000000381','未执行','0','未触发编排',1,1,'admin',NOW()),
('1995000000000000383','1995000000000000381','全部成功','1','所有动作均成功',2,1,'admin',NOW()),
('1995000000000000384','1995000000000000381','部分失败','2','存在on_fail=continue的失败动作',3,1,'admin',NOW()),
('1995000000000000385','1995000000000000381','失败','3','遇到on_fail=stop的失败动作中止',4,1,'admin',NOW());
-- 失败策略
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000386','动作失败策略','mes_xsl_integration_on_fail','集成动作失败后的处理策略',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000387','1995000000000000386','停止','stop','失败后停止后续动作',1,1,'admin',NOW()),
('1995000000000000388','1995000000000000386','继续','continue','失败后继续执行后续动作',2,1,'admin',NOW());

View File

@@ -0,0 +1,50 @@
-- 审核集成 Phase0菜单 + 权限挂在 MESToDing审批配置 父菜单 178046026420801
-- author: GHT date: 2026-06-05
SET NAMES utf8mb4;
-- 单据注册中心
INSERT INTO sys_permission(id,parent_id,name,url,component,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_route,is_leaf,keep_alive,hidden,hide_tab,description,status,del_flag,rule_flag,create_by,create_time,update_by,update_time,internal_or_external)
VALUES('178046026420838','178046026420801','单据注册中心','/xslmes/mesXslBizDocRegistryList','xslmes/approval/integration/MesXslBizDocRegistryList',NULL,NULL,0,NULL,'1',4.00,0,'ant-design:database-outlined',1,0,0,0,0,NULL,'1',0,0,'admin','2026-06-05 00:00:00',NULL,NULL,0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420839','178046026420838','查询单据注册',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_biz_doc_registry:list','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420840','178046026420838','新增单据注册',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_biz_doc_registry:add','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420841','178046026420838','编辑单据注册',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_biz_doc_registry:edit','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420842','178046026420838','删除单据注册',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_biz_doc_registry:delete','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
-- 集成方案管理含内嵌动作管理
INSERT INTO sys_permission(id,parent_id,name,url,component,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_route,is_leaf,keep_alive,hidden,hide_tab,description,status,del_flag,rule_flag,create_by,create_time,update_by,update_time,internal_or_external)
VALUES('178046026420830','178046026420801','集成方案管理','/xslmes/mesXslIntegrationPlanList','xslmes/approval/integration/MesXslIntegrationPlanList',NULL,NULL,0,NULL,'1',5.00,0,'ant-design:node-index-outlined',1,0,0,0,0,NULL,'1',0,0,'admin','2026-06-05 00:00:00',NULL,NULL,0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420831','178046026420830','查询集成方案',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_plan:list','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420832','178046026420830','新增集成方案',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_plan:add','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420833','178046026420830','编辑集成方案',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_plan:edit','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420834','178046026420830','删除集成方案',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_plan:delete','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420843','178046026420830','发布集成方案',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_plan:publish','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
-- 集成执行日志
INSERT INTO sys_permission(id,parent_id,name,url,component,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_route,is_leaf,keep_alive,hidden,hide_tab,description,status,del_flag,rule_flag,create_by,create_time,update_by,update_time,internal_or_external)
VALUES('178046026420835','178046026420801','集成执行日志','/xslmes/mesXslIntegrationLogList','xslmes/approval/integration/MesXslIntegrationLogList',NULL,NULL,0,NULL,'1',6.00,0,'ant-design:file-search-outlined',1,0,0,0,0,NULL,'1',0,0,'admin','2026-06-05 00:00:00',NULL,NULL,0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420836','178046026420835','查询集成日志',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_log:list','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
INSERT INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420837','178046026420835','重试集成动作',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_integration_log:retry','1',NULL,0,NULL,1,0,0,0,NULL,'admin','2026-06-05 00:00:00',NULL,NULL,0,0,'1',0);
-- 授权给超管角色f6817f48af4fb3af11b9e8bf182f618b
INSERT INTO sys_role_permission (id,role_id,permission_id,data_rule_ids,operate_date,operate_ip)
SELECT REPLACE(UUID(),'-',''),'f6817f48af4fb3af11b9e8bf182f618b',id,NULL,'2026-06-05 00:00:00','127.0.0.1'
FROM sys_permission
WHERE id IN (
'178046026420830','178046026420831','178046026420832','178046026420833','178046026420834','178046026420843',
'178046026420835','178046026420836','178046026420837',
'178046026420838','178046026420839','178046026420840','178046026420841','178046026420842'
);

View File

@@ -0,0 +1,106 @@
-- 审核集成 Phase0密炼PS编制 集成方案演示数据
-- 功能说明
-- 将密炼PS现有三节点审批校对审核批准的状态流转逻辑
-- 转化为可视化的集成方案配置验证 SQL_UPDATE 动作执行器的实际效果
-- 注意
-- 方案初始状态为"草稿(0)"不会自动触发
-- 需要在集成方案管理页面手动"发布"后才生效
-- 现有 @ApprovalBizAction HTTP 回调仍然生效两套并行SQL AND status=? 条件防重
-- author: GHT date: 2026-06-05
SET NAMES utf8mb4;
-- =============================================================
-- 方案一审批全部通过 推进主表 + 配合示方到最终批准态
-- 触发时机onApprove最终通过整个流程时
-- =============================================================
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`trigger_phase`,`exec_mode`,`match_condition`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
VALUES
('mxpsonapproveplan000001','mixer_ps_on_approve','密炼PS-审批通过批准态同步','mes_xsl_mixer_ps_compile','onApprove','async',NULL,'0',
'最终审批通过后主表 statusapprove配合示方 statusrecognition_pass',
0,0,'admin',NOW());
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`sql_template`,`exec_order`,`on_fail`,`enabled`,`remark`,`del_flag`,`create_by`,`create_time`)
VALUES
('mxpsonapprove_act001','mxpsonapproveplan000001',
'主表批准态','SQL_UPDATE',
'UPDATE mes_xsl_mixer_ps_compile SET status=''approve'', approve_time=NOW() WHERE id=#{source.id} AND status=''audit''',
1,'stop',1,'只在 audit 态才更新防止重复触发',0,'admin',NOW()),
('mxpsonapprove_act002','mxpsonapproveplan000001',
'配合示方认定通过','SQL_UPDATE',
'UPDATE mes_xsl_formula_spec SET status=''recognition_pass'', approve_time=NOW() WHERE issue_number=#{source.issue_number} AND issue_number IS NOT NULL',
2,'continue',1,'通过 issue_number 级联同步issue_number 为空时影响0行自动跳过',0,'admin',NOW()),
('mxpsonapprove_act003','mxpsonapproveplan000001',
'混炼示方同步批准时间','SQL_UPDATE',
'UPDATE mes_xsl_mixing_spec SET approve_time=NOW() WHERE issue_number=#{source.issue_number} AND issue_number IS NOT NULL',
3,'continue',1,'仅同步时间戳不改变混炼示方 status',0,'admin',NOW());
-- =============================================================
-- 方案二审批驳回 全量回退到编制态清空所有痕迹
-- 触发时机onReject任一节点被驳回时
-- =============================================================
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`trigger_phase`,`exec_mode`,`match_condition`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
VALUES
('mxpsonrejectplan000002','mixer_ps_on_reject','密炼PS-审批驳回恢复编制态','mes_xsl_mixer_ps_compile','onReject','async',NULL,'0',
'驳回后主表+配合示方回到 compile清空校对/审核/批准全部痕迹字段',
0,0,'admin',NOW());
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`sql_template`,`exec_order`,`on_fail`,`enabled`,`remark`,`del_flag`,`create_by`,`create_time`)
VALUES
('mxpsonreject_act001','mxpsonrejectplan000002',
'主表回退编制态','SQL_UPDATE',
'UPDATE mes_xsl_mixer_ps_compile SET status=''compile'', proofread_by=NULL, proofread_time=NULL, audit_by=NULL, audit_time=NULL, approve_by=NULL, approve_time=NULL WHERE id=#{source.id}',
1,'stop',1,'无条件回退清空所有审批痕迹',0,'admin',NOW()),
('mxpsonreject_act002','mxpsonrejectplan000002',
'配合示方回退编制态','SQL_UPDATE',
'UPDATE mes_xsl_formula_spec SET status=''compile'', proofread_by=NULL, proofread_time=NULL, audit_by=NULL, audit_time=NULL, approve_by=NULL, approve_time=NULL WHERE issue_number=#{source.issue_number} AND issue_number IS NOT NULL',
2,'continue',1,'级联回退配合示方状态',0,'admin',NOW()),
('mxpsonreject_act003','mxpsonrejectplan000002',
'混炼示方清空痕迹','SQL_UPDATE',
'UPDATE mes_xsl_mixing_spec SET proofread_by=NULL, proofread_time=NULL, audit_by=NULL, audit_time=NULL, approve_by=NULL, approve_time=NULL WHERE issue_number=#{source.issue_number} AND issue_number IS NOT NULL',
3,'continue',1,'混炼示方只清痕迹不改 status',0,'admin',NOW());
-- =============================================================
-- 方案三节点逐级通过 利用条件 WHERE 区分校对/审核两个节点
-- 触发时机onNodeApprove每通过一个中间节点时触发一次
-- 关键设计每个 UPDATE AND status='当前期望状态' 条件
-- status 不匹配时影响 0 自动跳过实现节点自动识别
-- =============================================================
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`trigger_phase`,`exec_mode`,`match_condition`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
VALUES
('mxpsnodeapprplan000003','mixer_ps_node_approve','密炼PS-节点通过逐级状态推进','mes_xsl_mixer_ps_compile','onNodeApprove','async',NULL,'0',
'利用条件 WHERE 区分校对/审核两节点每次只有一条 SQL 真正命中影响1行另一条影响0行自动跳过',
0,0,'admin',NOW());
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`sql_template`,`exec_order`,`on_fail`,`enabled`,`remark`,`del_flag`,`create_by`,`create_time`)
VALUES
-- 第12条校对节点通过当前 status=compile 时命中
('mxpsnodeappr_act001','mxpsnodeapprplan000003',
'校对通过-主表proofread','SQL_UPDATE',
'UPDATE mes_xsl_mixer_ps_compile SET status=''proofread'', proofread_time=NOW() WHERE id=#{source.id} AND status=''compile''',
1,'continue',1,'status=compile 才命中校对节点status=proofread 时影响0行自动跳过',0,'admin',NOW()),
('mxpsnodeappr_act002','mxpsnodeapprplan000003',
'校对通过-配合示方submit','SQL_UPDATE',
'UPDATE mes_xsl_formula_spec SET status=''submit'', proofread_time=NOW() WHERE issue_number=#{source.issue_number} AND status=''compile'' AND issue_number IS NOT NULL',
2,'continue',1,'配合示方校对态同步',0,'admin',NOW()),
-- 第34条审核节点通过当前 status=proofread 时命中
('mxpsnodeappr_act003','mxpsnodeapprplan000003',
'审核通过-主表audit','SQL_UPDATE',
'UPDATE mes_xsl_mixer_ps_compile SET status=''audit'', audit_time=NOW() WHERE id=#{source.id} AND status=''proofread''',
3,'continue',1,'status=proofread 才命中审核节点校对节点时影响0行跳过',0,'admin',NOW()),
('mxpsnodeappr_act004','mxpsnodeapprplan000003',
'审核通过-配合示方review_pass','SQL_UPDATE',
'UPDATE mes_xsl_formula_spec SET status=''review_pass'', audit_time=NOW() WHERE issue_number=#{source.issue_number} AND status=''submit'' AND issue_number IS NOT NULL',
4,'continue',1,'配合示方审核态同步',0,'admin',NOW());

View File

@@ -0,0 +1,5 @@
-- 审核集成 Phase0新增动作可视化配置字段
-- 用于存储可视化编辑器的配置 JSON支持重新打开时还原可视化状态
-- author: GHT date: 2026-06-05
ALTER TABLE `mes_xsl_integration_action`
ADD COLUMN `action_config` TEXT DEFAULT NULL COMMENT '可视化配置JSON可视化编辑器专用用于重新打开时还原配置' AFTER `sql_template`;

View File

@@ -0,0 +1,132 @@
-- 审批注册中心扩展注册配置 + 审批痕迹明细表每单据一行
-- author: GHT date: 2026-06-05 forXSLMES-20260605-K8R2
SET NAMES utf8mb4;
SET @db = DATABASE();
-- 扩展 mes_xsl_biz_doc_registry幂等列已存在则跳过
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'enabled_stages') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `enabled_stages` varchar(128) DEFAULT NULL COMMENT ''启用环节(多选逗号分隔 proofread,audit,approve)'' AFTER `enabled`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'status_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `status_field` varchar(64) DEFAULT ''status'' COMMENT ''业务状态字段名'' AFTER `enabled_stages`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'proofread_by_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `proofread_by_field` varchar(64) DEFAULT ''proofread_by'' COMMENT ''校对人字段名'' AFTER `status_field`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'proofread_time_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `proofread_time_field` varchar(64) DEFAULT ''proofread_time'' COMMENT ''校对时间字段名'' AFTER `proofread_by_field`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'audit_by_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `audit_by_field` varchar(64) DEFAULT ''audit_by'' COMMENT ''审核人字段名'' AFTER `proofread_time_field`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'audit_time_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `audit_time_field` varchar(64) DEFAULT ''audit_time'' COMMENT ''审核时间字段名'' AFTER `audit_by_field`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'approve_by_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `approve_by_field` varchar(64) DEFAULT ''approve_by'' COMMENT ''批准人字段名'' AFTER `audit_time_field`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_biz_doc_registry' AND COLUMN_NAME = 'approve_time_field') = 0,
'ALTER TABLE `mes_xsl_biz_doc_registry` ADD COLUMN `approve_time_field` varchar(64) DEFAULT ''approve_time'' COMMENT ''批准时间字段名'' AFTER `approve_by_field`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
ALTER TABLE `mes_xsl_biz_doc_registry` COMMENT='MES审批注册中心';
-- 密炼PS编制默认开启三环节
UPDATE `mes_xsl_biz_doc_registry`
SET `enabled_stages` = 'proofread,audit,approve',
`status_field` = 'status',
`proofread_by_field` = 'proofread_by',
`proofread_time_field` = 'proofread_time',
`audit_by_field` = 'audit_by',
`audit_time_field` = 'audit_time',
`approve_by_field` = 'approve_by',
`approve_time_field` = 'approve_time',
`update_by` = 'admin',
`update_time` = NOW()
WHERE `doc_code` = 'mixer_ps_compile' AND `del_flag` = 0;
-- 审批痕迹明细每业务单据一行 biz_table + biz_data_id 唯一
CREATE TABLE IF NOT EXISTS `mes_xsl_approval_trace` (
`id` varchar(32) NOT NULL COMMENT '主键',
`registry_id` varchar(32) DEFAULT NULL COMMENT '审批注册配置ID',
`biz_table` varchar(128) NOT NULL COMMENT '业务表名',
`biz_data_id` varchar(32) NOT NULL COMMENT '业务单据ID',
`proofread_by` varchar(80) DEFAULT NULL COMMENT '校对人',
`proofread_time` datetime DEFAULT NULL COMMENT '校对时间',
`audit_by` varchar(80) DEFAULT NULL COMMENT '审核人',
`audit_time` datetime DEFAULT NULL COMMENT '审核时间',
`approve_by` varchar(80) DEFAULT NULL COMMENT '批准人',
`approve_time` datetime DEFAULT NULL COMMENT '批准时间',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`del_flag` int DEFAULT 0 COMMENT '逻辑删除',
`tenant_id` int DEFAULT NULL COMMENT '租户ID',
`sys_org_code` varchar(64) DEFAULT NULL,
`create_by` varchar(50) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_by` varchar(50) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_approval_trace_biz` (`biz_table`, `biz_data_id`, `tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES审批痕迹明细(每单据一行)';
-- 审批环节字典注册中心多选
INSERT IGNORE INTO `sys_dict` (`id`,`dict_name`,`dict_code`,`description`,`del_flag`,`create_by`,`create_time`,`type`,`tenant_id`)
VALUES ('1995000000000000390','审批环节','mes_xsl_approval_stage','审批注册中心可启用环节',0,'admin',NOW(),0,0);
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000391','1995000000000000390','校对','proofread','校对环节',1,1,'admin',NOW()),
('1995000000000000392','1995000000000000390','审核','audit','审核环节',2,1,'admin',NOW()),
('1995000000000000393','1995000000000000390','批准','approve','批准环节',3,1,'admin',NOW());
-- 菜单重命名 + 新增审批痕迹
UPDATE `sys_permission`
SET `name` = '审批注册中心', `update_by` = 'admin', `update_time` = NOW()
WHERE `id` = '178046026420838';
INSERT IGNORE INTO `sys_permission`
(`id`,`parent_id`,`name`,`url`,`component`,`is_route`,`component_name`,`redirect`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`rule_flag`,`create_by`,`create_time`)
VALUES
('178046026420843','178046026420801','审批痕迹','/xslmes/mesXslApprovalTraceList','xslmes/approval/integration/MesXslApprovalTraceList',1,NULL,0,NULL,1,4.50,0,'ant-design:history-outlined',1,0,0,0,0,NULL,1,0,0,'admin',NOW());
INSERT IGNORE INTO `sys_permission`
(`id`,`parent_id`,`name`,`perms`,`perms_type`,`menu_type`,`sort_no`,`is_leaf`,`create_by`,`create_time`)
VALUES
('178046026420844','178046026420843','查询审批痕迹','xslmes:mes_xsl_approval_trace:list',1,2,1,1,'admin',NOW());
INSERT IGNORE INTO `sys_role_permission` (`id`,`role_id`,`permission_id`,`operate_date`,`operate_ip`)
VALUES (REPLACE(UUID(),'-',''),'f6817f48af4fb3af11b9e8bf182f618b','178046026420843',NOW(),'127.0.0.1');
INSERT IGNORE INTO `sys_role_permission` (`id`,`role_id`,`permission_id`,`operate_date`,`operate_ip`)
VALUES (REPLACE(UUID(),'-',''),'f6817f48af4fb3af11b9e8bf182f618b','178046026420844',NOW(),'127.0.0.1');

View File

@@ -0,0 +1,26 @@
-- 审批注册中心新增查看明细按钮权限并授权给已有注册中心权限的角色
-- author: GHT date: 2026-06-05 forXSLMES-20260605-K8R2
SET NAMES utf8mb4;
-- 审批注册中心下新增按钮权限查看审批明细列格式与 V3.9.2_132 按钮权限一致
INSERT IGNORE INTO sys_permission(id,parent_id,name,url,component,is_route,component_name,redirect,menu_type,perms,perms_type,sort_no,always_show,icon,is_leaf,keep_alive,hidden,hide_tab,description,create_by,create_time,update_by,update_time,del_flag,rule_flag,status,internal_or_external)
VALUES('178046026420845','178046026420838','查看审批明细',NULL,NULL,0,NULL,NULL,2,'xslmes:mes_xsl_biz_doc_registry:trace','1',5,0,NULL,1,0,0,0,'审批注册中心操作列查看审批痕迹明细','admin',NOW(),NULL,NULL,0,0,'1',0);
-- 超管角色授权
INSERT IGNORE INTO `sys_role_permission` (`id`,`role_id`,`permission_id`,`operate_date`,`operate_ip`)
VALUES (REPLACE(UUID(),'-',''),'f6817f48af4fb3af11b9e8bf182f618b','178046026420845',NOW(),'127.0.0.1');
-- 已有审批注册中心任意按钮权限的角色自动补查看明细权限
INSERT IGNORE INTO `sys_role_permission` (`id`,`role_id`,`permission_id`,`operate_date`,`operate_ip`)
SELECT REPLACE(UUID(),'-',''), rp.`role_id`, '178046026420845', NOW(), '127.0.0.1'
FROM `sys_role_permission` rp
WHERE rp.`permission_id` IN (
'178046026420839',
'178046026420840',
'178046026420841',
'178046026420842'
)
AND NOT EXISTS (
SELECT 1 FROM `sys_role_permission` x
WHERE x.`role_id` = rp.`role_id` AND x.`permission_id` = '178046026420845'
);

View File

@@ -0,0 +1,32 @@
-- 集成方案与审批注册中心环节绑定
-- author: GHT date: 2026-06-05 forXSLMES-20260605-K8R2
SET NAMES utf8mb4;
SET @db = DATABASE();
-- 集成方案关联注册中心 + 绑定审批环节
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_integration_plan' AND COLUMN_NAME = 'registry_id') = 0,
'ALTER TABLE `mes_xsl_integration_plan` ADD COLUMN `registry_id` varchar(32) DEFAULT NULL COMMENT ''审批注册中心ID'' AFTER `source_table`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_integration_plan' AND COLUMN_NAME = 'trigger_stage') = 0,
'ALTER TABLE `mes_xsl_integration_plan` ADD COLUMN `trigger_stage` varchar(32) DEFAULT NULL COMMENT ''绑定审批环节 proofread/audit/approve'' AFTER `trigger_phase`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 回填已有方案的注册中心与环节 source_table 关联
UPDATE `mes_xsl_integration_plan` p
INNER JOIN `mes_xsl_biz_doc_registry` r ON r.table_name = p.source_table AND r.del_flag = 0 AND r.enabled = 1
SET p.registry_id = r.id,
p.trigger_stage = CASE p.trigger_phase
WHEN 'onApprove' THEN 'approve'
WHEN 'onNodeApprove' THEN NULL
ELSE NULL
END,
p.update_by = 'admin',
p.update_time = NOW()
WHERE p.del_flag = 0 AND (p.registry_id IS NULL OR p.trigger_stage IS NULL);

View File

@@ -0,0 +1,87 @@
-- 集成方案审批注册中心环节同步动作 + 密炼PS无代码审批方案示例
-- author: GHT date: 2026-06-05 forXSLMES-20260605-K8R2
SET NAMES utf8mb4;
-- 集成动作类型字典扩展
INSERT IGNORE INTO `sys_dict_item` (`id`,`dict_id`,`item_text`,`item_value`,`description`,`sort_order`,`status`,`create_by`,`create_time`)
VALUES
('1995000000000000394','1995000000000000360','审批环节同步','REGISTRY_STAGE_SYNC','按审批注册中心更新源单状态/操作人/痕迹',6,1,'admin',NOW()),
('1995000000000000395','1995000000000000360','审批环节回退','REGISTRY_STAGE_REVERT','驳回时回退源单状态并清空痕迹',7,1,'admin',NOW());
-- 停用旧版 SQL 手写演示方案保留数据改为已停用
UPDATE `mes_xsl_integration_plan`
SET `status` = '2', `update_by` = 'admin', `update_time` = NOW()
WHERE `plan_code` IN ('mixer_ps_on_approve','mixer_ps_on_reject','mixer_ps_node_approve')
AND `del_flag` = 0;
-- 密炼PS 校对环节通过
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`registry_id`,`trigger_phase`,`trigger_stage`,`exec_mode`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
SELECT
'mxpsregproofread00001','mixer_ps_reg_proofread','密炼PS-校对通过(注册中心同步)',
'mes_xsl_mixer_ps_compile', r.id, 'onNodeApprove', 'proofread', 'async', '0',
'无需Java回调更新status=proofread并写校对人/时间+审批痕迹', 0, 0, 'admin', NOW()
FROM `mes_xsl_biz_doc_registry` r
WHERE r.table_name='mes_xsl_mixer_ps_compile' AND r.del_flag=0 AND r.enabled=1
LIMIT 1;
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`action_config`,`exec_order`,`on_fail`,`enabled`,`del_flag`,`create_by`,`create_time`)
VALUES
('mxpsregproofreadact01','mxpsregproofread00001','校对环节同步','REGISTRY_STAGE_SYNC',
'{"visualType":"REGISTRY_STAGE_SYNC","stage":"proofread","expectedFrom":"compile"}',
1,'stop',1,0,'admin',NOW());
-- 密炼PS 审核环节通过
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`registry_id`,`trigger_phase`,`trigger_stage`,`exec_mode`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
SELECT
'mxpsregaudit00000002','mixer_ps_reg_audit','密炼PS-审核通过(注册中心同步)',
'mes_xsl_mixer_ps_compile', r.id, 'onNodeApprove', 'audit', 'async', '0',
'无需Java回调更新status=audit并写审核人/时间+审批痕迹', 0, 0, 'admin', NOW()
FROM `mes_xsl_biz_doc_registry` r
WHERE r.table_name='mes_xsl_mixer_ps_compile' AND r.del_flag=0 AND r.enabled=1
LIMIT 1;
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`action_config`,`exec_order`,`on_fail`,`enabled`,`del_flag`,`create_by`,`create_time`)
VALUES
('mxpsregauditact00001','mxpsregaudit00000002','审核环节同步','REGISTRY_STAGE_SYNC',
'{"visualType":"REGISTRY_STAGE_SYNC","stage":"audit","expectedFrom":"proofread"}',
1,'stop',1,0,'admin',NOW());
-- 密炼PS 批准(全流程通过)
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`registry_id`,`trigger_phase`,`trigger_stage`,`exec_mode`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
SELECT
'mxpsregapprove000003','mixer_ps_reg_approve','密炼PS-批准通过(注册中心同步)',
'mes_xsl_mixer_ps_compile', r.id, 'onApprove', 'approve', 'async', '0',
'无需Java回调更新status=approve并写批准人/时间+审批痕迹', 0, 0, 'admin', NOW()
FROM `mes_xsl_biz_doc_registry` r
WHERE r.table_name='mes_xsl_mixer_ps_compile' AND r.del_flag=0 AND r.enabled=1
LIMIT 1;
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`action_config`,`exec_order`,`on_fail`,`enabled`,`del_flag`,`create_by`,`create_time`)
VALUES
('mxpsregapproveact01','mxpsregapprove000003','批准环节同步','REGISTRY_STAGE_SYNC',
'{"visualType":"REGISTRY_STAGE_SYNC","stage":"approve","expectedFrom":"audit"}',
1,'stop',1,0,'admin',NOW());
-- 密炼PS 驳回回退编制
INSERT IGNORE INTO `mes_xsl_integration_plan`
(`id`,`plan_code`,`plan_name`,`source_table`,`registry_id`,`trigger_phase`,`trigger_stage`,`exec_mode`,`status`,`remark`,`del_flag`,`tenant_id`,`create_by`,`create_time`)
SELECT
'mxpsregreject000004','mixer_ps_reg_reject','密炼PS-驳回回退(注册中心同步)',
'mes_xsl_mixer_ps_compile', r.id, 'onReject', NULL, 'async', '0',
'无需Java回调回退status=compile并清空环节痕迹', 0, 0, 'admin', NOW()
FROM `mes_xsl_biz_doc_registry` r
WHERE r.table_name='mes_xsl_mixer_ps_compile' AND r.del_flag=0 AND r.enabled=1
LIMIT 1;
INSERT IGNORE INTO `mes_xsl_integration_action`
(`id`,`plan_id`,`action_name`,`action_type`,`action_config`,`exec_order`,`on_fail`,`enabled`,`del_flag`,`create_by`,`create_time`)
VALUES
('mxpsregrejectact001','mxpsregreject000004','驳回回退编制','REGISTRY_STAGE_REVERT',
'{"visualType":"REGISTRY_STAGE_REVERT","targetStage":"compile"}',
1,'stop',1,0,'admin',NOW());

View File

@@ -0,0 +1,7 @@
-- XSLMES-20260605-K8R4台账增加 node_activity_map 字段
-- 存储 processForecast 结果JSON数组每项含 approvalMethod/totalActioners/completionAt
-- completionAt = 累计已处理任务数边界用于会签/依次审批多人等待完成判断
SET NAMES utf8mb4;
ALTER TABLE `mes_xsl_approval_record`
ADD COLUMN `node_activity_map` TEXT NULL COMMENT '钉钉节点活动映射(processForecast结果JSON数组含completionAt幂等边界)';

View File

@@ -0,0 +1,2 @@
-- 用户表新增钉钉用户ID字段
ALTER TABLE sys_user ADD COLUMN ding_user_id VARCHAR(100) DEFAULT NULL COMMENT '钉钉用户ID';

View File

@@ -0,0 +1,31 @@
-- 混炼示方主表新增状态字段复用配合示方状态字典
-- author: cursor date: 2026-06-08 forXSLMES-20260608-A01
SET NAMES utf8mb4;
SET @db = DATABASE();
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'mes_xsl_mixing_spec' AND COLUMN_NAME = 'status') = 0,
'ALTER TABLE `mes_xsl_mixing_spec` ADD COLUMN `status` varchar(32) DEFAULT ''compile'' COMMENT ''状态字典xslmes_formula_spec_status'' AFTER `change_date`',
'SELECT 1'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 按已有审批痕迹回填历史数据状态
UPDATE `mes_xsl_mixing_spec` SET `status` = 'obsolete' WHERE `del_flag` = 1;
UPDATE `mes_xsl_mixing_spec` SET `status` = 'recognition_pass' WHERE `del_flag` = 0 AND `approve_time` IS NOT NULL;
UPDATE `mes_xsl_mixing_spec` SET `status` = 'review_pass' WHERE `del_flag` = 0 AND `approve_time` IS NULL AND `audit_time` IS NOT NULL;
UPDATE `mes_xsl_mixing_spec` SET `status` = 'submit' WHERE `del_flag` = 0 AND `approve_time` IS NULL AND `audit_time` IS NULL AND `proofread_time` IS NOT NULL;
-- 混炼示方注册中心默认开启三环节并绑定 status 字段
UPDATE `mes_xsl_biz_doc_registry`
SET `enabled_stages` = 'proofread,audit,approve',
`status_field` = 'status',
`proofread_by_field` = 'proofread_by',
`proofread_time_field` = 'proofread_time',
`audit_by_field` = 'audit_by',
`audit_time_field` = 'audit_time',
`approve_by_field` = 'approve_by',
`approve_time_field` = 'approve_time',
`update_by` = 'admin',
`update_time` = NOW()
WHERE `doc_code` = 'mixing_spec' AND `del_flag` = 0;

View File

@@ -0,0 +1,5 @@
-- 审批注册中心增加列表接口路径字段用于 ResponseBodyAdvice 自动注入审批痕迹字段
ALTER TABLE mes_xsl_biz_doc_registry
ADD COLUMN list_api_path VARCHAR(500) DEFAULT NULL
COMMENT '列表接口路径(多个逗号分隔/xslmes/mesFormulaSpec/list)配置后自动注入审批痕迹字段到响应'
AFTER approve_time_field;

View File

@@ -0,0 +1,28 @@
-- 审批注册中心移除操作人/时间字段配置列
-- 操作人/时间统一由 mes_xsl_approval_trace 痕迹表承载业务表只保留状态字段
-- author: GHT date: 2026-06-09 for审批注册中心业务表只写状态操作人/时间由痕迹表承载
SET @db = DATABASE();
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_biz_doc_registry' AND COLUMN_NAME='proofread_by_field')>0,
'ALTER TABLE `mes_xsl_biz_doc_registry` DROP COLUMN `proofread_by_field`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_biz_doc_registry' AND COLUMN_NAME='proofread_time_field')>0,
'ALTER TABLE `mes_xsl_biz_doc_registry` DROP COLUMN `proofread_time_field`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_biz_doc_registry' AND COLUMN_NAME='audit_by_field')>0,
'ALTER TABLE `mes_xsl_biz_doc_registry` DROP COLUMN `audit_by_field`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_biz_doc_registry' AND COLUMN_NAME='audit_time_field')>0,
'ALTER TABLE `mes_xsl_biz_doc_registry` DROP COLUMN `audit_time_field`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_biz_doc_registry' AND COLUMN_NAME='approve_by_field')>0,
'ALTER TABLE `mes_xsl_biz_doc_registry` DROP COLUMN `approve_by_field`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_biz_doc_registry' AND COLUMN_NAME='approve_time_field')>0,
'ALTER TABLE `mes_xsl_biz_doc_registry` DROP COLUMN `approve_time_field`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

View File

@@ -0,0 +1,89 @@
-- =============================================
-- 钉钉回调日志表 mes_xsl_ding_callback_log
-- =============================================
CREATE TABLE `mes_xsl_ding_callback_log` (
`id` varchar(36) NOT NULL COMMENT '主键',
`event_id` varchar(100) DEFAULT NULL COMMENT '钉钉事件ID',
`event_type` varchar(50) DEFAULT NULL COMMENT '事件类型(bpms_instance_change/bpms_task_change)',
`process_instance_id` varchar(100) DEFAULT NULL COMMENT '审批实例ID',
`raw_data` text DEFAULT NULL COMMENT '原始推送数据JSON',
`received_time` datetime DEFAULT NULL COMMENT '接收时间',
`processed` tinyint(1) DEFAULT 0 COMMENT '是否已处理集成方案(0否1是)',
`process_remark` varchar(500) DEFAULT NULL COMMENT '处理备注',
`biz_table` varchar(100) DEFAULT NULL COMMENT '关联业务表',
`biz_data_id` varchar(100) DEFAULT NULL COMMENT '关联业务记录ID',
`record_id` varchar(100) DEFAULT NULL COMMENT '关联审批台账ID',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`update_time` datetime DEFAULT NULL COMMENT '更新日期',
`del_flag` tinyint(1) DEFAULT 0 COMMENT '逻辑删除 0正常 1删除',
`tenant_id` int DEFAULT 0 COMMENT '租户ID',
`sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门',
PRIMARY KEY (`id`),
KEY `idx_ding_cb_log_instance` (`process_instance_id`),
KEY `idx_ding_cb_log_event` (`event_id`),
KEY `idx_ding_cb_log_processed` (`processed`),
KEY `idx_ding_cb_log_received` (`received_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='钉钉回调日志';
-- =============================================
-- 菜单权限父节点178046026420801 MESToDing审批配置
-- =============================================
INSERT INTO `sys_permission`
(id, parent_id, name, url, component, component_name, redirect, menu_type,
perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive,
hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time,
update_by, update_time, internal_or_external)
VALUES
-- 主菜单页面
('178098992722901', '178046026420801', '钉钉回调日志', '/xslmes/mesXslDingCallbackLogList',
'xslmes/dingCallbackLog/MesXslDingCallbackLogList', 'MesXslDingCallbackLogList',
NULL, 0, NULL, '1', 6, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0,
'admin', NOW(), NULL, NULL, 0),
-- 添加按钮
('178098992722902', '178098992722901', '添加', NULL, NULL, NULL, NULL, 2,
'xslmes:mes_xsl_ding_callback_log:add', '1', 1, 0, NULL, 1, 1, 0, 0, 0,
NULL, '1', 0, 0, 'admin', NOW(), NULL, NULL, 0),
-- 编辑按钮
('178098992722903', '178098992722901', '编辑', NULL, NULL, NULL, NULL, 2,
'xslmes:mes_xsl_ding_callback_log:edit', '1', 2, 0, NULL, 1, 1, 0, 0, 0,
NULL, '1', 0, 0, 'admin', NOW(), NULL, NULL, 0),
-- 删除按钮
('178098992722904', '178098992722901', '删除', NULL, NULL, NULL, NULL, 2,
'xslmes:mes_xsl_ding_callback_log:delete', '1', 3, 0, NULL, 1, 1, 0, 0, 0,
NULL, '1', 0, 0, 'admin', NOW(), NULL, NULL, 0),
-- 批量删除按钮
('178098992722905', '178098992722901', '批量删除', NULL, NULL, NULL, NULL, 2,
'xslmes:mes_xsl_ding_callback_log:deleteBatch', '1', 4, 0, NULL, 1, 1, 0, 0, 0,
NULL, '1', 0, 0, 'admin', NOW(), NULL, NULL, 0),
-- 导出按钮
('178098992722906', '178098992722901', '导出', NULL, NULL, NULL, NULL, 2,
'xslmes:mes_xsl_ding_callback_log:exportXls', '1', 5, 0, NULL, 1, 1, 0, 0, 0,
NULL, '1', 0, 0, 'admin', NOW(), NULL, NULL, 0),
-- 导入按钮
('178098992722907', '178098992722901', '导入', NULL, NULL, NULL, NULL, 2,
'xslmes:mes_xsl_ding_callback_log:importExcel', '1', 6, 0, NULL, 1, 1, 0, 0, 0,
NULL, '1', 0, 0, 'admin', NOW(), NULL, NULL, 0);
-- =============================================
-- admin 角色授权角色ID: f6817f48af4fb3af11b9e8bf182f618b
-- =============================================
INSERT INTO `sys_role_permission` (id, role_id, permission_id, data_rule_ids)
VALUES
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722901', NULL),
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722902', NULL),
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722903', NULL),
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722904', NULL),
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722905', NULL),
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722906', NULL),
(REPLACE(UUID(),'-',''), 'f6817f48af4fb3af11b9e8bf182f618b', '178098992722907', NULL);

View File

@@ -0,0 +1,6 @@
-- GHT 20260609 钉钉Stream开发第三方配置页可视化Stream 接收节点白名单
ALTER TABLE sys_third_app_config
ADD COLUMN stream_receiver_enabled TINYINT(1) NULL DEFAULT NULL COMMENT '是否限制仅指定节点接收Stream(0-,1-,NULL-沿用YAML)' AFTER stream_enabled,
ADD COLUMN stream_designated_ips VARCHAR(1000) NULL DEFAULT NULL COMMENT '允许接收Stream的IP白名单(逗号分隔)' AFTER stream_receiver_enabled,
ADD COLUMN stream_designated_hosts VARCHAR(500) NULL DEFAULT NULL COMMENT '允许接收Stream的主机名白名单(逗号分隔)' AFTER stream_designated_ips,
ADD COLUMN stream_cluster_mode TINYINT(1) NULL DEFAULT NULL COMMENT 'Stream集群Redis选主(0-,1-,NULL-沿用YAML)' AFTER stream_designated_hosts;

View File

@@ -0,0 +1,7 @@
-- TCU温度条件新增是否附加重量字段
-- author: GHT date: 2026-06-10 for混炼示方TCU温度条件新增是否附加/重量字段
SET @db = DATABASE();
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=@db AND TABLE_NAME='mes_xsl_mixing_spec_tcu' AND COLUMN_NAME='is_attach')=0,
'ALTER TABLE `mes_xsl_mixing_spec_tcu` ADD COLUMN `is_attach` varchar(1) DEFAULT ''0'' COMMENT ''是否附加(字典yn)'' AFTER `drug_weigh_pos`, ADD COLUMN `attach_weight` decimal(18,6) DEFAULT NULL COMMENT ''附加重量'' AFTER `is_attach`','SELECT 1');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;

View File

@@ -0,0 +1,17 @@
-- IM 工作通知公众号系统账号审批等系统消息统一从此账号推送
SET NAMES utf8mb4;
INSERT IGNORE INTO `sys_user` (
`id`, `username`, `realname`, `password`, `salt`, `status`, `del_flag`, `activiti_sync`, `create_by`, `create_time`
) VALUES (
'1995000000000000999',
'im_work_notify',
'工作通知',
'disabled',
'',
2,
0,
1,
'system',
NOW()
);