|
|
@ -963,10 +963,11 @@ export function finalizeAIBubble(wrapper: HTMLElement, bubble: HTMLElement): voi |
|
|
// ==================== P1: RAG 引用来源渲染 ====================
|
|
|
// ==================== P1: RAG 引用来源渲染 ====================
|
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* 渲染 RAG 引用来源卡片(自定义折叠) |
|
|
|
|
|
|
|
|
* 渲染 RAG 引用来源卡片(t-button 折叠开关 + 自定义来源列表) |
|
|
* 说明:尝试用 <t-collapse> 替换,但 tdesign-web-components 的 collapse/collapse-panel |
|
|
* 说明:尝试用 <t-collapse> 替换,但 tdesign-web-components 的 collapse/collapse-panel |
|
|
* 依赖 omi 的 provide/inject 机制,在纯 DOM(createElement + appendChild)下无法建立 |
|
|
* 依赖 omi 的 provide/inject 机制,在纯 DOM(createElement + appendChild)下无法建立 |
|
|
* 注入链路(报 `this.injection.getCollapseValue is not a function`),故保留轻量自定义折叠。 |
|
|
|
|
|
|
|
|
* 注入链路(报 `this.injection.getCollapseValue is not a function`),故折叠开关改用 |
|
|
|
|
|
* t-button(标准组件、纯 DOM 可用),展开后的来源条目保留自定义渲染。 |
|
|
*/ |
|
|
*/ |
|
|
export function renderSources(wrapper: HTMLElement, sources: RagSource[]): void { |
|
|
export function renderSources(wrapper: HTMLElement, sources: RagSource[]): void { |
|
|
// 移除已有的来源卡片
|
|
|
// 移除已有的来源卡片
|
|
|
@ -978,24 +979,22 @@ export function renderSources(wrapper: HTMLElement, sources: RagSource[]): void |
|
|
const sourcesEl = document.createElement('div'); |
|
|
const sourcesEl = document.createElement('div'); |
|
|
sourcesEl.className = 'csk-sources csk-sources--collapsed'; |
|
|
sourcesEl.className = 'csk-sources csk-sources--collapsed'; |
|
|
|
|
|
|
|
|
// 头部
|
|
|
|
|
|
const header = document.createElement('div'); |
|
|
|
|
|
header.className = 'csk-sources__header'; |
|
|
|
|
|
|
|
|
|
|
|
const titleSpan = document.createElement('span'); |
|
|
|
|
|
titleSpan.className = 'csk-sources__title'; |
|
|
|
|
|
titleSpan.textContent = `📚 ${t('source_count', { n: sources.length })}`; |
|
|
|
|
|
|
|
|
|
|
|
const arrow = document.createElement('span'); |
|
|
|
|
|
arrow.className = 'csk-sources__arrow'; |
|
|
|
|
|
arrow.textContent = '▼'; |
|
|
|
|
|
|
|
|
|
|
|
header.appendChild(titleSpan); |
|
|
|
|
|
header.appendChild(arrow); |
|
|
|
|
|
|
|
|
// 折叠开关:t-button(标准组件,紧凑宽度,默认折叠)
|
|
|
|
|
|
const toggle = document.createElement('t-button'); |
|
|
|
|
|
toggle.className = 'csk-sources__toggle'; |
|
|
|
|
|
toggle.setAttribute('theme', 'default'); |
|
|
|
|
|
toggle.setAttribute('variant', 'text'); |
|
|
|
|
|
toggle.setAttribute('size', 'small'); |
|
|
|
|
|
|
|
|
// 点击折叠/展开
|
|
|
|
|
|
header.addEventListener('click', () => { |
|
|
|
|
|
|
|
|
const updateToggleLabel = () => { |
|
|
|
|
|
const collapsed = sourcesEl.classList.contains('csk-sources--collapsed'); |
|
|
|
|
|
toggle.textContent = `📚 ${t('source_count', { n: sources.length })} ${collapsed ? '▶' : '▼'}`; |
|
|
|
|
|
}; |
|
|
|
|
|
updateToggleLabel(); |
|
|
|
|
|
toggle.addEventListener('click', (e) => { |
|
|
|
|
|
e.stopPropagation(); |
|
|
sourcesEl.classList.toggle('csk-sources--collapsed'); |
|
|
sourcesEl.classList.toggle('csk-sources--collapsed'); |
|
|
|
|
|
updateToggleLabel(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// 内容
|
|
|
// 内容
|
|
|
@ -1030,7 +1029,7 @@ export function renderSources(wrapper: HTMLElement, sources: RagSource[]): void |
|
|
body.appendChild(item); |
|
|
body.appendChild(item); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
sourcesEl.appendChild(header); |
|
|
|
|
|
|
|
|
sourcesEl.appendChild(toggle); |
|
|
sourcesEl.appendChild(body); |
|
|
sourcesEl.appendChild(body); |
|
|
|
|
|
|
|
|
// 插入到消息气泡(t-chat-item)之后,作为来源卡片紧随气泡下方
|
|
|
// 插入到消息气泡(t-chat-item)之后,作为来源卡片紧随气泡下方
|
|
|
@ -1256,15 +1255,17 @@ export function renderSuggestions( |
|
|
list.className = 'csk-suggestions__list'; |
|
|
list.className = 'csk-suggestions__list'; |
|
|
|
|
|
|
|
|
for (const text of suggestions) { |
|
|
for (const text of suggestions) { |
|
|
// on* 回调(onClick)必须经 omi render 创建;tag 的 onClick 首参为原生事件,文本经 children 传入
|
|
|
|
|
|
createEventful('t-tag', { |
|
|
|
|
|
theme: 'primary', |
|
|
|
|
|
variant: 'light-outline', |
|
|
|
|
|
onClick: (e: Event) => { |
|
|
|
|
|
|
|
|
// t-button 走 slot 文本 + addEventListener(内部 fire 派发 CustomEvent),无需 omi render
|
|
|
|
|
|
const btn = document.createElement('t-button'); |
|
|
|
|
|
btn.textContent = text; |
|
|
|
|
|
btn.setAttribute('theme', 'default'); |
|
|
|
|
|
btn.setAttribute('variant', 'text'); |
|
|
|
|
|
btn.setAttribute('size', 'small'); |
|
|
|
|
|
btn.addEventListener('click', (e) => { |
|
|
e.stopPropagation(); |
|
|
e.stopPropagation(); |
|
|
onClick(text); |
|
|
onClick(text); |
|
|
}, |
|
|
|
|
|
}, list, text); |
|
|
|
|
|
|
|
|
}); |
|
|
|
|
|
list.appendChild(btn); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
section.appendChild(list); |
|
|
section.appendChild(list); |
|
|
|