diff --git a/modules/core/src/main/java/com/bytedesk/core/task/TaskRequest.java b/modules/core/src/main/java/com/bytedesk/core/task/TaskRequest.java index 89375b7f5a..107c518c68 100644 --- a/modules/core/src/main/java/com/bytedesk/core/task/TaskRequest.java +++ b/modules/core/src/main/java/com/bytedesk/core/task/TaskRequest.java @@ -31,7 +31,6 @@ public class TaskRequest extends BaseRequest { private static final long serialVersionUID = 1L; - private String name; private String description; diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEntity.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEntity.java new file mode 100644 index 0000000000..77c76e0181 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEntity.java @@ -0,0 +1,70 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-05-11 18:14:28 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-06-04 15:35:31 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import com.bytedesk.core.base.BaseEntity; +import com.bytedesk.core.constant.I18Consts; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +// import jakarta.persistence.EntityListeners; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +/** + * 待办任务list列表 + * + * TaskList entity for content categorization and organization + * Provides task_listging functionality for various system entities + * + * Database Table: bytedesk_core_task_list + * Purpose: Stores task_list definitions, colors, and organization settings + */ +@Entity +@Data +@SuperBuilder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +// @EntityListeners({TaskListEntityListener.class}) +@Table(name = "bytedesk_core_task_list") +public class TaskListEntity extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * Name of the task_list + */ + private String name; + + /** + * Description of the task_list + */ + @Builder.Default + private String description = I18Consts.I18N_DESCRIPTION; + + /** + * Type of task_list (CUSTOMER, TICKET, ARTICLE, etc.) + */ + @Builder.Default + @Column(name = "task_list_type") + private String type = TaskListTypeEnum.CUSTOMER.name(); + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEntityListener.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEntityListener.java new file mode 100644 index 0000000000..afa91351ed --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEntityListener.java @@ -0,0 +1,51 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-02-25 09:52:34 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-03-20 17:00:07 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import org.springframework.stereotype.Component; +import org.springframework.util.SerializationUtils; + +import com.bytedesk.core.config.BytedeskEventPublisher; +import com.bytedesk.core.task_list.event.TaskListCreateEvent; +import com.bytedesk.core.task_list.event.TaskListUpdateEvent; +import com.bytedesk.core.utils.ApplicationContextHolder; + +import jakarta.persistence.PostPersist; +import jakarta.persistence.PostUpdate; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class TaskListEntityListener { + + @PostPersist + public void onPostPersist(TaskListEntity task_list) { + log.info("onPostPersist: {}", task_list); + TaskListEntity cloneTaskList = SerializationUtils.clone(task_list); + // + BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class); + bytedeskEventPublisher.publishEvent(new TaskListCreateEvent(cloneTaskList)); + } + + @PostUpdate + public void onPostUpdate(TaskListEntity task_list) { + log.info("onPostUpdate: {}", task_list); + TaskListEntity cloneTaskList = SerializationUtils.clone(task_list); + // + BytedeskEventPublisher bytedeskEventPublisher = ApplicationContextHolder.getBean(BytedeskEventPublisher.class); + bytedeskEventPublisher.publishEvent(new TaskListUpdateEvent(cloneTaskList)); + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEventListener.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEventListener.java new file mode 100644 index 0000000000..99d90f1f63 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListEventListener.java @@ -0,0 +1,44 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-02-25 09:44:18 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-06-04 15:50:06 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import org.springframework.context.event.EventListener; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import com.bytedesk.core.rbac.organization.OrganizationEntity; +import com.bytedesk.core.rbac.organization.event.OrganizationCreateEvent; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +@AllArgsConstructor +public class TaskListEventListener { + + private final TaskListRestService task_listRestService; + + @Order(3) + @EventListener + public void onOrganizationCreateEvent(OrganizationCreateEvent event) { + OrganizationEntity organization = (OrganizationEntity) event.getSource(); + String orgUid = organization.getUid(); + log.info("thread - organization created: {}", organization.getName()); + task_listRestService.initTaskLists(orgUid); + } + + +} + diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListExcel.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListExcel.java new file mode 100644 index 0000000000..0113172b4f --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListExcel.java @@ -0,0 +1,47 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-08-01 06:18:10 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-07-04 18:00:51 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import java.time.ZonedDateTime; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.format.DateTimeFormat; +import com.alibaba.excel.annotation.write.style.ColumnWidth; + +import lombok.Data; + +/** + * https://github.com/alibaba/easyexcel + */ +@Data +public class TaskListExcel { + + @ExcelProperty(index = 0, value = "标签名称") + @ColumnWidth(20) + private String name; + + @ExcelProperty(index = 1, value = "类型") + @ColumnWidth(20) + private String type; + + @ExcelProperty(index = 2, value = "颜色") + @ColumnWidth(20) + private String color; + + @DateTimeFormat("yyyy-MM-dd HH:mm:ss") + @ExcelProperty(value = "创建时间", converter = com.bytedesk.core.converter.ZonedDateTimeConverter.class) + @ColumnWidth(25) + private ZonedDateTime createdAt; + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListInitData.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListInitData.java new file mode 100644 index 0000000000..96deca6f26 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListInitData.java @@ -0,0 +1,122 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-03-11 08:54:35 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-06-04 17:12:37 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +// import com.bytedesk.core.constant.I18Consts; + +public class TaskListInitData { + + /** + * Technical Support TaskLists + * 技术支持标签 + */ + public static final String[] TECHNICAL_SUPPORT = { + // I18Consts.I18N_PREFIX + "thread.task_list.technical_support", // parent + "技术支持", // parent + }; + + /** + * Service Request TaskLists + * 服务请求标签 + */ + public static final String[] SERVICE_REQUEST = { + // I18Consts.I18N_PREFIX + "thread.task_list.service_request", // parent + "服务请求", // parent + }; + + /** + * Consultation TaskLists + * 咨询标签 + */ + public static final String[] CONSULTATION = { + // I18Consts.I18N_PREFIX + "thread.task_list.consultation", // parent + "咨询", // parent + }; + + /** + * Complaint & Suggestion TaskLists + * 投诉与建议标签 + */ + public static final String[] COMPLAINT_SUGGESTION = { + // I18Consts.I18N_PREFIX + "thread.task_list.complaint_suggestion", // parent + "投诉建议", // parent + }; + + /** + * Operation & Maintenance TaskLists + * 运维标签 + */ + public static final String[] OPERATION_MAINTENANCE = { + // I18Consts.I18N_PREFIX + "thread.task_list.operation_maintenance", // parent + "运维", // parent + // 其他 + // I18Consts.I18N_PREFIX + "thread.task_list.other", + "其他", + }; + + /** + * Helper method to determine if a task_list is a parent task_list + * + * @param task_list The task_list key to check + * @return true if it's a parent task_list + */ + public static boolean isParentTaskList(String task_list) { + return !task_list.contains("."); + } + + /** + * Helper method to get parent task_list key for a child task_list + * + * @param childTaskList The child task_list key + * @return The parent task_list key + */ + public static String getParentTaskList(String childTaskList) { + if (isParentTaskList(childTaskList)) { + return null; + } + // 由于已将常量转为中文,此方法可能需要重新实现 + // 这里仅保留基本结构,具体实现需要根据新的标签体系来调整 + return null; + } + + /** + * Get all task_lists as a single array + * + * @return Array containing all task_lists + */ + public static String[] getAllTaskLists() { + int totalLength = TECHNICAL_SUPPORT.length + SERVICE_REQUEST.length + + CONSULTATION.length + COMPLAINT_SUGGESTION.length + + OPERATION_MAINTENANCE.length; + + String[] allTaskLists = new String[totalLength]; + int index = 0; + + System.arraycopy(TECHNICAL_SUPPORT, 0, allTaskLists, index, TECHNICAL_SUPPORT.length); + index += TECHNICAL_SUPPORT.length; + + System.arraycopy(SERVICE_REQUEST, 0, allTaskLists, index, SERVICE_REQUEST.length); + index += SERVICE_REQUEST.length; + + System.arraycopy(CONSULTATION, 0, allTaskLists, index, CONSULTATION.length); + index += CONSULTATION.length; + + System.arraycopy(COMPLAINT_SUGGESTION, 0, allTaskLists, index, COMPLAINT_SUGGESTION.length); + index += COMPLAINT_SUGGESTION.length; + + System.arraycopy(OPERATION_MAINTENANCE, 0, allTaskLists, index, OPERATION_MAINTENANCE.length); + + return allTaskLists; + } +} \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListInitializer.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListInitializer.java new file mode 100644 index 0000000000..e8f75a6960 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListInitializer.java @@ -0,0 +1,46 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-11-06 21:43:58 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-08-26 10:52:24 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.stereotype.Component; + +import com.bytedesk.core.constant.BytedeskConsts; + +import lombok.AllArgsConstructor; + +@Component +@AllArgsConstructor +public class TaskListInitializer implements SmartInitializingSingleton { + + private final TaskListRestService task_listRestService; + + @Override + public void afterSingletonsInstantiated() { + initPermissions(); + // create default + String orgUid = BytedeskConsts.DEFAULT_ORGANIZATION_UID; + task_listRestService.initTaskLists(orgUid); + } + + private void initPermissions() { + // for (PermissionEnum permission : PermissionEnum.values()) { + // String permissionValue = TaskListPermissions.ARTICLE_PREFIX + permission.name(); + // authorityService.createForPlatform(permissionValue); + // } + } + + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListPermissions.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListPermissions.java new file mode 100644 index 0000000000..cdce7685cc --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListPermissions.java @@ -0,0 +1,20 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-11-05 16:58:18 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-05-06 11:55:32 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import com.bytedesk.core.base.BasePermissions; + +public class TaskListPermissions extends BasePermissions { + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRepository.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRepository.java new file mode 100644 index 0000000000..7acb862798 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRepository.java @@ -0,0 +1,30 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-05-11 18:25:55 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-06-20 12:52:47 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface TaskListRepository extends JpaRepository, JpaSpecificationExecutor { + + Optional findByUid(String uid); + + Boolean existsByUid(String uid); + + Optional findByNameAndOrgUidAndTypeAndDeletedFalse(String name, String orgUid, String type); + + // Boolean existsByPlatform(String platform); +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRequest.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRequest.java new file mode 100644 index 0000000000..274de78385 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRequest.java @@ -0,0 +1,41 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-05-11 18:26:04 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-06-20 14:24:05 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import com.bytedesk.core.base.BaseRequest; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = false) +@AllArgsConstructor +@NoArgsConstructor +public class TaskListRequest extends BaseRequest { + + private static final long serialVersionUID = 1L; + + private String name; + + private String description; + + // @Builder.Default + // private String type = TaskListTypeEnum.CUSTOMER.name(); + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListResponse.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListResponse.java new file mode 100644 index 0000000000..28979fd03e --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListResponse.java @@ -0,0 +1,42 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-05-11 18:26:12 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-06-04 15:36:28 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + + +import com.bytedesk.core.base.BaseResponse; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class TaskListResponse extends BaseResponse { + + private static final long serialVersionUID = 1L; + + private String name; + + private String description; + + private String type; + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRestController.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRestController.java new file mode 100644 index 0000000000..903e685ff7 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRestController.java @@ -0,0 +1,123 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-05-11 18:25:36 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-08-20 17:05:57 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +// import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.context.annotation.Description; + +import com.bytedesk.core.annotation.ActionAnnotation; +import com.bytedesk.core.base.BaseRestController; +import com.bytedesk.core.utils.JsonResult; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; + +@RestController +@RequestMapping("/api/v1/task_list") +@AllArgsConstructor +@Tag(name = "TaskList Management", description = "TaskList management APIs for organizing and categorizing content with task_lists") +@Description("TaskList Management Controller - Content task_listging and categorization APIs") +public class TaskListRestController extends BaseRestController { + + private final TaskListRestService taskListRestService; + + @ActionAnnotation(title = "TaskList", action = "组织查询", description = "query task_list by org") + @Operation(summary = "Query TaskLists by Organization", description = "Retrieve task_lists for the current organization") + @Override + public ResponseEntity queryByOrg(TaskListRequest request) { + + Page task_lists = taskListRestService.queryByOrg(request); + + return ResponseEntity.ok(JsonResult.success(task_lists)); + } + + @ActionAnnotation(title = "TaskList", action = "用户查询", description = "query task_list by user") + @Operation(summary = "Query TaskLists by User", description = "Retrieve task_lists for the current user") + @Override + public ResponseEntity queryByUser(TaskListRequest request) { + + Page task_lists = taskListRestService.queryByUser(request); + + return ResponseEntity.ok(JsonResult.success(task_lists)); + } + + @ActionAnnotation(title = "TaskList", action = "查询详情", description = "query task_list by uid") + @Operation(summary = "Query TaskList by UID", description = "Retrieve a specific task_list by its unique identifier") + @Override + public ResponseEntity queryByUid(TaskListRequest request) { + + TaskListResponse task_list = taskListRestService.queryByUid(request); + + return ResponseEntity.ok(JsonResult.success(task_list)); + } + + @ActionAnnotation(title = "TaskList", action = "新建", description = "create task_list") + @Operation(summary = "Create TaskList", description = "Create a new task_list") + @Override + // @PreAuthorize("hasAuthority('TAG_CREATE')") + public ResponseEntity create(TaskListRequest request) { + + TaskListResponse task_list = taskListRestService.create(request); + + return ResponseEntity.ok(JsonResult.success(task_list)); + } + + @ActionAnnotation(title = "TaskList", action = "更新", description = "update task_list") + @Operation(summary = "Update TaskList", description = "Update an existing task_list") + @Override + // @PreAuthorize("hasAuthority('TAG_UPDATE')") + public ResponseEntity update(TaskListRequest request) { + + TaskListResponse task_list = taskListRestService.update(request); + + return ResponseEntity.ok(JsonResult.success(task_list)); + } + + @ActionAnnotation(title = "TaskList", action = "删除", description = "delete task_list") + @Operation(summary = "Delete TaskList", description = "Delete a task_list") + @Override + // @PreAuthorize("hasAuthority('TAG_DELETE')") + public ResponseEntity delete(TaskListRequest request) { + + taskListRestService.delete(request); + + return ResponseEntity.ok(JsonResult.success()); + } + + @ActionAnnotation(title = "TaskList", action = "导出", description = "export task_list") + @Operation(summary = "Export TaskLists", description = "Export task_lists to Excel format") + @Override + // @PreAuthorize("hasAuthority('TAG_EXPORT')") + @GetMapping("/export") + public Object export(TaskListRequest request, HttpServletResponse response) { + return exportTemplate( + request, + response, + taskListRestService, + TaskListExcel.class, + "TaskList", + "task_list" + ); + } + + + +} \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRestService.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRestService.java new file mode 100644 index 0000000000..22104bf1de --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListRestService.java @@ -0,0 +1,194 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-05-11 18:25:45 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-08-22 07:04:17 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import java.util.Optional; + +import org.modelmapper.ModelMapper; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.orm.ObjectOptimisticLockingFailureException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import com.bytedesk.core.base.BaseRestServiceWithExport; +import com.bytedesk.core.rbac.auth.AuthService; +import com.bytedesk.core.rbac.user.UserEntity; +import com.bytedesk.core.uid.UidUtils; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@AllArgsConstructor +public class TaskListRestService extends BaseRestServiceWithExport { + + private final TaskListRepository taskListRepository; + + private final ModelMapper modelMapper; + + private final UidUtils uidUtils; + + private final AuthService authService; + + @Override + protected Specification createSpecification(TaskListRequest request) { + return TaskListSpecification.search(request, authService); + } + + @Override + protected Page executePageQuery(Specification spec, Pageable pageable) { + return taskListRepository.findAll(spec, pageable); + } + + @Cacheable(value = "task_list", key = "#uid", unless="#result==null") + @Override + public Optional findByUid(String uid) { + return taskListRepository.findByUid(uid); + } + + @Cacheable(value = "task_list", key = "#name + '_' + #orgUid + '_' + #type", unless="#result==null") + public Optional findByNameAndOrgUidAndType(String name, String orgUid, String type) { + return taskListRepository.findByNameAndOrgUidAndTypeAndDeletedFalse(name, orgUid, type); + } + + public Boolean existsByUid(String uid) { + return taskListRepository.existsByUid(uid); + } + + @Transactional + @Override + public TaskListResponse create(TaskListRequest request) { + // 判断是否已经存在 + if (StringUtils.hasText(request.getUid()) && existsByUid(request.getUid())) { + return convertToResponse(findByUid(request.getUid()).get()); + } + // 检查name+orgUid+type是否已经存在 + if (StringUtils.hasText(request.getName()) && StringUtils.hasText(request.getOrgUid()) && StringUtils.hasText(request.getType())) { + Optional task_list = findByNameAndOrgUidAndType(request.getName(), request.getOrgUid(), request.getType()); + if (task_list.isPresent()) { + return convertToResponse(task_list.get()); + } + } + // + UserEntity user = authService.getUser(); + if (user != null) { + request.setUserUid(user.getUid()); + } + // + TaskListEntity entity = modelMapper.map(request, TaskListEntity.class); + if (!StringUtils.hasText(request.getUid())) { + entity.setUid(uidUtils.getUid()); + } + // + TaskListEntity savedEntity = save(entity); + if (savedEntity == null) { + throw new RuntimeException("Create task_list failed"); + } + return convertToResponse(savedEntity); + } + + @Transactional + @Override + public TaskListResponse update(TaskListRequest request) { + Optional optional = taskListRepository.findByUid(request.getUid()); + if (optional.isPresent()) { + TaskListEntity entity = optional.get(); + modelMapper.map(request, entity); + // + TaskListEntity savedEntity = save(entity); + if (savedEntity == null) { + throw new RuntimeException("Update task_list failed"); + } + return convertToResponse(savedEntity); + } + else { + throw new RuntimeException("TaskList not found"); + } + } + + @Override + protected TaskListEntity doSave(TaskListEntity entity) { + return taskListRepository.save(entity); + } + + @Override + public TaskListEntity handleOptimisticLockingFailureException(ObjectOptimisticLockingFailureException e, TaskListEntity entity) { + try { + Optional latest = taskListRepository.findByUid(entity.getUid()); + if (latest.isPresent()) { + TaskListEntity latestEntity = latest.get(); + // 合并需要保留的数据 + latestEntity.setName(entity.getName()); + // latestEntity.setOrder(entity.getOrder()); + // latestEntity.setDeleted(entity.isDeleted()); + return taskListRepository.save(latestEntity); + } + } catch (Exception ex) { + log.error("无法处理乐观锁冲突: {}", ex.getMessage(), ex); + throw new RuntimeException("无法处理乐观锁冲突: " + ex.getMessage(), ex); + } + return null; + } + + @Transactional + @Override + public void deleteByUid(String uid) { + Optional optional = taskListRepository.findByUid(uid); + if (optional.isPresent()) { + optional.get().setDeleted(true); + save(optional.get()); + // task_listRepository.delete(optional.get()); + } + else { + throw new RuntimeException("TaskList not found"); + } + } + + @Override + public void delete(TaskListRequest request) { + deleteByUid(request.getUid()); + } + + @Override + public TaskListResponse convertToResponse(TaskListEntity entity) { + return modelMapper.map(entity, TaskListResponse.class); + } + + @Override + public TaskListExcel convertToExcel(TaskListEntity entity) { + return modelMapper.map(entity, TaskListExcel.class); + } + + public void initTaskLists(String orgUid) { + // log.info("initThreadTaskList"); + // for (String task_list : TaskListInitData.getAllTaskLists()) { + // TaskListRequest task_listRequest = TaskListRequest.builder() + // .uid(Utils.formatUid(orgUid, task_list)) + // .name(task_list) + // .order(0) + // .type(TaskListTypeEnum.THREAD.name()) + // .level(LevelEnum.ORGANIZATION.name()) + // .platform(BytedeskConsts.PLATFORM_BYTEDESK) + // .orgUid(orgUid) + // .build(); + // create(task_listRequest); + // } + } + + + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListSpecification.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListSpecification.java new file mode 100644 index 0000000000..99df15e5b2 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListSpecification.java @@ -0,0 +1,57 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-07-09 22:19:21 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-08-18 15:44:34 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.jpa.domain.Specification; +import org.springframework.util.StringUtils; + +import com.bytedesk.core.base.BaseSpecification; +import com.bytedesk.core.rbac.auth.AuthService; + +import jakarta.persistence.criteria.Predicate; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TaskListSpecification extends BaseSpecification { + + public static Specification search(TaskListRequest request, AuthService authService) { + // log.info("request: {} orgUid: {} pageNumber: {} pageSize: {}", + // request, request.getOrgUid(), request.getPageNumber(), request.getPageSize()); + return (root, query, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + predicates.addAll(getBasicPredicates(root, criteriaBuilder, request, authService)); + // name + if (StringUtils.hasText(request.getName())) { + predicates.add(criteriaBuilder.like(root.get("name"), "%" + request.getName() + "%")); + } + // description + if (StringUtils.hasText(request.getDescription())) { + predicates.add(criteriaBuilder.like(root.get("description"), "%" + request.getDescription() + "%")); + } + // type + if (StringUtils.hasText(request.getType())) { + predicates.add(criteriaBuilder.equal(root.get("type"), request.getType())); + } + // + if (StringUtils.hasText(request.getUserUid())) { + predicates.add(criteriaBuilder.equal(root.get("userUid"), request.getUserUid())); + } + // + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListTypeEnum.java b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListTypeEnum.java new file mode 100644 index 0000000000..322e4111a8 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/TaskListTypeEnum.java @@ -0,0 +1,20 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2024-07-23 17:02:46 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-03-11 08:57:11 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * 联系:270580156@qq.com + * Copyright (c) 2024 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list; + +public enum TaskListTypeEnum { + THREAD, + CUSTOMER, + TICKET +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListCreateEvent.java b/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListCreateEvent.java new file mode 100644 index 0000000000..669a3a68c8 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListCreateEvent.java @@ -0,0 +1,36 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-02-25 09:59:29 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-02-25 10:00:34 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list.event; + +import org.springframework.context.ApplicationEvent; + +import com.bytedesk.core.task_list.TaskListEntity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class TaskListCreateEvent extends ApplicationEvent { + + private static final long serialVersionUID = 1L; + + private TaskListEntity task_list; + + public TaskListCreateEvent(TaskListEntity task_list) { + super(task_list); + this.task_list = task_list; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListDeleteEvent.java b/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListDeleteEvent.java new file mode 100644 index 0000000000..bed1c4357f --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListDeleteEvent.java @@ -0,0 +1,35 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-02-25 12:31:16 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-02-25 12:31:19 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list.event; + +import org.springframework.context.ApplicationEvent; + +import com.bytedesk.core.task_list.TaskListEntity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class TaskListDeleteEvent extends ApplicationEvent { + + private static final long serialVersionUID = 1L; + + private TaskListEntity task_list; + + public TaskListDeleteEvent(TaskListEntity task_list) { + super(task_list); + this.task_list = task_list; + } +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListUpdateEvent.java b/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListUpdateEvent.java new file mode 100644 index 0000000000..c3e7ec2589 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/event/TaskListUpdateEvent.java @@ -0,0 +1,36 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-02-25 09:59:29 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-02-25 10:01:00 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.task_list.event; + +import org.springframework.context.ApplicationEvent; + +import com.bytedesk.core.task_list.TaskListEntity; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = false) +public class TaskListUpdateEvent extends ApplicationEvent { + + private static final long serialVersionUID = 1L; + + private TaskListEntity task_list; + + public TaskListUpdateEvent(TaskListEntity task_list) { + super(task_list); + this.task_list = task_list; + } + +} diff --git a/modules/core/src/main/java/com/bytedesk/core/task_list/package-info.java b/modules/core/src/main/java/com/bytedesk/core/task_list/package-info.java new file mode 100644 index 0000000000..5e429b4188 --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/task_list/package-info.java @@ -0,0 +1,5 @@ + +@NonNullApi +package com.bytedesk.core.task_list; + +import org.springframework.lang.NonNullApi; diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestController.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestController.java index eaef3b5fb8..693e680fd2 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestController.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestController.java @@ -99,9 +99,14 @@ public class TicketSettingsRestController extends BaseRestController delete(TicketSettingsRequest request) { - - ticketSettingsRestService.delete(request); - + if (request == null || request.getUid() == null) { + return ResponseEntity.badRequest().body(JsonResult.error("uid is required")); + } + try { + ticketSettingsRestService.delete(request); + } catch (IllegalStateException ex) { + return ResponseEntity.badRequest().body(JsonResult.error(ex.getMessage())); + } return ResponseEntity.ok(JsonResult.success()); } diff --git a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestService.java b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestService.java index 1a49c67ab4..57291615cd 100644 --- a/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestService.java +++ b/modules/ticket/src/main/java/com/bytedesk/ticket/ticket_settings/TicketSettingsRestService.java @@ -840,6 +840,21 @@ public class TicketSettingsRestService extends @Transactional @Override public void deleteByUid(String uid) { + List activeBindings = bindingRepository + .findByTicketSettingsUidAndDeletedFalse(uid); + if (!activeBindings.isEmpty()) { + String boundWorkgroups = activeBindings.stream() + .map(TicketSettingsBindingEntity::getWorkgroupUid) + .filter(StringUtils::hasText) + .distinct() + .collect(Collectors.joining(",")); + throw new IllegalStateException( + boundWorkgroups.isEmpty() + ? "Ticket settings is bound to workgroups, please unbind before deleting." + : String.format( + "Ticket settings is bound to workgroups (%s), please unbind before deleting.", + boundWorkgroups)); + } Optional optional = ticketSettingsRepository.findByUid(uid); if (optional.isPresent()) { optional.get().setDeleted(true);