update
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-05-11 18:22:04
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-11 09:27:26
|
||||
* @LastEditTime: 2025-03-28 17:06:13
|
||||
* @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.
|
||||
@@ -70,9 +70,7 @@ public class CategoryRestService extends BaseRestService<CategoryEntity, Categor
|
||||
|
||||
@Override
|
||||
public Page<CategoryResponse> queryByOrg(CategoryRequest request) {
|
||||
|
||||
Pageable pageable = PageRequest.of(request.getPageNumber(), request.getPageSize(), Sort.Direction.ASC,
|
||||
"updatedAt");
|
||||
Pageable pageable = request.getPageable();
|
||||
Specification<CategoryEntity> specs = CategorySpecification.search(request);
|
||||
Page<CategoryEntity> page = categoryRepository.findAll(specs, pageable);
|
||||
return page.map(this::convertToResponse);
|
||||
@@ -117,7 +115,6 @@ public class CategoryRestService extends BaseRestService<CategoryEntity, Categor
|
||||
return categoryRepository.findByKbUidAndDeletedFalse(kbUid);
|
||||
}
|
||||
|
||||
|
||||
public Boolean existsByUid(String uid) {
|
||||
return categoryRepository.existsByUid(uid);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-06-08 14:43:05
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-11 08:41:22
|
||||
* @LastEditTime: 2025-03-28 17:03:58
|
||||
* @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.
|
||||
@@ -23,5 +23,6 @@ public enum CategoryTypeEnum {
|
||||
BLOG,
|
||||
EMAIL,
|
||||
TABOO,
|
||||
TICKET
|
||||
TICKET,
|
||||
FAQ
|
||||
}
|
||||
|
||||
@@ -54,7 +54,13 @@ public class BdDateUtils {
|
||||
return null;
|
||||
}
|
||||
// 使用 DateTimeFormatter 直接格式化 LocalDateTime
|
||||
return localDateTime.format(DateTimeFormatter.ofPattern(datetimeFormat));
|
||||
// return localDateTime.format(DateTimeFormatter.ofPattern(datetimeFormat));
|
||||
|
||||
// 使用应用配置的时区
|
||||
// ZonedDateTime zonedDateTime = localDateTime.atZone(LocaleContextHolder.getTimeZone().toZoneId());
|
||||
// 或者固定使用中国时区
|
||||
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
|
||||
return DateTimeFormatter.ofPattern(datetimeFormat).format(zonedDateTime);
|
||||
|
||||
// 或者如果一定要使用 SimpleDateFormat,可以这样转换:
|
||||
// try {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-03-01 17:20:46
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-24 18:26:28
|
||||
* @LastEditTime: 2025-03-28 14:22:30
|
||||
* @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.
|
||||
@@ -168,8 +168,6 @@ public class ConvertUtils {
|
||||
messageResponse.setExtra(extra);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return messageResponse;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-11-22 16:07:49
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2024-11-22 16:20:52
|
||||
* @LastEditTime: 2025-03-28 16:22: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.
|
||||
@@ -16,9 +16,9 @@ package com.bytedesk.kbase.faq;
|
||||
public class FaqConsts {
|
||||
private FaqConsts() {}
|
||||
|
||||
public static final String FAQ_CATEGORY_DEMO_UID_1 = "faq_category_demo_uid_1";
|
||||
public static final String FAQ_CATEGORY_DEMO_UID_2 = "faq_category_demo_uid_2";
|
||||
//
|
||||
public static final String FAQ_DEMO_UID_1 = "faq_demo_uid_1";
|
||||
public static final String FAQ_DEMO_UID_2 = "faq_demo_uid_2";
|
||||
// public static final String FAQ_CATEGORY_DEMO_UID_1 = "faq_category_demo_uid_1";
|
||||
// public static final String FAQ_CATEGORY_DEMO_UID_2 = "faq_category_demo_uid_2";
|
||||
// //
|
||||
// public static final String FAQ_DEMO_UID_1 = "faq_demo_uid_1";
|
||||
// public static final String FAQ_DEMO_UID_2 = "faq_demo_uid_2";
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-03-22 22:59:18
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-18 15:37:05
|
||||
* @LastEditTime: 2025-03-28 17:03: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.
|
||||
@@ -348,10 +348,12 @@ public class FaqRestService extends BaseRestService<FaqEntity, FaqRequest, FaqRe
|
||||
// create category
|
||||
CategoryRequest categoryRequest = CategoryRequest.builder()
|
||||
.name(excel.getCategory())
|
||||
.type(CategoryTypeEnum.FAQ.name())
|
||||
.kbUid(kbUid)
|
||||
.orgUid(orgUid)
|
||||
.build();
|
||||
categoryRequest.setType(CategoryTypeEnum.LLM.name());
|
||||
categoryRequest.setOrgUid(orgUid);
|
||||
// categoryRequest.setType(CategoryTypeEnum.FAQ.name());
|
||||
// categoryRequest.setOrgUid(orgUid);
|
||||
//
|
||||
CategoryResponse categoryResponse = categoryService.create(categoryRequest);
|
||||
faq.setCategoryUid(categoryResponse.getUid());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-06-12 07:20:15
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-02-26 12:56:15
|
||||
* @LastEditTime: 2025-03-28 16:22:30
|
||||
* @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.
|
||||
@@ -14,7 +14,6 @@
|
||||
package com.bytedesk.service.workgroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -27,8 +26,6 @@ import com.bytedesk.core.rbac.organization.OrganizationEntity;
|
||||
import com.bytedesk.core.rbac.organization.event.OrganizationCreateEvent;
|
||||
import com.bytedesk.core.rbac.user.UserEntity;
|
||||
import com.bytedesk.core.uid.UidUtils;
|
||||
import com.bytedesk.core.utils.Utils;
|
||||
import com.bytedesk.kbase.faq.FaqConsts;
|
||||
import com.bytedesk.service.agent.AgentEntity;
|
||||
import com.bytedesk.service.agent.AgentRestService;
|
||||
import com.bytedesk.service.worktime.WorktimeService;
|
||||
@@ -64,10 +61,10 @@ public class WorkgroupEventListener {
|
||||
agentUids.add(agent.getUid());
|
||||
});
|
||||
//
|
||||
List<String> faqUids = Arrays.asList(
|
||||
Utils.formatUid(orgUid, FaqConsts.FAQ_DEMO_UID_1),
|
||||
Utils.formatUid(orgUid, FaqConsts.FAQ_DEMO_UID_2)
|
||||
);
|
||||
// List<String> faqUids = Arrays.asList(
|
||||
// Utils.formatUid(orgUid, FaqConsts.FAQ_DEMO_UID_1),
|
||||
// Utils.formatUid(orgUid, FaqConsts.FAQ_DEMO_UID_2)
|
||||
// );
|
||||
//
|
||||
List<String> worktimeUids = new ArrayList<>();
|
||||
String worktimeUid = worktimeService.createDefault();
|
||||
@@ -83,8 +80,8 @@ public class WorkgroupEventListener {
|
||||
.build();
|
||||
// workgroupRequest.setUid(uidUtils.getUid());
|
||||
// workgroupRequest.setOrgUid(orgUid);
|
||||
workgroupRequest.getServiceSettings().setFaqUids(faqUids);
|
||||
workgroupRequest.getServiceSettings().setQuickFaqUids(faqUids);
|
||||
// workgroupRequest.getServiceSettings().setFaqUids(faqUids);
|
||||
// workgroupRequest.getServiceSettings().setQuickFaqUids(faqUids);
|
||||
workgroupRequest.getMessageLeaveSettings().setWorktimeUids(worktimeUids);
|
||||
|
||||
workgroupService.create(workgroupRequest);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2025-02-15 12:39:46
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-02-26 12:57:35
|
||||
* @LastEditTime: 2025-03-28 16:28:43
|
||||
* @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.
|
||||
@@ -13,26 +13,12 @@
|
||||
*/
|
||||
package com.bytedesk.ticket.process;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.bytedesk.core.rbac.organization.OrganizationEntity;
|
||||
import com.bytedesk.core.rbac.organization.event.OrganizationCreateEvent;
|
||||
import com.bytedesk.core.utils.Utils;
|
||||
import com.bytedesk.ticket.consts.TicketConsts;
|
||||
import com.bytedesk.ticket.process.event.TicketProcessCreateEvent;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -41,9 +27,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@RequiredArgsConstructor
|
||||
public class TicketProcessEventListener {
|
||||
|
||||
private final RepositoryService repositoryService;
|
||||
// private final RepositoryService repositoryService;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
// private final ResourceLoader resourceLoader;
|
||||
|
||||
private final TicketProcessRestService ticketProcessRestService;
|
||||
|
||||
@@ -53,66 +39,12 @@ public class TicketProcessEventListener {
|
||||
OrganizationEntity organization = (OrganizationEntity) event.getSource();
|
||||
String orgUid = organization.getUid();
|
||||
log.info("ticket process - organization created: {}", orgUid);
|
||||
|
||||
// 检查是否已经部署
|
||||
List<Deployment> existingDeployments = repositoryService.createDeploymentQuery()
|
||||
.deploymentTenantId(orgUid)
|
||||
.deploymentName(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.list();
|
||||
|
||||
if (!existingDeployments.isEmpty()) {
|
||||
log.info("工单流程已存在,跳过部署: tenantId={}", orgUid);
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取并部署流程
|
||||
try {
|
||||
Resource resource = resourceLoader.getResource("classpath:" + TicketConsts.TICKET_PROCESS_GROUP_PATH_SIMPLE);
|
||||
// String groupTicketBpmn20Xml = FileUtils.readFileToString(resource.getFile(), "UTF-8");
|
||||
String groupTicketBpmn20Xml = "";
|
||||
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
groupTicketBpmn20Xml = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
// 生成 processUid 并创建流程记录
|
||||
String processUid = Utils.formatUid(orgUid, TicketConsts.TICKET_PROCESS_KEY_GROUP_SIMPLE);
|
||||
TicketProcessRequest processRequest = TicketProcessRequest.builder()
|
||||
.name(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.key(TicketConsts.TICKET_PROCESS_KEY_GROUP_SIMPLE)
|
||||
.description(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.build();
|
||||
processRequest.setUid(processUid);
|
||||
processRequest.setContent(groupTicketBpmn20Xml);
|
||||
processRequest.setOrgUid(orgUid);
|
||||
ticketProcessRestService.create(processRequest);
|
||||
|
||||
// 部署流程
|
||||
Deployment deployment = repositoryService.createDeployment()
|
||||
.name(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.addClasspathResource(TicketConsts.TICKET_PROCESS_GROUP_PATH_SIMPLE)
|
||||
.tenantId(orgUid)
|
||||
.deploy();
|
||||
|
||||
// 更新 TicketProcessEntity
|
||||
Optional<TicketProcessEntity> processEntity = ticketProcessRestService.findByUid(processUid);
|
||||
if (processEntity.isPresent()) {
|
||||
processEntity.get().setDeploymentId(deployment.getId());
|
||||
processEntity.get().setDeployed(true);
|
||||
ticketProcessRestService.save(processEntity.get());
|
||||
}
|
||||
|
||||
log.info("部署租户流程成功: deploymentId={}, tenantId={}",
|
||||
deployment.getId(), deployment.getTenantId());
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("部署工单流程失败: tenantId={}", orgUid, e);
|
||||
}
|
||||
ticketProcessRestService.initProcess(orgUid);
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void onTicketProcessCreateEvent(TicketProcessCreateEvent event) {
|
||||
log.info("TicketProcessEventListener onTicketProcessCreateEvent: {}", event);
|
||||
}
|
||||
// @EventListener
|
||||
// public void onTicketProcessCreateEvent(TicketProcessCreateEvent event) {
|
||||
// log.info("TicketProcessEventListener onTicketProcessCreateEvent: {}", event);
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2025-02-15 13:03:35
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-20 11:41:17
|
||||
* @LastEditTime: 2025-03-28 16:28:29
|
||||
* @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.
|
||||
@@ -13,24 +13,10 @@
|
||||
*/
|
||||
package com.bytedesk.ticket.process;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.bytedesk.core.rbac.organization.OrganizationEntity;
|
||||
import com.bytedesk.core.rbac.organization.OrganizationRestService;
|
||||
import com.bytedesk.core.utils.Utils;
|
||||
import com.bytedesk.ticket.consts.TicketConsts;
|
||||
|
||||
import com.bytedesk.core.constant.BytedeskConsts;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -42,18 +28,22 @@ public class TicketProcessInitializer implements SmartInitializingSingleton {
|
||||
|
||||
// private final AuthorityRestService authorityService;
|
||||
|
||||
private final OrganizationRestService organizationService;
|
||||
// private final OrganizationRestService organizationService;
|
||||
|
||||
private final TicketProcessRestService ticketProcessRestService;
|
||||
|
||||
private final RepositoryService repositoryService;
|
||||
// private final RepositoryService repositoryService;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
// private final ResourceLoader resourceLoader;
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
initAuthority();
|
||||
initProcess();
|
||||
// initProcess();
|
||||
//
|
||||
String orgUid = BytedeskConsts.DEFAULT_ORGANIZATION_UID;
|
||||
log.info("ticket process - organization created: {}", orgUid);
|
||||
ticketProcessRestService.initProcess(orgUid);
|
||||
}
|
||||
|
||||
private void initAuthority() {
|
||||
@@ -71,66 +61,4 @@ public class TicketProcessInitializer implements SmartInitializingSingleton {
|
||||
// authorityService.create(authRequest);
|
||||
// }
|
||||
}
|
||||
|
||||
private void initProcess() {
|
||||
try {
|
||||
// 使用 getInputStream() 而不是 getFile()
|
||||
Resource resource = resourceLoader.getResource("classpath:" + TicketConsts.TICKET_PROCESS_GROUP_PATH_SIMPLE);
|
||||
String groupTicketBpmn20Xml = "";
|
||||
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
groupTicketBpmn20Xml = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
// 判断所有组织是否存在 TicketProcessEntity
|
||||
List<OrganizationEntity> organizations = organizationService.findAll();
|
||||
for (OrganizationEntity organization : organizations) {
|
||||
String orgUid = organization.getUid();
|
||||
// 检查是否已经部署
|
||||
List<Deployment> existingDeployments = repositoryService.createDeploymentQuery()
|
||||
.deploymentTenantId(orgUid)
|
||||
.deploymentName(TicketConsts.TICKET_PROCESS_NAME_GROUP)
|
||||
.list();
|
||||
|
||||
if (!existingDeployments.isEmpty()) {
|
||||
log.info("工单流程已存在,跳过部署: tenantId={}", orgUid);
|
||||
continue;
|
||||
}
|
||||
|
||||
String processUid = Utils.formatUid(orgUid, TicketConsts.TICKET_PROCESS_KEY_GROUP_SIMPLE);
|
||||
// 初始化 TicketProcessEntity
|
||||
TicketProcessRequest processRequest = TicketProcessRequest.builder()
|
||||
.name(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.key(TicketConsts.TICKET_PROCESS_KEY_GROUP_SIMPLE)
|
||||
.description(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.build();
|
||||
processRequest.setUid(processUid);
|
||||
processRequest.setOrgUid(orgUid);
|
||||
processRequest.setContent(groupTicketBpmn20Xml);
|
||||
ticketProcessRestService.create(processRequest);
|
||||
|
||||
// 部署流程
|
||||
Deployment deployment = repositoryService.createDeployment()
|
||||
.name(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.addClasspathResource(TicketConsts.TICKET_PROCESS_GROUP_PATH_SIMPLE)
|
||||
.tenantId(orgUid)
|
||||
.deploy();
|
||||
|
||||
// 更新 TicketProcessEntity
|
||||
Optional<TicketProcessEntity> processEntity = ticketProcessRestService.findByUid(processUid);
|
||||
if (processEntity.isPresent()) {
|
||||
processEntity.get().setDeploymentId(deployment.getId());
|
||||
processEntity.get().setDeployed(true);
|
||||
ticketProcessRestService.save(processEntity.get());
|
||||
}
|
||||
|
||||
log.info("部署租户流程成功: deploymentId={}, tenantId={}",
|
||||
deployment.getId(), deployment.getTenantId());
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("读取流程文件失败", e);
|
||||
throw new RuntimeException("读取流程文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-05-11 18:25:45
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-02-15 14:48:40
|
||||
* @LastEditTime: 2025-03-28 16:18:36
|
||||
* @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.
|
||||
@@ -13,14 +13,20 @@
|
||||
*/
|
||||
package com.bytedesk.ticket.process;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.flowable.engine.RepositoryService;
|
||||
import org.flowable.engine.repository.Deployment;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.orm.ObjectOptimisticLockingFailureException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -30,6 +36,8 @@ import com.bytedesk.core.base.BaseRestService;
|
||||
import com.bytedesk.core.rbac.auth.AuthService;
|
||||
import com.bytedesk.core.rbac.user.UserEntity;
|
||||
import com.bytedesk.core.uid.UidUtils;
|
||||
import com.bytedesk.core.utils.Utils;
|
||||
import com.bytedesk.ticket.consts.TicketConsts;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -37,7 +45,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class TicketProcessRestService extends BaseRestService<TicketProcessEntity, TicketProcessRequest, TicketProcessResponse> {
|
||||
public class TicketProcessRestService
|
||||
extends BaseRestService<TicketProcessEntity, TicketProcessRequest, TicketProcessResponse> {
|
||||
|
||||
private final TicketProcessRepository processRepository;
|
||||
|
||||
@@ -47,10 +56,13 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
|
||||
private final AuthService authService;
|
||||
|
||||
private final RepositoryService repositoryService;
|
||||
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
@Override
|
||||
public Page<TicketProcessResponse> queryByOrg(TicketProcessRequest request) {
|
||||
Pageable pageable = PageRequest.of(request.getPageNumber(), request.getPageSize(), Sort.Direction.ASC,
|
||||
"updatedAt");
|
||||
Pageable pageable = request.getPageable();
|
||||
Specification<TicketProcessEntity> spec = TicketProcessSpecification.search(request);
|
||||
Page<TicketProcessEntity> page = processRepository.findAll(spec, pageable);
|
||||
return page.map(this::convertToResponse);
|
||||
@@ -65,15 +77,11 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
}
|
||||
String userUid = user.getUid();
|
||||
request.setUserUid(userUid);
|
||||
//
|
||||
Pageable pageable = PageRequest.of(request.getPageNumber(), request.getPageSize(), Sort.Direction.ASC,
|
||||
"updatedAt");
|
||||
Specification<TicketProcessEntity> spec = TicketProcessSpecification.search(request);
|
||||
Page<TicketProcessEntity> page = processRepository.findAll(spec, pageable);
|
||||
return page.map(this::convertToResponse);
|
||||
//
|
||||
return queryByOrg(request);
|
||||
}
|
||||
|
||||
@Cacheable(value = "process", key = "#uid", unless="#result==null")
|
||||
@Cacheable(value = "process", key = "#uid", unless = "#result==null")
|
||||
@Override
|
||||
public Optional<TicketProcessEntity> findByUid(String uid) {
|
||||
return processRepository.findByUid(uid);
|
||||
@@ -81,7 +89,7 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
|
||||
@Override
|
||||
public TicketProcessResponse create(TicketProcessRequest request) {
|
||||
// 判断uid是否存在
|
||||
// 判断uid是否存在
|
||||
if (StringUtils.hasText(request.getUid())) {
|
||||
Optional<TicketProcessEntity> optional = processRepository.findByUid(request.getUid());
|
||||
if (optional.isPresent()) {
|
||||
@@ -92,9 +100,11 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
request.setUid(uidUtils.getUid());
|
||||
}
|
||||
// 流程key不能重复
|
||||
Optional<TicketProcessEntity> optionalKey = processRepository.findByKeyAndOrgUid(request.getKey(), request.getOrgUid());
|
||||
Optional<TicketProcessEntity> optionalKey = processRepository.findByKeyAndOrgUid(request.getKey(),
|
||||
request.getOrgUid());
|
||||
if (optionalKey.isPresent()) {
|
||||
throw new RuntimeException("Process key " + request.getKey() + " in org " + request.getOrgUid() + " already exists");
|
||||
throw new RuntimeException(
|
||||
"Process key " + request.getKey() + " in org " + request.getOrgUid() + " already exists");
|
||||
}
|
||||
|
||||
UserEntity user = authService.getUser();
|
||||
@@ -103,7 +113,7 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
} else {
|
||||
// 如果用户为空,则为系统自动创建
|
||||
}
|
||||
|
||||
|
||||
TicketProcessEntity entity = modelMapper.map(request, TicketProcessEntity.class);
|
||||
// entity.setUid(uidUtils.getUid()); // 移动到开头
|
||||
|
||||
@@ -123,14 +133,13 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
entity.setName(request.getName());
|
||||
entity.setContent(request.getContent());
|
||||
entity.setDescription(request.getDescription());
|
||||
//
|
||||
//
|
||||
TicketProcessEntity savedEntity = save(entity);
|
||||
if (savedEntity == null) {
|
||||
throw new RuntimeException("Update process failed");
|
||||
}
|
||||
return convertToResponse(savedEntity);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new RuntimeException("TicketProcess not found");
|
||||
}
|
||||
}
|
||||
@@ -151,8 +160,7 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
if (optional.isPresent()) {
|
||||
optional.get().setDeleted(true);
|
||||
save(optional.get());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
throw new RuntimeException("TicketProcess not found");
|
||||
}
|
||||
}
|
||||
@@ -163,7 +171,8 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleOptimisticLockingFailureException(ObjectOptimisticLockingFailureException e, TicketProcessEntity entity) {
|
||||
public void handleOptimisticLockingFailureException(ObjectOptimisticLockingFailureException e,
|
||||
TicketProcessEntity entity) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'handleOptimisticLockingFailureException'");
|
||||
}
|
||||
@@ -173,5 +182,66 @@ public class TicketProcessRestService extends BaseRestService<TicketProcessEntit
|
||||
return modelMapper.map(entity, TicketProcessResponse.class);
|
||||
}
|
||||
|
||||
|
||||
public void initProcess(String orgUid) {
|
||||
// 检查是否已经部署
|
||||
List<Deployment> existingDeployments = repositoryService.createDeploymentQuery()
|
||||
.deploymentTenantId(orgUid)
|
||||
.deploymentName(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.list();
|
||||
|
||||
if (!existingDeployments.isEmpty()) {
|
||||
log.info("工单流程已存在,跳过部署: tenantId={}", orgUid);
|
||||
return;
|
||||
}
|
||||
|
||||
// 读取并部署流程
|
||||
try {
|
||||
Resource resource = resourceLoader
|
||||
.getResource("classpath:" + TicketConsts.TICKET_PROCESS_GROUP_PATH_SIMPLE);
|
||||
// String groupTicketBpmn20Xml = FileUtils.readFileToString(resource.getFile(),
|
||||
// "UTF-8");
|
||||
String groupTicketBpmn20Xml = "";
|
||||
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
groupTicketBpmn20Xml = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
// 生成 processUid 并创建流程记录
|
||||
String processUid = Utils.formatUid(orgUid, TicketConsts.TICKET_PROCESS_KEY_GROUP_SIMPLE);
|
||||
TicketProcessRequest processRequest = TicketProcessRequest.builder()
|
||||
.uid(processUid)
|
||||
.name(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.content(groupTicketBpmn20Xml)
|
||||
.key(TicketConsts.TICKET_PROCESS_KEY_GROUP_SIMPLE)
|
||||
.description(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.orgUid(orgUid)
|
||||
.build();
|
||||
// processRequest.setUid(processUid);
|
||||
// processRequest.setContent(groupTicketBpmn20Xml);
|
||||
// processRequest.setOrgUid(orgUid);
|
||||
create(processRequest);
|
||||
|
||||
// 部署流程
|
||||
Deployment deployment = repositoryService.createDeployment()
|
||||
.name(TicketConsts.TICKET_PROCESS_NAME_GROUP_SIMPLE)
|
||||
.addClasspathResource(TicketConsts.TICKET_PROCESS_GROUP_PATH_SIMPLE)
|
||||
.tenantId(orgUid)
|
||||
.deploy();
|
||||
|
||||
// 更新 TicketProcessEntity
|
||||
Optional<TicketProcessEntity> processEntity = findByUid(processUid);
|
||||
if (processEntity.isPresent()) {
|
||||
processEntity.get().setDeploymentId(deployment.getId());
|
||||
processEntity.get().setDeployed(true);
|
||||
save(processEntity.get());
|
||||
}
|
||||
|
||||
log.info("部署租户流程成功: deploymentId={}, tenantId={}",
|
||||
deployment.getId(), deployment.getTenantId());
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("部署工单流程失败: tenantId={}", orgUid, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2025-01-29 12:24:32
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-26 17:45:49
|
||||
* @LastEditTime: 2025-03-28 16:43:26
|
||||
* @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.
|
||||
@@ -705,17 +705,20 @@ public class TicketService {
|
||||
}
|
||||
|
||||
try {
|
||||
// 4. 添加评论。
|
||||
// 注意添加评论一定要放在complete之前,否则会报错找不到task
|
||||
// 4. 添加评论
|
||||
Comment comment = taskService.addComment(task.getId(), ticket.getProcessInstanceId(),
|
||||
TicketStatusEnum.RESOLVED.name(), "工单已解决");
|
||||
comment.setUserId(assigneeUid); // 设置评论的userId为当前认领人
|
||||
taskService.saveComment(comment);
|
||||
|
||||
// 5. 完成任务
|
||||
taskService.complete(task.getId());
|
||||
// 5. 设置流程变量,添加这段代码
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
variables.put("verified", false); // 默认设置为false,等待客户验证
|
||||
|
||||
// 6. 完成任务,传入变量
|
||||
taskService.complete(task.getId(), variables);
|
||||
|
||||
// 6. 更新工单状态
|
||||
// 7. 更新工单状态
|
||||
ticket.setStatus(TicketStatusEnum.RESOLVED.name());
|
||||
ticket.setResolvedTime(LocalDateTime.now());
|
||||
ticketRepository.save(ticket);
|
||||
@@ -787,7 +790,7 @@ public class TicketService {
|
||||
|
||||
// 8. 更新工单状态
|
||||
if (request.getVerified()) {
|
||||
ticket.setStatus(TicketStatusEnum.CLOSED.name());
|
||||
ticket.setStatus(request.getVerified() ? TicketStatusEnum.VERIFIED_OK.name() : TicketStatusEnum.VERIFIED_FAIL.name());
|
||||
ticket.setVerified(true);
|
||||
ticket.setClosedTime(LocalDateTime.now());
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2024-01-29 16:17:36
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-03-01 08:46:58
|
||||
* @LastEditTime: 2025-03-28 14:32:22
|
||||
* @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.
|
||||
@@ -14,6 +14,7 @@
|
||||
package com.bytedesk.starter.runner;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
@@ -38,6 +39,9 @@ public class InitDataRunner implements ApplicationRunner {
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
// 在应用的主类或配置类中
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
// TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||
String localIP = NetworkUtils.getFirstNonLoopbackIP();
|
||||
List<String> allIPs = NetworkUtils.getLocalIPs();
|
||||
|
||||
@@ -49,7 +53,7 @@ public class InitDataRunner implements ApplicationRunner {
|
||||
log.info("Other Network IPs:");
|
||||
allIPs.stream()
|
||||
.filter(ip -> !ip.equals(localIP))
|
||||
.forEach(ip -> log.info(" http://{}:{}", ip, port));
|
||||
.forEach(ip -> log.info("http://{}:{}", ip, port));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><link rel="icon" type="image/x-icon" href="/agent/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>微语</title><script type="module" crossorigin src="/agent/agent/assets/js/index-GOHxOdpv.js"></script><link rel="stylesheet" crossorigin href="/agent/agent/assets/css/index-gWOepWFe.css"></head><body><div id="root"></div><script src="https://www.weiyuai.cn/agent/assets/js/0.3.5/sdk.js"></script><script src="https://www.weiyuai.cn/agent/assets/js/2.0.2/index.js" async></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="UTF-8"/><link rel="icon" type="image/x-icon" href="/agent/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>微语</title><script type="module" crossorigin src="/agent/agent/assets/js/index-C1jiQc_M.js"></script><link rel="stylesheet" crossorigin href="/agent/agent/assets/css/index-gWOepWFe.css"></head><body><div id="root"></div><script src="https://www.weiyuai.cn/agent/assets/js/0.3.5/sdk.js"></script><script src="https://www.weiyuai.cn/agent/assets/js/2.0.2/index.js" async></script></body></html>
|
||||
1794
starter/src/main/resources/templates/chat/assets/index-COpaTw7c.js
Normal file
|
After Width: | Height: | Size: 226 KiB |
@@ -0,0 +1,15 @@
|
||||
<!--
|
||||
* @Author: jackning 270580156@qq.com
|
||||
* @Date: 2025-02-09 18:26:27
|
||||
* @LastEditors: jackning 270580156@qq.com
|
||||
* @LastEditTime: 2025-02-09 18:26: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.
|
||||
* 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售
|
||||
* Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE
|
||||
* contact: 270580156@qq.com
|
||||
* 技术/商务联系:270580156@qq.com
|
||||
* Copyright (c) 2025 by bytedesk.com, All Rights Reserved.
|
||||
-->
|
||||
# 自定义图标
|
||||
27
starter/src/main/resources/templates/chat/icons/generate_icns.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
|
||||
###
|
||||
# @Author: jackning 270580156@qq.com
|
||||
# @Date: 2024-03-27 10:52:01
|
||||
# @LastEditors: jackning 270580156@qq.com
|
||||
# @LastEditTime: 2024-03-27 10:56: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.
|
||||
# 仅支持企业内部员工自用,严禁私自用于销售、二次销售或者部署SaaS方式销售
|
||||
# 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.
|
||||
###
|
||||
mkdir logo.iconset
|
||||
sips -z 16 16 logo1024.png --out logo.iconset/icon_16x16.png
|
||||
sips -z 32 32 logo1024.png --out logo.iconset/icon_16x16@2x.png
|
||||
sips -z 32 32 logo1024.png --out logo.iconset/icon_32x32.png
|
||||
sips -z 64 64 logo1024.png --out logo.iconset/icon_32x32@2x.png
|
||||
sips -z 128 128 logo1024.png --out logo.iconset/icon_128x128.png
|
||||
sips -z 256 256 logo1024.png --out logo.iconset/icon_128x128@2x.png
|
||||
sips -z 256 256 logo1024.png --out logo.iconset/icon_256x256.png
|
||||
sips -z 512 512 logo1024.png --out logo.iconset/icon_256x256@2x.png
|
||||
sips -z 512 512 logo1024.png --out logo.iconset/icon_512x512.png
|
||||
sips -z 1024 1024 logo1024.png --out logo.iconset/icon_512x512@2x.png
|
||||
iconutil -c icns logo.iconset -o icon.icns
|
||||
BIN
starter/src/main/resources/templates/chat/icons/icon.icns
Normal file
BIN
starter/src/main/resources/templates/chat/icons/icon.ico
Normal file
|
After Width: | Height: | Size: 286 KiB |
BIN
starter/src/main/resources/templates/chat/icons/icon.png
Normal file
|
After Width: | Height: | Size: 714 B |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 778 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 130 KiB |
BIN
starter/src/main/resources/templates/chat/icons/logo.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
starter/src/main/resources/templates/chat/icons/logo1024.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
starter/src/main/resources/templates/chat/icons/logo192.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
starter/src/main/resources/templates/chat/icons/logo512.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
@@ -25,7 +25,7 @@
|
||||
<meta name="format-detection" content="email=no">
|
||||
<!-- title将由JavaScript动态设置,使用国际化 -->
|
||||
<title>ByteDesk</title>
|
||||
<script type="module" crossorigin src="/chat/assets/index-C5y6TUnm.js"></script>
|
||||
<script type="module" crossorigin src="/chat/assets/index-COpaTw7c.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/chat/assets/index-DTmg-Kms.css">
|
||||
</head>
|
||||
|
||||
|
||||