From 41bc41cfcde502741034276a99d72e28cd85b632 Mon Sep 17 00:00:00 2001 From: wangys <3401275564@qq.com> Date: Wed, 24 Dec 2025 19:50:38 +0800 Subject: [PATCH] =?UTF-8?q?=E8=81=8A=E5=A4=A9=E5=AE=A4=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=B7=A5=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../postgres/sql/createTableWorkcase.sql | 4 +- .../xyzh/api/workcase/dto/TbWorkcaseDTO.java | 3 + .../controller/WorkcaseController.java | 4 +- .../workcase/service/WorkcaseServiceImpl.java | 43 ++- .../resources/mapper/TbChatRoomMapper.xml | 1 + .../resources/mapper/TbWorkcaseMapper.xml | 7 +- .../workcase/src/types/workcase/workcase.ts | 2 + .../packages/workcase_wechat/api/base.ts | 39 ++- .../packages/workcase_wechat/api/file/file.ts | 74 ++++ .../workcase_wechat/api/file/index.ts | 1 + .../packages/workcase_wechat/api/index.ts | 3 +- .../pages/chatRoom/chatRoom/chatRoom.uvue | 21 ++ .../workcaseDetail/workcaseDetail.scss | 52 ++- .../workcaseDetail/workcaseDetail.uvue | 317 +++++++++++++----- .../workcase_wechat/types/file/file.ts | 40 +++ .../workcase_wechat/types/file/index.ts | 1 + .../packages/workcase_wechat/types/index.ts | 3 +- .../types/workcase/workcase.ts | 12 +- 18 files changed, 519 insertions(+), 108 deletions(-) create mode 100644 urbanLifelineWeb/packages/workcase_wechat/api/file/file.ts create mode 100644 urbanLifelineWeb/packages/workcase_wechat/api/file/index.ts create mode 100644 urbanLifelineWeb/packages/workcase_wechat/types/file/file.ts create mode 100644 urbanLifelineWeb/packages/workcase_wechat/types/file/index.ts diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql index a325f5dc..53ab72e9 100644 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql +++ b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql @@ -227,7 +227,7 @@ DROP TABLE IF EXISTS workcase.tb_workcase CASCADE; CREATE TABLE workcase.tb_workcase( optsn VARCHAR(50) NOT NULL, -- 流水号 workcase_id VARCHAR(50) NOT NULL, -- 工单ID - chat_id VARCHAR(50) NOT NULL, -- 对话ID + room_id VARCHAR(50) NOT NULL, -- 聊天室ID user_id VARCHAR(50) NOT NULL, -- 来客ID username VARCHAR(200) NOT NULL, -- 来客姓名 phone VARCHAR(20) NOT NULL, -- 来客电话 @@ -248,7 +248,7 @@ CREATE TABLE workcase.tb_workcase( delete_time TIMESTAMPTZ DEFAULT NULL, -- 删除时间 deleted BOOLEAN NOT NULL DEFAULT false, -- 是否删除 PRIMARY KEY (workcase_id), - UNIQUE (chat_id), + UNIQUE (room_id), UNIQUE (optsn) ); diff --git a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java index f1ed67de..9ae90763 100644 --- a/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java +++ b/urbanLifelineServ/apis/api-workcase/src/main/java/org/xyzh/api/workcase/dto/TbWorkcaseDTO.java @@ -22,6 +22,9 @@ public class TbWorkcaseDTO extends BaseDTO{ @Schema(description = "工单ID") private String workcaseId; + @Schema(description = "聊天室ID") + private String roomId; + @Schema(description = "来客ID") private String userId; diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java index 37b46241..728d4afd 100644 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java +++ b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/controller/WorkcaseController.java @@ -47,8 +47,10 @@ public class WorkcaseController { @PostMapping public ResultDomain createWorkcase(@RequestBody TbWorkcaseDTO workcase) { ValidationResult vr = ValidationUtils.validate(workcase, Arrays.asList( + ValidationUtils.requiredString("deviceNamePlateImg", "设备名称牌图片"), + ValidationUtils.requiredString("type", "问题类型"), ValidationUtils.requiredString("userId", "用户ID"), - ValidationUtils.requiredString("type", "问题类型") + ValidationUtils.requiredString("username", "用户名称") )); if (!vr.isValid()) { return ResultDomain.failure(vr.getAllErrors()); diff --git a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java index 7c085d29..34858989 100644 --- a/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java +++ b/urbanLifelineServ/workcase/src/main/java/org/xyzh/workcase/service/WorkcaseServiceImpl.java @@ -10,6 +10,7 @@ import org.xyzh.api.workcase.dto.TbWorkcaseDTO; import org.xyzh.api.workcase.dto.TbWorkcaseDeviceDTO; import org.xyzh.api.workcase.dto.TbWorkcaseProcessDTO; import org.xyzh.api.workcase.service.WorkcaseService; +import org.xyzh.common.auth.utils.LoginUtil; import org.xyzh.common.core.domain.ResultDomain; import org.xyzh.common.core.page.PageDomain; import org.xyzh.common.core.page.PageParam; @@ -19,6 +20,8 @@ import org.xyzh.workcase.enums.WorkcaseProcessAction; import org.xyzh.workcase.mapper.TbWorkcaseDeviceMapper; import org.xyzh.workcase.mapper.TbWorkcaseMapper; import org.xyzh.workcase.mapper.TbWorkcaseProcessMapper; +import org.xyzh.api.workcase.dto.TbChatRoomDTO; +import org.xyzh.api.workcase.service.ChatRoomService; import com.alibaba.fastjson2.JSONObject; @@ -35,11 +38,36 @@ public class WorkcaseServiceImpl implements WorkcaseService { @Autowired private TbWorkcaseDeviceMapper workcaseDeviceMapper; + @Autowired + private ChatRoomService chatRoomService; + // ====================== 工单管理 ====================== @Override public ResultDomain createWorkcase(TbWorkcaseDTO workcase) { - logger.info("创建工单: userId={}, type={}", workcase.getUserId(), workcase.getType()); + logger.info("创建工单: userId={}, type={}, roomId={}", workcase.getUserId(), workcase.getType(), workcase.getRoomId()); + + // 如果没有 roomId,先创建聊天室 + boolean needCreateRoom = (workcase.getRoomId() == null || workcase.getRoomId().isEmpty()); + if (needCreateRoom) { + logger.info("未提供 roomId,先创建聊天室"); + TbChatRoomDTO chatRoom = new TbChatRoomDTO(); + chatRoom.setGuestId(workcase.getUserId()); + chatRoom.setGuestName(workcase.getUsername()); + chatRoom.setRoomType("workcase"); + chatRoom.setRoomName("工单客服-" + workcase.getUsername()); + chatRoom.setStatus("active"); + chatRoom.setCreator(workcase.getCreator()); + + ResultDomain roomResult = chatRoomService.createChatRoom(chatRoom); + if (!roomResult.getSuccess() || roomResult.getData() == null) { + logger.error("创建聊天室失败: {}", roomResult.getMessage()); + return ResultDomain.failure("创建聊天室失败: " + roomResult.getMessage()); + } + + workcase.setRoomId(roomResult.getData().getRoomId()); + logger.info("聊天室创建成功: roomId={}", workcase.getRoomId()); + } if (workcase.getWorkcaseId() == null || workcase.getWorkcaseId().isEmpty()) { workcase.setWorkcaseId(IdUtil.generateUUID()); @@ -53,9 +81,11 @@ public class WorkcaseServiceImpl implements WorkcaseService { if (workcase.getEmergency() == null || workcase.getEmergency().isEmpty()) { workcase.setEmergency("normal"); } + workcase.setCreator(LoginUtil.getCurrentUserId()); int rows = workcaseMapper.insertWorkcase(workcase); if (rows > 0) { + // 创建工单处理记录 TbWorkcaseProcessDTO process = new TbWorkcaseProcessDTO(); process.setProcessId(IdUtil.generateUUID()); process.setOptsn(IdUtil.getOptsn()); @@ -65,9 +95,16 @@ public class WorkcaseServiceImpl implements WorkcaseService { process.setCreator(workcase.getCreator()); workcaseProcessMapper.insertWorkcaseProcess(process); - syncWorkcaseToCrm(workcase); - sendWechatKefuWelcome(workcase); + // 如果是新创建的聊天室,更新聊天室的 workcaseId + + logger.info("更新聊天室的工单ID: roomId={}, workcaseId={}", workcase.getRoomId(), workcase.getWorkcaseId()); + TbChatRoomDTO updateRoom = new TbChatRoomDTO(); + updateRoom.setRoomId(workcase.getRoomId()); + updateRoom.setWorkcaseId(workcase.getWorkcaseId()); + chatRoomService.updateChatRoom(updateRoom); + + syncWorkcaseToCrm(workcase); return ResultDomain.success("创建成功", workcase); } return ResultDomain.failure("创建失败"); diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml index 70fc27db..95559895 100644 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml +++ b/urbanLifelineServ/workcase/src/main/resources/mapper/TbChatRoomMapper.xml @@ -76,6 +76,7 @@ UPDATE workcase.tb_chat_room + workcase_id = #{workcaseId}, room_name = #{roomName}, room_type = #{roomType}, status = #{status}, diff --git a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml b/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml index 66ae1142..01e4b87b 100644 --- a/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml +++ b/urbanLifelineServ/workcase/src/main/resources/mapper/TbWorkcaseMapper.xml @@ -4,6 +4,7 @@ + @@ -27,13 +28,13 @@ - workcase_id, optsn, user_id, username, phone, type, device, device_code, device_name_plate, device_name_plate_img, + workcase_id, room_id, optsn, user_id, username, phone, type, device, device_code, device_name_plate, device_name_plate_img, address, description, imgs, emergency, status, processor, creator, create_time, update_time, delete_time, deleted INSERT INTO workcase.tb_workcase ( - optsn, workcase_id, user_id, username, phone, type, device_name_plate_img, creator + optsn, workcase_id, room_id, user_id, username, phone, type, device_name_plate_img, creator , device , device_code , device_name_plate @@ -44,7 +45,7 @@ , status , processor ) VALUES ( - #{optsn}, #{workcaseId}, #{userId}, #{username}, #{phone}, #{type}, #{deviceNamePlateImg}, #{creator} + #{optsn}, #{workcaseId}, #{roomId}, #{userId}, #{username}, #{phone}, #{type}, #{deviceNamePlateImg}, #{creator} , #{device} , #{deviceCode} , #{deviceNamePlate} diff --git a/urbanLifelineWeb/packages/workcase/src/types/workcase/workcase.ts b/urbanLifelineWeb/packages/workcase/src/types/workcase/workcase.ts index 20b53d20..ed69b3c9 100644 --- a/urbanLifelineWeb/packages/workcase/src/types/workcase/workcase.ts +++ b/urbanLifelineWeb/packages/workcase/src/types/workcase/workcase.ts @@ -6,6 +6,8 @@ import type { BaseDTO } from 'shared/types' export interface TbWorkcaseDTO extends BaseDTO { /** 工单ID */ workcaseId?: string + /** 聊天室ID */ + roomId: string /** 来客ID */ userId?: string /** 来客姓名 */ diff --git a/urbanLifelineWeb/packages/workcase_wechat/api/base.ts b/urbanLifelineWeb/packages/workcase_wechat/api/base.ts index 36604843..00a68aae 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/api/base.ts +++ b/urbanLifelineWeb/packages/workcase_wechat/api/base.ts @@ -7,6 +7,7 @@ declare const uni: { getStorageSync: (key: string) => any request: (options: any) => void + uploadFile: (options: any) => void } import type { ResultDomain } from '../types' @@ -46,4 +47,40 @@ export function request(options: { }) } - +// 文件上传方法 +export function uploadFile(options: { + url: string + filePath: string + name?: string + formData?: Record + header?: Record +}): Promise> { + return new Promise((resolve, reject) => { + const token = uni.getStorageSync('token') as string + uni.uploadFile({ + url: BASE_URL + options.url, + filePath: options.filePath, + name: options.name || 'file', + formData: options.formData, + header: { + ...(token ? { 'Authorization': `Bearer ${token}` } : {}), + ...options.header + }, + success: (res: any) => { + try { + if (res.statusCode === 200) { + const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data + resolve(result as ResultDomain) + } else { + reject(new Error(`上传失败: ${res.statusCode}`)) + } + } catch (error) { + reject(new Error('解析响应失败')) + } + }, + fail: (err: any) => { + reject(err) + } + }) + }) +} diff --git a/urbanLifelineWeb/packages/workcase_wechat/api/file/file.ts b/urbanLifelineWeb/packages/workcase_wechat/api/file/file.ts new file mode 100644 index 00000000..cb4aa8e8 --- /dev/null +++ b/urbanLifelineWeb/packages/workcase_wechat/api/file/file.ts @@ -0,0 +1,74 @@ +import { request, uploadFile } from '../base' +import type { ResultDomain, TbSysFileDTO, FileUploadParam, BatchFileUploadParam } from '../../types' +import { BASE_URL } from '../../config' + +export const fileAPI = { + baseUrl: '/urban-lifeline/file', + + /** + * 上传单个文件(uni-app 版本) + * @param filePath 文件临时路径 + * @param param 文件上传参数 + * @returns Promise> + */ + uploadFile(filePath: string, param?: FileUploadParam): Promise> { + return uploadFile({ + url: `${this.baseUrl}/upload`, + filePath: filePath, + name: 'file', + formData: { + module: param?.module || '', + optsn: param?.optsn || '', + uploader: param?.uploader || '' + } + }) + }, + + /** + * 批量上传文件(uni-app 版本) + * @param filePaths 文件临时路径数组 + * @param param 批量文件上传参数 + * @returns Promise> + */ + async batchUploadFiles(filePaths: string[], param?: BatchFileUploadParam): Promise> { + const uploadPromises = filePaths.map(filePath => + this.uploadFile(filePath, param) + ) + + try { + const results = await Promise.all(uploadPromises) + // 返回包含所有上传文件的结果 + const uploadedFiles = results + .filter((r: ResultDomain) => r.success && r.data) + .map((r: ResultDomain) => r.data!) + + return { + success: true, + dataList: uploadedFiles + } as ResultDomain + } catch (error) { + return { + success: false, + message: '批量上传失败' + } as ResultDomain + } + }, + + /** + * 获取文件信息 + * @param fileId 文件ID + * @returns Promise> + */ + getFileById(fileId: string): Promise> { + return request({ url: `${BASE_URL}${this.baseUrl}/${fileId}`, method: 'GET' }) + }, + + /** + * 获取文件下载 URL + * @param fileId 文件ID + * @returns string + */ + getDownloadUrl(fileId: string): string { + return `${BASE_URL}${this.baseUrl}/download/${fileId}` + } +} \ No newline at end of file diff --git a/urbanLifelineWeb/packages/workcase_wechat/api/file/index.ts b/urbanLifelineWeb/packages/workcase_wechat/api/file/index.ts new file mode 100644 index 00000000..d0a70d56 --- /dev/null +++ b/urbanLifelineWeb/packages/workcase_wechat/api/file/index.ts @@ -0,0 +1 @@ +export * from './file' diff --git a/urbanLifelineWeb/packages/workcase_wechat/api/index.ts b/urbanLifelineWeb/packages/workcase_wechat/api/index.ts index 80acc5a0..864eedb6 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/api/index.ts +++ b/urbanLifelineWeb/packages/workcase_wechat/api/index.ts @@ -1,4 +1,5 @@ export * from "./base" export * from "./sys" export * from "./workcase" -export * from "./ai" \ No newline at end of file +export * from "./ai" +export * from "./file" \ No newline at end of file diff --git a/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue b/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue index 8ca3a57f..754757af 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue +++ b/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue @@ -106,6 +106,7 @@