feat: 新增预算助手报告组件并优化报销交互细节

新增预算助手报告视图模型和组件,优化报销洞察面板和消息项
样式细节,完善预算中心页面布局和文档中心视图,增强报销创
建会话管理和提交编排器,调整 Vite 构建配置,补充单元测试。
This commit is contained in:
caoxiaozhu
2026-05-27 12:27:17 +08:00
parent b1a9c8a194
commit 7d32eae74e
23 changed files with 1197 additions and 464 deletions

View File

@@ -86,6 +86,7 @@ export function useTravelReimbursementFlow({
FLOW_STEP_STATUS_FAILED
}) {
const flowRunId = ref('')
const flowSessionType = ref('')
const flowStartedAt = ref(0)
const flowFinishedAt = ref(0)
const flowSteps = ref([])
@@ -94,15 +95,23 @@ export function useTravelReimbursementFlow({
let flowTickTimer = 0
const flowSimulationTimers = []
const activeFlowSteps = computed(() => (
flowSessionType.value === resolveCurrentFlowSessionType()
? flowSteps.value
: []
))
const completedFlowStepCount = computed(
() => flowSteps.value.filter((step) => step.status === FLOW_STEP_STATUS_COMPLETED).length
() => activeFlowSteps.value.filter((step) => step.status === FLOW_STEP_STATUS_COMPLETED).length
)
const rawRunningFlowStep = computed(
() => flowSteps.value.find((step) => step.status === FLOW_STEP_STATUS_RUNNING) || null
)
const runningFlowStep = computed(
() => flowSteps.value.find((step) => step.status === FLOW_STEP_STATUS_RUNNING) || null
() => activeFlowSteps.value.find((step) => step.status === FLOW_STEP_STATUS_RUNNING) || null
)
const visibleFlowSteps = computed(() => {
const visibleSteps = []
for (const step of flowSteps.value) {
for (const step of activeFlowSteps.value) {
visibleSteps.push(step)
if (step.status !== FLOW_STEP_STATUS_COMPLETED) {
break
@@ -111,19 +120,23 @@ export function useTravelReimbursementFlow({
return visibleSteps
})
const flowOverallStatusTone = computed(() => {
if (flowSteps.value.some((step) => step.status === FLOW_STEP_STATUS_FAILED)) {
if (activeFlowSteps.value.some((step) => step.status === FLOW_STEP_STATUS_FAILED)) {
return 'failed'
}
if (runningFlowStep.value) {
return 'running'
}
if (flowSteps.value.length && completedFlowStepCount.value === flowSteps.value.length && flowStartedAt.value) {
if (
activeFlowSteps.value.length
&& completedFlowStepCount.value === activeFlowSteps.value.length
&& flowStartedAt.value
) {
return 'completed'
}
return 'pending'
})
const flowOverallStatusText = computed(() => {
const total = flowSteps.value.length
const total = activeFlowSteps.value.length
const completed = completedFlowStepCount.value
if (flowOverallStatusTone.value === 'failed') {
return `异常 ${completed}/${total}`
@@ -146,13 +159,17 @@ export function useTravelReimbursementFlow({
return formatFlowDuration(finishedAt - flowStartedAt.value)
}
const measuredDuration = flowSteps.value.reduce((total, step) => {
const measuredDuration = activeFlowSteps.value.reduce((total, step) => {
const duration = Number(step.durationMs)
return total + (Number.isFinite(duration) && duration > 0 ? duration : 0)
}, 0)
return measuredDuration ? formatFlowDuration(measuredDuration) : '--'
})
function resolveCurrentFlowSessionType() {
return String(activeSessionType?.value || '').trim()
}
function startFlowTick() {
if (flowTickTimer) {
return
@@ -183,6 +200,7 @@ export function useTravelReimbursementFlow({
const shouldOpenDrawer = options.openDrawer !== false
const startedAt = Number(options.startedAt)
flowRunId.value = ''
flowSessionType.value = String(options.sessionType || resolveCurrentFlowSessionType()).trim()
flowStartedAt.value = Number.isFinite(startedAt) && startedAt >= 0 ? startedAt : Date.now()
flowFinishedAt.value = 0
if (shouldOpenDrawer) {
@@ -242,6 +260,9 @@ export function useTravelReimbursementFlow({
}
function startFlowStep(key, patch = {}) {
if (!flowSessionType.value) {
flowSessionType.value = resolveCurrentFlowSessionType()
}
const normalizedPatch = normalizeFlowStepPatch(key, patch)
const explicitStartedAt = Number(normalizedPatch.startedAt)
const startedAt = Number.isFinite(explicitStartedAt) && explicitStartedAt > 0
@@ -327,7 +348,7 @@ export function useTravelReimbursementFlow({
function failCurrentFlowStep(error) {
clearFlowSimulationTimers()
const currentStep = runningFlowStep.value || flowSteps.value.find((step) => step.status === FLOW_STEP_STATUS_PENDING)
const currentStep = rawRunningFlowStep.value || flowSteps.value.find((step) => step.status === FLOW_STEP_STATUS_PENDING)
failFlowStep(
currentStep?.key || 'orchestrator-error',
error?.message || '智能体调用失败',
@@ -695,9 +716,11 @@ export function useTravelReimbursementFlow({
return {
flowRunId,
flowSessionType,
flowStartedAt,
flowFinishedAt,
flowSteps,
activeFlowSteps,
visibleFlowSteps,
flowRefreshBusy,
flowTick,