From 3bafe63e1cd2b857763a00ef41b408fe7c8dda8d Mon Sep 17 00:00:00 2001 From: jack ning Date: Sat, 15 Nov 2025 13:38:18 +0800 Subject: [PATCH] update --- modules/call/readme.md | 2 +- modules/call/readme.zh.md | 2 +- .../bytedesk/ticket/ticket/TicketEntity.java | 6 + .../bytedesk/ticket/ticket/TicketExcel.java | 8 +- .../ticket/ticket/TicketRepository.java | 4 + .../bytedesk/ticket/ticket/TicketRequest.java | 2 + .../ticket/ticket/TicketResponse.java | 2 + .../ticket/ticket/TicketRestService.java | 107 ++++++++++ .../ticket/ticket/TicketSpecification.java | 4 + .../ticket_settings/TicketSettingsEntity.java | 9 +- .../TicketSettingsRequest.java | 1 + .../TicketSettingsRestService.java | 189 +++++++++++------- 12 files changed, 251 insertions(+), 85 deletions(-) diff --git a/modules/call/readme.md b/modules/call/readme.md index c50c713400..1bff19daaf 100644 --- a/modules/call/readme.md +++ b/modules/call/readme.md @@ -1 +1 @@ -# Call Center +# Bytedesk AI Call Center diff --git a/modules/call/readme.zh.md b/modules/call/readme.zh.md index e1c7e72366..2ee5d524a0 100644 --- a/modules/call/readme.zh.md +++ b/modules/call/readme.zh.md @@ -1 +1 @@ -# 微语智能呼叫中心系统 +# 微语AI智能呼叫中心系统 diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketEntity.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketEntity.java index aee3e8c9f2..a1089f683b 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketEntity.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketEntity.java @@ -88,6 +88,12 @@ public class TicketEntity extends BaseEntity { @Builder.Default private String priority = TicketPriorityEnum.LOW.name(); // 优先级(低/中/高/紧急) + /** + * Human friendly ticket number generated from ticket settings + */ + // @Column(name = "ticket_number", length = 64, unique = true) + private String ticketNumber; + /** * Type of ticket (AGENT, GROUP) */ diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketExcel.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketExcel.java index 6a4aeabb39..4c8daff73d 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketExcel.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketExcel.java @@ -23,9 +23,13 @@ import lombok.Data; @Data public class TicketExcel { - @ExcelProperty(value = "标题") + // @ExcelProperty(value = "标题") + // @ColumnWidth(20) + // private String title; + + @ExcelProperty(value = "工单编号") @ColumnWidth(20) - private String title; + private String ticketNumber; @ExcelProperty(value = "描述") @ColumnWidth(20) diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRepository.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRepository.java index ec908f0e54..2904fd75a4 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRepository.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRepository.java @@ -24,6 +24,10 @@ public interface TicketRepository extends JpaRepository, Jpa Optional findByUid(String uid); + Optional findByTicketNumber(String ticketNumber); + + boolean existsByTicketNumber(String ticketNumber); + Optional findByProcessInstanceId(String processInstanceId); List findByWorkgroupUidContainingAndCreatedAtBetween( diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRequest.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRequest.java index 62d936dd69..dd3b3154d6 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRequest.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRequest.java @@ -44,6 +44,8 @@ public class TicketRequest extends BaseRequest { private String phone; // 联系邮箱 private String email; + + private String ticketNumber; // private String searchText; // private String status; diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketResponse.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketResponse.java index b777f3ad03..0d3255c79b 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketResponse.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketResponse.java @@ -41,6 +41,8 @@ public class TicketResponse extends BaseResponse { private String contactName; private String phone; private String email; + + private String ticketNumber; // private String status; private String priority; diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRestService.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRestService.java index 26f7c892b9..d07b4b22bb 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRestService.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketRestService.java @@ -53,6 +53,9 @@ import com.bytedesk.ticket.attachment.TicketAttachmentRepository; import com.bytedesk.ticket.ticket.event.TicketUpdateAssigneeEvent; import com.bytedesk.ticket.ticket.event.TicketUpdateDepartmentEvent; import com.bytedesk.ticket.utils.TicketConvertUtils; +import com.bytedesk.ticket.ticket_settings.TicketSettingsResponse; +import com.bytedesk.ticket.ticket_settings.TicketSettingsRestService; +import com.bytedesk.ticket.ticket_settings.sub.dto.TicketBasicSettingsResponse; import com.bytedesk.core.topic.TopicUtils; import lombok.AllArgsConstructor; @@ -82,6 +85,8 @@ public class TicketRestService private final CategoryRestService categoryRestService; + private final TicketSettingsRestService ticketSettingsRestService; + @Cacheable(value = "ticket", key = "#uid", unless = "#result == null") @Override public Optional findByUid(String uid) { @@ -117,6 +122,8 @@ public class TicketRestService ticket.setStatus(TicketStatusEnum.NEW.name()); } ticket.setReporter(request.getReporterJson()); + + ensureTicketNumber(ticket, request); // 先保存工单 TicketEntity savedTicket = save(ticket); // 保存附件 @@ -361,4 +368,104 @@ public class TicketRestService return ticketRepository.findAll(specification, pageable); } + private void ensureTicketNumber(TicketEntity ticket, TicketRequest request) { + if (ticket == null || StringUtils.hasText(ticket.getTicketNumber())) { + return; + } + String orgUid = resolveOrgUid(ticket, request); + String workgroupUid = resolveWorkgroupUid(ticket, request); + ticket.setTicketNumber(generateTicketNumber(orgUid, workgroupUid)); + } + + private String generateTicketNumber(String orgUid, String workgroupUid) { + TicketBasicSettingsResponse basicSettings = fetchBasicSettings(orgUid, workgroupUid); + String prefix = resolvePrefix(basicSettings); + int numericLength = resolveNumericLength(prefix, basicSettings); + for (int i = 0; i < 5; i++) { + String candidate = prefix + buildNumericPart(numericLength); + if (!ticketRepository.existsByTicketNumber(candidate)) { + return candidate; + } + } + return prefix + uidUtils.getUid(); + } + + private TicketBasicSettingsResponse fetchBasicSettings(String orgUid, String workgroupUid) { + if (!StringUtils.hasText(orgUid) || !StringUtils.hasText(workgroupUid)) { + return null; + } + try { + TicketSettingsResponse settings = ticketSettingsRestService.getOrDefaultByWorkgroup(orgUid, workgroupUid); + if (settings == null) { + return null; + } + return settings.getBasicSettings() != null + ? settings.getBasicSettings() + : settings.getDraftBasicSettings(); + } catch (Exception ex) { + log.warn("Failed to load ticket settings for org {} workgroup {}: {}", orgUid, workgroupUid, ex.getMessage()); + return null; + } + } + + private String resolvePrefix(TicketBasicSettingsResponse basicSettings) { + if (basicSettings != null && StringUtils.hasText(basicSettings.getNumberPrefix())) { + return basicSettings.getNumberPrefix().trim().toUpperCase(); + } + return "TK"; + } + + private int resolveNumericLength(String prefix, TicketBasicSettingsResponse basicSettings) { + int prefixLength = StringUtils.hasText(prefix) ? prefix.length() : 0; + Integer configuredLength = basicSettings != null ? basicSettings.getNumberLength() : null; + int totalLength = (configuredLength != null && configuredLength > prefixLength) + ? configuredLength + : prefixLength + 8; + int numericLength = totalLength - prefixLength; + numericLength = Math.max(numericLength, 4); + return Math.min(numericLength, 32); + } + + private String buildNumericPart(int length) { + String raw = uidUtils.getUid(); + if (length <= 0) { + return raw; + } + if (raw.length() > length) { + return raw.substring(raw.length() - length); + } + StringBuilder builder = new StringBuilder(); + for (int i = raw.length(); i < length; i++) { + builder.append('0'); + } + builder.append(raw); + return builder.toString(); + } + + private String resolveOrgUid(TicketEntity ticket, TicketRequest request) { + if (ticket != null && StringUtils.hasText(ticket.getOrgUid())) { + return ticket.getOrgUid(); + } + if (request != null && StringUtils.hasText(request.getOrgUid())) { + return request.getOrgUid(); + } + UserEntity user = authService.getUser(); + if (user != null && StringUtils.hasText(user.getOrgUid())) { + return user.getOrgUid(); + } + return BytedeskConsts.DEFAULT_ORGANIZATION_UID; + } + + private String resolveWorkgroupUid(TicketEntity ticket, TicketRequest request) { + if (ticket != null && StringUtils.hasText(ticket.getWorkgroupUid())) { + return ticket.getWorkgroupUid(); + } + if (request != null && StringUtils.hasText(request.getWorkgroupUid())) { + return request.getWorkgroupUid(); + } + if (ticket != null && StringUtils.hasText(ticket.getDepartmentUid())) { + return ticket.getDepartmentUid(); + } + return BytedeskConsts.DEFAULT_WORKGROUP_UID; + } } \ No newline at end of file diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketSpecification.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketSpecification.java index 0f64b33d48..77480ab443 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketSpecification.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket/TicketSpecification.java @@ -49,6 +49,10 @@ public class TicketSpecification extends BaseSpecification