diff --git a/pages/home/index/index.vue b/pages/home/index/index.vue
index 14b6ea5..39fc0e9 100644
--- a/pages/home/index/index.vue
+++ b/pages/home/index/index.vue
@@ -159,6 +159,11 @@
{{ message.displayTime }}
+
+
+ {{ message.message }}
+
+
@@ -258,6 +265,8 @@
class="message-content"
:class="{
'message-content-width': !message.isLoading,
+ 'message-content-structured':
+ getStructuredMessageBlocks(message).length,
}"
>
@@ -266,7 +275,53 @@
-
+
+
+
+ {{ block.value }}
+
+
+
+
+ {{
+ block.name
+ }}
+
+
+
+
@@ -322,6 +377,8 @@
class="message-content"
:class="{
'message-content-width': !message.isLoading,
+ 'message-content-structured':
+ getStructuredMessageBlocks(message).length,
}"
>
@@ -329,6 +386,53 @@
+
+
+
+ {{ block.value }}
+
+
+
+
+ {{
+ block.name
+ }}
+
+
+
+
@@ -1080,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;
// 从消息列表中移除加载状态消息
@@ -1087,12 +1192,19 @@ 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,
+ id: messageId || Math.random().toString(36).substring(2, 15),
+ message: message,
sendDate: "",
isSend: true,
isRead: false,
@@ -1160,6 +1272,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);
@@ -1259,7 +1472,7 @@ export default {
onScrollToUpper() {
console.log("触发上拉刷新");
- if (!this.currentDMid) return;
+ // if (!this.currentDMid) return;
if (this.isLiveAgentChat) return;
// 如果已经没有更多数据或正在切换对话或当前对话为空(新建对话),不再触发上拉刷新
@@ -1307,8 +1520,15 @@ export default {
// 回答反馈:点赞/点踩(统一调用刷新&上一页回退逻辑)
handleFeedback(message, isHelp) {
this.$u.api.ModifyStatus({ id: message.id, isHelp }).then((res) => {
- if (!res.succeed) return;
- this.$u.toast("操作成功");
+ if (!res.succeed) {
+ uni.showToast({
+ title: res.error || "操作失败",
+ icon: "none",
+ });
+
+ return;
+ }
+ // this.$u.toast("操作成功"); // 去除操作成功提示
// 刷新当前页;若空则自动回退上一页并刷新
this.refreshPageWithFallback();
});
@@ -1685,6 +1905,12 @@ export default {
color: #999999;
padding: 20rpx;
}
+ .message-tip {
+ text-align: center;
+ font-size: 24rpx;
+ color: #999999;
+ padding-bottom: 40rpx;
+ }
.message-left,
.message-right {
@@ -1720,6 +1946,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 +2024,89 @@ 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: flex;
+ align-items: center;
+ width: 500rpx;
+ max-width: 100%;
+ padding: 24rpx;
+ background-color: #ffffff;
+ 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;
+ }
+ }
+ }
+ }
}
.message-content-width {
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 @@
图形验证码
- ({
...item,
+ rawMessage: item && item.message,
message: processChatMessageContent(item && item.message),
}));