fix(frontend): improve offline and legacy browser support

This commit is contained in:
wizardchen
2026-05-21 11:04:53 +08:00
committed by lyingbug
parent 8f4626158d
commit 9f6148784a
4 changed files with 41 additions and 26 deletions

View File

@@ -24,7 +24,7 @@
"papaparse": "^5.5.3",
"pinia": "^3.0.4",
"swiper": "^12.1.4",
"tdesign-icons-vue-next": "^0.4.4",
"tdesign-icons-vue-next": "0.4.4",
"tdesign-vue-next": "^1.19.2",
"vue": "^3.5.34",
"vue-demi": "^0.14.10",

View File

@@ -28,7 +28,7 @@
"papaparse": "^5.5.3",
"pinia": "^3.0.4",
"swiper": "^12.1.4",
"tdesign-icons-vue-next": "^0.4.4",
"tdesign-icons-vue-next": "0.4.4",
"tdesign-vue-next": "^1.19.2",
"vue": "^3.5.34",
"vue-demi": "^0.14.10",
@@ -54,11 +54,13 @@
"overrides": {
"lightningcss": "none",
"esbuild": "^0.25.0",
"serialize-javascript": "^7.0.3"
"serialize-javascript": "^7.0.3",
"tdesign-icons-vue-next": "0.4.4"
},
"resolutions": {
"lightningcss": "none",
"esbuild": "^0.25.0",
"serialize-javascript": "^7.0.3"
"serialize-javascript": "^7.0.3",
"tdesign-icons-vue-next": "0.4.4"
}
}

View File

@@ -24,15 +24,15 @@ const SVG_SCRIPT_CLASS = "t-svg-js-stylesheet--unique-class";
const ICONFONT_LINK_CLASS = "t-iconfont-stylesheet--unique-class";
// 对齐 tdesign-icons-vue-next 0.4.x 内部硬编码的地址;多版本号并存以兼容潜在升级。
const BLOCKED_SCRIPT_URLS = [
"https://tdesign.gtimg.com/icon/0.4.0/fonts/index.js",
"https://tdesign.gtimg.com/icon/0.4.1/fonts/index.js",
];
const BLOCKED_ICON_VERSIONS = ["0.4.0", "0.4.1", "0.4.2", "0.4.3", "0.4.4"];
const BLOCKED_LINK_URLS = [
"https://tdesign.gtimg.com/icon/0.4.0/fonts/index.css",
"https://tdesign.gtimg.com/icon/0.4.1/fonts/index.css",
];
const BLOCKED_SCRIPT_URLS = BLOCKED_ICON_VERSIONS.map(
(version) => `https://tdesign.gtimg.com/icon/${version}/fonts/index.js`,
);
const BLOCKED_LINK_URLS = BLOCKED_ICON_VERSIONS.map(
(version) => `https://tdesign.gtimg.com/icon/${version}/fonts/index.css`,
);
let installed = false;

View File

@@ -274,6 +274,16 @@ const getUserQuery = (index) => {
}
return '';
};
const findLastMessage = (predicate) => {
for (let i = messagesList.length - 1; i >= 0; i--) {
const item = messagesList[i];
if (predicate(item)) {
return item;
}
}
return undefined;
};
watch([() => route.params], (newvalue) => {
isFirstEnter.value = true;
if (newvalue[0].chatid) {
@@ -732,7 +742,7 @@ onChunk((data) => {
});
// 检查是否是继续流式传输(消息已存在)
const existingMessage = messagesList.findLast((item) => item.id === data.id || item.request_id === data.id);
const existingMessage = findLastMessage((item) => item.id === data.id || item.request_id === data.id);
if (!existingMessage) {
// 新消息,设置 loading 状态
loading.value = true;
@@ -783,7 +793,7 @@ onChunk((data) => {
return;
}
// 非 Agent 模式:将 references 保存到消息中供 botmsg 使用
let existingMessage = messagesList.findLast((item) => item.request_id === data.id || item.id === data.id);
let existingMessage = findLastMessage((item) => item.request_id === data.id || item.id === data.id);
// 如果消息还不存在,先创建一个空的 assistant 消息
if (!existingMessage) {
@@ -831,7 +841,7 @@ onChunk((data) => {
// 文案拼进 content保留用户点停止时已经流式输出的内容不变。
if (data.response_type === 'stop') {
console.log('[Stop Event] Non-agent generation stopped');
const stoppedMessage = messagesList.findLast((item) => {
const stoppedMessage = findLastMessage((item) => {
if (item.request_id === data.id) return true;
return item.id === data.id;
});
@@ -846,7 +856,7 @@ onChunk((data) => {
}
// 检查消息是否已经完成,如果已完成则忽略后续的完成事件(防止空内容覆盖)
const existingMessage = messagesList.findLast((item) => {
const existingMessage = findLastMessage((item) => {
if (item.request_id === data.id) {
return true
}
@@ -902,7 +912,7 @@ onChunk((data) => {
})
// 处理 Agent 流式数据 (Cursor-style UI)
const handleAgentChunk = (data) => {
let message = messagesList.findLast((item) => item.request_id === data.id || item.id === data.id);
let message = findLastMessage((item) => item.request_id === data.id || item.id === data.id);
if (!message) {
// 创建新的 Assistant 消息 - 此时开始显示内容,关闭 loading
@@ -1266,7 +1276,7 @@ const handleAgentChunk = (data) => {
};
const updateAssistantSession = (payload) => {
const message = messagesList.findLast((item) => {
const message = findLastMessage((item) => {
if (item.request_id === payload.id) {
return true
}
@@ -1549,16 +1559,19 @@ onBeforeRouteUpdate((to, from, next) => {
width: 100%;
/*
给每条消息加 containment
- contain: layout paint style → 一条消息的内部布局/重绘不会让浏览器去 invalidate 整个文档
(之前 hover 到 session 列表也变白就是因为 invalidation 跨边界扩散)
- content-visibility: auto + contain-intrinsic-size → 视口外的消息直接跳过渲染,
极大降低长会话的 layout / paint 成本。
给每条消息加 layout/style containment
- 一条消息的内部布局变化不再让浏览器去 invalidate 整个文档
这是修掉"hover session 列表也变白"那个问题的关键
- 不要再用 content-visibility: auto / contain-intrinsic-size
agent 消息真实高度差异巨大(几百 ~ 数千 px估的占位高度会让消息进入视口时
反复发生"占位 -> 真实高度"的大幅 layout shift + 首次 paint 滞后,
反而在向上滚动时制造"未画完"的白屏闪烁
当前 handleMsgList 全流程 ~50ms根本无需跳过渲染老老实实正常渲染最稳
- 不开 contain: paintAgentStreamDisplay 里有 tooltip / popover 等会溢出的浮层
paint containment 会把它们裁掉
*/
.msg-item-wrapper {
contain: layout paint style;
content-visibility: auto;
contain-intrinsic-size: auto 400px;
contain: layout style;
}
.botanswer_laoding_gif {