Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
大米 2025-02-07 16:37:27 +08:00
commit c48a5c34be
29 changed files with 278 additions and 122 deletions

View File

@ -0,0 +1,75 @@
package com.nflg.mobilebroken.admin.controller;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.nflg.mobilebroken.common.constant.STATE;
import com.nflg.mobilebroken.common.exception.NflgException;
import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.util.AdminUserUtil;
import com.nflg.mobilebroken.starter.service.FileUploadService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* 文件上传相关接口
*
* @author 曹鹏飞
**/
@RestController
@RequestMapping("/file")
public class FileController extends ControllerBase {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
@Resource
private FileUploadService fileUploadService;
/**
* 上传单个文件
*
* @param file 要上传的文件
* @return 可访问的文件url
*/
@PostMapping("uploadSingleFile")
public ApiResult<String> uploadSingleFile(@RequestParam("file") MultipartFile file) {
try {
return ApiResult.success(fileUploadService.upload(buildFilePath(file.getOriginalFilename()), file));
} catch (Exception ex) {
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
}
}
private String buildFilePath(String fileName) {
return StrUtil.format("admin/{}/{}/{}/{}", LocalDateTime.now().format(FORMATTER), AdminUserUtil.getUserId(),
RandomUtil.randomString(4), fileName);
}
/**
* 上传多个文件
*
* @param files 要上传的文件列表
* @return 可访问的文件url列表
*/
@PostMapping("uploadMultipleFiles")
public ApiResult<List<String>> uploadMultipleFiles(@Valid @RequestParam("files") @NotEmpty List<MultipartFile> files) {
try {
List<String> list = new ArrayList<>();
for (MultipartFile f : files) {
list.add(fileUploadService.upload(buildFilePath(f.getOriginalFilename()), f));
}
return ApiResult.success(list);
} catch (Exception ex) {
throw new NflgException(STATE.BusinessError, "上传文件失败:" + ex.getMessage());
}
}
}

View File

@ -24,7 +24,7 @@ public class SSEController extends ControllerBase {
@GetMapping(value = "connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @GetMapping(value = "connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter connect(@RequestParam String userId) { public SseEmitter connect(@RequestParam String userId) {
SseEmitter sse = adminSSEManagerService.connect(userId); SseEmitter sse = adminSSEManagerService.connect(Integer.valueOf(userId));
try { try {
sse.send("您已连接"); sse.send("您已连接");
} catch (IOException e) { } catch (IOException e) {

View File

@ -1,6 +1,8 @@
package com.nflg.mobilebroken.admin.service.impl; package com.nflg.mobilebroken.admin.service.impl;
import com.nflg.mobilebroken.common.constant.Constant; import com.nflg.mobilebroken.common.constant.Constant;
import com.nflg.mobilebroken.common.pojo.dto.NotifyDTO;
import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import com.nflg.mobilebroken.common.pojo.dto.UserDTO; import com.nflg.mobilebroken.common.pojo.dto.UserDTO;
import com.nflg.mobilebroken.starter.service.INotifyPushService; import com.nflg.mobilebroken.starter.service.INotifyPushService;
import com.nflg.mobilebroken.starter.service.SSEManagerService; import com.nflg.mobilebroken.starter.service.SSEManagerService;
@ -27,7 +29,10 @@ public class SSEINotifyPushService implements INotifyPushService {
@Override @Override
public void push(UserDTO user, String subject, String content) { public void push(UserDTO user, String subject, String content) {
try { try {
sseManagerService.send(user.getId().toString(), subject, content); SSEMessageDTO message = new SSEMessageDTO()
.setType(2)
.setData(new NotifyDTO().setSubject(subject).setContent(content));
sseManagerService.send(user.getId(), message);
} catch (IOException e) { } catch (IOException e) {
log.error("发送SSE失败", e); log.error("发送SSE失败", e);
} }

View File

@ -50,7 +50,7 @@ public class FileController extends ControllerBase {
} }
private String buildFilePath(String fileName){ private String buildFilePath(String fileName){
return StrUtil.format("{}/{}/{}/{}", LocalDateTime.now().format(FORMATTER), AppUserUtil.getUserId(), return StrUtil.format("cfs/{}/{}/{}/{}", LocalDateTime.now().format(FORMATTER), AppUserUtil.getUserId(),
RandomUtil.randomString(4),fileName); RandomUtil.randomString(4),fileName);
} }

View File

@ -1,7 +1,5 @@
package com.nflg.mobilebroken.cfs.controller; package com.nflg.mobilebroken.cfs.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nflg.mobilebroken.common.constant.Constant; import com.nflg.mobilebroken.common.constant.Constant;
import com.nflg.mobilebroken.common.pojo.ApiResult; import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.PageData; import com.nflg.mobilebroken.common.pojo.PageData;
@ -43,11 +41,7 @@ public class MessageController extends ControllerBase {
*/ */
@PostMapping("searchMessages") @PostMapping("searchMessages")
public ApiResult<PageData<AppMessageVO>> searchMessages(@RequestBody AppMessageSearchRequest request) { public ApiResult<PageData<AppMessageVO>> searchMessages(@RequestBody AppMessageSearchRequest request) {
IPage<AppMessageVO> page = new Page<>(); return ApiResult.success(appMessageService.search(AppUserUtil.getUserId(), request));
page.setCurrent(request.getPage());
page.setSize(request.getPageSize());
appMessageService.search(AppUserUtil.getUserId(), request.getTitle(), page);
return ApiResult.success(page);
} }
/** /**
@ -79,11 +73,7 @@ public class MessageController extends ControllerBase {
*/ */
@GetMapping("getNotReadMessages") @GetMapping("getNotReadMessages")
public ApiResult<PageData<AppMessageVO>> getNotReadMessages(@RequestParam(defaultValue = "10") Integer num) { public ApiResult<PageData<AppMessageVO>> getNotReadMessages(@RequestParam(defaultValue = "10") Integer num) {
IPage<AppMessageVO> page = new Page<>(); return ApiResult.success(appMessageService.getNotReadMessage(AppUserUtil.getUserId(), num));
page.setCurrent(1);
page.setSize(num);
appMessageService.getNotReadMessage(AppUserUtil.getUserId(), num, page);
return ApiResult.success(page);
} }
/** /**

View File

@ -28,7 +28,7 @@ public class SSEController extends ControllerBase {
private APPSSEManagerService sseManagerService; private APPSSEManagerService sseManagerService;
@GetMapping(value = "connect",produces = MediaType.TEXT_EVENT_STREAM_VALUE) @GetMapping(value = "connect",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter connect(@RequestParam String userId){ public SseEmitter connect(@RequestParam Integer userId) {
SseEmitter sse=sseManagerService.connect(userId); SseEmitter sse=sseManagerService.connect(userId);
try { try {
sse.send("您已连接"); sse.send("您已连接");

View File

@ -1,6 +1,8 @@
package com.nflg.mobilebroken.cfs.controller; package com.nflg.mobilebroken.cfs.controller;
import com.nflg.mobilebroken.common.pojo.ApiResult; import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.dto.NotifyDTO;
import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import com.nflg.mobilebroken.starter.service.impl.APPSSEManagerService; import com.nflg.mobilebroken.starter.service.impl.APPSSEManagerService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@ -21,7 +23,10 @@ public class TestController extends ControllerBase {
@GetMapping("sse/send") @GetMapping("sse/send")
public ApiResult<Void> sendSse(@RequestParam String userId, @RequestParam String message) throws IOException { public ApiResult<Void> sendSse(@RequestParam String userId, @RequestParam String message) throws IOException {
sseManagerService.send(userId,"测试消息",message); SSEMessageDTO messageDTO = new SSEMessageDTO()
.setType(2)
.setData(new NotifyDTO().setSubject("消息测试").setContent("消息内容"));
sseManagerService.send(Integer.valueOf(userId), messageDTO);
return ApiResult.success(); return ApiResult.success();
} }
} }

View File

@ -5,29 +5,38 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.mobilebroken.common.constant.TicketState; import com.nflg.mobilebroken.common.constant.TicketState;
import com.nflg.mobilebroken.common.pojo.ApiResult; import com.nflg.mobilebroken.common.pojo.ApiResult;
import com.nflg.mobilebroken.common.pojo.PageData; import com.nflg.mobilebroken.common.pojo.PageData;
import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import com.nflg.mobilebroken.common.pojo.dto.TicketChatDTO;
import com.nflg.mobilebroken.common.pojo.request.*; import com.nflg.mobilebroken.common.pojo.request.*;
import com.nflg.mobilebroken.common.pojo.vo.*; import com.nflg.mobilebroken.common.pojo.vo.*;
import com.nflg.mobilebroken.common.util.AppUserUtil; import com.nflg.mobilebroken.common.util.AppUserUtil;
import com.nflg.mobilebroken.common.util.MultilingualUtil; import com.nflg.mobilebroken.common.util.MultilingualUtil;
import com.nflg.mobilebroken.common.util.PageUtil; import com.nflg.mobilebroken.common.util.PageUtil;
import com.nflg.mobilebroken.common.util.VUtils;
import com.nflg.mobilebroken.repository.entity.*; import com.nflg.mobilebroken.repository.entity.*;
import com.nflg.mobilebroken.repository.service.*; import com.nflg.mobilebroken.repository.service.*;
import com.nflg.mobilebroken.starter.service.impl.APPSSEManagerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.time.Instant; import java.time.Instant;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
* 工单相关接口 * 工单相关接口
* @author 曹鹏飞 * @author 曹鹏飞
**/ **/
@Slf4j
@RestController @RestController
@RequestMapping("/ticket") @RequestMapping("/ticket")
//@SaUserCheckLogin //@SaUserCheckLogin
@ -42,8 +51,6 @@ public class TiketController extends ControllerBase {
@Resource @Resource
private ITicketFollowService ticketFollowService; private ITicketFollowService ticketFollowService;
// @Resource
// private ITicketChatService ticketChatService;
@Resource @Resource
private TicketChatService ticketChatService; private TicketChatService ticketChatService;
@ -68,6 +75,9 @@ public class TiketController extends ControllerBase {
@Resource @Resource
private ITBaseCustomerService customerService; private ITBaseCustomerService customerService;
@Resource
private APPSSEManagerService sseManagerService;
/** /**
* 搜索设备 * 搜索设备
* *
@ -108,9 +118,9 @@ public class TiketController extends ControllerBase {
@PostMapping("/addTiket") @PostMapping("/addTiket")
public ApiResult<Void> addTiket(@Valid @RequestBody TicketAddRequest request) { public ApiResult<Void> addTiket(@Valid @RequestBody TicketAddRequest request) {
Integer ticketId = ticketService.add(request, AppUserUtil.getUserId()); Integer ticketId = ticketService.add(request, AppUserUtil.getUserId());
ticketChatService.add(new TicketChat() ticketChatService.add(new TicketChatDTO()
.setTicketId(ticketId) .setTicketId(ticketId)
.setMessages(Collections.singletonList(new ChatMessageVO() .setMessages(Collections.singletonList(new ChatMessageDTO()
.setFrom("system") .setFrom("system")
.setSenderId(0) .setSenderId(0)
.setSenderName("服务助手") .setSenderName("服务助手")
@ -159,15 +169,21 @@ public class TiketController extends ControllerBase {
AppUser user = appUserService.getById(ticket.getUserId()); AppUser user = appUserService.getById(ticket.getUserId());
AppArea appArea = appAreaService.getById(user.getAreaId()); AppArea appArea = appAreaService.getById(user.getAreaId());
TBaseCustomer company = customerService.getById(Integer.valueOf(user.getCompanyId())); TBaseCustomer company = customerService.getById(Integer.valueOf(user.getCompanyId()));
DeviceInfoVO device = deviceService.getByDeviceNo(ticket.getDeviceNo());
TicketInfoVO vo = new TicketInfoVO() TicketInfoVO vo = new TicketInfoVO()
.setId(ticket.getId()) .setId(ticket.getId())
.setTitle(ticket.getTitle()) .setTitle(ticket.getTitle())
.setDeviceNo(ticket.getDeviceNo())
.setModelNo(device.getModelNo())
.setComponent(ticket.getComponent())
.setUseTime(ticket.getUseTime())
.setDescription(ticket.getDescription()) .setDescription(ticket.getDescription())
.setState(ticket.getState()) .setState(ticket.getState())
.setAttachments(StrUtil.isNotBlank(ticket.getAttachments()) ? StrUtil.split(",", ticket.getAttachments()) : Collections.emptyList()) .setAttachments(StrUtil.isNotBlank(ticket.getAttachments()) ? StrUtil.split(",", ticket.getAttachments()) : Collections.emptyList())
.setCreateUserId(ticket.getUserId()) .setCreateUserId(ticket.getUserId())
.setCreateUserName(user.getName()) .setCreateUserName(user.getName())
.setCreateUserAvatar(user.getAvatar()) .setCreateUserAvatar(user.getAvatar())
.setCreateTime(ticket.getCreateTime())
.setAreaName(appArea.getName()) .setAreaName(appArea.getName())
.setCompanyName(company.getAgencyCompanyName()); .setCompanyName(company.getAgencyCompanyName());
return ApiResult.success(vo); return ApiResult.success(vo);
@ -179,7 +195,7 @@ public class TiketController extends ControllerBase {
* @return 聊天记录 * @return 聊天记录
**/ **/
@GetMapping("getChatMessages") @GetMapping("getChatMessages")
public ApiResult<List<ChatMessageVO>> getChatMessages(@Valid @RequestParam @NotNull Integer ticketId) { public ApiResult<List<ChatMessageDTO>> getChatMessages(@Valid @RequestParam @NotNull Integer ticketId) {
return ApiResult.success(ticketChatService.getMessages(ticketId)); return ApiResult.success(ticketChatService.getMessages(ticketId));
} }
@ -189,10 +205,17 @@ public class TiketController extends ControllerBase {
**/ **/
@PostMapping("addChatMessage") @PostMapping("addChatMessage")
public ApiResult<Void> addChatMessage(@Valid @RequestBody AddChatMessageRequest request){ public ApiResult<Void> addChatMessage(@Valid @RequestBody AddChatMessageRequest request){
ChatMessageVO message = new ChatMessageVO() Ticket ticket = ticketService.getById(request.getTicketId());
VUtils.trueThrowBusinessError(Objects.isNull(ticket)).throwMessage("工单不存在");
VUtils.trueThrowBusinessError(Objects.equals(ticket.getState(), TicketState.Revoked.getState())
|| Objects.equals(ticket.getState(), TicketState.Closed.getState()))
.throwMessage("当前工单状态不允许发送消息");
AppUser user = appUserService.getById(AppUserUtil.getUserId());
ChatMessageDTO message = new ChatMessageDTO()
.setFrom("app") .setFrom("app")
.setSenderId(AppUserUtil.getUserId()) .setSenderId(user.getId())
.setSenderName(AppUserUtil.getUserName()) .setSenderName(user.getName())
.setSenderAvatar(user.getAvatar())
.setContent(request.getContent()) .setContent(request.getContent())
.setCreateTime(Instant.now()) .setCreateTime(Instant.now())
.setAttachments(request.getAttachments()); .setAttachments(request.getAttachments());
@ -201,6 +224,20 @@ public class TiketController extends ControllerBase {
// chat.getMessages().add(message); // chat.getMessages().add(message);
// ticketChatService.save(chat); // ticketChatService.save(chat);
ticketChatService.addMessage(request.getTicketId(), message); ticketChatService.addMessage(request.getTicketId(), message);
//推送消息
String handle = ticket.getHandle();
if (StrUtil.isNotBlank(handle)) {
SSEMessageDTO messageDTO = new SSEMessageDTO()
.setType(1)
.setData(message);
StrUtil.split(handle, ",").forEach(userId -> {
try {
sseManagerService.send(Integer.valueOf(userId), messageDTO);
} catch (IOException e) {
log.error("发送SSE消息出错", e);
}
});
}
return ApiResult.success(); return ApiResult.success();
} }

View File

@ -51,6 +51,10 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId> <artifactId>spring-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,14 +1,18 @@
package com.nflg.mobilebroken.common.pojo.vo; package com.nflg.mobilebroken.common.pojo.dto;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
public class ChatMessageVO { public class ChatMessageDTO {
@Id
private String id;
//来源 //来源
private String from; private String from;
@ -19,6 +23,9 @@ public class ChatMessageVO {
// 发送者名称 // 发送者名称
private String senderName; private String senderName;
// 发送者头像
private String senderAvatar;
// 消息内容 // 消息内容
private String content; private String content;
@ -29,5 +36,5 @@ public class ChatMessageVO {
private Instant createTime; private Instant createTime;
// 引用的消息 // 引用的消息
private ChatMessageVO quote; private ChatMessageDTO quote;
} }

View File

@ -0,0 +1,13 @@
package com.nflg.mobilebroken.common.pojo.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class NotifyDTO {
private String subject;
private String content;
}

View File

@ -0,0 +1,15 @@
package com.nflg.mobilebroken.common.pojo.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class SSEMessageDTO {
//类型1工单会话消息2消息提醒
private int type;
//消息内容
private Object data;
}

View File

@ -1,6 +1,5 @@
package com.nflg.mobilebroken.repository.entity; package com.nflg.mobilebroken.common.pojo.dto;
import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
@ -12,12 +11,12 @@ import java.util.List;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
@Document(collection = "TicketChat") @Document(collection = "TicketChat")
public class TicketChat { public class TicketChatDTO {
@Id @Id
private String id; private String id;
private Integer ticketId; private Integer ticketId;
private List<ChatMessageVO> messages = new ArrayList<>(); private List<ChatMessageDTO> messages = new ArrayList<>();
} }

View File

@ -1,6 +1,6 @@
package com.nflg.mobilebroken.common.pojo.request; package com.nflg.mobilebroken.common.pojo.request;
import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO; import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
@ -22,5 +22,5 @@ public class AddChatMessageRequest {
private List<String> attachments; private List<String> attachments;
// 引用的消息 // 引用的消息
private ChatMessageVO quote; private ChatMessageDTO quote;
} }

View File

@ -9,6 +9,8 @@ import java.time.LocalDateTime;
@Accessors(chain = true) @Accessors(chain = true)
public class AppMessageVO { public class AppMessageVO {
private int id;
//工单id //工单id
private int ticketId; private int ticketId;

View File

@ -3,6 +3,7 @@ package com.nflg.mobilebroken.common.pojo.vo;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@Data @Data
@ -27,6 +28,9 @@ public class TicketInfoVO {
//创建人头像 //创建人头像
private String createUserAvatar; private String createUserAvatar;
//提交时间
private LocalDateTime createTime;
//工单状态 //工单状态
private Byte state; private Byte state;
@ -36,6 +40,18 @@ public class TicketInfoVO {
//所属区域 //所属区域
private String areaName; private String areaName;
//设备编号
private String deviceNo;
//设备机型
private String modelNo;
//问题部位
private String component;
//使用时长单位: 小时
private Integer useTime;
//附件 //附件
private List<String> attachments; private List<String> attachments;
} }

View File

@ -3,13 +3,14 @@ package com.nflg.mobilebroken.repository.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
/** /**
* <p> * <p>
* 用户端-用户 * 用户端-用户
@ -85,9 +86,9 @@ public class AppUser implements Serializable {
private Boolean isPrimary; private Boolean isPrimary;
/** /**
* 职位编码 * 职位id
*/ */
private String titleCode; private Integer titleId;
/** /**
* 所属销售代表 * 所属销售代表

View File

@ -75,9 +75,9 @@ public class AppUserApplyfor implements Serializable {
private Byte type; private Byte type;
/** /**
* 职位编码 * 职位id
*/ */
private String titleCode; private Integer titleId;
/** /**
* 处理状态0待审核1审核通过2审核不通过 * 处理状态0待审核1审核通过2审核不通过

View File

@ -15,7 +15,7 @@ import com.nflg.mobilebroken.repository.entity.AppMessage;
*/ */
public interface AppMessageMapper extends BaseMapper<AppMessage> { public interface AppMessageMapper extends BaseMapper<AppMessage> {
void getNotReadMessage(Integer userId, Integer num, IPage<AppMessageVO> page); IPage<AppMessageVO> getNotReadMessage(Integer userId, Integer num, IPage<AppMessageVO> page);
void search(Integer userId, String title, IPage<AppMessageVO> page); IPage<AppMessageVO> search(Integer userId, String title, IPage<AppMessageVO> page);
} }

View File

@ -2,6 +2,7 @@ package com.nflg.mobilebroken.repository.service;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.nflg.mobilebroken.common.pojo.request.AppMessageSearchRequest;
import com.nflg.mobilebroken.common.pojo.vo.AppMessageVO; import com.nflg.mobilebroken.common.pojo.vo.AppMessageVO;
import com.nflg.mobilebroken.repository.entity.AppMessage; import com.nflg.mobilebroken.repository.entity.AppMessage;
@ -17,9 +18,9 @@ import java.util.List;
*/ */
public interface IAppMessageService extends IService<AppMessage> { public interface IAppMessageService extends IService<AppMessage> {
void getNotReadMessage(Integer userId, Integer num, IPage<AppMessageVO> page); IPage<AppMessageVO> getNotReadMessage(Integer userId, Integer num);
void search(Integer userId, String title, IPage<AppMessageVO> page); IPage<AppMessageVO> search(Integer userId, AppMessageSearchRequest request);
void setReaded(List<Integer> ids); void setReaded(List<Integer> ids);

View File

@ -1,17 +0,0 @@
package com.nflg.mobilebroken.repository.service;
import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO;
import com.nflg.mobilebroken.repository.entity.TicketChat;
import org.apache.ibatis.annotations.Update;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
public interface ITicketChatService extends MongoRepository<TicketChat, String> {
@Query("{ 'ticketId': ?0 }")
TicketChat findByTicketId(Integer ticketId);
@Query("{ 'ticketId': ?0 }")
@Update("{ '$push': { 'messages': ?1 } }")
void pushMessage(Integer ticketId, ChatMessageVO message);
}

View File

@ -1,7 +1,7 @@
package com.nflg.mobilebroken.repository.service; package com.nflg.mobilebroken.repository.service;
import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO; import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
import com.nflg.mobilebroken.repository.entity.TicketChat; import com.nflg.mobilebroken.common.pojo.dto.TicketChatDTO;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Query;
@ -19,26 +19,26 @@ public class TicketChatService {
@Resource @Resource
private MongoTemplate mongoTemplate; private MongoTemplate mongoTemplate;
public void add(TicketChat ticketChat) { public void add(TicketChatDTO ticketChatDTO) {
mongoTemplate.save(ticketChat); mongoTemplate.save(ticketChatDTO);
} }
public List<ChatMessageVO> getMessages(Integer ticketId) { public List<ChatMessageDTO> getMessages(Integer ticketId) {
Query query = new Query(Criteria.where("ticketId").is(ticketId)); Query query = new Query(Criteria.where("ticketId").is(ticketId));
TicketChat ticketChat = mongoTemplate.findOne(query, TicketChat.class); TicketChatDTO ticketChatDTO = mongoTemplate.findOne(query, TicketChatDTO.class);
if (Objects.isNull(ticketChat)) { if (Objects.isNull(ticketChatDTO)) {
return Collections.emptyList(); return Collections.emptyList();
} else { } else {
return ticketChat.getMessages(); return ticketChatDTO.getMessages();
} }
} }
public void addMessage(Integer ticketId, ChatMessageVO newMessage) { public void addMessage(Integer ticketId, ChatMessageDTO newMessage) {
// 创建查询条件查找 ticketId = ticketId TicketChat // 创建查询条件查找 ticketId = ticketId TicketChat
Query query = new Query(Criteria.where("ticketId").is(ticketId)); Query query = new Query(Criteria.where("ticketId").is(ticketId));
// 创建更新操作 messages 列表中添加新消息 // 创建更新操作 messages 列表中添加新消息
Update update = new Update().push("messages", newMessage); Update update = new Update().push("messages", newMessage);
// 执行更新操作 // 执行更新操作
mongoTemplate.findAndModify(query, update, TicketChat.class); mongoTemplate.findAndModify(query, update, TicketChatDTO.class);
} }
} }

View File

@ -1,7 +1,9 @@
package com.nflg.mobilebroken.repository.service.impl; package com.nflg.mobilebroken.repository.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nflg.mobilebroken.common.pojo.request.AppMessageSearchRequest;
import com.nflg.mobilebroken.common.pojo.vo.AppMessageVO; import com.nflg.mobilebroken.common.pojo.vo.AppMessageVO;
import com.nflg.mobilebroken.repository.entity.AppMessage; import com.nflg.mobilebroken.repository.entity.AppMessage;
import com.nflg.mobilebroken.repository.mapper.AppMessageMapper; import com.nflg.mobilebroken.repository.mapper.AppMessageMapper;
@ -22,13 +24,13 @@ import java.util.List;
public class AppMessageServiceImpl extends ServiceImpl<AppMessageMapper, AppMessage> implements IAppMessageService { public class AppMessageServiceImpl extends ServiceImpl<AppMessageMapper, AppMessage> implements IAppMessageService {
@Override @Override
public void getNotReadMessage(Integer userId, Integer num, IPage<AppMessageVO> page) { public IPage<AppMessageVO> getNotReadMessage(Integer userId, Integer num) {
baseMapper.getNotReadMessage(userId, num, page); return baseMapper.getNotReadMessage(userId, num, new Page<>(1, num));
} }
@Override @Override
public void search(Integer userId, String title, IPage<AppMessageVO> page) { public IPage<AppMessageVO> search(Integer userId, AppMessageSearchRequest request) {
baseMapper.search(userId,title,page); return baseMapper.search(userId, request.getTitle(), new Page<>(request.getPage(), request.getPageSize()));
} }
@Override @Override

View File

@ -63,6 +63,7 @@ public class AppUserApplyforServiceImpl extends ServiceImpl<AppUserApplyforMappe
.setState(AppUserApplyForState.PENDINGAPPROVAL.getState().byteValue()) .setState(AppUserApplyForState.PENDINGAPPROVAL.getState().byteValue())
.setAreaId(request.getAreaId()) .setAreaId(request.getAreaId())
.setCompanyId(request.getCompanyId()) .setCompanyId(request.getCompanyId())
.setTitleId(request.getTitleId())
.setType(AppUserApplyforType.ADD.getState().byteValue()) .setType(AppUserApplyforType.ADD.getState().byteValue())
.setCreateBy(AdminUserUtil.getUserId()) .setCreateBy(AdminUserUtil.getUserId())
.setCreateTime(LocalDateTime.now()); .setCreateTime(LocalDateTime.now());
@ -99,10 +100,7 @@ public class AppUserApplyforServiceImpl extends ServiceImpl<AppUserApplyforMappe
VUtils.trueThrowBusinessError(Objects.isNull(applyfor)).throwMessage("审批信息不存在"); VUtils.trueThrowBusinessError(Objects.isNull(applyfor)).throwMessage("审批信息不存在");
AppUserApplyforVO vo = new AppUserApplyforVO(); AppUserApplyforVO vo = new AppUserApplyforVO();
AppArea area = appAreaService.getById(applyfor.getAreaId()); AppArea area = appAreaService.getById(applyfor.getAreaId());
TBasePosition position = positionService.lambdaQuery() TBasePosition position = positionService.getById(applyfor.getTitleId());
.eq(TBasePosition::getDataValidState, 1)
.eq(TBasePosition::getPositionCode, applyfor.getTitleCode())
.one();
String titleName = Objects.isNull(position) ? "" : position.getPositionName(); String titleName = Objects.isNull(position) ? "" : position.getPositionName();
vo.setApplyfor(new AppUserApplyforInfoVO() vo.setApplyfor(new AppUserApplyforInfoVO()
.setAreaName(area.getName()) .setAreaName(area.getName())
@ -141,7 +139,7 @@ public class AppUserApplyforServiceImpl extends ServiceImpl<AppUserApplyforMappe
.setPassword(PASSWORDENCODER.encode(request.getPassword())) .setPassword(PASSWORDENCODER.encode(request.getPassword()))
.setAreaId(applyfor.getAreaId()) .setAreaId(applyfor.getAreaId())
.setCompanyId(String.valueOf(applyfor.getCompanyId())) .setCompanyId(String.valueOf(applyfor.getCompanyId()))
.setTitleCode(applyfor.getTitleCode()) .setTitleId(applyfor.getTitleId())
.setEnable(true) .setEnable(true)
.setCreateBy(applyfor.getCreateBy()) .setCreateBy(applyfor.getCreateBy())
.setCreateTime(LocalDateTime.now()) .setCreateTime(LocalDateTime.now())

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!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.AppMessageMapper"> <mapper namespace="com.nflg.mobilebroken.repository.mapper.AppMessageMapper">
<select id="getNotReadMessage"> <select id="getNotReadMessage" resultType="com.nflg.mobilebroken.common.pojo.vo.AppMessageVO">
SELECT t.id AS 'ticketId',t.`no` AS 'ticketNo',t.title AS 'ticketTitle',m.content,m.create_time AS 'createTime',u.`name` AS 'ticketCreateBy',t.create_time AS 'ticketCreateTime',t.handle AS 'ticketHandleBy',m.is_read AS 'isRead' SELECT t.id AS 'ticketId',t.`no` AS 'ticketNo',t.title AS 'ticketTitle',m.content,m.create_time AS 'createTime',u.`name` AS 'ticketCreateBy',t.create_time AS 'ticketCreateTime',t.handle AS 'ticketHandleBy',m.is_read AS 'isRead'
FROM app_message m FROM app_message m
INNER JOIN ticket t ON m.ticket_id=t.id INNER JOIN ticket t ON m.ticket_id=t.id
@ -10,7 +10,7 @@
WHERE m.is_read=0 AND m.user_id=#{userId} WHERE m.is_read=0 AND m.user_id=#{userId}
ORDER BY m.id ORDER BY m.id
</select> </select>
<select id="search"> <select id="search" resultType="com.nflg.mobilebroken.common.pojo.vo.AppMessageVO">
SELECT t.id AS 'ticketId',t.`no` AS 'ticketNo',t.title AS 'ticketTitle',m.content,m.create_time AS 'createTime',u.`name` AS 'ticketCreateBy',t.create_time AS 'ticketCreateTime',t.handle AS 'ticketHandleBy',m.is_read AS 'isRead' SELECT t.id AS 'ticketId',t.`no` AS 'ticketNo',t.title AS 'ticketTitle',m.content,m.create_time AS 'createTime',u.`name` AS 'ticketCreateBy',t.create_time AS 'ticketCreateTime',t.handle AS 'ticketHandleBy',m.is_read AS 'isRead'
FROM app_message m FROM app_message m
INNER JOIN ticket t ON m.ticket_id=t.id INNER JOIN ticket t ON m.ticket_id=t.id

View File

@ -19,7 +19,25 @@ public class SSEManagerBase {
VUtils.trueThrow(IS_SHUTDOWN).throwMessage(STATE.ServiceConnectRefused,"SSE服务已关闭"); VUtils.trueThrow(IS_SHUTDOWN).throwMessage(STATE.ServiceConnectRefused,"SSE服务已关闭");
} }
protected SseEmitter connect(String userId, Map<String, SseEmitter> emitters){ protected static void shutdown(Map<Integer, SseEmitter> emitters) {
IS_SHUTDOWN=true;
log.warn("准备关闭SSE服务");
emitters.forEach((k,v)->{
try {
v.send("因SSE服务关闭,连接即将断开");
}catch (Exception ex){
log.error("SSE发送消息失败:"+k,ex);
}
v.complete();
});
log.warn("SSE服务已关闭");
}
protected static void close(SseEmitter emitter){
emitter.complete();
}
protected SseEmitter connect(Integer userId, Map<Integer, SseEmitter> emitters) {
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE); SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
emitters.put(userId, emitter); emitters.put(userId, emitter);
emitter.onError((ex) -> { emitter.onError((ex) -> {
@ -41,27 +59,9 @@ public class SSEManagerBase {
return emitter; return emitter;
} }
protected static void close(SseEmitter emitter){ protected void send(Object message, SseEmitter emitter) throws IOException {
emitter.complete();
}
protected static void shutdown(Map<String, SseEmitter> emitters){
IS_SHUTDOWN=true;
log.warn("准备关闭SSE服务");
emitters.forEach((k,v)->{
try {
v.send("因SSE服务关闭,连接即将断开");
}catch (Exception ex){
log.error("SSE发送消息失败:"+k,ex);
}
v.complete();
});
log.warn("SSE服务已关闭");
}
public void send(String subject, String message,SseEmitter emitter) throws IOException {
VUtils.trueThrowBusinessError(Objects.isNull(emitter)).throwMessage("没有找到sse"); VUtils.trueThrowBusinessError(Objects.isNull(emitter)).throwMessage("没有找到sse");
log.error("没有找到sse: "); log.error("没有找到sse: ");
emitter.send(subject+":"+message); emitter.send(message);
} }
} }

View File

@ -1,16 +1,17 @@
package com.nflg.mobilebroken.starter.service; package com.nflg.mobilebroken.starter.service;
import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException; import java.io.IOException;
public interface SSEManagerService { public interface SSEManagerService {
SseEmitter connect(String userId); SseEmitter connect(Integer userId);
void send(String userId,String subject, String message) throws IOException; void send(Integer userId, SSEMessageDTO message) throws IOException;
void close(String userId); void close(Integer userId);
void shutdown(); void shutdown();
} }

View File

@ -1,6 +1,7 @@
package com.nflg.mobilebroken.starter.service.impl; package com.nflg.mobilebroken.starter.service.impl;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import com.nflg.mobilebroken.starter.service.SSEManagerBase; import com.nflg.mobilebroken.starter.service.SSEManagerBase;
import com.nflg.mobilebroken.starter.service.SSEManagerService; import com.nflg.mobilebroken.starter.service.SSEManagerService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -16,28 +17,28 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j @Slf4j
public class APPSSEManagerService extends SSEManagerBase implements SSEManagerService { public class APPSSEManagerService extends SSEManagerBase implements SSEManagerService {
public static final Map<String, SseEmitter> EMITTERS = new ConcurrentHashMap<>(); public static final Map<Integer, SseEmitter> EMITTERS = new ConcurrentHashMap<>();
@Override @Override
public SseEmitter connect(String userId) { public SseEmitter connect(Integer userId) {
check(); check();
log.info("APP端SSE已连接:"+userId); log.info("APP端SSE已连接:"+userId);
return connect(userId,EMITTERS); return connect(userId,EMITTERS);
} }
@Override @Override
public void send(String userId, String subject, String message) throws IOException { public void send(Integer userId, SSEMessageDTO message) throws IOException {
log.info(StrUtil.format("APP端SSE发送消息,用户id: {},标题: {},内容: {}", userId, subject, message)); log.info(StrUtil.format("APP端SSE发送消息,用户id: {},内容: {}", userId, message));
SseEmitter emitter = EMITTERS.get(userId); SseEmitter emitter = EMITTERS.get(userId);
if (Objects.isNull(emitter)) { if (Objects.isNull(emitter)) {
log.error("用户未连接SSE: " + userId); log.error("用户未连接SSE: " + userId);
} else { } else {
send(subject, message, emitter); send(message, emitter);
} }
} }
@Override @Override
public void close(String userId) { public void close(Integer userId) {
log.info("APP端SSE连接主动关闭:"+userId); log.info("APP端SSE连接主动关闭:"+userId);
close(EMITTERS.remove(userId)); close(EMITTERS.remove(userId));
} }

View File

@ -1,6 +1,7 @@
package com.nflg.mobilebroken.starter.service.impl; package com.nflg.mobilebroken.starter.service.impl;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.nflg.mobilebroken.common.pojo.dto.SSEMessageDTO;
import com.nflg.mobilebroken.starter.service.SSEManagerBase; import com.nflg.mobilebroken.starter.service.SSEManagerBase;
import com.nflg.mobilebroken.starter.service.SSEManagerService; import com.nflg.mobilebroken.starter.service.SSEManagerService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -16,28 +17,28 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j @Slf4j
public class AdminSSEManagerService extends SSEManagerBase implements SSEManagerService { public class AdminSSEManagerService extends SSEManagerBase implements SSEManagerService {
protected static final Map<String, SseEmitter> EMITTERS = new ConcurrentHashMap<>(); protected static final Map<Integer, SseEmitter> EMITTERS = new ConcurrentHashMap<>();
@Override @Override
public SseEmitter connect(String userId) { public SseEmitter connect(Integer userId) {
check(); check();
log.info("管理端SSE已连接:"+userId); log.info("管理端SSE已连接:"+userId);
return connect(userId,EMITTERS); return connect(userId,EMITTERS);
} }
@Override @Override
public void send(String userId, String subject, String message) throws IOException { public void send(Integer userId, SSEMessageDTO message) throws IOException {
log.info(StrUtil.format("管理端端SSE发送消息,用户id: {},标题: {},内容: {}", userId, subject, message)); log.info(StrUtil.format("管理端端SSE发送消息,用户id: {},内容: {}", userId, message));
SseEmitter emitter = EMITTERS.get(userId); SseEmitter emitter = EMITTERS.get(userId);
if (Objects.isNull(emitter)) { if (Objects.isNull(emitter)) {
log.error("用户未连接SSE: " + userId); log.error("用户未连接SSE: " + userId);
} else { } else {
send(subject, message, emitter); send(message, emitter);
} }
} }
@Override @Override
public void close(String userId) { public void close(Integer userId) {
close(EMITTERS.remove(userId)); close(EMITTERS.remove(userId));
log.info("管理端SSE连接主动关闭:"+userId); log.info("管理端SSE连接主动关闭:"+userId);
} }