按钮组件,链接显示修复
This commit is contained in:
@@ -467,6 +467,35 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断链接是否为可下载文件
|
||||||
|
const isDownloadLink = (url) => {
|
||||||
|
const supportedExtensions = ['html', 'htm', 'xlsx', 'xls', 'pdf', 'zip', 'rar', '7z', 'md', 'markdown',
|
||||||
|
'docx', 'doc', 'pptx', 'ppt', 'txt', 'csv', 'json', 'xml', 'yaml', 'yml',
|
||||||
|
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'ico', 'tiff', 'tif', 'dxf'
|
||||||
|
]
|
||||||
|
const extPattern = supportedExtensions.join('|')
|
||||||
|
const extRegex = new RegExp(`\\.(${extPattern})(?:\\?|$)`, 'i')
|
||||||
|
return extRegex.test(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染下载按钮 HTML
|
||||||
|
const renderDownloadBtn = (href, displayName) => {
|
||||||
|
const ext = ((href.split('.').pop() || '').split('?')[0] || '').toLowerCase()
|
||||||
|
const fileInfo = getFileTypeInfo(ext)
|
||||||
|
const name = displayName || extractFileNameFromUrl(href)
|
||||||
|
return '<span class="chat-inline-link chat-download-btn" data-url="' + href + '">'
|
||||||
|
+ '<span class="chat-dl-icon">' + fileInfo.emoji + '</span>'
|
||||||
|
+ '<span class="chat-dl-name">' + name + '</span>'
|
||||||
|
+ '</span>'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 支持的文件扩展名(用于原始 URL 检测)
|
||||||
|
const supportedExtensions = ['html', 'htm', 'xlsx', 'xls', 'pdf', 'zip', 'rar', '7z', 'md', 'markdown',
|
||||||
|
'docx', 'doc', 'pptx', 'ppt', 'txt', 'csv', 'json', 'xml', 'yaml', 'yml',
|
||||||
|
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'webp', 'ico', 'tiff', 'tif', 'dxf'
|
||||||
|
]
|
||||||
|
const extPattern = supportedExtensions.join('|')
|
||||||
|
|
||||||
// Markdown转HTML节点
|
// Markdown转HTML节点
|
||||||
const pareseMarkdown = (content) => {
|
const pareseMarkdown = (content) => {
|
||||||
if (!content) return ''
|
if (!content) return ''
|
||||||
@@ -476,14 +505,60 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
try {
|
try {
|
||||||
// 转义单词中的单下划线,防止 snarkdown 误解析为斜体
|
// 转义单词中的单下划线,防止 snarkdown 误解析为斜体
|
||||||
content = escapeLoneUnderscores(content)
|
content = escapeLoneUnderscores(content)
|
||||||
|
|
||||||
|
// 修复1: URL 中的中文括号编码,防止 snarkdown 截断URL
|
||||||
|
// [text](http://xxx/高二(1)班.xlsx) → [text](http://xxx/高二%281%29班.xlsx)
|
||||||
|
content = content.replace(
|
||||||
|
/\[([^\]]+)\]\((https?:\/\/[^\s]+)\)/g,
|
||||||
|
(m, name, url) => '[' + name + '](' + url.replace(/\(/g, '%28').replace(/\)/g, '%29') + ')'
|
||||||
|
)
|
||||||
|
|
||||||
|
// 修复2: 误用括号 [高二](1)班成绩表 → 高二(1)班成绩表
|
||||||
|
// 当 (数字/短文本) 后紧跟中文时,说明不是真实URL,还原为纯文本
|
||||||
|
content = content.replace(
|
||||||
|
/\[([^\]]+)\]\((\d{1,2}|[^\s)]{1,3})\)(?=[\u4e00-\u9fff])/g,
|
||||||
|
'$1($2)'
|
||||||
|
)
|
||||||
|
|
||||||
// 先转换表格,再用 snarkdown 处理其他 Markdown
|
// 先转换表格,再用 snarkdown 处理其他 Markdown
|
||||||
content = convertMarkdownTable(content)
|
content = convertMarkdownTable(content)
|
||||||
let html = snarkdown(content)
|
let html = snarkdown(content)
|
||||||
// 将 <a href="..."> 替换为自定义 span,避免 WebView 触发默认下载
|
|
||||||
|
// 步骤1:暂存 <a> 标签,避免 raw URL 替换误伤 href 内的链接
|
||||||
|
const linkPlaceholders = []
|
||||||
html = html.replace(
|
html = html.replace(
|
||||||
/<a\s+href="([^"]*)"[^>]*>(.*?)<\/a>/gi,
|
/<a\s+href="([^"]*)"[^>]*>(.*?)<\/a>/gi,
|
||||||
'<span class="chat-inline-link" data-url="$1">$2</span>'
|
(match, href, innerText) => {
|
||||||
|
const idx = linkPlaceholders.length
|
||||||
|
linkPlaceholders.push({ href, innerText })
|
||||||
|
return '\x00LINK_' + idx + '\x00'
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 步骤2:将正文中的原始文件 URL 替换为下载按钮
|
||||||
|
const rawUrlRegex = new RegExp(
|
||||||
|
`https?://[^\\s<>"'']+\\.(${extPattern})(?:[?#][^\\s<>"'']*)?`,
|
||||||
|
'gi'
|
||||||
|
)
|
||||||
|
html = html.replace(rawUrlRegex, (url) => {
|
||||||
|
return renderDownloadBtn(url)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 步骤3:恢复 <a> 标签并分类处理
|
||||||
|
html = html.replace(/\x00LINK_(\d+)\x00/g, (_, idx) => {
|
||||||
|
const { href, innerText } = linkPlaceholders[idx]
|
||||||
|
if (isDownloadLink(href)) {
|
||||||
|
const plainText = innerText
|
||||||
|
.replace(/<[^>]*>/g, ' ')
|
||||||
|
.replace(/ /gi, ' ')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim()
|
||||||
|
return renderDownloadBtn(href, plainText)
|
||||||
|
}
|
||||||
|
// 普通链接保持原有样式
|
||||||
|
return '<span class="chat-inline-link" data-url="' + href + '">' + innerText + '</span>'
|
||||||
|
})
|
||||||
|
|
||||||
return html
|
return html
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析失败', e)
|
console.error('解析失败', e)
|
||||||
@@ -839,6 +914,50 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
}
|
}
|
||||||
return urlStr
|
return urlStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 文件类型 → 图标和标签映射
|
||||||
|
const getFileTypeInfo = (ext) => {
|
||||||
|
const map = {
|
||||||
|
// 文档类
|
||||||
|
pdf: { emoji: '📕', label: 'PDF', color: '#e74c3c' },
|
||||||
|
doc: { emoji: '📘', label: 'Word', color: '#2b579a' },
|
||||||
|
docx: { emoji: '📘', label: 'Word', color: '#2b579a' },
|
||||||
|
xls: { emoji: '📗', label: 'Excel', color: '#217346' },
|
||||||
|
xlsx: { emoji: '📗', label: 'Excel', color: '#217346' },
|
||||||
|
ppt: { emoji: '📙', label: 'PPT', color: '#d24726' },
|
||||||
|
pptx: { emoji: '📙', label: 'PPT', color: '#d24726' },
|
||||||
|
txt: { emoji: '📄', label: '文本', color: '#666' },
|
||||||
|
md: { emoji: '📝', label: 'Markdown', color: '#333' },
|
||||||
|
markdown: { emoji: '📝', label: 'Markdown', color: '#333' },
|
||||||
|
csv: { emoji: '📊', label: 'CSV', color: '#217346' },
|
||||||
|
json: { emoji: '📋', label: 'JSON', color: '#f0a500' },
|
||||||
|
xml: { emoji: '📋', label: 'XML', color: '#e67e22' },
|
||||||
|
yaml: { emoji: '📋', label: 'YAML', color: '#e67e22' },
|
||||||
|
yml: { emoji: '📋', label: 'YAML', color: '#e67e22' },
|
||||||
|
// 压缩包
|
||||||
|
zip: { emoji: '📦', label: 'ZIP', color: '#f39c12' },
|
||||||
|
rar: { emoji: '📦', label: 'RAR', color: '#f39c12' },
|
||||||
|
'7z': { emoji: '📦', label: '7Z', color: '#f39c12' },
|
||||||
|
// 网页
|
||||||
|
html: { emoji: '🌐', label: '网页', color: '#e44d26' },
|
||||||
|
htm: { emoji: '🌐', label: '网页', color: '#e44d26' },
|
||||||
|
// 图片
|
||||||
|
jpg: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
jpeg: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
png: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
gif: { emoji: '🖼️', label: 'GIF', color: '#9b59b6' },
|
||||||
|
bmp: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
svg: { emoji: '🖼️', label: 'SVG', color: '#9b59b6' },
|
||||||
|
webp: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
ico: { emoji: '🖼️', label: '图标', color: '#9b59b6' },
|
||||||
|
tiff: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
tif: { emoji: '🖼️', label: '图片', color: '#9b59b6' },
|
||||||
|
// CAD/设计类
|
||||||
|
dxf: { emoji: '📐', label: 'CAD/DXF', color: '#2c3e50' },
|
||||||
|
}
|
||||||
|
return map[ext] || { emoji: '📎', label: ext.toUpperCase(), color: '#888' }
|
||||||
|
}
|
||||||
|
|
||||||
const showMessageDetail = (message) => {
|
const showMessageDetail = (message) => {
|
||||||
detailLinks.value = extractLinks(message.content || '')
|
detailLinks.value = extractLinks(message.content || '')
|
||||||
showMessageModal.value = true
|
showMessageModal.value = true
|
||||||
@@ -1381,7 +1500,8 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
const takeConversationMessages = async () => {
|
const takeConversationMessages = async () => {
|
||||||
try {
|
try {
|
||||||
allmessages.value = await getConversationMessages(userToken.value, currentSessionId.value) || [];
|
allmessages.value = await getConversationMessages(userToken.value, currentSessionId.value) || [];
|
||||||
// console.log("获取到的所有消息:", JSON.stringify(allmessages.value) );
|
console.log("获取到的所有消息:", JSON.stringify(allmessages.value) );
|
||||||
|
console.log("获取到的所有消息:", allmessages.value);
|
||||||
// currentMessages.value = allmessages.value.slice(-pageInfoNumber);
|
// currentMessages.value = allmessages.value.slice(-pageInfoNumber);
|
||||||
// 数据获取后执行滚动
|
// 数据获取后执行滚动
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
@@ -1654,6 +1774,43 @@ import { openFile as openFileNative, downloadAndOpen } from '@/utils/fileOpener.
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 可下载文件链接 → 按钮卡片样式 */
|
||||||
|
.chat-download-btn {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
padding: 8rpx 14rpx;
|
||||||
|
margin: 4rpx 0;
|
||||||
|
background: #f5f7fb;
|
||||||
|
border: 2rpx solid #e4e8f0;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: #333 !important;
|
||||||
|
word-break: break-all;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #eef1f7;
|
||||||
|
border-color: #c8cde0;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-dl-icon {
|
||||||
|
font-size: 26rpx !important;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-dl-name {
|
||||||
|
font-size: 16px !important;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 流式气泡中的加载动画 */
|
/* 流式气泡中的加载动画 */
|
||||||
|
|||||||
227
unpackage/dist/dev/app-plus/app-service.js
vendored
227
unpackage/dist/dev/app-plus/app-service.js
vendored
@@ -5800,21 +5800,127 @@ This will fail in production.`);
|
|||||||
text = text.replace(/\x00\x00/g, "__");
|
text = text.replace(/\x00\x00/g, "__");
|
||||||
return text;
|
return text;
|
||||||
};
|
};
|
||||||
|
const isDownloadLink = (url) => {
|
||||||
|
const supportedExtensions2 = [
|
||||||
|
"html",
|
||||||
|
"htm",
|
||||||
|
"xlsx",
|
||||||
|
"xls",
|
||||||
|
"pdf",
|
||||||
|
"zip",
|
||||||
|
"rar",
|
||||||
|
"7z",
|
||||||
|
"md",
|
||||||
|
"markdown",
|
||||||
|
"docx",
|
||||||
|
"doc",
|
||||||
|
"pptx",
|
||||||
|
"ppt",
|
||||||
|
"txt",
|
||||||
|
"csv",
|
||||||
|
"json",
|
||||||
|
"xml",
|
||||||
|
"yaml",
|
||||||
|
"yml",
|
||||||
|
"jpg",
|
||||||
|
"jpeg",
|
||||||
|
"png",
|
||||||
|
"gif",
|
||||||
|
"bmp",
|
||||||
|
"svg",
|
||||||
|
"webp",
|
||||||
|
"ico",
|
||||||
|
"tiff",
|
||||||
|
"tif",
|
||||||
|
"dxf"
|
||||||
|
];
|
||||||
|
const extPattern2 = supportedExtensions2.join("|");
|
||||||
|
const extRegex = new RegExp(`\\.(${extPattern2})(?:\\?|$)`, "i");
|
||||||
|
return extRegex.test(url);
|
||||||
|
};
|
||||||
|
const renderDownloadBtn = (href, displayName) => {
|
||||||
|
const ext = ((href.split(".").pop() || "").split("?")[0] || "").toLowerCase();
|
||||||
|
const fileInfo = getFileTypeInfo(ext);
|
||||||
|
const name2 = displayName || extractFileNameFromUrl(href);
|
||||||
|
return '<span class="chat-inline-link chat-download-btn" data-url="' + href + '"><span class="chat-dl-icon">' + fileInfo.emoji + '</span><span class="chat-dl-name">' + name2 + "</span></span>";
|
||||||
|
};
|
||||||
|
const supportedExtensions = [
|
||||||
|
"html",
|
||||||
|
"htm",
|
||||||
|
"xlsx",
|
||||||
|
"xls",
|
||||||
|
"pdf",
|
||||||
|
"zip",
|
||||||
|
"rar",
|
||||||
|
"7z",
|
||||||
|
"md",
|
||||||
|
"markdown",
|
||||||
|
"docx",
|
||||||
|
"doc",
|
||||||
|
"pptx",
|
||||||
|
"ppt",
|
||||||
|
"txt",
|
||||||
|
"csv",
|
||||||
|
"json",
|
||||||
|
"xml",
|
||||||
|
"yaml",
|
||||||
|
"yml",
|
||||||
|
"jpg",
|
||||||
|
"jpeg",
|
||||||
|
"png",
|
||||||
|
"gif",
|
||||||
|
"bmp",
|
||||||
|
"svg",
|
||||||
|
"webp",
|
||||||
|
"ico",
|
||||||
|
"tiff",
|
||||||
|
"tif",
|
||||||
|
"dxf"
|
||||||
|
];
|
||||||
|
const extPattern = supportedExtensions.join("|");
|
||||||
const pareseMarkdown = (content) => {
|
const pareseMarkdown = (content) => {
|
||||||
if (!content)
|
if (!content)
|
||||||
return "";
|
return "";
|
||||||
content = sanitizeContent(content);
|
content = sanitizeContent(content);
|
||||||
try {
|
try {
|
||||||
content = escapeLoneUnderscores(content);
|
content = escapeLoneUnderscores(content);
|
||||||
|
content = content.replace(
|
||||||
|
/\[([^\]]+)\]\((https?:\/\/[^\s]+)\)/g,
|
||||||
|
(m, name2, url) => "[" + name2 + "](" + url.replace(/\(/g, "%28").replace(/\)/g, "%29") + ")"
|
||||||
|
);
|
||||||
|
content = content.replace(
|
||||||
|
/\[([^\]]+)\]\((\d{1,2}|[^\s)]{1,3})\)(?=[\u4e00-\u9fff])/g,
|
||||||
|
"$1($2)"
|
||||||
|
);
|
||||||
content = convertMarkdownTable(content);
|
content = convertMarkdownTable(content);
|
||||||
let html = t(content);
|
let html = t(content);
|
||||||
|
const linkPlaceholders = [];
|
||||||
html = html.replace(
|
html = html.replace(
|
||||||
/<a\s+href="([^"]*)"[^>]*>(.*?)<\/a>/gi,
|
/<a\s+href="([^"]*)"[^>]*>(.*?)<\/a>/gi,
|
||||||
'<span class="chat-inline-link" data-url="$1">$2</span>'
|
(match, href, innerText) => {
|
||||||
|
const idx = linkPlaceholders.length;
|
||||||
|
linkPlaceholders.push({ href, innerText });
|
||||||
|
return "\0LINK_" + idx + "\0";
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
const rawUrlRegex = new RegExp(
|
||||||
|
`https?://[^\\s<>"'']+\\.(${extPattern})(?:[?#][^\\s<>"'']*)?`,
|
||||||
|
"gi"
|
||||||
|
);
|
||||||
|
html = html.replace(rawUrlRegex, (url) => {
|
||||||
|
return renderDownloadBtn(url);
|
||||||
|
});
|
||||||
|
html = html.replace(/\x00LINK_(\d+)\x00/g, (_, idx) => {
|
||||||
|
const { href, innerText } = linkPlaceholders[idx];
|
||||||
|
if (isDownloadLink(href)) {
|
||||||
|
const plainText = innerText.replace(/<[^>]*>/g, " ").replace(/ /gi, " ").replace(/\s+/g, " ").trim();
|
||||||
|
return renderDownloadBtn(href, plainText);
|
||||||
|
}
|
||||||
|
return '<span class="chat-inline-link" data-url="' + href + '">' + innerText + "</span>";
|
||||||
|
});
|
||||||
return html;
|
return html;
|
||||||
} catch (e2) {
|
} catch (e2) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:489", "解析失败", e2);
|
formatAppLog("error", "at pages/Chat/Chat.vue:564", "解析失败", e2);
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -5865,7 +5971,7 @@ This will fail in production.`);
|
|||||||
files
|
files
|
||||||
};
|
};
|
||||||
} catch (e2) {
|
} catch (e2) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:558", "解析文件信息失败:", e2);
|
formatAppLog("error", "at pages/Chat/Chat.vue:633", "解析文件信息失败:", e2);
|
||||||
return {
|
return {
|
||||||
textContent: content,
|
textContent: content,
|
||||||
files: []
|
files: []
|
||||||
@@ -5903,7 +6009,7 @@ This will fail in production.`);
|
|||||||
closeNewChatModal();
|
closeNewChatModal();
|
||||||
takeUserConversations();
|
takeUserConversations();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:604", "新建普通会话失败:", error);
|
formatAppLog("error", "at pages/Chat/Chat.vue:679", "新建普通会话失败:", error);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "创建会话失败,请重试",
|
title: "创建会话失败,请重试",
|
||||||
icon: "none"
|
icon: "none"
|
||||||
@@ -5946,7 +6052,7 @@ This will fail in production.`);
|
|||||||
};
|
};
|
||||||
const previewFileArray = vue.ref([]);
|
const previewFileArray = vue.ref([]);
|
||||||
const uploadPhoto = () => {
|
const uploadPhoto = () => {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:664", "点击了拍照上传");
|
formatAppLog("log", "at pages/Chat/Chat.vue:739", "点击了拍照上传");
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 1,
|
count: 1,
|
||||||
sourceType: ["camera", "album"],
|
sourceType: ["camera", "album"],
|
||||||
@@ -5969,7 +6075,7 @@ This will fail in production.`);
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:682", "选择图片失败", err);
|
formatAppLog("error", "at pages/Chat/Chat.vue:757", "选择图片失败", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -5978,12 +6084,12 @@ This will fail in production.`);
|
|||||||
};
|
};
|
||||||
const fileList = vue.ref([]);
|
const fileList = vue.ref([]);
|
||||||
const uploadFile = () => {
|
const uploadFile = () => {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:693", "点击了上传文件");
|
formatAppLog("log", "at pages/Chat/Chat.vue:768", "点击了上传文件");
|
||||||
chooseFile({
|
chooseFile({
|
||||||
count: 5,
|
count: 5,
|
||||||
type: "all",
|
type: "all",
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:698", "成功了");
|
formatAppLog("log", "at pages/Chat/Chat.vue:773", "成功了");
|
||||||
fileList.value = res.tempFiles;
|
fileList.value = res.tempFiles;
|
||||||
previewFileArray.value.push(...res.tempFiles);
|
previewFileArray.value.push(...res.tempFiles);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -5992,7 +6098,7 @@ This will fail in production.`);
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:709", "选择失败:", err);
|
formatAppLog("error", "at pages/Chat/Chat.vue:784", "选择失败:", err);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "选择失败",
|
title: "选择失败",
|
||||||
icon: "error"
|
icon: "error"
|
||||||
@@ -6096,6 +6202,47 @@ This will fail in production.`);
|
|||||||
}
|
}
|
||||||
return urlStr;
|
return urlStr;
|
||||||
};
|
};
|
||||||
|
const getFileTypeInfo = (ext) => {
|
||||||
|
const map = {
|
||||||
|
// 文档类
|
||||||
|
pdf: { emoji: "📕", label: "PDF", color: "#e74c3c" },
|
||||||
|
doc: { emoji: "📘", label: "Word", color: "#2b579a" },
|
||||||
|
docx: { emoji: "📘", label: "Word", color: "#2b579a" },
|
||||||
|
xls: { emoji: "📗", label: "Excel", color: "#217346" },
|
||||||
|
xlsx: { emoji: "📗", label: "Excel", color: "#217346" },
|
||||||
|
ppt: { emoji: "📙", label: "PPT", color: "#d24726" },
|
||||||
|
pptx: { emoji: "📙", label: "PPT", color: "#d24726" },
|
||||||
|
txt: { emoji: "📄", label: "文本", color: "#666" },
|
||||||
|
md: { emoji: "📝", label: "Markdown", color: "#333" },
|
||||||
|
markdown: { emoji: "📝", label: "Markdown", color: "#333" },
|
||||||
|
csv: { emoji: "📊", label: "CSV", color: "#217346" },
|
||||||
|
json: { emoji: "📋", label: "JSON", color: "#f0a500" },
|
||||||
|
xml: { emoji: "📋", label: "XML", color: "#e67e22" },
|
||||||
|
yaml: { emoji: "📋", label: "YAML", color: "#e67e22" },
|
||||||
|
yml: { emoji: "📋", label: "YAML", color: "#e67e22" },
|
||||||
|
// 压缩包
|
||||||
|
zip: { emoji: "📦", label: "ZIP", color: "#f39c12" },
|
||||||
|
rar: { emoji: "📦", label: "RAR", color: "#f39c12" },
|
||||||
|
"7z": { emoji: "📦", label: "7Z", color: "#f39c12" },
|
||||||
|
// 网页
|
||||||
|
html: { emoji: "🌐", label: "网页", color: "#e44d26" },
|
||||||
|
htm: { emoji: "🌐", label: "网页", color: "#e44d26" },
|
||||||
|
// 图片
|
||||||
|
jpg: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
jpeg: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
png: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
gif: { emoji: "🖼️", label: "GIF", color: "#9b59b6" },
|
||||||
|
bmp: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
svg: { emoji: "🖼️", label: "SVG", color: "#9b59b6" },
|
||||||
|
webp: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
ico: { emoji: "🖼️", label: "图标", color: "#9b59b6" },
|
||||||
|
tiff: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
tif: { emoji: "🖼️", label: "图片", color: "#9b59b6" },
|
||||||
|
// CAD/设计类
|
||||||
|
dxf: { emoji: "📐", label: "CAD/DXF", color: "#2c3e50" }
|
||||||
|
};
|
||||||
|
return map[ext] || { emoji: "📎", label: ext.toUpperCase(), color: "#888" };
|
||||||
|
};
|
||||||
const showMessageDetail = (message) => {
|
const showMessageDetail = (message) => {
|
||||||
detailLinks.value = extractLinks(message.content || "");
|
detailLinks.value = extractLinks(message.content || "");
|
||||||
showMessageModal.value = true;
|
showMessageModal.value = true;
|
||||||
@@ -6190,7 +6337,7 @@ This will fail in production.`);
|
|||||||
previewFileArray.value = [];
|
previewFileArray.value = [];
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:940", "文件上传失败:", err);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1059", "文件上传失败:", err);
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: "文件上传失败,请重试",
|
title: "文件上传失败,请重试",
|
||||||
icon: "error"
|
icon: "error"
|
||||||
@@ -6324,15 +6471,15 @@ This will fail in production.`);
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const stopConversation = async () => {
|
const stopConversation = async () => {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1110", "中断对话 - 当前会话ID:", currentSessionId.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1229", "中断对话 - 当前会话ID:", currentSessionId.value);
|
||||||
try {
|
try {
|
||||||
await socketStore.send({
|
await socketStore.send({
|
||||||
type: "stop",
|
type: "stop",
|
||||||
conversation_id: currentSessionId.value
|
conversation_id: currentSessionId.value
|
||||||
});
|
});
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1116", "中断指令已发送成功");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1235", "中断指令已发送成功");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:1118", "中断指令发送失败:", err);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1237", "中断指令发送失败:", err);
|
||||||
}
|
}
|
||||||
if (streamingMessageId.value) {
|
if (streamingMessageId.value) {
|
||||||
allmessages.value = allmessages.value.filter((m) => m._id !== streamingMessageId.value);
|
allmessages.value = allmessages.value.filter((m) => m._id !== streamingMessageId.value);
|
||||||
@@ -6350,9 +6497,9 @@ This will fail in production.`);
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
vue.watch(() => socketStore.isThinking, (newVal, oldVal) => {
|
vue.watch(() => socketStore.isThinking, (newVal, oldVal) => {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1142", "isThinking 变化:", oldVal, "→", newVal, "messageString:", socketStore.messageString);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1261", "isThinking 变化:", oldVal, "→", newVal, "messageString:", socketStore.messageString);
|
||||||
if (!oldVal && newVal) {
|
if (!oldVal && newVal) {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1145", "AI开始回复(跨设备同步),锁定输入框");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1264", "AI开始回复(跨设备同步),锁定输入框");
|
||||||
isThinking.value = true;
|
isThinking.value = true;
|
||||||
if (!streamingMessageId.value) {
|
if (!streamingMessageId.value) {
|
||||||
streamingMessageId.value = "streaming-" + Date.now();
|
streamingMessageId.value = "streaming-" + Date.now();
|
||||||
@@ -6366,7 +6513,7 @@ This will fail in production.`);
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (oldVal && !newVal) {
|
if (oldVal && !newVal) {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1161", "AI回复结束(正常/中断),解锁并刷新消息列表");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1280", "AI回复结束(正常/中断),解锁并刷新消息列表");
|
||||||
if (streamingMessageId.value) {
|
if (streamingMessageId.value) {
|
||||||
allmessages.value = allmessages.value.filter((m) => m._id !== streamingMessageId.value);
|
allmessages.value = allmessages.value.filter((m) => m._id !== streamingMessageId.value);
|
||||||
streamingMessageId.value = null;
|
streamingMessageId.value = null;
|
||||||
@@ -6420,15 +6567,15 @@ This will fail in production.`);
|
|||||||
UserData.value = await getUserInfo(userToken.value);
|
UserData.value = await getUserInfo(userToken.value);
|
||||||
UserId.value = UserData.value._id;
|
UserId.value = UserData.value._id;
|
||||||
UserAvatar.value = UserData.value.avatar || "";
|
UserAvatar.value = UserData.value.avatar || "";
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1227", "用户信息已加载:", UserId.value, UserAvatar.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1346", "用户信息已加载:", UserId.value, UserAvatar.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:1229", "获取用户信息失败:", error);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1348", "获取用户信息失败:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const takeUserConversations = async () => {
|
const takeUserConversations = async () => {
|
||||||
try {
|
try {
|
||||||
userToken.value = getToken();
|
userToken.value = getToken();
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1237", "token:", userToken.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1356", "token:", userToken.value);
|
||||||
UserConversations.value = await getUserConversations(userToken.value) || [];
|
UserConversations.value = await getUserConversations(userToken.value) || [];
|
||||||
const savedSessionId = getCurrentSessionId();
|
const savedSessionId = getCurrentSessionId();
|
||||||
if (savedSessionId && UserConversations.value.some((c) => c._id === savedSessionId)) {
|
if (savedSessionId && UserConversations.value.some((c) => c._id === savedSessionId)) {
|
||||||
@@ -6438,7 +6585,7 @@ This will fail in production.`);
|
|||||||
} else {
|
} else {
|
||||||
currentSessionId.value = "";
|
currentSessionId.value = "";
|
||||||
}
|
}
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1249", "保存会话id:", currentSessionId.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1368", "保存会话id:", currentSessionId.value);
|
||||||
uni.setStorageSync("currentSessionId", currentSessionId.value);
|
uni.setStorageSync("currentSessionId", currentSessionId.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -6450,17 +6597,17 @@ This will fail in production.`);
|
|||||||
const FriendInfoList = vue.ref([]);
|
const FriendInfoList = vue.ref([]);
|
||||||
const takeFriendList = async () => {
|
const takeFriendList = async () => {
|
||||||
try {
|
try {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1264", "开始获取好友列表");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1383", "开始获取好友列表");
|
||||||
const friendList = await getChatFriend(UserId.value);
|
const friendList = await getChatFriend(UserId.value);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1267", "friendList:", friendList);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1386", "friendList:", friendList);
|
||||||
if (friendList && friendList.length) {
|
if (friendList && friendList.length) {
|
||||||
FriendInfoList.value = await takeUserAvatar(friendList);
|
FriendInfoList.value = await takeUserAvatar(friendList);
|
||||||
} else {
|
} else {
|
||||||
FriendInfoList.value = [];
|
FriendInfoList.value = [];
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1272", "好友列表为空");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1391", "好友列表为空");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:1275", "获取好友列表失败:", error);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1394", "获取好友列表失败:", error);
|
||||||
FriendInfoList.value = [];
|
FriendInfoList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
UserConversations.value = FriendInfoList.value;
|
UserConversations.value = FriendInfoList.value;
|
||||||
@@ -6487,17 +6634,17 @@ This will fail in production.`);
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:1305", "获取好友头像失败", err);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1424", "获取好友头像失败", err);
|
||||||
return friendList;
|
return friendList;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const GroupList = vue.ref([]);
|
const GroupList = vue.ref([]);
|
||||||
const takeGroupList = async () => {
|
const takeGroupList = async () => {
|
||||||
try {
|
try {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1315", "开始获取群聊列表");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1434", "开始获取群聊列表");
|
||||||
GroupList.value = await getGroup(UserId.value);
|
GroupList.value = await getGroup(UserId.value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:1320", "获取群聊列表失败:", error);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1439", "获取群聊列表失败:", error);
|
||||||
GroupList.value = [];
|
GroupList.value = [];
|
||||||
} finally {
|
} finally {
|
||||||
UserConversations.value = GroupList.value;
|
UserConversations.value = GroupList.value;
|
||||||
@@ -6509,22 +6656,22 @@ This will fail in production.`);
|
|||||||
return [];
|
return [];
|
||||||
try {
|
try {
|
||||||
const memberIds = memberList.map((item) => item.groupContactId);
|
const memberIds = memberList.map((item) => item.groupContactId);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1334", "请求头像的ID列表:", memberIds);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1453", "请求头像的ID列表:", memberIds);
|
||||||
const memberAvatarList = await getUserAvatar(userToken.value, memberIds);
|
const memberAvatarList = await getUserAvatar(userToken.value, memberIds);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1336", "头像接口返回数据:", memberAvatarList);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1455", "头像接口返回数据:", memberAvatarList);
|
||||||
const userMap = new Map(memberAvatarList.map((user) => [user.user_id, user]) || []);
|
const userMap = new Map(memberAvatarList.map((user) => [user.user_id, user]) || []);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1339", "userMap的keys:", Array.from(userMap.keys()));
|
formatAppLog("log", "at pages/Chat/Chat.vue:1458", "userMap的keys:", Array.from(userMap.keys()));
|
||||||
return memberList.map((member) => {
|
return memberList.map((member) => {
|
||||||
const memberId = member.groupContactId;
|
const memberId = member.groupContactId;
|
||||||
const userInfo = userMap.get(memberId);
|
const userInfo = userMap.get(memberId);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1344", `查找 ${memberId} 的头像:`, userInfo);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1463", `查找 ${memberId} 的头像:`, userInfo);
|
||||||
return {
|
return {
|
||||||
...member,
|
...member,
|
||||||
avatar: (userInfo == null ? void 0 : userInfo.avatar) || null
|
avatar: (userInfo == null ? void 0 : userInfo.avatar) || null
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
formatAppLog("error", "at pages/Chat/Chat.vue:1351", "获取群成员头像失败", err);
|
formatAppLog("error", "at pages/Chat/Chat.vue:1470", "获取群成员头像失败", err);
|
||||||
return memberList;
|
return memberList;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -6545,6 +6692,8 @@ This will fail in production.`);
|
|||||||
const takeConversationMessages = async () => {
|
const takeConversationMessages = async () => {
|
||||||
try {
|
try {
|
||||||
allmessages.value = await getConversationMessages(userToken.value, currentSessionId.value) || [];
|
allmessages.value = await getConversationMessages(userToken.value, currentSessionId.value) || [];
|
||||||
|
formatAppLog("log", "at pages/Chat/Chat.vue:1503", "获取到的所有消息:", JSON.stringify(allmessages.value));
|
||||||
|
formatAppLog("log", "at pages/Chat/Chat.vue:1504", "获取到的所有消息:", allmessages.value);
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -6571,12 +6720,12 @@ This will fail in production.`);
|
|||||||
const takeGroupMessages = async () => {
|
const takeGroupMessages = async () => {
|
||||||
try {
|
try {
|
||||||
allmessages.value = await getGroupMessages(currentSessionId.value) || [];
|
allmessages.value = await getGroupMessages(currentSessionId.value) || [];
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1415", "群聊消息:", allmessages.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1535", "群聊消息:", allmessages.value);
|
||||||
const memberList = await getGroupMemberList(currentSessionId.value);
|
const memberList = await getGroupMemberList(currentSessionId.value);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1418", "获取到的群成员列表:", memberList);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1538", "获取到的群成员列表:", memberList);
|
||||||
if (memberList && memberList.length) {
|
if (memberList && memberList.length) {
|
||||||
groupMemberList.value = await takeGroupMemberAvatar(memberList);
|
groupMemberList.value = await takeGroupMemberAvatar(memberList);
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1421", "群成员列表(带头像):", groupMemberList.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1541", "群成员列表(带头像):", groupMemberList.value);
|
||||||
} else {
|
} else {
|
||||||
groupMemberList.value = [];
|
groupMemberList.value = [];
|
||||||
}
|
}
|
||||||
@@ -6600,9 +6749,9 @@ This will fail in production.`);
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
vue.watch(() => friendSocketStore.MessageReceived, (newId) => {
|
vue.watch(() => friendSocketStore.MessageReceived, (newId) => {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1468", "收到了好友消息");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1588", "收到了好友消息");
|
||||||
if (newId) {
|
if (newId) {
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1470", "ChatType:", ChatType.value);
|
formatAppLog("log", "at pages/Chat/Chat.vue:1590", "ChatType:", ChatType.value);
|
||||||
switch (ChatType.value) {
|
switch (ChatType.value) {
|
||||||
case 0:
|
case 0:
|
||||||
takeConversationMessages();
|
takeConversationMessages();
|
||||||
@@ -6617,7 +6766,7 @@ This will fail in production.`);
|
|||||||
friendSocketStore.MessageReceived = false;
|
friendSocketStore.MessageReceived = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
formatAppLog("log", "at pages/Chat/Chat.vue:1486", "default 分支");
|
formatAppLog("log", "at pages/Chat/Chat.vue:1606", "default 分支");
|
||||||
friendSocketStore.MessageReceived = false;
|
friendSocketStore.MessageReceived = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -6696,7 +6845,7 @@ This will fail in production.`);
|
|||||||
onUnload(() => {
|
onUnload(() => {
|
||||||
socketStore.disconnect();
|
socketStore.disconnect();
|
||||||
});
|
});
|
||||||
const __returned__ = { friendSocketStore, handleFriendConnect, socketStore, ChatType, wyxdWorkspaceId, wyxdFilePath, wyxdFileName, wyxdUserToken, hasWyxdFile, convertMarkdownTable, renderTable, escapeLoneUnderscores, pareseMarkdown, sanitizeContent, previewImage, openFile: openFile$1, formatFileSize: formatFileSize2, parseFileInfo, selectNormalChat, showNewChatModal, closeNewChatModal, isChatSidebar, handleChatSidebar, goWorkSpace, goWyxdViewer, goCloudDatabase, logOut, previewFileArray, uploadPhoto, deleteImage, fileList, uploadFile, handleConnect, isThinking, isSelfSent, isUploading, isLoadingMessages, uploadedFiles, streamingMessageId, showMessageModal, detailLinks, handleChatContentClick, extractLinks, extractFileNameFromUrl, showMessageDetail, closeMessageDetail, downloadToast, get downloadToastTimer() {
|
const __returned__ = { friendSocketStore, handleFriendConnect, socketStore, ChatType, wyxdWorkspaceId, wyxdFilePath, wyxdFileName, wyxdUserToken, hasWyxdFile, convertMarkdownTable, renderTable, escapeLoneUnderscores, isDownloadLink, renderDownloadBtn, supportedExtensions, extPattern, pareseMarkdown, sanitizeContent, previewImage, openFile: openFile$1, formatFileSize: formatFileSize2, parseFileInfo, selectNormalChat, showNewChatModal, closeNewChatModal, isChatSidebar, handleChatSidebar, goWorkSpace, goWyxdViewer, goCloudDatabase, logOut, previewFileArray, uploadPhoto, deleteImage, fileList, uploadFile, handleConnect, isThinking, isSelfSent, isUploading, isLoadingMessages, uploadedFiles, streamingMessageId, showMessageModal, detailLinks, handleChatContentClick, extractLinks, extractFileNameFromUrl, getFileTypeInfo, showMessageDetail, closeMessageDetail, downloadToast, get downloadToastTimer() {
|
||||||
return downloadToastTimer;
|
return downloadToastTimer;
|
||||||
}, set downloadToastTimer(v) {
|
}, set downloadToastTimer(v) {
|
||||||
downloadToastTimer = v;
|
downloadToastTimer = v;
|
||||||
|
|||||||
33
unpackage/dist/dev/app-plus/pages/Chat/Chat.css
vendored
33
unpackage/dist/dev/app-plus/pages/Chat/Chat.css
vendored
@@ -1716,6 +1716,7 @@ to { opacity: 1; transform: translateY(0);
|
|||||||
/* 普通正文 */
|
/* 普通正文 */
|
||||||
/* 粗体和斜体样式 */
|
/* 粗体和斜体样式 */
|
||||||
/* 气泡内的内联链接(替代 <a> 标签,点击由 JS 拦截处理) */
|
/* 气泡内的内联链接(替代 <a> 标签,点击由 JS 拦截处理) */
|
||||||
|
/* 可下载文件链接 → 按钮卡片样式 */
|
||||||
}
|
}
|
||||||
.chat-content h1 {
|
.chat-content h1 {
|
||||||
font-size: 1.3125rem;
|
font-size: 1.3125rem;
|
||||||
@@ -1761,6 +1762,38 @@ to { opacity: 1; transform: translateY(0);
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
.chat-content .chat-download-btn {
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
padding: 0.25rem 0.4375rem;
|
||||||
|
margin: 0.125rem 0;
|
||||||
|
background: #f5f7fb;
|
||||||
|
border: 0.0625rem solid #e4e8f0;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: #333 !important;
|
||||||
|
word-break: break-all;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
.chat-content .chat-download-btn:active {
|
||||||
|
background: #eef1f7;
|
||||||
|
border-color: #c8cde0;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
.chat-content .chat-download-btn .chat-dl-icon {
|
||||||
|
font-size: 0.8125rem !important;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.chat-content .chat-download-btn .chat-dl-name {
|
||||||
|
font-size: 16px !important;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
/* 流式气泡中的加载动画 */
|
/* 流式气泡中的加载动画 */
|
||||||
.bubble-loading-dots {
|
.bubble-loading-dots {
|
||||||
|
|||||||
Reference in New Issue
Block a user