fix(personal): align assistant citations and UI state

This commit is contained in:
2026-07-12 12:07:28 +08:00
parent c8ef15ee9e
commit 36b7bf28bf
14 changed files with 181 additions and 61 deletions
+18 -26
View File
@@ -51,7 +51,7 @@
<text class="answer-text">{{ answer.answer }}</text>
<view v-if="answer.citations?.length" class="citation-list">
<text class="citation-heading">引用依据</text>
<button v-for="citation in answer.citations" :key="`${citation.domain}-${citation.sourceId}`" class="citation-card" @click="openCitation(citation)">
<button v-for="citation in answer.citations" :key="`${citation.domain}-${citation.sourceId}`" class="citation-card" :disabled="!citation.itemId" @click="openCitation(citation)">
<view class="citation-head">
<text class="domain-badge" :class="citation.domain.toLowerCase()">{{ citationLabel(citation) }}</text>
<text class="citation-title">{{ citation.title }}</text>
@@ -67,14 +67,14 @@
<script setup lang="ts">
import { computed, ref } from 'vue';
import type { PersonalAskResponse, PersonalCitation } from '@/types/api';
import { askPersonalAssistant, loadPersonalItem, type KnowledgeScope } from '@/services/personal-assistant';
import { askPersonalAssistant, type KnowledgeScope } from '@/services/personal-assistant';
const scopes = ref<KnowledgeScope[]>(['PERSONAL']);
const queryText = ref('');
const asking = ref(false);
const answer = ref<PersonalAskResponse>();
const message = ref('');
const citationSourceTypes = ref<Record<string, string>>({});
let requestGeneration = 0;
const enterpriseEnabled = computed(() => scopes.value.includes('ENTERPRISE'));
const toggleEnterprise = () => {
@@ -84,53 +84,45 @@ const toggleEnterprise = () => {
const submitQuestion = async () => {
const question = queryText.value.trim();
if (!question || asking.value) return;
const generation = ++requestGeneration;
asking.value = true;
answer.value = undefined;
message.value = '';
try {
answer.value = await askPersonalAssistant({ queryText: question, scope: scopes.value, outputFormat: 'ACTION_PLAN' });
await resolveCitationTypes(answer.value.citations || []);
const response = await askPersonalAssistant({ queryText: question, scope: scopes.value, outputFormat: 'ACTION_PLAN' });
if (generation !== requestGeneration) 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'];
message.value = '当前岗位没有企业知识权限,已仅查询我的资料。';
try {
answer.value = await askPersonalAssistant({ queryText: question, scope: ['PERSONAL'], outputFormat: 'ACTION_PLAN' });
await resolveCitationTypes(answer.value.citations || []);
const personalResponse = await askPersonalAssistant({ queryText: question, scope: ['PERSONAL'], outputFormat: 'ACTION_PLAN' });
if (generation !== requestGeneration) return;
answer.value = personalResponse;
} catch (personalError) {
if (generation !== requestGeneration) return;
answer.value = undefined;
message.value = personalError instanceof Error ? personalError.message : '我的资料查询失败,请稍后重试';
}
} else {
message.value = text;
}
} finally {
asking.value = false;
if (generation === requestGeneration) asking.value = false;
}
};
const resolveCitationTypes = async (citations: PersonalCitation[]) => {
const personalIds = Array.from(new Set(citations
.filter((citation) => citation.domain === 'PERSONAL' && /^\d+$/.test(citation.sourceId))
.map((citation) => citation.sourceId)));
const resolved = await Promise.all(personalIds.map(async (id) => {
try {
const item = await loadPersonalItem(Number(id));
return [id, item.sourceType] as const;
} catch {
return [id, ''] as const;
}
}));
citationSourceTypes.value = Object.fromEntries(resolved);
};
const citationLabel = (citation: PersonalCitation) => {
if (citation.domain === 'ENTERPRISE') return '企业 SOP';
return /^https?:/i.test(citation.sourceId) || citationSourceTypes.value[citation.sourceId] === 'URL' ? '外部网页' : '我的资料';
return citation.sourceType === 'URL' ? '外部网页' : '我的资料';
};
const openCitation = (citation: PersonalCitation) => {
if (citation.domain !== 'PERSONAL' || !/^\d+$/.test(citation.sourceId)) return;
uni.navigateTo({ url: `/pages/user/assistant/item?id=${encodeURIComponent(citation.sourceId)}` });
if (citation.domain !== 'PERSONAL' || !citation.itemId) return;
uni.navigateTo({ url: `/pages/user/assistant/item?id=${citation.itemId}` });
};
const goBack = () => uni.navigateBack();