diff --git a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/domain/command/ChatAppendMessageCommand.java b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/domain/command/ChatAppendMessageCommand.java index ed3abb9..0c8e63f 100644 --- a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/domain/command/ChatAppendMessageCommand.java +++ b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/domain/command/ChatAppendMessageCommand.java @@ -12,7 +12,11 @@ public class ChatAppendMessageCommand implements Serializable { private BigInteger deptId; private BigInteger sessionId; private BigInteger userId; + private String userAccount; private BigInteger assistantId; + private String assistantCode; + private String assistantName; + private String sessionTitle; private BigInteger senderId; private String senderName; private String senderRole; @@ -62,6 +66,14 @@ public class ChatAppendMessageCommand implements Serializable { this.userId = userId; } + public String getUserAccount() { + return userAccount; + } + + public void setUserAccount(String userAccount) { + this.userAccount = userAccount; + } + public BigInteger getAssistantId() { return assistantId; } @@ -70,6 +82,30 @@ public class ChatAppendMessageCommand implements Serializable { this.assistantId = assistantId; } + public String getAssistantCode() { + return assistantCode; + } + + public void setAssistantCode(String assistantCode) { + this.assistantCode = assistantCode; + } + + public String getAssistantName() { + return assistantName; + } + + public void setAssistantName(String assistantName) { + this.assistantName = assistantName; + } + + public String getSessionTitle() { + return sessionTitle; + } + + public void setSessionTitle(String sessionTitle) { + this.sessionTitle = sessionTitle; + } + public BigInteger getSenderId() { return senderId; } diff --git a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/repository/mysql/MySqlChatSessionRepository.java b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/repository/mysql/MySqlChatSessionRepository.java index 5ead304..dbae1fd 100644 --- a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/repository/mysql/MySqlChatSessionRepository.java +++ b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/repository/mysql/MySqlChatSessionRepository.java @@ -41,19 +41,22 @@ public class MySqlChatSessionRepository { String sql = "INSERT INTO `" + table + "` " + "(id, tenant_id, dept_id, user_id, user_account, assistant_id, assistant_code, assistant_name, title, last_message_preview, message_count, access_at, created, created_by, modified, modified_by, is_deleted) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, '', 0, ?, ?, ?, ?, ?, 0) " + - "ON DUPLICATE KEY UPDATE user_account=VALUES(user_account), assistant_id=VALUES(assistant_id), assistant_code=VALUES(assistant_code), " + - "assistant_name=VALUES(assistant_name), title=VALUES(title), access_at=VALUES(access_at), modified=VALUES(modified), modified_by=VALUES(modified_by), is_deleted=0"; + "ON DUPLICATE KEY UPDATE user_account=COALESCE(NULLIF(VALUES(user_account), ''), user_account), " + + "assistant_id=VALUES(assistant_id), assistant_code=COALESCE(NULLIF(VALUES(assistant_code), ''), assistant_code), " + + "assistant_name=COALESCE(NULLIF(VALUES(assistant_name), ''), assistant_name), " + + "title=COALESCE(NULLIF(VALUES(title), ''), title), " + + "access_at=VALUES(access_at), modified=VALUES(modified), modified_by=VALUES(modified_by), is_deleted=0"; jdbcTemplate.batchUpdate(sql, commands, commands.size(), (ps, command) -> { Timestamp operateAt = timestamp(command.getOperateAt()); ps.setObject(1, command.getSessionId()); ps.setObject(2, command.getTenantId()); ps.setObject(3, command.getDeptId()); ps.setObject(4, command.getUserId()); - ps.setString(5, command.getUserAccount()); + ps.setString(5, safeString(command.getUserAccount())); ps.setObject(6, command.getAssistantId()); - ps.setString(7, command.getAssistantCode()); - ps.setString(8, command.getAssistantName()); - ps.setString(9, command.getTitle()); + ps.setString(7, safeString(command.getAssistantCode())); + ps.setString(8, safeString(command.getAssistantName())); + ps.setString(9, safeString(command.getTitle())); ps.setTimestamp(10, operateAt); ps.setTimestamp(11, operateAt); ps.setObject(12, command.getOperatorId()); @@ -272,4 +275,8 @@ public class MySqlChatSessionRepository { private Timestamp timestamp(Date value) { return new Timestamp((value == null ? new Date() : value).getTime()); } + + private String safeString(String value) { + return value == null ? "" : value; + } } diff --git a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyService.java b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyService.java index e6e8f7f..fda6f3b 100644 --- a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyService.java +++ b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyService.java @@ -106,6 +106,7 @@ public class ChatPersistMySqlApplyService { insertedCommands = logRepository.appendMessages(appendCommands); } if (!insertedCommands.isEmpty()) { + sessionRepository.createOrTouchBatch(buildSessionUpserts(insertedCommands)); summaryCommands.clear(); for (ChatAppendMessageCommand insertedCommand : insertedCommands) { accumulateSummary(summaryCommands, insertedCommand); @@ -139,9 +140,74 @@ public class ChatPersistMySqlApplyService { } } + List buildSessionUpserts(List commands) { + if (commands == null || commands.isEmpty()) { + return List.of(); + } + Map upserts = new LinkedHashMap<>(); + for (ChatAppendMessageCommand command : commands) { + if (command == null || command.getSessionId() == null) { + continue; + } + ChatSessionUpsertCommand upsert = upserts.computeIfAbsent(command.getSessionId(), key -> { + ChatSessionUpsertCommand created = new ChatSessionUpsertCommand(); + created.setSessionId(command.getSessionId()); + created.setTenantId(command.getTenantId()); + created.setDeptId(command.getDeptId()); + created.setUserId(command.getUserId()); + created.setAssistantId(command.getAssistantId()); + created.setOperateAt(null); + return created; + }); + if (upsert.getTenantId() == null) { + upsert.setTenantId(command.getTenantId()); + } + if (upsert.getDeptId() == null) { + upsert.setDeptId(command.getDeptId()); + } + if (upsert.getUserId() == null) { + upsert.setUserId(command.getUserId()); + } + if (upsert.getAssistantId() == null) { + upsert.setAssistantId(command.getAssistantId()); + } + if (isBlank(upsert.getUserAccount()) && !isBlank(command.getUserAccount())) { + upsert.setUserAccount(command.getUserAccount().trim()); + } + if (isBlank(upsert.getAssistantCode()) && !isBlank(command.getAssistantCode())) { + upsert.setAssistantCode(command.getAssistantCode().trim()); + } + if (isBlank(upsert.getAssistantName()) && !isBlank(command.getAssistantName())) { + upsert.setAssistantName(command.getAssistantName().trim()); + } + if (isBlank(upsert.getTitle()) && !isBlank(command.getSessionTitle())) { + upsert.setTitle(command.getSessionTitle().trim()); + } + Date operateAt = defaultDate(command.getCreated()); + if (upsert.getOperateAt() == null || !operateAt.before(upsert.getOperateAt())) { + upsert.setOperateAt(operateAt); + upsert.setOperatorId(command.getCreatedBy()); + } + } + for (ChatSessionUpsertCommand upsert : upserts.values()) { + if (isBlank(upsert.getUserAccount())) { + upsert.setUserAccount(""); + } + if (isBlank(upsert.getTitle())) { + upsert.setTitle("会话-" + upsert.getSessionId()); + } + if (upsert.getOperateAt() == null) { + upsert.setOperateAt(new Date()); + } + if (upsert.getOperatorId() == null) { + upsert.setOperatorId(upsert.getUserId()); + } + } + return new ArrayList<>(upserts.values()); + } + private YearMonth resolveMonth(Date createdAt) { - Date created = createdAt == null ? new Date() : createdAt; - return YearMonth.from(created.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); + return YearMonth.from(defaultDate(createdAt).toInstant().atZone(ZoneId.systemDefault()).toLocalDate()); } private String trimPreview(String text) { @@ -150,4 +216,12 @@ public class ChatPersistMySqlApplyService { } return text.length() <= 200 ? text : text.substring(0, 200); } + + private boolean isBlank(String value) { + return value == null || value.isBlank(); + } + + private Date defaultDate(Date value) { + return value == null ? new Date() : value; + } } diff --git a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/impl/ChatlogRuntimeListener.java b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/impl/ChatlogRuntimeListener.java index 48041b4..b398447 100644 --- a/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/impl/ChatlogRuntimeListener.java +++ b/easyflow-modules/easyflow-module-chatlog/src/main/java/tech/easyflow/chatlog/service/impl/ChatlogRuntimeListener.java @@ -105,7 +105,11 @@ public class ChatlogRuntimeListener implements ChatRuntimeListener { command.setDeptId(defaultNumber(context.getDeptId())); command.setSessionId(context.getSessionId()); command.setUserId(defaultNumber(context.getUserId())); + command.setUserAccount(context.getUserAccount()); command.setAssistantId(defaultNumber(context.getAssistantId())); + command.setAssistantCode(context.getAssistantCode()); + command.setAssistantName(context.getAssistantName()); + command.setSessionTitle(context.getSessionTitle()); command.setSenderId(defaultNumber(message.getSenderId())); command.setSenderName(message.getSenderName()); command.setSenderRole(message.getRole()); diff --git a/easyflow-modules/easyflow-module-chatlog/src/test/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyServiceTest.java b/easyflow-modules/easyflow-module-chatlog/src/test/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyServiceTest.java new file mode 100644 index 0000000..a5f6b25 --- /dev/null +++ b/easyflow-modules/easyflow-module-chatlog/src/test/java/tech/easyflow/chatlog/service/ChatPersistMySqlApplyServiceTest.java @@ -0,0 +1,72 @@ +package tech.easyflow.chatlog.service; + +import org.junit.Assert; +import org.junit.Test; +import tech.easyflow.chatlog.domain.command.ChatAppendMessageCommand; +import tech.easyflow.chatlog.domain.command.ChatSessionUpsertCommand; + +import java.math.BigInteger; +import java.util.Date; +import java.util.List; + +public class ChatPersistMySqlApplyServiceTest { + + private final ChatPersistMySqlApplyService service = + new ChatPersistMySqlApplyService(null, null, null, null); + + @Test + public void shouldBuildMissingSessionUpsertFromMessageMetadata() { + ChatAppendMessageCommand first = new ChatAppendMessageCommand(); + first.setSessionId(BigInteger.valueOf(101)); + first.setTenantId(BigInteger.ONE); + first.setDeptId(BigInteger.TEN); + first.setUserId(BigInteger.valueOf(12)); + first.setUserAccount("admin"); + first.setAssistantId(BigInteger.valueOf(99)); + first.setAssistantCode("test-bot"); + first.setAssistantName("测试助手"); + first.setSessionTitle("你是谁"); + first.setCreatedBy(BigInteger.valueOf(12)); + first.setCreated(new Date(1_000L)); + + ChatAppendMessageCommand second = new ChatAppendMessageCommand(); + second.setSessionId(BigInteger.valueOf(101)); + second.setTenantId(BigInteger.ONE); + second.setDeptId(BigInteger.TEN); + second.setUserId(BigInteger.valueOf(12)); + second.setAssistantId(BigInteger.valueOf(99)); + second.setCreatedBy(BigInteger.valueOf(12)); + second.setCreated(new Date(2_000L)); + + List upserts = service.buildSessionUpserts(List.of(first, second)); + + Assert.assertEquals(1, upserts.size()); + ChatSessionUpsertCommand upsert = upserts.get(0); + Assert.assertEquals(BigInteger.valueOf(101), upsert.getSessionId()); + Assert.assertEquals("admin", upsert.getUserAccount()); + Assert.assertEquals("test-bot", upsert.getAssistantCode()); + Assert.assertEquals("测试助手", upsert.getAssistantName()); + Assert.assertEquals("你是谁", upsert.getTitle()); + Assert.assertEquals(new Date(2_000L), upsert.getOperateAt()); + } + + @Test + public void shouldFallbackTitleWhenMessageMetadataMissing() { + ChatAppendMessageCommand command = new ChatAppendMessageCommand(); + command.setSessionId(BigInteger.valueOf(202)); + command.setTenantId(BigInteger.ONE); + command.setDeptId(BigInteger.ONE); + command.setUserId(BigInteger.valueOf(7)); + command.setAssistantId(BigInteger.valueOf(8)); + command.setCreatedBy(BigInteger.valueOf(7)); + command.setCreated(new Date(3_000L)); + + List upserts = service.buildSessionUpserts(List.of(command)); + + Assert.assertEquals(1, upserts.size()); + ChatSessionUpsertCommand upsert = upserts.get(0); + Assert.assertEquals("", upsert.getUserAccount()); + Assert.assertEquals("会话-202", upsert.getTitle()); + Assert.assertEquals(BigInteger.valueOf(7), upsert.getOperatorId()); + } +}