feat(chat): 添加消息附件验证和撤回功能

- 在 AddChatMessageRequest 中添加 @Valid 注解验证附件、图片和被艾特用户列表
- 为 FileUploadVO 添加文件id、名称和路径的非空验证
- 为 RemindUserRequest 添加用户id和名称的非空验证
- 实现消息撤回时自动删除相关附件记录功能
- 重构派工单搜索接口,添加用户ID参数和排序逻辑
- 更新工单重新开启权限判断逻辑,限制仅用户本人可操作
This commit is contained in:
曹鹏飞 2026-01-08 13:44:48 +08:00
parent 49cec25f53
commit 76e8235d75
10 changed files with 50 additions and 13 deletions

View File

@ -328,15 +328,16 @@ public class TicketController extends ControllerBase {
if (Objects.nonNull(part)) { if (Objects.nonNull(part)) {
vo.setComponent(part.getPartName()); vo.setComponent(part.getPartName());
} }
vo.setCanReopen(Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState())
&& !ticketSolutionAuditService.lambdaQuery().eq(TicketSolutionAudit::getTicketId, ticket.getId()).exists());
} else { } else {
GongfuDevicePart part = part1Service.getByIdAndLanguage(ticket.getComponentId(), MultilingualUtil.getLanguage()); GongfuDevicePart part = part1Service.getByIdAndLanguage(ticket.getComponentId(), MultilingualUtil.getLanguage());
if (Objects.nonNull(part)) { if (Objects.nonNull(part)) {
vo.setComponent(part.getPartName()); vo.setComponent(part.getPartName());
} }
vo.setCanReopen(false);
} }
vo.setCanReopen((StrUtil.equals(ticket.getUserPlatform(), AppUserUtil.getFrom()) && Objects.equals(ticket.getUserId(), AppUserUtil.getUserId()))
&& Objects.equals(ticket.getState(), TicketState.ProcessingCompleted.getState())
&& !ticketEvaluateService.lambdaQuery().eq(TicketEvaluate::getTicketId, ticket.getId()).exists()
);
return ApiResult.success(vo); return ApiResult.success(vo);
} }

View File

@ -3,6 +3,7 @@ package com.nflg.mobilebroken.common.pojo.request;
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO; import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import java.util.List; import java.util.List;
@ -20,14 +21,17 @@ public class AddChatMessageRequest {
private String audioUrl; private String audioUrl;
//附件列表 //附件列表
@Valid
private List<FileUploadVO> attachments; private List<FileUploadVO> attachments;
//图片列表 //图片列表
@Valid
private List<FileUploadVO> images; private List<FileUploadVO> images;
// 引用的消息 // 引用的消息
private String quoteId; private String quoteId;
//被艾特的用户列表 //被艾特的用户列表
@Valid
private List<RemindUserRequest> remindUsers; private List<RemindUserRequest> remindUsers;
} }

View File

@ -2,16 +2,21 @@ package com.nflg.mobilebroken.common.pojo.request;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data @Data
public class RemindUserRequest { public class RemindUserRequest {
/** /**
* 用户id * 用户id
*/ */
@NotNull
private Integer id; private Integer id;
/** /**
* 用户名 * 用户名
*/ */
@NotBlank
private String name; private String name;
} }

View File

@ -5,6 +5,9 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
@AllArgsConstructor @AllArgsConstructor
@ -14,16 +17,19 @@ public class FileUploadVO {
/** /**
* 文件id * 文件id
*/ */
@NotNull(message = "文件id不能为空")
private Integer id; private Integer id;
/** /**
* 显示名称 * 显示名称
*/ */
@NotBlank(message = "文件名称不能为空")
private String fileName; private String fileName;
/** /**
* url路径 * url路径
*/ */
@NotBlank(message = "文件路径不能为空")
private String url; private String url;
/** /**

View File

@ -210,7 +210,7 @@ public class DispatchController extends ControllerBase {
*/ */
@PostMapping("/search") @PostMapping("/search")
public ApiResult<PageData<DispatchVO>> search(@Valid @RequestBody DispatchSearchRequest request) { public ApiResult<PageData<DispatchVO>> search(@Valid @RequestBody DispatchSearchRequest request) {
return ApiResult.success(dispatchService.search(request)); return ApiResult.success(dispatchService.search(request, AdminUserUtil.getUserId()));
} }
/** /**

View File

@ -19,7 +19,7 @@ import java.util.List;
*/ */
public interface GongfuDispatchMapper extends BaseMapper<GongfuDispatch> { public interface GongfuDispatchMapper extends BaseMapper<GongfuDispatch> {
IPage<DispatchVO> search(DispatchSearchRequest request, Page<?> objectPage); IPage<DispatchVO> search(DispatchSearchRequest request, Integer userId, Page<?> objectPage);
DispatchVO getInfo(Long id); DispatchVO getInfo(Long id);

View File

@ -18,7 +18,7 @@ import java.util.List;
*/ */
public interface IGongfuDispatchService extends IService<GongfuDispatch> { public interface IGongfuDispatchService extends IService<GongfuDispatch> {
IPage<DispatchVO> search(DispatchSearchRequest request); IPage<DispatchVO> search(DispatchSearchRequest request, Integer userId);
DispatchVO getInfo(Long id); DispatchVO getInfo(Long id);

View File

@ -8,8 +8,10 @@ import com.nflg.mobilebroken.common.pojo.dto.ChatMessageDTO;
import com.nflg.mobilebroken.common.pojo.dto.TicketChatDTO; import com.nflg.mobilebroken.common.pojo.dto.TicketChatDTO;
import com.nflg.mobilebroken.common.pojo.dto.TicketSet; import com.nflg.mobilebroken.common.pojo.dto.TicketSet;
import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO; import com.nflg.mobilebroken.common.pojo.vo.ChatMessageVO;
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
import com.nflg.mobilebroken.common.util.MultilingualUtil; import com.nflg.mobilebroken.common.util.MultilingualUtil;
import com.nflg.mobilebroken.common.util.VUtils; import com.nflg.mobilebroken.common.util.VUtils;
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
import com.nflg.mobilebroken.repository.entity.ParamConfig; import com.nflg.mobilebroken.repository.entity.ParamConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
@ -23,6 +25,7 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -38,6 +41,9 @@ public class TicketChatService {
@Resource @Resource
private IParamConfigService paramConfigService; private IParamConfigService paramConfigService;
@Resource
private IFileUploadRecordService fileUploadRecordService;
public void add(TicketChatDTO ticketChatDTO) { public void add(TicketChatDTO ticketChatDTO) {
mongoTemplate.save(ticketChatDTO); mongoTemplate.save(ticketChatDTO);
} }
@ -147,6 +153,19 @@ public class TicketChatService {
log.info("消息撤回 找到消息"); log.info("消息撤回 找到消息");
message.setContent("消息已撤回"); message.setContent("消息已撤回");
flag=true; flag=true;
//删除消息附件
List<Integer> fileIds = new ArrayList<>();
if (CollectionUtil.isNotEmpty(message.getAttachments())) {
fileIds.addAll(message.getAttachments().stream().map(FileUploadVO::getId).collect(Collectors.toList()));
}
if (CollectionUtil.isNotEmpty(message.getImages())) {
fileIds.addAll(message.getImages().stream().map(FileUploadVO::getId).collect(Collectors.toList()));
}
if (CollectionUtil.isNotEmpty(fileIds)) {
fileUploadRecordService.lambdaUpdate()
.in(FileUploadRecord::getId, fileIds)
.remove();
}
} }
} }
if (flag && Objects.nonNull(message.getQuote()) && message.getQuote().getId().equals(messageId)){ if (flag && Objects.nonNull(message.getQuote()) && message.getQuote().getId().equals(messageId)){

View File

@ -18,6 +18,7 @@ import java.util.Objects;
* <p> * <p>
* 派工单 服务实现类 * 派工单 服务实现类
* </p> * </p>
*
* @author 代码生成器生成 * @author 代码生成器生成
* @since 2025 * @since 2025
*/ */
@ -25,8 +26,8 @@ import java.util.Objects;
public class GongfuDispatchServiceImpl extends ServiceImpl<GongfuDispatchMapper, GongfuDispatch> implements IGongfuDispatchService { public class GongfuDispatchServiceImpl extends ServiceImpl<GongfuDispatchMapper, GongfuDispatch> implements IGongfuDispatchService {
@Override @Override
public IPage<DispatchVO> search(DispatchSearchRequest request) { public IPage<DispatchVO> search(DispatchSearchRequest request, Integer userId) {
return baseMapper.search(request, new Page<>(request.getPage(), request.getPageSize())); return baseMapper.search(request, userId, new Page<>(request.getPage(), request.getPageSize()));
} }
@Override @Override

View File

@ -3,7 +3,8 @@
<mapper namespace="com.nflg.mobilebroken.repository.mapper.GongfuDispatchMapper"> <mapper namespace="com.nflg.mobilebroken.repository.mapper.GongfuDispatchMapper">
<select id="search" resultType="com.nflg.mobilebroken.common.pojo.vo.DispatchVO"> <select id="search" resultType="com.nflg.mobilebroken.common.pojo.vo.DispatchVO">
SELECT da.*,dv.customer_name,bc.agency_company_name as agent_name,af.reason as "delayReason",af2.id as "applyforId" SELECT da.*,dv.customer_name,bc.agency_company_name as agent_name,af.reason as "delayReason",af2.id as
"applyforId",if(da.create_by_id =#{userId} or da.handler_user_id = #{userId},1,0) AS usort
FROM gongfu_dispatch da FROM gongfu_dispatch da
LEFT JOIN v_gongfu_device dv ON da.device_no=dv.device_no LEFT JOIN v_gongfu_device dv ON da.device_no=dv.device_no
LEFT JOIN t_base_customer bc ON dv.agent_code=bc.agency_company_code LEFT JOIN t_base_customer bc ON dv.agent_code=bc.agency_company_code
@ -42,7 +43,7 @@
) )
</if> </if>
</where> </where>
ORDER BY da.state,da.id DESC ORDER BY usort DESC,da.state,da.plan_start_date DESC,da.id DESC
</select> </select>
<select id="getInfo" resultType="com.nflg.mobilebroken.common.pojo.vo.DispatchVO"> <select id="getInfo" resultType="com.nflg.mobilebroken.common.pojo.vo.DispatchVO">