feat: 报销预审会话状态管理与工作台交互增强

- 新增差旅报销会话状态管理与对话模型重构
- 增强风险观测服务与运行时聊天上下文作用域
- 优化工作台图标资源、助理意图识别与摘要工具
- 完善报销创建视图样式与差旅详情页标准调整交互
- 补充风险观测、运行时聊天与报销端点测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-04 11:03:29 +08:00
parent 87da5df91b
commit 1cbf3fee44
60 changed files with 4156 additions and 393 deletions

View File

@@ -16,6 +16,7 @@ import {
SESSION_TYPE_APPLICATION,
SESSION_TYPE_BUDGET,
SESSION_TYPE_EXPENSE,
SESSION_TYPE_STEWARD,
buildInitialInsightFromConversation,
buildWelcomeInsight,
buildWelcomeQuickActions,
@@ -35,6 +36,15 @@ import {
normalizeGuidedFlowState
} from './travelReimbursementGuidedFlowModel.js'
const STEWARD_IDLE_INSIGHT = {
intent: 'idle',
metricLabel: '',
metricValue: '',
title: '',
summary: '',
agent: null
}
export function useTravelReimbursementSessionState({
props,
currentUser,
@@ -79,6 +89,9 @@ export function useTravelReimbursementSessionState({
if (!Array.isArray(messages) || !messages.length) {
return []
}
if (isStewardSessionType(sessionType)) {
return messages.filter((message) => !message?.isWelcome)
}
const currentActions = buildWelcomeQuickActions(
sessionType,
currentUser.value,
@@ -92,6 +105,27 @@ export function useTravelReimbursementSessionState({
))
}
function isStewardSessionType(sessionType) {
return normalizeAssistantSessionType(sessionType) === SESSION_TYPE_STEWARD
}
function buildSessionMessages(restoredMessages, sessionType) {
if (Array.isArray(restoredMessages) && restoredMessages.length) {
return restoredMessages
}
if (isStewardSessionType(sessionType)) {
return []
}
return [createWelcomeAssistantMessage(props.entrySource, linkedRequest.value, sessionType, currentUser.value)]
}
function buildSessionInsight(sessionType) {
if (isStewardSessionType(sessionType)) {
return { ...STEWARD_IDLE_INSIGHT }
}
return buildWelcomeInsight(props.entrySource, linkedRequest.value, sessionType, currentUser.value)
}
function buildConversationSessionState(conversation, fallbackSessionType = resolveDefaultSessionTypeFromEntry()) {
const sessionType = resolveAccessibleSessionType(
resolveInitialSessionType(conversation, fallbackSessionType),
@@ -103,13 +137,12 @@ export function useTravelReimbursementSessionState({
return {
sessionType,
messages: restoredMessages.length
? restoredMessages
: [createWelcomeAssistantMessage(props.entrySource, linkedRequest.value, sessionType, currentUser.value)],
messages: buildSessionMessages(restoredMessages, sessionType),
conversationId: resolveInitialConversationId(conversation),
draftClaimId: resolveInitialDraftClaimId(conversation),
currentInsight:
initialInsight || buildWelcomeInsight(props.entrySource, linkedRequest.value, sessionType, currentUser.value),
currentInsight: isStewardSessionType(sessionType)
? buildSessionInsight(sessionType)
: initialInsight || buildSessionInsight(sessionType),
reviewFilePreviews: restoredReviewFilePreviews,
composerDraft: '',
attachedFiles: [],
@@ -127,17 +160,10 @@ export function useTravelReimbursementSessionState({
)
return {
sessionType: normalizedSessionType,
messages: [
createWelcomeAssistantMessage(props.entrySource, linkedRequest.value, normalizedSessionType, currentUser.value)
],
messages: buildSessionMessages([], normalizedSessionType),
conversationId: '',
draftClaimId: '',
currentInsight: buildWelcomeInsight(
props.entrySource,
linkedRequest.value,
normalizedSessionType,
currentUser.value
),
currentInsight: buildSessionInsight(normalizedSessionType),
reviewFilePreviews: [],
composerDraft: '',
attachedFiles: [],
@@ -169,14 +195,12 @@ export function useTravelReimbursementSessionState({
return {
sessionType,
messages: restoredMessages.length
? restoredMessages
: [createWelcomeAssistantMessage(props.entrySource, linkedRequest.value, sessionType, currentUser.value)],
messages: buildSessionMessages(restoredMessages, sessionType),
conversationId: String(state.conversationId || '').trim(),
draftClaimId: String(state.draftClaimId || '').trim(),
currentInsight:
state.currentInsight
|| buildWelcomeInsight(props.entrySource, linkedRequest.value, sessionType, currentUser.value),
currentInsight: isStewardSessionType(sessionType)
? buildSessionInsight(sessionType)
: state.currentInsight || buildSessionInsight(sessionType),
reviewFilePreviews: filterPersistableFilePreviews(state.reviewFilePreviews),
composerDraft: String(state.composerDraft || ''),
attachedFiles: [],
@@ -301,26 +325,15 @@ export function useTravelReimbursementSessionState({
nextState.sessionType,
resolveDefaultSessionTypeFromEntry()
)
messages.value = Array.isArray(nextState.messages) && nextState.messages.length
? nextState.messages
: [
createWelcomeAssistantMessage(
props.entrySource,
linkedRequest.value,
activeSessionType.value,
currentUser.value
)
]
messages.value = buildSessionMessages(
refreshWelcomeQuickActions(nextState.messages, activeSessionType.value),
activeSessionType.value
)
conversationId.value = String(nextState.conversationId || '').trim()
draftClaimId.value = String(nextState.draftClaimId || '').trim()
currentInsight.value =
nextState.currentInsight
|| buildWelcomeInsight(
props.entrySource,
linkedRequest.value,
activeSessionType.value,
currentUser.value
)
currentInsight.value = isStewardSessionType(activeSessionType.value)
? buildSessionInsight(activeSessionType.value)
: nextState.currentInsight || buildSessionInsight(activeSessionType.value)
reviewFilePreviews.value = Array.isArray(nextState.reviewFilePreviews) ? nextState.reviewFilePreviews : []
composerDraft.value = String(nextState.composerDraft || '')
if (runtimeRefs.attachedFiles) {