fix(knowledge): make protected file downloads WebView-safe
This commit is contained in:
@@ -229,7 +229,7 @@
|
||||
<view class="resource-copy">
|
||||
<text class="resource-title">{{ resource.title }}</text>
|
||||
<text class="resource-meta">
|
||||
{{ resource.loading ? '正在安全读取…' : resource.type === 'VIDEO' ? (resource.localUrl ? '已加载,可直接播放' : '点击加载操作视频') : '点击查看或下载原文件' }}
|
||||
{{ resource.loading ? (resource.type === 'VIDEO' ? '正在安全读取…' : '正在生成安全下载链接…') : resource.type === 'VIDEO' ? (resource.localUrl ? '已加载,可直接播放' : '点击加载操作视频') : '点击下载原文件' }}
|
||||
</text>
|
||||
</view>
|
||||
<text class="resource-arrow">›</text>
|
||||
@@ -423,6 +423,7 @@ import {
|
||||
chooseKnowledgeMedia,
|
||||
generateSummaryCard,
|
||||
queryKnowledgeTool,
|
||||
requestKnowledgeResourceDownloadLink,
|
||||
searchKnowledge,
|
||||
searchKnowledgeWithMedia,
|
||||
submitAnswerFeedback
|
||||
@@ -1206,24 +1207,36 @@ const openKnowledgeResource = async (resource: KnowledgeResource) => {
|
||||
if (resource.type === 'VIDEO' && resource.localUrl) return;
|
||||
resource.loading = true;
|
||||
try {
|
||||
if (resource.type === 'FILE') {
|
||||
const downloadUrl = await requestKnowledgeResourceDownloadLink(resource.attachmentId);
|
||||
if (typeof document !== 'undefined') {
|
||||
const link = document.createElement('a');
|
||||
link.href = downloadUrl;
|
||||
link.target = '_blank';
|
||||
link.rel = 'noreferrer';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
return;
|
||||
}
|
||||
uni.downloadFile({
|
||||
url: downloadUrl,
|
||||
success: (response) => {
|
||||
if (response.statusCode >= 200 && response.statusCode < 300 && response.tempFilePath) {
|
||||
uni.openDocument({ filePath: response.tempFilePath, showMenu: true });
|
||||
return;
|
||||
}
|
||||
uni.showToast({ title: '文件下载失败,请稍后重试', icon: 'none' });
|
||||
},
|
||||
fail: () => uni.showToast({ title: '文件下载失败,请稍后重试', icon: 'none' })
|
||||
});
|
||||
return;
|
||||
}
|
||||
const localUrl = await authenticatedFileUrl(resource.contentUrl);
|
||||
if (resource.localUrl && resource.localUrl !== localUrl) {
|
||||
releaseAuthenticatedFileUrl(resource.localUrl);
|
||||
}
|
||||
resource.localUrl = localUrl;
|
||||
if (resource.type === 'FILE') {
|
||||
if (typeof document !== 'undefined') {
|
||||
const link = document.createElement('a');
|
||||
link.href = localUrl;
|
||||
link.download = resource.title || '资料文件';
|
||||
link.target = '_blank';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
link.remove();
|
||||
} else {
|
||||
uni.openDocument({ filePath: localUrl, showMenu: true });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
uni.showToast({ title: requestErrorText(error, '资料读取失败'), icon: 'none' });
|
||||
} finally {
|
||||
|
||||
@@ -167,6 +167,17 @@ export const queryKnowledgeTool = async (
|
||||
return normalizeUnifiedResponse(response);
|
||||
};
|
||||
|
||||
export const requestKnowledgeResourceDownloadLink = async (attachmentId: number) => {
|
||||
const response = await apiRequest<{ url: string }>({
|
||||
url: `/api/knowledge/resources/${encodeURIComponent(String(attachmentId))}/download-link`,
|
||||
method: 'POST'
|
||||
});
|
||||
if (!response.url?.startsWith('/api/knowledge/resources/')) {
|
||||
throw new Error('资料下载链接无效');
|
||||
}
|
||||
return apiUrl(response.url);
|
||||
};
|
||||
|
||||
const normalizeUnifiedResponse = (response: UnifiedKnowledgeResponse): KnowledgeSearchResponse => {
|
||||
const legacy = response.legacy || ({} as KnowledgeSearchResponse);
|
||||
const citationSnippets = (response.citations || []).map((item) => normalizeSnippet({
|
||||
|
||||
@@ -24,9 +24,13 @@ test('问师傅支持显式新对话、版本回写和受控原文件或视频
|
||||
assert.match(header, /class="new-chat-text">新对话/);
|
||||
assert.match(page, /const contextVersion = ref\(0\)/);
|
||||
assert.match(page, /applyConversationState\(nextResult\)/);
|
||||
assert.match(page, /requestKnowledgeResourceDownloadLink\(resource\.attachmentId\)/);
|
||||
assert.match(page, /authenticatedFileUrl\(resource\.contentUrl\)/);
|
||||
assert.match(page, /releaseAuthenticatedFileUrl\(resource\.localUrl\)/);
|
||||
assert.match(page, /resource\.type === 'VIDEO' && resource\.localUrl/);
|
||||
assert.doesNotMatch(page, /link\.href = localUrl/);
|
||||
assert.match(page, /link\.rel = 'noreferrer'/);
|
||||
assert.match(page, /点击下载原文件/);
|
||||
assert.match(page, /msg\.result\.rewrittenQuery !== msg\.result\.queryText/);
|
||||
assert.match(page, /已结合本次对话理解/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user