From 0d64cf0f21430239d09e96a921fcca34025daaed Mon Sep 17 00:00:00 2001 From: let5sne Date: Sun, 12 Jul 2026 12:15:02 +0800 Subject: [PATCH] fix(mobile): preserve assistant IDs and scope state --- mobile-uni/src/pages/user/assistant/index.vue | 22 ++++++++----- mobile-uni/src/pages/user/assistant/item.vue | 12 +++++-- .../src/pages/user/assistant/library.vue | 3 +- .../src/pages/user/assistant/sessions.vue | 9 +++--- .../src/services/personal-assistant-id.ts | 14 +++++++++ mobile-uni/src/services/personal-assistant.ts | 31 ++++++++++--------- mobile-uni/src/types/api.ts | 20 ++++++------ mobile-uni/tests/personal-assistant.test.mjs | 19 ++++++++++++ 8 files changed, 91 insertions(+), 39 deletions(-) create mode 100644 mobile-uni/src/services/personal-assistant-id.ts diff --git a/mobile-uni/src/pages/user/assistant/index.vue b/mobile-uni/src/pages/user/assistant/index.vue index 76321df3..174812f9 100644 --- a/mobile-uni/src/pages/user/assistant/index.vue +++ b/mobile-uni/src/pages/user/assistant/index.vue @@ -15,7 +15,7 @@ 我的资料 个人收藏,仅自己可见 - @@ -68,6 +68,7 @@ import { computed, ref } from 'vue'; import type { PersonalAskResponse, PersonalCitation } from '@/types/api'; import { askPersonalAssistant, type KnowledgeScope } from '@/services/personal-assistant'; +import { personalItemRoute } from '@/services/personal-assistant-id'; const scopes = ref(['PERSONAL']); const queryText = ref(''); @@ -77,7 +78,12 @@ const message = ref(''); let requestGeneration = 0; const enterpriseEnabled = computed(() => scopes.value.includes('ENTERPRISE')); -const toggleEnterprise = () => { +const scopeKey = (value: KnowledgeScope[]) => value.join(','); +const changeScope = () => { + if (asking.value) return; + requestGeneration += 1; + answer.value = undefined; + message.value = ''; scopes.value = enterpriseEnabled.value ? ['PERSONAL'] : ['PERSONAL', 'ENTERPRISE']; }; @@ -85,22 +91,24 @@ const submitQuestion = async () => { const question = queryText.value.trim(); if (!question || asking.value) return; const generation = ++requestGeneration; + const scopeSnapshot = [...scopes.value]; asking.value = true; answer.value = undefined; message.value = ''; try { - const response = await askPersonalAssistant({ queryText: question, scope: scopes.value, outputFormat: 'ACTION_PLAN' }); - if (generation !== requestGeneration) return; + const response = await askPersonalAssistant({ queryText: question, scope: scopeSnapshot, outputFormat: 'ACTION_PLAN' }); + if (generation !== requestGeneration || scopeKey(scopes.value) !== scopeKey(scopeSnapshot)) return; answer.value = response; } catch (error) { if (generation !== requestGeneration) return; const text = error instanceof Error ? error.message : '提问失败,请稍后重试'; if (enterpriseEnabled.value && /ENTERPRISE_SCOPE_FORBIDDEN|企业知识|FORBIDDEN/i.test(text)) { scopes.value = ['PERSONAL']; + const fallbackScope: KnowledgeScope[] = ['PERSONAL']; message.value = '当前岗位没有企业知识权限,已仅查询我的资料。'; try { - const personalResponse = await askPersonalAssistant({ queryText: question, scope: ['PERSONAL'], outputFormat: 'ACTION_PLAN' }); - if (generation !== requestGeneration) return; + const personalResponse = await askPersonalAssistant({ queryText: question, scope: fallbackScope, outputFormat: 'ACTION_PLAN' }); + if (generation !== requestGeneration || scopeKey(scopes.value) !== scopeKey(fallbackScope)) return; answer.value = personalResponse; } catch (personalError) { if (generation !== requestGeneration) return; @@ -122,7 +130,7 @@ const citationLabel = (citation: PersonalCitation) => { const openCitation = (citation: PersonalCitation) => { if (citation.domain !== 'PERSONAL' || !citation.itemId) return; - uni.navigateTo({ url: `/pages/user/assistant/item?id=${citation.itemId}` }); + uni.navigateTo({ url: personalItemRoute(citation.itemId) }); }; const goBack = () => uni.navigateBack(); diff --git a/mobile-uni/src/pages/user/assistant/item.vue b/mobile-uni/src/pages/user/assistant/item.vue index d3bccec6..3fc94928 100644 --- a/mobile-uni/src/pages/user/assistant/item.vue +++ b/mobile-uni/src/pages/user/assistant/item.vue @@ -34,8 +34,9 @@ import { ref } from 'vue'; import { onLoad } from '@dcloudio/uni-app'; import type { PersonalItem, PersonalItemSourceType, PersonalItemStatus } from '@/types/api'; import { deletePersonalItem, downloadPersonalItem, loadPersonalItem, retryPersonalItem } from '@/services/personal-assistant'; +import { normalizeBackendId } from '@/services/personal-assistant-id'; -const itemId = ref(0); const item = ref(); const loading = ref(false); const busy = ref(false); const message = ref(''); +const itemId = ref(''); const item = ref(); const loading = ref(false); const busy = ref(false); const message = ref(''); const statusText = (status: PersonalItemStatus) => ({ QUEUED: '等待处理', PARSING: '解析中', READY: '可检索', FAILED: '解析失败', DELETING: '删除中', DELETED: '已删除' })[status]; const statusDescription = (status: PersonalItemStatus) => ({ QUEUED: '已进入解析队列。', PARSING: '正在提取正文和建立搜索索引。', READY: '已完成解析,可用于个人助理问答。', FAILED: '本次解析失败,可查看公开原因后重试。', DELETING: '正在清理附件、正文和索引。', DELETED: '资料已删除。' })[status]; const sourceText = (source: PersonalItemSourceType) => ({ TEXT: '文字', FILE: '文件', URL: '外部网页' })[source]; @@ -45,7 +46,14 @@ const download = async () => { busy.value = true; try { const result = await dow const confirmDelete = () => uni.showModal({ title: '确认删除资料', content: '附件、解析正文和搜索索引会清除,删除后无法恢复。', confirmText: '确认删除', confirmColor: '#e70014', success: (result) => { if (result.confirm) void remove(); } }); const remove = async () => { busy.value = true; message.value = ''; try { await deletePersonalItem(itemId.value); uni.redirectTo({ url: '/pages/user/assistant/library' }); } catch (error) { message.value = error instanceof Error ? error.message : '删除失败,请重试'; } finally { busy.value = false; } }; const goBack = () => uni.navigateBack(); -onLoad((options) => { itemId.value = Number(options?.id || 0); if (!Number.isSafeInteger(itemId.value) || itemId.value <= 0) message.value = '资料不存在或无权访问'; else void load(); }); +onLoad((options) => { + try { + itemId.value = normalizeBackendId(String(options?.id || '')); + void load(); + } catch { + message.value = '资料不存在或无权访问'; + } +});