diff --git a/.gitignore b/.gitignore index 42eae94a..c121daee 100644 --- a/.gitignore +++ b/.gitignore @@ -202,4 +202,5 @@ cython_debug/ 江西城市生命线-可交互原型/frontend/node_modules/* THAI-Platform/* urbanLifelineWeb/packages/wechat_demo/* -urbanLifelineWeb/packages/workcase_wechat/unpackage/* \ No newline at end of file +urbanLifelineWeb/packages/workcase_wechat/unpackage/* +docs/AI训练资料 \ No newline at end of file diff --git a/difyPlugin/.vscode/launch.json b/difyPlugin/.vscode/launch.json new file mode 100644 index 00000000..3ef0a12c --- /dev/null +++ b/difyPlugin/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "DifyPlugin: FastAPI", + "type": "debugpy", + "request": "launch", + "program": "run.py", + "cwd": "${workspaceFolder}", + "python": "F:\\Environment\\conda\\envs\\difyPlugin\\python.exe", + "env": { + "PYTHONPATH": "${workspaceFolder}/difyPlugin" + }, + "jinja": true + } + ] +} \ No newline at end of file diff --git a/difyPlugin/.vscode/settings.json b/difyPlugin/.vscode/settings.json new file mode 100644 index 00000000..e69de29b diff --git a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql index 6afc2457..825f42ba 100644 --- a/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql +++ b/urbanLifelineServ/.bin/database/postgres/sql/createTableWorkcase.sql @@ -38,6 +38,7 @@ CREATE TABLE workcase.tb_chat_room( guest_name VARCHAR(100) NOT NULL, -- 来客姓名 ai_session_id VARCHAR(50) DEFAULT NULL, -- AI对话会话ID(从ai.tb_chat同步) message_count INTEGER NOT NULL DEFAULT 0, -- 消息总数 + device_code VARCHAR(50) NOT NULL, -- 设备代码 last_message_time TIMESTAMPTZ DEFAULT NULL, -- 最后消息时间 last_message TEXT DEFAULT NULL, -- 最后一条消息内容(用于列表展示) comment_level INTEGER DEFAULT 0, -- 服务评分(1-5) diff --git a/urbanLifelineServ/.vscode/launch.json b/urbanLifelineServ/.vscode/launch.json index 2fee27d0..0fc9038e 100644 --- a/urbanLifelineServ/.vscode/launch.json +++ b/urbanLifelineServ/.vscode/launch.json @@ -1,20 +1,6 @@ { "version": "0.2.0", "configurations": [ - { - "type": "java", - "name": "URLQRCodeParseTest", - "request": "launch", - "mainClass": "org.xyzh.workcase.test.URLQRCodeParseTest", - "projectName": "workcase" - }, - { - "type": "java", - "name": "QRCodeTest", - "request": "launch", - "mainClass": "org.xyzh.workcase.test.QRCodeTest", - "projectName": "workcase" - }, { "type": "java", "name": "AesEncryptUtil", diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java index bd5c419c..53c84a69 100644 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java +++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/client/DifyApiClient.java @@ -284,9 +284,8 @@ public class DifyApiClient { dataMap.put("process_rule", defaultProcessRule); } - // 默认设置文档形式和语言 - dataMap.put("doc_form", "text_model"); - dataMap.put("doc_language", "Chinese"); + // 只保留官方支持的参数 + // doc_form 和 doc_language 不是请求参数,移除 String dataJson = JSON.toJSONString(dataMap); logger.info("上传文档到知识库: datasetId={}, file={}, data={}", datasetId, originalFilename, dataJson); diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java index a65ebb79..56b03532 100644 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java +++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/controller/KnowledgeController.java @@ -235,10 +235,10 @@ public class KnowledgeController { * @since 2025-12-18 */ @PreAuthorize("hasAuthority('ai:knowledge:file:delete')") - @DeleteMapping("/file/{fileId}") - public ResultDomain deleteFile(@PathVariable("fileId") @NotBlank String fileId) { - logger.info("删除知识库文件: fileId={}", fileId); - return knowledgeService.deleteKnowledgeFileById(fileId); + @DeleteMapping("/file/{fileRootId}") + public ResultDomain deleteFile(@PathVariable("fileRootId") @NotBlank String fileRootId) { + logger.info("删除知识库文件: fileId={}", fileRootId); + return knowledgeService.deleteKnowledgeFileById(fileRootId); } /** diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java index 01592252..561b8412 100644 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java +++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/mapper/TbKnowledgeMapper.java @@ -32,6 +32,8 @@ public interface TbKnowledgeMapper { */ int deleteKnowledge(TbKnowledge knowledge); + int updateKnowledgeFileCount(@Param("knowledgeId") String knowledgeId, @Param("num") Integer num); + /** * 根据ID查询知识库 */ diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java index 925fb3c9..2e0e3880 100644 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java +++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/AgentChatServiceImpl.java @@ -300,6 +300,7 @@ public class AgentChatServiceImpl implements AgentChatService { sessionData.put("apiKey", agent.getApiKey()); sessionData.put("outer", agent.getIsOuter()); sessionData.put("service", prepareData.getService()); + sessionData.put("isGuest", "guest".equals(loginDomain.getUser().getStatus())); String cacheKey = CHAT_SESSION_PREFIX + sessionId; redisService.set(cacheKey, sessionData, SESSION_TTL, TimeUnit.SECONDS); @@ -335,6 +336,7 @@ public class AgentChatServiceImpl implements AgentChatService { String apiKey = (String) sessionData.get("apiKey"); String service = (String) sessionData.get("service"); Boolean outer = (Boolean) sessionData.get("outer"); + Boolean isGuest = (Boolean) sessionData.get("isGuest"); @SuppressWarnings("unchecked") List filesData = (List) sessionData.get("filesData"); @@ -375,7 +377,7 @@ public class AgentChatServiceImpl implements AgentChatService { if(outer && NonUtils.isNotEmpty(service)){ TbKnowledge filter = new TbKnowledge(); filter.setService(service); - filter.setCategory("external"); + filter.setCategory(isGuest?"external":"internal"); ResultDomain knowledgeRD = knowledgeService.listKnowledges(filter); List datasets = new ArrayList<>(); if(knowledgeRD.getSuccess()){ diff --git a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java index 43de2d3f..d9daa98a 100644 --- a/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java +++ b/urbanLifelineServ/ai/src/main/java/org/xyzh/ai/service/impl/KnowledgeServiceImpl.java @@ -533,6 +533,7 @@ public class KnowledgeServiceImpl implements KnowledgeService { knowledgeFile.setDifyFileId(difyFileId); knowledgeFile.setVersion(1); + knowledgeMapper.updateKnowledgeFileCount(knowledgeId, 1); int rows = knowledgeFileMapper.insertKnowledgeFile(knowledgeFile); if (rows > 0) { logger.info("保存知识库文件记录成功: knowledgeId={}, fileId={}, difyFileId={}", knowledgeId, fileId, difyFileId); @@ -722,10 +723,13 @@ public class KnowledgeServiceImpl implements KnowledgeService { if (!difyDocIds.isEmpty()) { aiFileUploadService.batchDeleteFilesFromDify(knowledge.getDifyDatasetId(), difyDocIds); } + }else{ + return ResultDomain.failure("知识库未关联Dify"); } // 3. 软删除本地记录和minio文件 int rows = knowledgeFileMapper.deleteFilesByRootId(fileRootId); + knowledgeMapper.updateKnowledgeFileCount(knowledge.getKnowledgeId(), -1); if (rows > 0) { logger.info("删除知识库文件成功: fileRootId={}", fileRootId); for (TbKnowledgeFile file : versions) { diff --git a/urbanLifelineServ/ai/src/main/resources/application-dev.yml b/urbanLifelineServ/ai/src/main/resources/application-dev.yml index da48f901..310d49ba 100644 --- a/urbanLifelineServ/ai/src/main/resources/application-dev.yml +++ b/urbanLifelineServ/ai/src/main/resources/application-dev.yml @@ -29,7 +29,12 @@ security: spring: application: name: ai-service - + # 文件上传配置 + servlet: + multipart: + enabled: true + max-file-size: 500MB + max-request-size: 500MB # ================== Spring Cloud Nacos ================== cloud: nacos: @@ -72,6 +77,7 @@ dubbo: name: urban-lifeline-agent qos-enable: false protocol: + payload: 110100480 name: dubbo port: -1 registry: diff --git a/urbanLifelineServ/ai/src/main/resources/application.yml b/urbanLifelineServ/ai/src/main/resources/application.yml index dc0f506e..35253da8 100644 --- a/urbanLifelineServ/ai/src/main/resources/application.yml +++ b/urbanLifelineServ/ai/src/main/resources/application.yml @@ -72,6 +72,7 @@ dubbo: name: urban-lifeline-agent qos-enable: false protocol: + payload: 110100480 name: dubbo port: -1 registry: diff --git a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml b/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml index 1fb778ad..7c27ab65 100644 --- a/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml +++ b/urbanLifelineServ/ai/src/main/resources/mapper/TbKnowledgeMapper.xml @@ -112,6 +112,12 @@ WHERE knowledge_id = #{knowledgeId} AND deleted = false + + UPDATE ai.tb_knowledge + SET document_count = document_count + #{num} + WHERE knowledge_id = #{knowledgeId} AND deleted = false + + SELECT r.room_id, r.optsn, r.workcase_id, r.room_name, r.room_type, r.status, - r.guest_id, r.guest_name, r.ai_session_id, r.message_count, + r.guest_id, r.guest_name, r.ai_session_id, r.message_count, r.device_code, r.last_message_time, r.last_message, r.comment_level, r.closed_by, r.closed_time, r.creator, r.create_time, r.update_time, r.delete_time, r.deleted, COALESCE(m.unread_count, 0) as unread_count diff --git a/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue b/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue index 5be1119c..f32aebb2 100644 --- a/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue +++ b/urbanLifelineWeb/packages/platform/src/views/public/Login/Login.vue @@ -134,10 +134,9 @@ async function handleLogin() { if (response.success && response.data) { const loginData = response.data - // 8. 保存 Token + // 8. 保存 Token(只用 TokenManager,避免格式不一致) if (loginData.token) { TokenManager.setToken(loginData.token, loginForm.rememberMe) - localStorage.setItem('token', loginData.token) } // 9. 保存 LoginDomain 到 LocalStorage diff --git a/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts b/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts index 61e6986e..583ac287 100644 --- a/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts +++ b/urbanLifelineWeb/packages/shared/src/api/ai/aiKnowledge.ts @@ -162,8 +162,8 @@ export const aiKnowledgeAPI = { * 删除知识库文件 * @param fileId 文件ID */ - async deleteFile(fileId: string): Promise> { - const response = await api.delete(`${this.baseUrl}/file/${fileId}`) + async deleteFile(fileRootId: string): Promise> { + const response = await api.delete(`${this.baseUrl}/file/${fileRootId}`) return response.data }, diff --git a/urbanLifelineWeb/packages/workcase/src/router/index.ts b/urbanLifelineWeb/packages/workcase/src/router/index.ts index 7729243a..a68dc7c8 100644 --- a/urbanLifelineWeb/packages/workcase/src/router/index.ts +++ b/urbanLifelineWeb/packages/workcase/src/router/index.ts @@ -64,9 +64,9 @@ router.beforeEach(async (to, from, next) => { const newToken = loginDomain.token // 保存到localStorage(覆盖旧的登录状态) - localStorage.setItem('token', newToken) - localStorage.setItem('loginDomain', JSON.stringify(loginDomain)) + // 只用 TokenManager 存储 token,避免格式不一致 TokenManager.setToken(newToken) + localStorage.setItem('loginDomain', JSON.stringify(loginDomain)) console.log('[Workcase Router] Token验证成功,登录状态已刷新') } else { diff --git a/urbanLifelineWeb/packages/workcase/src/types/workcase/chatRoom.ts b/urbanLifelineWeb/packages/workcase/src/types/workcase/chatRoom.ts index 3ff50bdb..b63298ec 100644 --- a/urbanLifelineWeb/packages/workcase/src/types/workcase/chatRoom.ts +++ b/urbanLifelineWeb/packages/workcase/src/types/workcase/chatRoom.ts @@ -13,6 +13,7 @@ export interface TbChatRoomDTO extends BaseDTO { status?: string guestId?: string guestName?: string + deviceCode?: string aiSessionId?: string currentAgentId?: string agentCount?: number @@ -164,6 +165,7 @@ export interface ChatRoomVO extends BaseVO { status?: string guestId?: string guestName?: string + deviceCode?: string aiSessionId?: string currentAgentId?: string currentAgentName?: string diff --git a/urbanLifelineWeb/packages/workcase/src/views/admin/knowledge/KnowLedgeView.vue b/urbanLifelineWeb/packages/workcase/src/views/admin/knowledge/KnowLedgeView.vue index 6ffa3bc4..0e42e839 100644 --- a/urbanLifelineWeb/packages/workcase/src/views/admin/knowledge/KnowLedgeView.vue +++ b/urbanLifelineWeb/packages/workcase/src/views/admin/knowledge/KnowLedgeView.vue @@ -278,7 +278,7 @@ const deleteFile = async (row: DocumentItem) => { cancelButtonText: '取消', type: 'warning' }) - const result = await aiKnowledgeAPI.deleteFile(row.id) + const result = await aiKnowledgeAPI.deleteFile(row.fileRootId) if (result.success) { ElMessage.success('删除成功') fetchDocuments(activeKnowledgeId.value) @@ -306,7 +306,7 @@ const customKnowledgeUpload = async (files: File[]) => { const result = await aiKnowledgeAPI.uploadToKnowledge(files[0], targetKnowledgeId) if (result.success) { ElMessage.success('文件上传成功') - fetchKnowledges() + // fetchKnowledges() fetchDocuments(activeKnowledgeId.value) } else { throw new Error(result.message || '上传失败') @@ -316,7 +316,7 @@ const customKnowledgeUpload = async (files: File[]) => { const result = await aiKnowledgeAPI.batchUploadToKnowledge(files, targetKnowledgeId) if (result.success) { ElMessage.success('文件上传成功') - fetchKnowledges() + // fetchKnowledges() fetchDocuments(activeKnowledgeId.value) } else { throw new Error(result.message || '上传失败') diff --git a/urbanLifelineWeb/packages/workcase/src/views/public/ChatRoom/ChatRoomView.vue b/urbanLifelineWeb/packages/workcase/src/views/public/ChatRoom/ChatRoomView.vue index 2aa200b1..5e0fc663 100644 --- a/urbanLifelineWeb/packages/workcase/src/views/public/ChatRoom/ChatRoomView.vue +++ b/urbanLifelineWeb/packages/workcase/src/views/public/ChatRoom/ChatRoomView.vue @@ -189,7 +189,7 @@ import { Client } from '@stomp/stompjs' // WebSocket配置 (通过Nginx代理访问网关,再到workcase服务) // SockJS URL (http://) const getWsUrl = () => { - const token = localStorage.getItem('token')! + const token = JSON.parse(localStorage.getItem('token')!).value const protocol = window.location.protocol const host = window.location.host return `${protocol}//${host}/api/urban-lifeline/workcase/ws/chat-sockjs?token=${encodeURIComponent(token)}` @@ -557,32 +557,6 @@ const startMeeting = async () => { } return } - - // 没有活跃会议,创建新会议 - const createResult = await workcaseChatAPI.createVideoMeeting({ - roomId: currentRoomId.value, - meetingName: currentRoom.value?.roomName || '视频会议' - }) - - if (createResult.success && createResult.data) { - const currentMeetingId = createResult.data.meetingId! - - // 开始会议 - await workcaseChatAPI.startVideoMeeting(currentMeetingId) - - // 加入会议获取会议页面URL - const joinResult = await workcaseChatAPI.joinVideoMeeting(currentMeetingId) - if (joinResult.success && joinResult.data?.iframeUrl) { - // 使用router跳转到JitsiMeetingView页面,附加roomId参数用于返回 - const meetingUrl = joinResult.data.iframeUrl + `&roomId=${currentRoomId.value}` - router.push(meetingUrl) - ElMessage.success('会议已创建') - } else { - ElMessage.error(joinResult.message || '获取会议链接失败') - } - } else { - ElMessage.error(createResult.message || '创建会议失败') - } } catch (error) { console.error('发起会议失败:', error) ElMessage.error('发起会议失败') @@ -707,8 +681,16 @@ const subscribeToRoom = (roomId: string) => { // 避免重复添加自己发送的普通消息 // 但会议消息(meet类型)始终添加,因为它是系统生成的通知 if (chatMessage.messageType === 'meet' || chatMessage.senderId !== loginDomain.user.userId) { - messages.value.push(chatMessage) - scrollToBottom() + // 会议消息延时处理,等待数据库事务提交 + if (chatMessage.messageType === 'meet') { + console.log('[ChatRoom] 收到会议消息,延时1秒后刷新') + setTimeout(() => { + loadMessages(roomId) + }, 1000) + } else { + messages.value.push(chatMessage) + scrollToBottom() + } } }) } diff --git a/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue b/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue index f872ed28..df920823 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue +++ b/urbanLifelineWeb/packages/workcase_wechat/pages/chatRoom/chatRoom/chatRoom.uvue @@ -784,6 +784,16 @@ function handleNewMessage(message: ChatRoomMessageVO) { return } + // 会议消息延时处理,等待数据库事务提交 + if (message.messageType === 'meet') { + console.log('[chatRoom] 收到会议消息,延时1秒后刷新') + setTimeout(async () => { + // 重新加载最新消息,确保获取到完整的会议消息数据 + await loadMessages() + }, 1000) + return + } + // 添加新消息到列表 messages.push(message) nextTick(() => scrollToBottom()) diff --git a/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.scss b/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.scss index 0cc4288c..16853d0b 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.scss +++ b/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.scss @@ -696,3 +696,110 @@ opacity: 1; } } + +// 设备代码输入弹窗样式 +.device-code-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-mask { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); +} + +.modal-content { + position: relative; + background-color: white; + border-radius: 16px; + width: 80%; + max-width: 320px; + padding: 20px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); +} + +.modal-header { + margin-bottom: 20px; +} + +.modal-title { + font-size: 18px; + font-weight: 600; + color: #333; + text-align: center; + display: block; +} + +.modal-body { + margin-bottom: 20px; +} + +.device-code-input { + width: 100%; + height: 44px; + padding: 0 12px; + border: 1px solid #ddd; + border-radius: 8px; + font-size: 16px; + background-color: #f9f9f9; + box-sizing: border-box; +} + +.device-code-input:focus { + border-color: #007AFF; + background-color: white; + outline: none; +} + +.modal-footer { + display: flex; + flex-direction: row; + gap: 12px; +} + +.modal-btn { + flex: 1; + height: 44px; + border-radius: 8px; + border: none; + font-size: 16px; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s; +} + +.modal-btn.cancel { + background-color: #f5f5f5; + color: #666; +} + +.modal-btn.cancel:active { + background-color: #e5e5e5; +} + +.modal-btn.confirm { + background-color: #007AFF; + color: white; +} + +.modal-btn.confirm:active { + background-color: #0056b3; +} + +.modal-btn .btn-text { + font-size: 16px; +} diff --git a/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.uvue b/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.uvue index 6a90f8bf..3744829a 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.uvue +++ b/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.uvue @@ -148,6 +148,33 @@ + + + + + + + 请输入设备代码 + + + + + + + + + + - diff --git a/urbanLifelineWeb/packages/workcase_wechat/types/workcase/chatRoom.ts b/urbanLifelineWeb/packages/workcase_wechat/types/workcase/chatRoom.ts index 8bad3526..4aca5422 100644 --- a/urbanLifelineWeb/packages/workcase_wechat/types/workcase/chatRoom.ts +++ b/urbanLifelineWeb/packages/workcase_wechat/types/workcase/chatRoom.ts @@ -13,8 +13,9 @@ export interface TbChatRoomDTO extends BaseDTO { roomType?: string status?: string guestId?: string - commentLevel?: number guestName?: string + deviceCode?: string + commentLevel?: number aiSessionId?: string currentAgentId?: string agentCount?: number @@ -164,8 +165,9 @@ export interface ChatRoomVO extends BaseVO { roomType?: string status?: string guestId?: string - commentLevel?: string guestName?: string + commentLevel?: string + deviceCode?: string aiSessionId?: string currentAgentId?: string currentAgentName?: string diff --git a/修改点.md b/修改点.md new file mode 100644 index 00000000..ede63519 --- /dev/null +++ b/修改点.md @@ -0,0 +1,4 @@ +1. createTableWorkcase.sql 修改了tb_chat_room 增加了device_code字段。修改相关dto\vo\xml。 +2. WorkcaseChatController.java 修改创建聊天室的接口,增加了deviceCode字段必传。 +3. 修改workcase/types/workcase/chatRoom.ts里的dto和vo。修改workcase_wechat/types/workcase/chatRoom.ts的dto和vo +4. 修改workcase_wechat/pages/index/index.uvue。新增const deviceCode = ref('');只有这个有值时,才让用户创建聊天室和工单(工单自动填入表单),否则弹窗让用户填写 \ No newline at end of file