feat: 新增预算助手报告组件并优化报销交互细节
新增预算助手报告视图模型和组件,优化报销洞察面板和消息项 样式细节,完善预算中心页面布局和文档中心视图,增强报销创 建会话管理和提交编排器,调整 Vite 构建配置,补充单元测试。
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user