From 3c4aaa0f77c67c3db3140afc7fc8e83d19a787d0 Mon Sep 17 00:00:00 2001 From: yangzhe Date: Thu, 19 Mar 2026 09:07:13 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix(login):=20=E4=BF=AE=E5=A4=8D=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/login/login/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/login/login/index.vue b/pages/login/login/index.vue index 0dd48cd..9c9a016 100644 --- a/pages/login/login/index.vue +++ b/pages/login/login/index.vue @@ -106,7 +106,7 @@ 图形验证码 - Date: Thu, 19 Mar 2026 11:06:30 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat(chat):=20AI=E5=9B=9E=E5=A4=8D=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=BB=93=E6=9E=84=E5=8C=96=E6=B6=88=E6=81=AF=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=EF=BC=8C=E5=8C=85=E6=8B=AC=E6=96=87=E6=9C=AC=E3=80=81?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E5=92=8C=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/index/index.vue | 289 ++++++++++++++++++++++++++++++++++++- utils/chat.js | 1 + 2 files changed, 285 insertions(+), 5 deletions(-) diff --git a/pages/home/index/index.vue b/pages/home/index/index.vue index 14b6ea5..79dd9e2 100644 --- a/pages/home/index/index.vue +++ b/pages/home/index/index.vue @@ -258,6 +258,8 @@ class="message-content" :class="{ 'message-content-width': !message.isLoading, + 'message-content-structured': + getStructuredMessageBlocks(message).length, }" > @@ -266,7 +268,47 @@ - + + + + {{ block.value }} + + + + + {{ + block.name + }} + + + @@ -322,6 +364,8 @@ class="message-content" :class="{ 'message-content-width': !message.isLoading, + 'message-content-structured': + getStructuredMessageBlocks(message).length, }" > @@ -329,6 +373,47 @@ + + + + {{ block.value }} + + + + + {{ + block.name + }} + + + @@ -1087,12 +1172,20 @@ export default { (msg) => !msg.isLoading, ); + const answerTypeLabel = data.detailedExplanation; // 文字 + const imageUrl = data.imageUrl; // 图片 + const nearbyPaths = data.nearbyPaths; // 文件 + const message = `{\r\n "answerTypeLabel": ${JSON.stringify( + answerTypeLabel || "", + )},\r\n "imageUrl": ${JSON.stringify( + imageUrl || "", + )},\r\n "nearbyPaths": ${JSON.stringify(nearbyPaths || "")}\r\n}`; + // 创建AI回复消息对象 const aiMessage = { id: - data.conversationId || - Math.random().toString(36).substring(2, 15), - message: data.detailedExplanation, + this.currentDMid || Math.random().toString(36).substring(2, 15), + message: message, sendDate: "", isSend: true, isRead: false, @@ -1160,6 +1253,107 @@ export default { this.handleGetConversationDetail(); }, + // 解析结构化消息块 + getStructuredMessageBlocks(message) { + const rawMessage = + (message && (message.rawMessage || message.message)) || ""; + if (!rawMessage || typeof rawMessage !== "string") return []; + + let parsed = null; + try { + parsed = JSON.parse(rawMessage); + } catch (error) { + return []; + } + if (!parsed || typeof parsed !== "object") return []; + + const answerTypeLabel = (parsed.answerTypeLabel || "").trim(); + const imageUrl = parsed.imageUrl || ""; + const nearbyPaths = parsed.nearbyPaths || ""; + + if (!answerTypeLabel && !imageUrl && !nearbyPaths) return []; + + const blocks = []; + if (answerTypeLabel) { + blocks.push({ type: "text", value: answerTypeLabel }); + } + + this.normalizeResourceList(imageUrl).forEach((item) => { + const url = this.formatMessageResourceUrl(item); + if (url) blocks.push({ type: "image", url }); + }); + + this.normalizeResourceList(nearbyPaths).forEach((item) => { + const url = this.formatMessageResourceUrl(item); + if (!url) return; + blocks.push({ + type: "file", + url, + name: this.getFileNameFromPath(item), + }); + }); + + return blocks; + }, + normalizeResourceList(value) { + if (!value) return []; + if (Array.isArray(value)) { + return value.map((item) => String(item || "").trim()).filter(Boolean); + } + return String(value) + .split(/[\n,|]/) + .map((item) => item.trim()) + .filter(Boolean); + }, + formatMessageResourceUrl(path) { + if (!path) return ""; + const currentPath = String(path).trim(); + if (!currentPath) return ""; + if ( + currentPath.startsWith("http://") || + currentPath.startsWith("https://") || + currentPath.startsWith("blob:") + ) { + return currentPath; + } + const cleanPath = currentPath.replace(/\\/g, "/"); + const cleanBaseUrl = (this.baseUrl || "") + .replace(/\\/g, "/") + .replace(/\/$/, ""); + if (!cleanBaseUrl) return cleanPath; + if (cleanPath.startsWith("/")) return `${cleanBaseUrl}${cleanPath}`; + return `${cleanBaseUrl}/${cleanPath}`; + }, + getFileNameFromPath(path) { + const cleanPath = String(path || "") + .replace(/\\/g, "/") + .split("?")[0]; + const segments = cleanPath.split("/"); + const fileName = segments[segments.length - 1] || "下载文件"; + try { + return decodeURIComponent(fileName); + } catch (error) { + return fileName; + } + }, + previewMessageImage(url) { + if (!url) return; + uni.previewImage({ + current: url, + urls: [url], + }); + }, + downloadMessageFile(url) { + if (!url) return; + if (typeof window !== "undefined" && window.open) { + window.open(url, "_blank"); + return; + } + uni.downloadFile({ + url, + }); + }, + // 处理消息内容,如果是JSON格式则解析并格式化 processMessageContent(message) { return processChatMessageContent(message); @@ -1307,7 +1501,14 @@ export default { // 回答反馈:点赞/点踩(统一调用刷新&上一页回退逻辑) handleFeedback(message, isHelp) { this.$u.api.ModifyStatus({ id: message.id, isHelp }).then((res) => { - if (!res.succeed) return; + if (!res.succeed) { + uni.showToast({ + title: res.error || "操作失败", + icon: "none", + }); + + return; + } this.$u.toast("操作成功"); // 刷新当前页;若空则自动回退上一页并刷新 this.refreshPageWithFallback(); @@ -1720,6 +1921,12 @@ export default { font-size: 28rpx; line-height: 1.5; + &.message-content-structured { + background-color: transparent; + padding: 0; + border-radius: 0; + } + /* 加载动画样式 */ .loading-dots { display: flex; @@ -1792,6 +1999,78 @@ export default { font-size: 24rpx; } } + + .structured-message { + .structured-item + .structured-item { + margin-top: 16rpx; + } + + .structured-item { + max-width: 100%; + } + + .structured-item-text { + .structured-text { + display: inline-block; + background-color: #ffffff; + color: #333333; + font-size: 28rpx; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; + padding: 20rpx 24rpx; + border-radius: 0 16rpx 16rpx 16rpx; + } + } + + .structured-text { + display: inline-block; + color: #333333; + font-size: 28rpx; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; + } + + .structured-item-image { + .structured-image { + display: block; + max-width: 240rpx; + border-radius: 12rpx; + } + } + + .structured-image { + display: block; + max-width: 240rpx; + border-radius: 12rpx; + } + + .structured-item-file { + .structured-file { + display: inline-flex; + align-items: center; + max-width: 100%; + padding: 16rpx 20rpx; + background-color: #ffffff; + border-radius: 12rpx; + } + } + + .structured-file { + display: inline-flex; + align-items: center; + max-width: 100%; + padding: 8rpx 0; + } + + .structured-file-name { + margin-left: 8rpx; + font-size: 26rpx; + color: #4370fe; + word-break: break-all; + } + } } .message-content-width { diff --git a/utils/chat.js b/utils/chat.js index 38c146d..38243b5 100644 --- a/utils/chat.js +++ b/utils/chat.js @@ -164,6 +164,7 @@ export function processChatMessageContent(message) { export function sortChatMessages(list = []) { const processedList = (list || []).map((item) => ({ ...item, + rawMessage: item && item.message, message: processChatMessageContent(item && item.message), })); From 526a580e145ba8282b23b0b86bcf97d77712f423 Mon Sep 17 00:00:00 2001 From: yangzhe Date: Thu, 19 Mar 2026 13:45:51 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat(ui):=20=E4=BC=98=E5=8C=96=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=B6=88=E6=81=AF=E7=9A=84=E8=A7=86=E8=A7=89=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E5=92=8C=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/index/index.vue | 80 ++++++++++++++++++----------- static/common/images/icon-file.png | Bin 0 -> 3095 bytes 2 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 static/common/images/icon-file.png diff --git a/pages/home/index/index.vue b/pages/home/index/index.vue index 79dd9e2..b8b4ab2 100644 --- a/pages/home/index/index.vue +++ b/pages/home/index/index.vue @@ -298,14 +298,20 @@ class="structured-file" @click="downloadMessageFile(block.url)" > - + {{ block.name }} + @@ -403,14 +409,20 @@ class="structured-file" @click="downloadMessageFile(block.url)" > - + {{ block.name }} + @@ -1183,8 +1195,7 @@ export default { // 创建AI回复消息对象 const aiMessage = { - id: - this.currentDMid || Math.random().toString(36).substring(2, 15), + id: data.id || Math.random().toString(36).substring(2, 15), message: message, sendDate: "", isSend: true, @@ -2048,28 +2059,39 @@ export default { .structured-item-file { .structured-file { - display: inline-flex; + display: flex; align-items: center; + width: 500rpx; max-width: 100%; - padding: 16rpx 20rpx; + padding: 24rpx; background-color: #ffffff; - border-radius: 12rpx; + border-radius: 16rpx; + box-sizing: border-box; + + .structured-file-icon { + width: 48rpx; + height: 62rpx; + flex-shrink: 0; + margin-right: 20rpx; + } + + .structured-file-name { + flex: 1; + font-size: 28rpx; + color: #333333; + word-break: break-all; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; + } + + .structured-file-download { + flex-shrink: 0; + margin-left: 20rpx; + } } } - - .structured-file { - display: inline-flex; - align-items: center; - max-width: 100%; - padding: 8rpx 0; - } - - .structured-file-name { - margin-left: 8rpx; - font-size: 26rpx; - color: #4370fe; - word-break: break-all; - } } } diff --git a/static/common/images/icon-file.png b/static/common/images/icon-file.png new file mode 100644 index 0000000000000000000000000000000000000000..404e8cafc132ceebb1721e549e15ba71766e0d37 GIT binary patch literal 3095 zcmaJ@c|4SB8&>xHbPAy~#<3k{jIoay>)4ygGBGJKW(H%-VrCd4B!voxIEdod_iUA| zLyNMNuN2Ad2npGerNlQn)j5BBeee5w-{*Pm-+f*8cKz{OazxvRi^z%a@bHM+*&>~} zD~$Wu3JGxk#ZJ=`+(njUg=M+Wd{}H8gUDk}pm`Gkb`+d1(V2)NZ~{Ata2_6BB@zb9 z!lI7C@H7e-x9bBAq0qT#9v--92pxwf6IlRnqA!Vx050CS3j~k|2%wuD3WB0r68%WF zp$wu+C>nzgCF6|=0n-@1TG~cNM!OtPD2VF;VsfY~TnLEDRQkq%Br@>~ z5}ie&Q31P*IB!}I3jyS2`gaKw`gd9?^J|;94buw2(Y3U}klm8LIigVi-<3l7?#*O5 z6aUHge-bk>96C|UnaHFCG4R~M`6%s%qQfj1L>!C8z|d#`-@54NM`O{Lel$7&stwi# zsJW4-1R9&E{sn+S!R)9^7LJN1+944@E(MrGBEYQl%?%CB4Gf_=dOF(L*4jqaNL_P% zD{X72p{}Kcfx$N{l7T` z5Ba`g2|v!o;D=Z(ZZcZCll|AEznQr5+1-BEE%)$U`9vyL?hLN3G3%|3JUl{|?U3e} zkiq$DWERFvs(r_I+D9d^^V9wOXEDV>2TGo&i5$?(fd@!A^#4p2t&py$b^e@lWNRY5 zY^;ezy5UNql)eh?GYKd!7eM|B^oYC^j?C0otS}Q+k?baa$d}Oy@OZ|B+EMvbvV@TeQ9;X%@$OIE)uw&n25r!K8m$fr3D{H zK!3}!Xi$s%*f~)0L^#Lkg|zygAH0+4EJAwyAyIVRsJ#a&%clFVPFx!mFOb*04=ad% zARqAD!=b3`@)UEq-s;he(1z1v9g9n0@sZ%d{}fjigNvmVWs~==UO4x{-2Fz}OVM0F zYg8h5DoaNyws>+pJi9MNXvSyu=UJfto@8Z~omH9G-JWbU5r4VrJdJo(*_f|lvi!Z$ z?YSVs9CGQ+(zmune*1sYBu0q~x{`&W5ee8LsWABUS~|>L^rq9J{H)f5!+T+InF8q- zk*K(Hs(m)lCMH&?yhyRb~H$iQZF%p@3WG-X-%j0cc1n~x;8d|n= zEk>L+q)*2g6iww<6pA`s>d0N1>L%ZR1guWh0=YMq%X5yusi`R3KOp9w;Uq5U^7Jgn z{=Fkeq`p-|EuqM-alR>$-r6IXG@xKH{rp5oYUA1%ypS|}{z1*J`IXJVCm?HdkvW@zvsOV^$w0oT#n{{Cv zpZ$SYFu|u3=&_SG#*qI-1IQXWo?IsyOUHzZxmLWJ(yr?Ntu6bb%7Oh6Af>?BC%^(3 z;$Py~!J}C@*Bd4uRtgPi#9*h<$m_L^oR5_Qo_J&Gp})?^opc(GkUNp9z~_gudZi?D zr)H{-f6#JHkLfQirm@G>dLSaj^VY)LV2$2<&6B{r?kI{{Sy`)plsjDe@#1aJNzh1^ zM!%mRh}D8p?8f_#vC_`35L5*NCT7E_6Mfb)g!>iqd zQtu5kg13;3szd86Tz@_JoAvmkdR@wqc5|v0I<%cT%vC&jpZ#9Vhb8IKRjY&kG?JS!< zLykN`aSl%L2o`8~i$i!Dti`JoV4(t=RdVAF=gsVUJ$A|s3oc@}R15DVI&@=SuC;A~ znI7l1UZA6o-|XH%f>bxjl=Z8;=2XDs6_@E(GN$72P4Q@>XrHZTb8-pqraz=9cOje% z^rCxKOrmf90exNnG;k%+UzeS^tZ!j5D(PGSs^#oknwKEnp%~@`xJf^5X(fk6NI;av zl%-RJMGCOW(%6?Kd4ak3kfe#xGl_3UQPmT0CVC!b$Db;^eI-f$dJv}13m`ujBiYDF zY%?wEt~qSb4&p3@XPt7)$T_;Y7VQ)EaW7q7@u^;-nDg_viw!$kbytHpEzxryyMJ-V zsNAJpt5wxx)OBK4p4g7>q3tU%)jJ5+u1L)UIUn~@O>PH}o>f30-?XXpId2rpYZt@Gv)(Mg{UcLcqU zOkZ3S-JCdSH}6?c9OjoYi&{9neWUJ0WXIaI5&n#yW)@Pr77URJCPIgT%pN{CQ`aO4 zReWY#$xe$)n;y{2Y_y7xXG8M1!@n7MaK5KHwWU@b^c=`Ddc*wrA*=yS~om^*&+&+an zg>9*VujV{ZVynaNAU2bP&n;BN%ZROm;tcv~W{EwRlnA~iL?_p75}})Y`|e$9oO2Ne zbhv%t4a$Tw}k?(w4D&yx%GQZ^w9>s zuyLaV_u`^v3V3P#=jhE8LGZ`3)e<2@HwK`pBl}8$>;N>wpfjF$%w~9%u6KX>_)_2Db8VApviI1o z>H(*`>WuKIE(0gV*W2|JjJ*|#Y-8fPf{Wo~2uN@(^!MpIdKU^FmxL)R)`O)BhJpJ} z^Bs#s|Lc_y*4+>u7ZWZCfORdF6^e(UHF$#N|1WQ(|9whXVAuGP>BWf!hv2Y0e zl-ZQ}p0_^{c~cOvpDowQttQz;pGw>LZnf1+h_⁡MaNsB@PCq Date: Thu, 19 Mar 2026 14:20:52 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E4=B8=8A=E6=8B=89?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E7=9A=84currentDMid=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/index/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/home/index/index.vue b/pages/home/index/index.vue index b8b4ab2..6b49928 100644 --- a/pages/home/index/index.vue +++ b/pages/home/index/index.vue @@ -1464,7 +1464,7 @@ export default { onScrollToUpper() { console.log("触发上拉刷新"); - if (!this.currentDMid) return; + // if (!this.currentDMid) return; if (this.isLiveAgentChat) return; // 如果已经没有更多数据或正在切换对话或当前对话为空(新建对话),不再触发上拉刷新 From f7a13b1a9de5b43bb12280726863266b062c32f7 Mon Sep 17 00:00:00 2001 From: yangzhe Date: Thu, 19 Mar 2026 15:17:13 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix(=E6=B6=88=E6=81=AF=E5=B1=95=E7=A4=BA):?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=E7=B3=BB=E7=BB=9F=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E5=B9=B6=E7=A7=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84=E6=88=90=E5=8A=9F=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/index/index.vue | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pages/home/index/index.vue b/pages/home/index/index.vue index 6b49928..4f9a8dd 100644 --- a/pages/home/index/index.vue +++ b/pages/home/index/index.vue @@ -159,6 +159,11 @@ {{ message.displayTime }} + + + {{ message.message }} + + Date: Thu, 19 Mar 2026 15:26:54 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=98=BE=E7=A4=BA=E6=9D=A1=E4=BB=B6=E5=8F=8A?= =?UTF-8?q?AI=E6=B6=88=E6=81=AFID=E8=B5=8B=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/home/index/index.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pages/home/index/index.vue b/pages/home/index/index.vue index 4f9a8dd..39fc0e9 100644 --- a/pages/home/index/index.vue +++ b/pages/home/index/index.vue @@ -231,7 +231,9 @@ @@ -1182,6 +1184,7 @@ export default { if (res.succeed) { console.log("hotQuestionsDetail.....", res.data); this.currentDMid = res.data.dmId; + const messageId = res.data.messageId; const data = res.data.entityInfo; // 从消息列表中移除加载状态消息 @@ -1200,7 +1203,7 @@ export default { // 创建AI回复消息对象 const aiMessage = { - id: data.id || Math.random().toString(36).substring(2, 15), + id: messageId || Math.random().toString(36).substring(2, 15), message: message, sendDate: "", isSend: true,