feat(web): 工作台 AI 模式与差旅/风险建议交互优化

- 新增 PersonalWorkbenchAiMode 组件、AI 侧边栏与 orb 机器人视觉资源
- 新增 aiApplicationDraftModel / aiExpenseDraftModel / aiWorkbenchConversationStore
  及业务准入 aiSidebarBusinessAccess,支撑 AI 模式下的申请与报销草稿
- 顶栏、侧边栏、工作台样式重构,适配 AI 模式切换与响应式布局
- 同步 steward plan/off_topic、差旅报销引导流、风险建议卡片等测试
This commit is contained in:
caoxiaozhu
2026-06-18 22:12:24 +08:00
parent a6674a1e76
commit 0cde1f8990
65 changed files with 8011 additions and 1608 deletions

View File

@@ -9,7 +9,11 @@ import { fetchAllApprovalExpenseClaims, fetchExpenseClaimDetail } from '../servi
import { fetchOntologyParse } from '../services/ontology.js'
import { fetchLatestConversation } from '../services/orchestrator.js'
import { clearAssistantSessionSnapshotForDraftClaim } from '../utils/assistantSessionSnapshot.js'
import { ASSISTANT_SCOPE_SESSION_STEWARD } from '../utils/assistantSessionScope.js'
import {
ASSISTANT_SCOPE_SESSION_STEWARD,
buildUnsupportedBusinessScopeConversation,
resolveAssistantScopeGuard
} from '../utils/assistantSessionScope.js'
import { buildDetailAlerts } from '../utils/detailAlerts.js'
import { normalizeRequestForUi } from '../utils/requestViewModel.js'
import {
@@ -293,10 +297,11 @@ export function useAppShell() {
view === 'documents'
&& activeView.value === 'documents'
&& route.name === 'app-documents'
setView(view)
const navigation = setView(view)
if (shouldRefreshCurrentDocumentCenter) {
void reloadDocumentCenterRequests()
}
return navigation
}
function openFinancialAssistantCreate(source) {
@@ -459,6 +464,36 @@ export function useAppShell() {
smartEntryRevealToken.value += 1
return
}
const prompt = String(payload.prompt || '').trim()
const files = Array.isArray(payload.files) ? payload.files : []
const scopeGuard = prompt
? resolveAssistantScopeGuard(prompt, String(payload.sessionType || '').trim(), {
attachmentCount: files.length
})
: null
if (scopeGuard?.blocked) {
smartEntryOpen.value = true
smartEntryContext.value = {
prompt: '',
source: payload.source ?? 'workbench',
request: payload.request ?? selectedRequest.value,
files,
conversation: buildUnsupportedBusinessScopeConversation(prompt, {
attachmentCount: files.length
}),
scope: null,
sessionType: ASSISTANT_SCOPE_SESSION_STEWARD,
budgetContext: payload.budgetContext && typeof payload.budgetContext === 'object'
? payload.budgetContext
: null,
initialPromptAutoSubmit: false,
initialApplicationPreview: null
}
smartEntrySessionId.value += 1
return
}
const [conversation, sessionType] = await Promise.all([
resolveSmartEntryConversation(payload),
resolveSmartEntrySessionType(payload)

View File

@@ -147,7 +147,7 @@ export function useNavigation() {
return resolveAppViewFromRoute(route)
},
set(view) {
setView(view)
void setView(view)
}
})
@@ -159,10 +159,10 @@ export function useNavigation() {
const targetName = resolveTargetRouteName(view)
if (route.name === targetName) {
return
return Promise.resolve()
}
router.push({ name: targetName, params: {}, query: {}, hash: '' })
return router.push({ name: targetName, params: {}, query: {}, hash: '' })
}
return { activeView, currentView, setView, navItems }