feat: 工单添加解决方案逻辑
This commit is contained in:
parent
13bfc612bf
commit
eed33c0ef1
|
|
@ -99,6 +99,12 @@ public class TicketController extends ControllerBase {
|
|||
@Resource
|
||||
private ITBasePartService partService;
|
||||
|
||||
@Resource
|
||||
private ITicketSolutionService ticketSolutionService;
|
||||
|
||||
@Resource
|
||||
private ITicketSolutionAuditService ticketSolutionAuditService;
|
||||
|
||||
/**
|
||||
* 获取问题类型
|
||||
* @return 问题类型列表
|
||||
|
|
@ -276,6 +282,19 @@ public class TicketController extends ControllerBase {
|
|||
.setExperienceEvaluation(vo.getExperienceEvaluation());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工单根本原因分析
|
||||
* @param ticketId 工单id
|
||||
* @return 根本原因分析
|
||||
*/
|
||||
@GetMapping("getReason")
|
||||
@ApiMark(moduleName = "工单管理", apiName = "获取工单根本原因分析",isPublic = true)
|
||||
public ApiResult<String> getReason(@Valid @RequestParam @NotNull Integer ticketId){
|
||||
Ticket ticket=ticketService.getById(ticketId);
|
||||
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
|
||||
return ApiResult.success(ticket.getReason());
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出搜索工单
|
||||
* @param request 请求参数
|
||||
|
|
@ -399,30 +418,30 @@ public class TicketController extends ControllerBase {
|
|||
return ApiResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭工单
|
||||
* @param request 请求参数
|
||||
*/
|
||||
@PostMapping("closeTicket")
|
||||
@MethodInfoMark(value = "关闭工单", menuName = "工单管理")
|
||||
@ApiMark(moduleName = "工单管理", apiName = "关闭工单")
|
||||
public ApiResult<Void> closeTicket(@Valid @RequestBody TicketCloseRequest request) {
|
||||
Ticket ticket=ticketService.closeTicket(request);
|
||||
ticketEventPublisher.publishTicketCloseEvent(ticket);
|
||||
ChatMessageDTO message = new ChatMessageDTO()
|
||||
.setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
|
||||
.setFrom("system")
|
||||
.setTicketState(ticket.getState())
|
||||
.setSenderId(0)
|
||||
.setSenderName("服务助手")
|
||||
.setContent("<b>工单已关闭</b><br/>感谢你的使用,如有问题,请重新提交新的工单。")
|
||||
.setCreateTime(Instant.now());
|
||||
ticketChatService.addMessage(request.getTicketId(), message);
|
||||
//推送消息
|
||||
ssePushService.sendTicketMessageToAdmin(ticket.getId(),message);
|
||||
ssePushService.sendTicketMessageToApp(ticket.getId(),message);
|
||||
return ApiResult.success();
|
||||
}
|
||||
// /**
|
||||
// * 关闭工单
|
||||
// * @param request 请求参数
|
||||
// */
|
||||
// @PostMapping("closeTicket")
|
||||
// @MethodInfoMark(value = "关闭工单", menuName = "工单管理")
|
||||
// @ApiMark(moduleName = "工单管理", apiName = "关闭工单")
|
||||
// public ApiResult<Void> closeTicket(@Valid @RequestBody TicketCloseRequest request) {
|
||||
// Ticket ticket=ticketService.closeTicket(request);
|
||||
// ticketEventPublisher.publishTicketCloseEvent(ticket);
|
||||
// ChatMessageDTO message = new ChatMessageDTO()
|
||||
// .setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
|
||||
// .setFrom("system")
|
||||
// .setTicketState(ticket.getState())
|
||||
// .setSenderId(0)
|
||||
// .setSenderName("服务助手")
|
||||
// .setContent("<b>工单已关闭</b><br/>感谢你的使用,如有问题,请重新提交新的工单。")
|
||||
// .setCreateTime(Instant.now());
|
||||
// ticketChatService.addMessage(request.getTicketId(), message);
|
||||
// //推送消息
|
||||
// ssePushService.sendTicketMessageToAdmin(ticket.getId(),message);
|
||||
// ssePushService.sendTicketMessageToApp(ticket.getId(),message);
|
||||
// return ApiResult.success();
|
||||
// }
|
||||
|
||||
/**
|
||||
* 导出工单为pdf
|
||||
|
|
@ -490,7 +509,7 @@ public class TicketController extends ControllerBase {
|
|||
.setUrgency(ticket.getUrgency())
|
||||
.setUpdateTime(DateTimeUtil.format(ticket.getUpdateTime()))
|
||||
.setHandleUserName(handle)
|
||||
.setSolution(ticket.getSolution())
|
||||
.setSolution(ticket.getReason())
|
||||
.setImages(images)
|
||||
.setFiles(files);
|
||||
Map<String, Object> variables = new HashMap<>();
|
||||
|
|
@ -579,6 +598,7 @@ public class TicketController extends ControllerBase {
|
|||
.setNo(ticket.getNo())
|
||||
.setTitle(ticket.getTitle())
|
||||
.setDeviceNo(ticket.getDeviceNo())
|
||||
.setDeviceAddress(ticket.getDeviceAddress())
|
||||
.setModelNo(device.getModelNo())
|
||||
.setDeviceType(device.getDeviceType())
|
||||
.setComponent(ticket.getComponent())
|
||||
|
|
@ -603,8 +623,7 @@ public class TicketController extends ControllerBase {
|
|||
.setAreaName(areaName)
|
||||
.setCompanyName(device.getCustomerName())
|
||||
.setHandle(handle)
|
||||
.setSolution(ticket.getSolution())
|
||||
.setSolutionAttachments(StrUtil.isNotBlank(ticket.getSolutionAttachments()) ? StrUtil.split(ticket.getSolutionAttachments(), ",") : Collections.emptyList())
|
||||
.setSolution(ticket.getReason())
|
||||
.setEvaluate(getTicketEvaluate(ticket.getId()));
|
||||
return ApiResult.success(vo);
|
||||
}
|
||||
|
|
@ -727,4 +746,48 @@ public class TicketController extends ControllerBase {
|
|||
ticketEventPublisher.publishTicketReplyEvent(ticket);
|
||||
return ApiResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工单解决方案措施
|
||||
* @param ticketId 工单编号
|
||||
* @return 解决方案措施
|
||||
**/
|
||||
@GetMapping("getSolutionMeasures")
|
||||
@ApiMark(moduleName = "工单管理", apiName = "获取工单解决方案措施")
|
||||
public ApiResult<List<SolutionMeasuresVO>> getSolutionMeasures(@Valid @RequestParam @NotNull Integer ticketId){
|
||||
return ApiResult.success(ticketSolutionService.getSolutionMeasures(ticketId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存工单解决方案措施
|
||||
* @param request 请求信息
|
||||
**/
|
||||
@PostMapping("saveSolutionMeasures")
|
||||
@ApiMark(moduleName = "工单管理", apiName = "保存工单解决方案措施")
|
||||
public ApiResult<Void> saveSolutionMeasures(@Valid @RequestBody SolutionMeasuresSaveRequest request){
|
||||
ticketSolutionService.saveSolutionMeasures(request);
|
||||
return ApiResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工单解决方案评审部门
|
||||
* @param ticketId 工单编号
|
||||
* @return 评审部门
|
||||
**/
|
||||
@GetMapping("getSolutionReviewDepartment")
|
||||
@ApiMark(moduleName = "工单管理", apiName = "获取工单解决方案评审部门")
|
||||
public ApiResult<List<SolutionReviewDepartmentVO>> getSolutionReviewDepartment(@Valid @RequestParam @NotNull Integer ticketId){
|
||||
return ApiResult.success(ticketSolutionAuditService.getByTicket(ticketId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存工单解决方案评审部门
|
||||
* @param request 请求信息
|
||||
**/
|
||||
@PostMapping("saveSolutionReviewDepartment")
|
||||
@ApiMark(moduleName = "工单管理", apiName = "保存工单解决方案评审部门")
|
||||
public ApiResult<Void> saveSolutionReviewDepartment(@Valid @RequestBody SolutionReviewDepartmentSaveRequest request){
|
||||
ticketSolutionAuditService.saveSolutionReviewDepartment(request);
|
||||
return ApiResult.success();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,12 @@ import cn.hutool.core.date.DatePattern;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.nflg.mobilebroken.admin.pojo.dto.TiketTimeoutDTO;
|
||||
import com.nflg.mobilebroken.admin.publisher.TicketEventPublisher;
|
||||
import com.nflg.mobilebroken.admin.service.SsePushService;
|
||||
import com.nflg.mobilebroken.common.constant.Constant;
|
||||
import com.nflg.mobilebroken.common.constant.MessageSubType;
|
||||
import com.nflg.mobilebroken.common.constant.UserState;
|
||||
import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
|
||||
import com.nflg.mobilebroken.common.pojo.request.TicketEvaluateAddRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.TicketEvaluateAddVO;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.TicketEvaluateItemVO;
|
||||
|
|
@ -22,6 +25,7 @@ import org.springframework.stereotype.Component;
|
|||
import javax.annotation.Resource;
|
||||
import javax.mail.MessagingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
|
|
@ -68,6 +72,15 @@ public class TicketScheduledTasks {
|
|||
@Resource
|
||||
private IDeviceService deviceService;
|
||||
|
||||
@Resource
|
||||
private TicketEventPublisher ticketEventPublisher;
|
||||
|
||||
@Resource
|
||||
private TicketChatService ticketChatService;
|
||||
|
||||
@Resource
|
||||
private SsePushService ssePushService;
|
||||
|
||||
/**
|
||||
* 工单评论邀请邮件
|
||||
* 每天午夜12点执行一次
|
||||
|
|
@ -126,6 +139,21 @@ public class TicketScheduledTasks {
|
|||
tickets.forEach(ticket -> {
|
||||
request.setTicketId(ticket.getId());
|
||||
ticketEvaluateService.add(request);
|
||||
if (ticketService.close(ticket)){
|
||||
ticketEventPublisher.publishTicketCloseEvent(ticket);
|
||||
ChatMessageDTO message = new ChatMessageDTO()
|
||||
.setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
|
||||
.setFrom("system")
|
||||
.setTicketState(ticket.getState())
|
||||
.setSenderId(0)
|
||||
.setSenderName("服务助手")
|
||||
.setContent("<b>工单已关闭</b><br/>感谢你的使用,如有问题,请重新提交新的工单。")
|
||||
.setCreateTime(Instant.now());
|
||||
ticketChatService.addMessage(request.getTicketId(), message);
|
||||
//推送消息
|
||||
ssePushService.sendTicketMessageToAdmin(ticket.getId(),message);
|
||||
ssePushService.sendTicketMessageToApp(ticket.getId(),message);
|
||||
}
|
||||
});
|
||||
log.info("【工单自动评论】执行完成");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
public class Test {
|
||||
|
||||
@org.junit.jupiter.api.Test
|
||||
public void test1(){
|
||||
LocalDate t1=LocalDateTime.now().toLocalDate();
|
||||
LocalDate t2=LocalDateTime.now().toLocalDate().minusDays(1);
|
||||
System.out.println(t1);
|
||||
System.out.println(t2);
|
||||
System.out.println(ChronoUnit.DAYS.between(null, t1));
|
||||
}
|
||||
}
|
||||
|
|
@ -206,6 +206,7 @@ public class TiketController extends ControllerBase {
|
|||
.setNo(ticket.getNo())
|
||||
.setTitle(ticket.getTitle())
|
||||
.setDeviceNo(ticket.getDeviceNo())
|
||||
.setDeviceAddress(ticket.getDeviceAddress())
|
||||
.setModelNo(device.getModelNo())
|
||||
.setComponent(ticket.getComponent())
|
||||
.setUseTime(ticket.getUseTime())
|
||||
|
|
@ -221,8 +222,7 @@ public class TiketController extends ControllerBase {
|
|||
.setSolveTime(ticket.getSolveTime())
|
||||
.setCompanyName(StrUtil.join(",",companys.stream().map(TBaseCustomer::getAgencyCompanyName).collect(Collectors.toList())))
|
||||
.setHandle(handle)
|
||||
.setSolution(ticket.getSolution())
|
||||
.setSolutionAttachments(StrUtil.isNotBlank(ticket.getSolutionAttachments()) ? StrUtil.split(ticket.getSolutionAttachments(), ",") : Collections.emptyList())
|
||||
.setSolution(ticket.getReason())
|
||||
.setEvaluate(getTicketEvaluate(ticket.getId()));
|
||||
return ApiResult.success(vo);
|
||||
}
|
||||
|
|
@ -386,7 +386,20 @@ public class TiketController extends ControllerBase {
|
|||
**/
|
||||
@PostMapping("addTicketEvaluate")
|
||||
public ApiResult<Void> addTicketEvaluate(@Valid @RequestBody TicketEvaluateAddRequest request) {
|
||||
ticketEvaluateService.add(request);
|
||||
Ticket ticket=ticketEvaluateService.add(request);
|
||||
ticketEventPublisher.publishTicketEvaluateEvent(ticket, MultilingualUtil.getLanguage(), MultilingualUtil.getZone());
|
||||
ChatMessageDTO message = new ChatMessageDTO()
|
||||
.setId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr())
|
||||
.setFrom("system")
|
||||
.setTicketState(ticket.getState())
|
||||
.setSenderId(0)
|
||||
.setSenderName("服务助手")
|
||||
.setContent("<b>工单已评价</b><br/>感谢你的评价。")
|
||||
.setCreateTime(Instant.now());
|
||||
ticketChatService.addMessage(request.getTicketId(), message);
|
||||
//推送消息
|
||||
ssePushService.sendTicketMessageToAdmin(ticket.getId(),message);
|
||||
ssePushService.sendTicketMessageToApp(ticket.getId(),message);
|
||||
return ApiResult.success();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.nflg.mobilebroken.cfs.event;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import com.nflg.mobilebroken.common.constant.MessageSubType;
|
||||
import com.nflg.mobilebroken.common.constant.MessageType;
|
||||
import com.nflg.mobilebroken.repository.entity.AdminMessage;
|
||||
import com.nflg.mobilebroken.repository.entity.AdminUser;
|
||||
import com.nflg.mobilebroken.repository.entity.Ticket;
|
||||
import com.nflg.mobilebroken.repository.service.*;
|
||||
import com.nflg.mobilebroken.starter.service.EmailService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class TicketEvaluateEvent extends ApplicationEvent implements ApplicationContextAware {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER= DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
|
||||
private final Ticket ticket;
|
||||
private final String language;
|
||||
private final String zone;
|
||||
|
||||
private IDictionaryItemTranslateService dictionaryItemTranslateService;
|
||||
private IAppUserService appUserService;
|
||||
private EmailService emailService;
|
||||
private ITBaseDeviceTypeService deviceTypeService;
|
||||
private IAdminUserService adminUserService;
|
||||
private IAdminMessageService adminMessageService;
|
||||
|
||||
public TicketEvaluateEvent(Object source, Ticket ticket,String language,String zone) {
|
||||
super(source);
|
||||
this.ticket = ticket;
|
||||
this.language = language;
|
||||
this.zone = zone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.dictionaryItemTranslateService = applicationContext.getBean(IDictionaryItemTranslateService.class);
|
||||
this.appUserService = applicationContext.getBean(IAppUserService.class);
|
||||
this.emailService = applicationContext.getBean(EmailService.class);
|
||||
this.adminUserService = applicationContext.getBean(IAdminUserService.class);
|
||||
this.adminMessageService = applicationContext.getBean(IAdminMessageService.class);
|
||||
this.deviceTypeService = applicationContext.getBean(ITBaseDeviceTypeService.class);
|
||||
}
|
||||
|
||||
public void send(){
|
||||
sendUserMessage();
|
||||
}
|
||||
|
||||
private void sendUserMessage(){
|
||||
//我的待办
|
||||
List<Integer> cqms=deviceTypeService.getCqmsByDeviceType(ticket.getDeviceNo());
|
||||
if (CollectionUtil.isEmpty(cqms)){
|
||||
log.warn("该设备尚未设置CQM负责人:{}", ticket.getDeviceNo());
|
||||
}else {
|
||||
List<AdminUser> cqmUsers = adminUserService.listByIds(cqms);
|
||||
if (CollectionUtil.isNotEmpty(cqmUsers)) {
|
||||
cqmUsers.forEach(c -> adminMessageService.add(
|
||||
new AdminMessage()
|
||||
.setNo(ticket.getNo())
|
||||
.setTitle(ticket.getTitle())
|
||||
.setUserId(c.getId())
|
||||
.setSourceId(ticket.getId())
|
||||
.setSource(0)
|
||||
.setType(MessageType.WorkOrderAssignment.getState())
|
||||
.setSubType(MessageSubType.TicketCompletion.getState())
|
||||
.setIsRead(false)
|
||||
.setCreateTime(LocalDateTime.now()))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.nflg.mobilebroken.cfs.listener;
|
||||
|
||||
import com.nflg.mobilebroken.cfs.event.TicketCreateEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.TicketEvaluateEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.TicketReplyEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.TicketRevokeEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
|
|
@ -27,4 +28,10 @@ public class TicketEventListener {
|
|||
public void handleTicketRevokeEvent(TicketRevokeEvent event) {
|
||||
event.send();
|
||||
}
|
||||
|
||||
@Async
|
||||
@EventListener
|
||||
public void handleTicketEvaluateEvent(TicketEvaluateEvent event) {
|
||||
event.send();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
package com.nflg.mobilebroken.cfs.publisher;
|
||||
|
||||
import com.nflg.mobilebroken.cfs.event.TicketCreateEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.TicketReopenEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.TicketReplyEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.TicketRevokeEvent;
|
||||
import com.nflg.mobilebroken.cfs.event.*;
|
||||
import com.nflg.mobilebroken.repository.entity.Ticket;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
|
@ -43,4 +40,10 @@ public class TicketEventPublisher {
|
|||
event.setApplicationContext(applicationContext);
|
||||
eventPublisher.publishEvent(event);
|
||||
}
|
||||
|
||||
public void publishTicketEvaluateEvent(Ticket ticket, String language, String zone) {
|
||||
TicketEvaluateEvent event = new TicketEvaluateEvent(this, ticket, language, zone);
|
||||
event.setApplicationContext(applicationContext);
|
||||
eventPublisher.publishEvent(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,4 +111,7 @@ public class Constant {
|
|||
public static final String DICTIONARY_ITEM_ACCOUNT_HAS_EXPIRED="AccountHasExpired";
|
||||
|
||||
public static final List<String> ROLE_CODE_TICKET_MANAGERS = ListUtil.of(TITLE_DIRECTOROF_BUSINESS_UNIT,TITLE_TECHNICAL_MANAGER,TITLE_SALES_MANAGER,TITLE_TEST_MANAGER,TITLE_QUALITY_MANAGER,DICTIONARY_TYPE_TITLE_CQM);
|
||||
|
||||
public static final String DICTIONARY_SOLUTION_MEASURES = "SolutionMeasures";
|
||||
public static final String DICTIONARY_SOLUTION_REVIEW_DEPARTMENT = "SolutionReviewDepartment";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ public enum MessageSubType {
|
|||
TicketClosed(7, "工单关闭"),
|
||||
TicketRevoke(8, "工单撤销"),
|
||||
TicketReopen(9, "工单重启"),
|
||||
TicketTimeout(10, "工单超时");
|
||||
TicketTimeout(10, "工单超时"),
|
||||
TicketSolutionAudit(11, "工单解决方案审核");
|
||||
|
||||
private final Integer state;
|
||||
private final String description;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.nflg.mobilebroken.common.pojo.request;
|
||||
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionMeasuresVO;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SolutionMeasuresSaveRequest {
|
||||
|
||||
/**
|
||||
* 工单编号
|
||||
*/
|
||||
@NotNull
|
||||
private Integer ticketId;
|
||||
|
||||
/**
|
||||
* 根本原因
|
||||
*/
|
||||
@NotBlank
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 解决措施
|
||||
*/
|
||||
@Valid
|
||||
@NotEmpty
|
||||
private List<SolutionMeasuresVO> solutionMeasures;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.nflg.mobilebroken.common.pojo.request;
|
||||
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionReviewDepartmentVO;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class SolutionReviewDepartmentSaveRequest {
|
||||
|
||||
@NotNull
|
||||
private Integer ticketId;
|
||||
|
||||
@NotEmpty
|
||||
private List<SolutionReviewDepartmentVO> departments;
|
||||
}
|
||||
|
|
@ -34,4 +34,8 @@ public class TicketAddRequest {
|
|||
|
||||
//附件
|
||||
private List<String> attachments;
|
||||
|
||||
//设备地址
|
||||
@Size(max = 300, message = "设备地址长度不能超过300")
|
||||
private String deviceAddress;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.nflg.mobilebroken.common.constant.TicketState;
|
||||
import com.nflg.mobilebroken.common.constant.TicketUrgency;
|
||||
|
|
@ -8,6 +9,7 @@ import org.ttzero.excel.annotation.ExcelColumn;
|
|||
import org.ttzero.excel.annotation.IgnoreExport;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Objects;
|
||||
|
||||
@Data
|
||||
|
|
@ -51,9 +53,21 @@ public class AdminTicketVO {
|
|||
@ExcelColumn("问题类型")
|
||||
private String question;
|
||||
|
||||
//解决方案
|
||||
@ExcelColumn("解决方案")
|
||||
private String solution;
|
||||
//根本原因分析
|
||||
@IgnoreExport
|
||||
private String reason;
|
||||
|
||||
public String getReason() {
|
||||
return StrUtil.subWithLength(reason, 0, 10);
|
||||
}
|
||||
|
||||
//根本原因分析
|
||||
@ExcelColumn("根本原因分析")
|
||||
private String reason1;
|
||||
|
||||
public String getReason1() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
//代理区域
|
||||
@ExcelColumn("代理区域")
|
||||
|
|
@ -164,4 +178,18 @@ public class AdminTicketVO {
|
|||
//评价
|
||||
@IgnoreExport
|
||||
private TicketEvaluateVO evaluate;
|
||||
|
||||
//处理时长
|
||||
@ExcelColumn("处理时长")
|
||||
private Long processingTime;
|
||||
|
||||
public Long getProcessingTime() {
|
||||
if (TicketState.Processing.getState().compareTo(state)>=0){
|
||||
return ChronoUnit.DAYS.between(createTime.toLocalDate(),LocalDateTime.now().toLocalDate())+1;
|
||||
}
|
||||
if (TicketState.Closed.getState().compareTo(state)>=0) {
|
||||
return ChronoUnit.DAYS.between(completeTime, LocalDateTime.now()) + 1;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SolutionMeasuresItemVO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 措施名称
|
||||
*/
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
@NotBlank
|
||||
private String superintendent;
|
||||
|
||||
/**
|
||||
* 计划日期
|
||||
*/
|
||||
@NotBlank
|
||||
private String scheduleDate;
|
||||
|
||||
/**
|
||||
* 确认日期
|
||||
*/
|
||||
@NotBlank
|
||||
private String confirmedDate;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
private Integer createUserId;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class SolutionMeasuresVO {
|
||||
|
||||
@NotNull
|
||||
private Integer id;
|
||||
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@Valid
|
||||
private List<SolutionMeasuresItemVO> items;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
public class SolutionReviewDepartmentVO {
|
||||
|
||||
private Integer id;
|
||||
|
||||
//部门名称
|
||||
@NotBlank
|
||||
private String deptName;
|
||||
|
||||
//用户id
|
||||
@NotNull
|
||||
private Integer userId;
|
||||
|
||||
//用户名称
|
||||
private String userName;
|
||||
}
|
||||
|
|
@ -98,11 +98,13 @@ public class TicketInfoVO {
|
|||
//解决方案
|
||||
private String solution;
|
||||
|
||||
//解决方案附件
|
||||
private List<String> solutionAttachments;
|
||||
|
||||
/**
|
||||
* 解决时间
|
||||
*/
|
||||
private LocalDateTime solveTime;
|
||||
|
||||
/**
|
||||
* 设备地址
|
||||
*/
|
||||
private String deviceAddress;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ public class Ticket implements Serializable {
|
|||
*/
|
||||
private String attachments;
|
||||
|
||||
/**
|
||||
* 设备地址
|
||||
*/
|
||||
private String deviceAddress;
|
||||
|
||||
/**
|
||||
* 状态,0:待处理;1:处理中;2:处理完成;3:已关闭
|
||||
*/
|
||||
|
|
@ -95,12 +100,7 @@ public class Ticket implements Serializable {
|
|||
/**
|
||||
* 解决方案
|
||||
*/
|
||||
private String solution;
|
||||
|
||||
/**
|
||||
* 解决方案附件
|
||||
*/
|
||||
private String solutionAttachments;
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 解决时间
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
package com.nflg.mobilebroken.repository.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("ticket_solution")
|
||||
public class TicketSolution implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 工单id
|
||||
*/
|
||||
private Integer ticketId;
|
||||
|
||||
/**
|
||||
* 字典项id
|
||||
*/
|
||||
private Integer dictionaryId;
|
||||
|
||||
/**
|
||||
* 字典项值
|
||||
*/
|
||||
private String dictionaryName;
|
||||
|
||||
/**
|
||||
* 负责人
|
||||
*/
|
||||
private String superintendent;
|
||||
|
||||
/**
|
||||
* 计划日期
|
||||
*/
|
||||
private String scheduleDate;
|
||||
|
||||
/**
|
||||
* 确认日期
|
||||
*/
|
||||
private String confirmedDate;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建人id
|
||||
*/
|
||||
private Integer createUserid;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.nflg.mobilebroken.repository.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("ticket_solution_audit")
|
||||
public class TicketSolutionAudit implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 工单id
|
||||
*/
|
||||
private Integer ticketId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.nflg.mobilebroken.repository.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@TableName("ticket_solution_audit_state")
|
||||
public class TicketSolutionAuditState implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 工单id
|
||||
*/
|
||||
private Integer ticketId;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
/**
|
||||
* 审核状态,0:不通过;1:通过
|
||||
*/
|
||||
private Integer state;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 审核不通过的原因
|
||||
*/
|
||||
private String reason;
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ import com.nflg.mobilebroken.repository.entity.DictionaryItem;
|
|||
import org.apache.ibatis.annotations.Select;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 字典值 Mapper 接口
|
||||
|
|
@ -19,4 +21,6 @@ public interface DictionaryItemMapper extends BaseMapper<DictionaryItem> {
|
|||
Integer getId(@Param("dictionaryName") String dictionaryName, @Param("dictionaryItemName") String dictionaryItemName);
|
||||
|
||||
String getName(String dictionaryCode, String itemCode);
|
||||
|
||||
List<DictionaryItem> getListByDictionaryCode(String code);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.nflg.mobilebroken.repository.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionReviewDepartmentVO;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolutionAudit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
public interface TicketSolutionAuditMapper extends BaseMapper<TicketSolutionAudit> {
|
||||
|
||||
List<SolutionReviewDepartmentVO> getByTicket(Integer ticketId);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.nflg.mobilebroken.repository.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolutionAuditState;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
public interface TicketSolutionAuditStateMapper extends BaseMapper<TicketSolutionAuditState> {
|
||||
|
||||
boolean existsNotPass(Integer id);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.nflg.mobilebroken.repository.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolution;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
public interface TicketSolutionMapper extends BaseMapper<TicketSolution> {
|
||||
|
||||
}
|
||||
|
|
@ -52,4 +52,6 @@ public interface IAdminUserService extends IService<AdminUser> {
|
|||
void deleteAccount(Integer id);
|
||||
|
||||
List<Integer> getTickerMangagers();
|
||||
|
||||
List<Integer> getCQMIds();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import com.nflg.mobilebroken.common.pojo.request.DictionaryItemSearchRequest;
|
|||
import com.nflg.mobilebroken.common.pojo.request.SaveDictionaryItemRequest;
|
||||
import com.nflg.mobilebroken.repository.entity.DictionaryItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 字典值 服务类
|
||||
|
|
@ -21,4 +23,6 @@ public interface IDictionaryItemService extends IService<DictionaryItem> {
|
|||
void save(SaveDictionaryItemRequest request);
|
||||
|
||||
Integer getId(String dictionaryName, String dictionaryItemName);
|
||||
|
||||
List<DictionaryItem> getListByDictionaryCode(String code);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.nflg.mobilebroken.repository.service;
|
|||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.nflg.mobilebroken.common.pojo.request.TicketEvaluateAddRequest;
|
||||
import com.nflg.mobilebroken.repository.entity.Ticket;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketEvaluate;
|
||||
|
||||
/**
|
||||
|
|
@ -14,5 +15,5 @@ import com.nflg.mobilebroken.repository.entity.TicketEvaluate;
|
|||
*/
|
||||
public interface ITicketEvaluateService extends IService<TicketEvaluate> {
|
||||
|
||||
void add(TicketEvaluateAddRequest request);
|
||||
Ticket add(TicketEvaluateAddRequest request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public interface ITicketService extends IService<Ticket> {
|
|||
|
||||
Ticket completeTicket(Integer id);
|
||||
|
||||
Ticket closeTicket(TicketCloseRequest request);
|
||||
// Ticket closeTicket(TicketCloseRequest request);
|
||||
|
||||
List<AdminTicketVO> exportSearch(AdminTicketSearchRequest request);
|
||||
|
||||
|
|
@ -54,4 +54,6 @@ public interface ITicketService extends IService<Ticket> {
|
|||
List<TicketVO> getAdminFavorites(Integer userId,Integer favoritesId);
|
||||
|
||||
Ticket rejectTicket(Integer id);
|
||||
|
||||
boolean close(Ticket ticket);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package com.nflg.mobilebroken.repository.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.nflg.mobilebroken.common.pojo.request.SolutionReviewDepartmentSaveRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionReviewDepartmentVO;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolutionAudit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
public interface ITicketSolutionAuditService extends IService<TicketSolutionAudit> {
|
||||
|
||||
List<SolutionReviewDepartmentVO> getByTicket(Integer ticketId);
|
||||
|
||||
void saveSolutionReviewDepartment(SolutionReviewDepartmentSaveRequest request);
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.nflg.mobilebroken.repository.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolutionAuditState;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
public interface ITicketSolutionAuditStateService extends IService<TicketSolutionAuditState> {
|
||||
|
||||
boolean existsNotPass(Integer id);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.nflg.mobilebroken.repository.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.nflg.mobilebroken.common.pojo.request.SolutionMeasuresSaveRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionMeasuresVO;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolution;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
public interface ITicketSolutionService extends IService<TicketSolution> {
|
||||
|
||||
List<SolutionMeasuresVO> getSolutionMeasures(Integer ticketId);
|
||||
|
||||
void saveSolutionMeasures(SolutionMeasuresSaveRequest request);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.nflg.mobilebroken.repository.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
|
|
@ -339,6 +340,11 @@ public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser
|
|||
return baseMapper.getTickerMangagers(Constant.ROLE_CODE_TICKET_MANAGERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Integer> getCQMIds() {
|
||||
return baseMapper.getTickerMangagers(ListUtil.of(Constant.DICTIONARY_TYPE_TITLE_CQM));
|
||||
}
|
||||
|
||||
private String getDepartmentName(Long departmentId) {
|
||||
TBaseDepartment department = departmentService.lambdaQuery()
|
||||
.eq(TBaseDepartment::getId, departmentId)
|
||||
|
|
|
|||
|
|
@ -130,4 +130,9 @@ public class DictionaryItemServiceImpl extends ServiceImpl<DictionaryItemMapper,
|
|||
public Integer getId(String dictionaryName, String dictionaryItemName) {
|
||||
return baseMapper.getId(dictionaryName, dictionaryItemName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DictionaryItem> getListByDictionaryCode(String code) {
|
||||
return baseMapper.getListByDictionaryCode(code);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class TicketEvaluateServiceImpl extends ServiceImpl<TicketEvaluateMapper,
|
|||
private ITicketService ticketService;
|
||||
|
||||
@Override
|
||||
public void add(TicketEvaluateAddRequest request) {
|
||||
public Ticket add(TicketEvaluateAddRequest request) {
|
||||
Ticket ticket = ticketService.getById(request.getTicketId());
|
||||
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
|
||||
VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState())
|
||||
|
|
@ -47,5 +47,6 @@ public class TicketEvaluateServiceImpl extends ServiceImpl<TicketEvaluateMapper,
|
|||
.setFeedback(request.getFeedback())
|
||||
.setCreateTime(LocalDateTime.now());
|
||||
save(ticketEvaluate);
|
||||
return ticket;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,7 @@ import com.nflg.mobilebroken.common.util.AdminUserUtil;
|
|||
import com.nflg.mobilebroken.common.util.AppUserUtil;
|
||||
import com.nflg.mobilebroken.common.util.TicketUtl;
|
||||
import com.nflg.mobilebroken.common.util.VUtils;
|
||||
import com.nflg.mobilebroken.repository.entity.AdminUser;
|
||||
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
||||
import com.nflg.mobilebroken.repository.entity.Ticket;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketEvaluate;
|
||||
import com.nflg.mobilebroken.repository.entity.*;
|
||||
import com.nflg.mobilebroken.repository.mapper.TicketMapper;
|
||||
import com.nflg.mobilebroken.repository.service.*;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -52,6 +49,9 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||
@Resource
|
||||
private IFileUploadRecordService fileUploadRecordService;
|
||||
|
||||
@Resource
|
||||
private ITicketSolutionAuditStateService ticketSolutionAuditStateService;
|
||||
|
||||
@Override
|
||||
public Ticket add(TicketAddRequest request, Integer userId) {
|
||||
Ticket lastTicket=lambdaQuery()
|
||||
|
|
@ -63,6 +63,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||
Ticket ticket = new Ticket()
|
||||
.setNo(no)
|
||||
.setDeviceNo(request.getDeviceNo())
|
||||
.setDeviceAddress(request.getDeviceAddress())
|
||||
.setComponent(request.getComponent())
|
||||
.setUseTime(request.getUseTime())
|
||||
.setTitle(request.getTitle())
|
||||
|
|
@ -204,28 +205,27 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Ticket closeTicket(TicketCloseRequest request) {
|
||||
Ticket ticket = getById(request.getTicketId());
|
||||
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("未找到工单");
|
||||
VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState()))
|
||||
.throwMessage("非处理完成状态不允许关闭");
|
||||
VUtils.trueThrowBusinessError(!ticketEvaluateService.lambdaQuery()
|
||||
.eq(TicketEvaluate::getTicketId, request.getTicketId())
|
||||
.exists())
|
||||
.throwMessage("工单尚未评价,不能关闭");
|
||||
List<Integer> tickerMangagers = adminUserService.getTickerMangagers();
|
||||
tickerMangagers.addAll(Arrays.stream(ticket.getHandle().split(",")).map(Integer::parseInt).collect(Collectors.toList()));
|
||||
VUtils.trueThrowBusinessError(tickerMangagers.stream().noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId())))
|
||||
.throwMessage("你无权关闭工单");
|
||||
ticket.setState(TicketState.Closed.getState());
|
||||
ticket.setSolution(request.getSolution());
|
||||
ticket.setSolutionAttachments(StrUtil.join(",", request.getAttachments()));
|
||||
ticket.setSolveTime(LocalDateTime.now());
|
||||
ticket.setCurrentHandle(AdminUserUtil.getUserId());
|
||||
updateById(ticket);
|
||||
return ticket;
|
||||
}
|
||||
// @Override
|
||||
// public Ticket closeTicket(TicketCloseRequest request) {
|
||||
// Ticket ticket = getById(request.getTicketId());
|
||||
// VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("未找到工单");
|
||||
// VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState()))
|
||||
// .throwMessage("非处理完成状态不允许关闭");
|
||||
// VUtils.trueThrowBusinessError(!ticketEvaluateService.lambdaQuery()
|
||||
// .eq(TicketEvaluate::getTicketId, request.getTicketId())
|
||||
// .exists())
|
||||
// .throwMessage("工单尚未评价,不能关闭");
|
||||
// List<Integer> tickerMangagers = adminUserService.getTickerMangagers();
|
||||
// tickerMangagers.addAll(Arrays.stream(ticket.getHandle().split(",")).map(Integer::parseInt).collect(Collectors.toList()));
|
||||
// VUtils.trueThrowBusinessError(tickerMangagers.stream().noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId())))
|
||||
// .throwMessage("你无权关闭工单");
|
||||
// ticket.setState(TicketState.Closed.getState());
|
||||
// ticket.setReason(request.getSolution());
|
||||
// ticket.setSolveTime(LocalDateTime.now());
|
||||
// ticket.setCurrentHandle(AdminUserUtil.getUserId());
|
||||
// updateById(ticket);
|
||||
// return ticket;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public List<AdminTicketVO> exportSearch(AdminTicketSearchRequest request) {
|
||||
|
|
@ -346,4 +346,28 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||
updateById(ticket);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
public boolean close(Ticket ticket){
|
||||
if (!Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState())){
|
||||
return false;
|
||||
}
|
||||
if (!ticketEvaluateService.lambdaQuery()
|
||||
.eq(TicketEvaluate::getTicketId, ticket.getId())
|
||||
.exists()){
|
||||
return false;
|
||||
}
|
||||
if (!ticketSolutionAuditStateService.lambdaQuery().eq(TicketSolutionAuditState::getTicketId, ticket.getId()).exists()) {
|
||||
return false;
|
||||
}
|
||||
if (ticketSolutionAuditStateService.existsNotPass(ticket.getId())){
|
||||
return false;
|
||||
}
|
||||
return lambdaUpdate()
|
||||
.set(Ticket::getState, TicketState.Closed.getState())
|
||||
.set(Ticket::getSolveTime, LocalDateTime.now())
|
||||
.set(Ticket::getUpdateTime, LocalDateTime.now())
|
||||
.eq(Ticket::getId, ticket.getId())
|
||||
.eq(Ticket::getState, TicketState.ProcessingCompleted.getState())
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.nflg.mobilebroken.repository.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.nflg.mobilebroken.common.constant.Constant;
|
||||
import com.nflg.mobilebroken.common.pojo.request.SolutionReviewDepartmentSaveRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionReviewDepartmentVO;
|
||||
import com.nflg.mobilebroken.repository.entity.DictionaryItem;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolutionAudit;
|
||||
import com.nflg.mobilebroken.repository.mapper.TicketSolutionAuditMapper;
|
||||
import com.nflg.mobilebroken.repository.service.IDictionaryItemService;
|
||||
import com.nflg.mobilebroken.repository.service.ITicketSolutionAuditService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
@Service
|
||||
public class TicketSolutionAuditServiceImpl extends ServiceImpl<TicketSolutionAuditMapper, TicketSolutionAudit> implements ITicketSolutionAuditService {
|
||||
|
||||
@Resource
|
||||
private IDictionaryItemService dictionaryItemService;
|
||||
|
||||
@Override
|
||||
public List<SolutionReviewDepartmentVO> getByTicket(Integer ticketId) {
|
||||
List<DictionaryItem> items=dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_SOLUTION_REVIEW_DEPARTMENT);
|
||||
List<SolutionReviewDepartmentVO> vos=baseMapper.getByTicket(ticketId);
|
||||
items.forEach(item->{
|
||||
if (vos.stream().noneMatch(vo->vo.getDeptName().equals(item.getName()))){
|
||||
SolutionReviewDepartmentVO vo=new SolutionReviewDepartmentVO();
|
||||
vo.setDeptName(item.getName());
|
||||
vos.add(vo);
|
||||
}
|
||||
});
|
||||
return vos;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveSolutionReviewDepartment(SolutionReviewDepartmentSaveRequest request) {
|
||||
remove(new LambdaQueryWrapper<TicketSolutionAudit>()
|
||||
.eq(TicketSolutionAudit::getTicketId,request.getTicketId())
|
||||
.notIn(TicketSolutionAudit::getDeptName,request.getDepartments().stream().map(SolutionReviewDepartmentVO::getDeptName).collect(Collectors.toList())));
|
||||
List<TicketSolutionAudit> forAdd=new ArrayList<>();
|
||||
List<TicketSolutionAudit> forUpdate=new ArrayList<>();
|
||||
request.getDepartments().forEach(detp->{
|
||||
TicketSolutionAudit audit=new TicketSolutionAudit()
|
||||
.setTicketId(request.getTicketId())
|
||||
.setDeptName(detp.getDeptName())
|
||||
.setUserId(detp.getUserId());
|
||||
if (Objects.isNull(detp.getId())){
|
||||
audit.setCreateTime(LocalDateTime.now());
|
||||
forAdd.add(audit);
|
||||
}else {
|
||||
audit.setId(detp.getId());
|
||||
forUpdate.add(audit);
|
||||
}
|
||||
});
|
||||
if (CollectionUtil.isNotEmpty(forAdd)){
|
||||
saveBatch(forAdd);
|
||||
}
|
||||
if (CollectionUtil.isNotEmpty(forUpdate)){
|
||||
updateBatchById(forUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.nflg.mobilebroken.repository.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolutionAuditState;
|
||||
import com.nflg.mobilebroken.repository.mapper.TicketSolutionAuditStateMapper;
|
||||
import com.nflg.mobilebroken.repository.service.ITicketSolutionAuditStateService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
@Service
|
||||
public class TicketSolutionAuditStateServiceImpl extends ServiceImpl<TicketSolutionAuditStateMapper, TicketSolutionAuditState> implements ITicketSolutionAuditStateService {
|
||||
|
||||
@Override
|
||||
public boolean existsNotPass(Integer id) {
|
||||
return baseMapper.existsNotPass(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
package com.nflg.mobilebroken.repository.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.nflg.mobilebroken.common.constant.Constant;
|
||||
import com.nflg.mobilebroken.common.constant.TicketState;
|
||||
import com.nflg.mobilebroken.common.pojo.request.SolutionMeasuresSaveRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionMeasuresItemVO;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.SolutionMeasuresVO;
|
||||
import com.nflg.mobilebroken.common.util.AdminUserUtil;
|
||||
import com.nflg.mobilebroken.common.util.VUtils;
|
||||
import com.nflg.mobilebroken.repository.entity.DictionaryItem;
|
||||
import com.nflg.mobilebroken.repository.entity.Ticket;
|
||||
import com.nflg.mobilebroken.repository.entity.TicketSolution;
|
||||
import com.nflg.mobilebroken.repository.mapper.TicketSolutionMapper;
|
||||
import com.nflg.mobilebroken.repository.service.IAdminUserService;
|
||||
import com.nflg.mobilebroken.repository.service.IDictionaryItemService;
|
||||
import com.nflg.mobilebroken.repository.service.ITicketService;
|
||||
import com.nflg.mobilebroken.repository.service.ITicketSolutionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author 代码生成器生成
|
||||
* @since 2025
|
||||
*/
|
||||
@Service
|
||||
public class TicketSolutionServiceImpl extends ServiceImpl<TicketSolutionMapper, TicketSolution> implements ITicketSolutionService {
|
||||
|
||||
@Resource
|
||||
private ITicketService ticketService;
|
||||
|
||||
@Resource
|
||||
private IDictionaryItemService dictionaryItemService;
|
||||
|
||||
@Resource
|
||||
private IAdminUserService adminUserService;
|
||||
|
||||
@Override
|
||||
public List<SolutionMeasuresVO> getSolutionMeasures(Integer ticketId) {
|
||||
Ticket ticket = ticketService.getById(ticketId);
|
||||
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
|
||||
List<String> initialNames= new ArrayList<>();
|
||||
if (Objects.equals(ticket.getState(), TicketState.Processing.getState())) {
|
||||
List<DictionaryItem> items = dictionaryItemService.getListByDictionaryCode(Constant.DICTIONARY_SOLUTION_MEASURES);
|
||||
initialNames=items.stream().map(DictionaryItem::getValue).collect(Collectors.toList());
|
||||
}
|
||||
List<TicketSolution> solutions = lambdaQuery().eq(TicketSolution::getTicketId, ticketId).orderByAsc(TicketSolution::getId).list();
|
||||
Map<String, List<TicketSolution>> groupedSolutions = solutions.stream().collect(Collectors.groupingBy(TicketSolution::getDictionaryName, LinkedHashMap::new, Collectors.toList()));
|
||||
if (CollectionUtil.isEmpty(groupedSolutions)) {
|
||||
return initialNames.stream().map(ticketSolutions -> new SolutionMeasuresVO()
|
||||
.setName(ticketSolutions)
|
||||
.setItems(Collections.emptyList()))
|
||||
.collect(Collectors.toList());
|
||||
} else if (CollectionUtil.isEmpty(initialNames)) {
|
||||
return groupedSolutions.entrySet().stream().map(ks -> new SolutionMeasuresVO()
|
||||
.setName(ks.getKey())
|
||||
.setItems(ks.getValue().stream().map(v -> new SolutionMeasuresItemVO()
|
||||
.setName(v.getDictionaryName())
|
||||
.setSuperintendent(v.getSuperintendent())
|
||||
.setScheduleDate(v.getScheduleDate())
|
||||
.setConfirmedDate(v.getConfirmedDate())
|
||||
.setRemark(v.getRemark())
|
||||
.setCreateUserId(v.getCreateUserid())).collect(Collectors.toList())
|
||||
)).collect(Collectors.toList());
|
||||
} else {
|
||||
List<SolutionMeasuresVO> vos = new ArrayList<>();
|
||||
initialNames.forEach(name -> {
|
||||
List<TicketSolution> values = groupedSolutions.get(name);
|
||||
if (CollectionUtil.isEmpty(values)) {
|
||||
vos.add(new SolutionMeasuresVO().setName(name).setItems(Collections.emptyList()));
|
||||
} else {
|
||||
vos.add(new SolutionMeasuresVO()
|
||||
.setName(name)
|
||||
.setItems(values.stream().map(v -> new SolutionMeasuresItemVO()
|
||||
.setName(v.getDictionaryName())
|
||||
.setSuperintendent(v.getSuperintendent())
|
||||
.setScheduleDate(v.getScheduleDate())
|
||||
.setConfirmedDate(v.getConfirmedDate())
|
||||
.setRemark(v.getRemark())
|
||||
.setCreateUserId(v.getCreateUserid())).collect(Collectors.toList())
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
return vos;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveSolutionMeasures(SolutionMeasuresSaveRequest request) {
|
||||
Ticket ticket=ticketService.getById(request.getTicketId());
|
||||
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
|
||||
VUtils.trueThrowBusinessError(!Objects.equals(ticket.getState(), TicketState.Processing.getState())
|
||||
&& !Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState()))
|
||||
.throwMessage("当前工单状态不允许修改解决方案");
|
||||
List<Integer> cqmIds=adminUserService.getCQMIds();
|
||||
cqmIds.addAll(Arrays.stream(ticket.getHandle().split(",")).map(Integer::parseInt).collect(Collectors.toList()));
|
||||
VUtils.trueThrowBusinessError(cqmIds.stream().noneMatch(uid -> Objects.equals(uid, AdminUserUtil.getUserId())))
|
||||
.throwMessage("无权修改解决方案");
|
||||
ticketService.lambdaUpdate()
|
||||
.set(Ticket::getReason, request.getReason())
|
||||
.eq(Ticket::getId, request.getTicketId())
|
||||
.update();
|
||||
baseMapper.delete(new LambdaQueryWrapper<TicketSolution>()
|
||||
.eq(TicketSolution::getTicketId,request.getTicketId())
|
||||
.notIn(TicketSolution::getId, request.getSolutionMeasures().stream().flatMap(s -> s.getItems().stream()).map(SolutionMeasuresItemVO::getId).collect(Collectors.toList()))
|
||||
);
|
||||
List<TicketSolution> forAdd=new ArrayList<>();
|
||||
List<TicketSolution> forUpdate=new ArrayList<>();
|
||||
for (SolutionMeasuresVO solutionMeasuresVO : request.getSolutionMeasures()) {
|
||||
for (SolutionMeasuresItemVO solutionMeasuresItemVO : solutionMeasuresVO.getItems()){
|
||||
TicketSolution solution=new TicketSolution()
|
||||
.setTicketId(request.getTicketId())
|
||||
.setDictionaryId(solutionMeasuresVO.getId())
|
||||
.setDictionaryName(solutionMeasuresVO.getName())
|
||||
.setSuperintendent(solutionMeasuresItemVO.getSuperintendent())
|
||||
.setScheduleDate(solutionMeasuresItemVO.getScheduleDate())
|
||||
.setConfirmedDate(solutionMeasuresItemVO.getConfirmedDate());
|
||||
if (Objects.isNull(solutionMeasuresItemVO.getId())){
|
||||
solution.setCreateUserid(AdminUserUtil.getUserId())
|
||||
.setCreateTime(LocalDateTime.now());
|
||||
forAdd.add(solution);
|
||||
}else {
|
||||
solution.setId(solutionMeasuresItemVO.getId());
|
||||
forUpdate.add(solution);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CollectionUtil.isNotEmpty(forAdd)){
|
||||
saveBatch(forAdd);
|
||||
}
|
||||
if (CollectionUtil.isNotEmpty(forUpdate)){
|
||||
updateBatchById(forUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,4 +8,12 @@
|
|||
INNER JOIN dictionary_item di ON d.id=di.dictionary_id
|
||||
WHERE d.`code`=#{dictionaryCode} AND di.`code`=#{itemCode}
|
||||
</select>
|
||||
|
||||
<select id="getListByDictionaryCode" resultType="com.nflg.mobilebroken.repository.entity.DictionaryItem">
|
||||
SELECT di.*
|
||||
FROM dictionary d
|
||||
INNER JOIN dictionary_item di ON d.id=di.dictionary_id
|
||||
WHERE d.`code`=#{code}
|
||||
ORDER BY di.id
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.nflg.mobilebroken.repository.mapper.TicketSolutionAuditMapper">
|
||||
|
||||
<select id="getByTicket" resultType="com.nflg.mobilebroken.common.pojo.vo.SolutionReviewDepartmentVO">
|
||||
SELECT tsa.id,tsa.dept_name,tsa.user_id,au.user_name
|
||||
FROM ticket_solution_audit tsa
|
||||
LEFT JOIN admin_user au ON tsa.user_id=au.id
|
||||
WHERE tsa.ticket_id=#{ticketId}
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.nflg.mobilebroken.repository.mapper.TicketSolutionAuditStateMapper">
|
||||
|
||||
<select id="existsNotPass" resultType="boolean">
|
||||
SELECT EXISTS
|
||||
(SELECT 1
|
||||
FROM ticket_solution_audit tsa
|
||||
LEFT JOIN ticket_solution_audit_state tsas ON tsa.ticket_id = tsas.ticket_id
|
||||
AND tsa.user_id = tsas.user_id
|
||||
WHERE tsa.ticket_id = #{id}
|
||||
AND tsas.state != 1)
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.nflg.mobilebroken.repository.mapper.TicketSolutionMapper">
|
||||
|
||||
</mapper>
|
||||
|
|
@ -33,7 +33,7 @@ public class CodeGenerator {
|
|||
, Paths.get(System.getProperty("user.dir")) + "/src/main/resources/mapper"))
|
||||
)
|
||||
.strategyConfig(builder -> {
|
||||
builder.addInclude("ticket_favorites") //只生成指定表
|
||||
builder.addInclude("ticket_solution_audit,ticket_solution_audit_state") //只生成指定表
|
||||
.entityBuilder()
|
||||
.enableLombok()
|
||||
.enableChainModel()
|
||||
|
|
|
|||
Loading…
Reference in New Issue