feat: 新增风险图谱算法与系统仪表盘及操作反馈体系

后端新增风险图谱算法模块、风险观察与反馈服务、规则 DSL
校验器和可解释性引擎,完善系统仪表盘和财务仪表盘统计,
优化 agent 运行和编排执行链路,清理旧开发文档,前端新增
系统趋势、负载热力图等多种仪表盘图表组件,完善操作反馈
对话框和工作台日期选择器,优化报销创建和审批详情交互,
补充单元测试覆盖。
This commit is contained in:
caoxiaozhu
2026-05-30 15:46:51 +08:00
parent 4c59941ec6
commit 7989f3a159
314 changed files with 30073 additions and 20626 deletions

View File

@@ -57,6 +57,8 @@ export function useTravelReimbursementSubmitComposer(ctx) {
currentInsight,
currentUser,
draftClaimId,
emitOperationCompleted,
emitRequestUpdated,
extractReviewAttachmentNames,
failCurrentFlowStep,
fetchExpenseClaims,
@@ -101,6 +103,36 @@ export function useTravelReimbursementSubmitComposer(ctx) {
const pendingAttachmentAssociations = new Map()
function isSubmittedApplicationDraftPayload(draftPayload) {
return (
String(draftPayload?.draft_type || '').trim() === 'expense_application'
&& String(draftPayload?.status || '').trim() === 'submitted'
)
}
function buildOperationFeedbackState(context) {
if (!context) {
return null
}
return {
context,
submitting: false,
submitted: false,
dismissed: false,
rating: 0,
reason: '',
error: ''
}
}
function resolveAssistantResultText(payload, fallbackAnswer) {
const result = payload?.result && typeof payload.result === 'object' ? payload.result : {}
if (isSubmittedApplicationDraftPayload(result.draft_payload)) {
return ''
}
return result.answer || result.message || fallbackAnswer
}
function createPendingAttachmentAssociationId() {
return `attachment-association-${Date.now()}-${Math.random().toString(16).slice(2)}`
}
@@ -411,6 +443,7 @@ export function useTravelReimbursementSubmitComposer(ctx) {
? initialExtraContext
: mergeBusinessTimeIntoExtraContext(initialExtraContext, selectedBusinessTimeContext)
const reviewAction = String(extraContext.review_action || '').trim()
const feedbackOperationType = String(options.feedbackOperationType || '').trim()
const attachmentAssociationConfirmed = Boolean(
options.associationConfirmed ||
extraContext.attachment_association_confirmed ||
@@ -966,7 +999,12 @@ export function useTravelReimbursementSubmitComposer(ctx) {
const fallbackAnswer = reviewActionResult === 'link_to_existing_draft'
? (resultClaimNo ? `已将本次上传的票据关联到草稿 ${resultClaimNo}` : '已将本次上传的票据关联到现有草稿。')
: '智能体已完成处理。'
const assistantMessage = createMessage('assistant', payload?.result?.answer || payload?.result?.message || fallbackAnswer, [], {
const operationFeedbackContext = String(payload?.status || '').trim() === 'succeeded'
? emitOperationCompleted?.(payload, {
operationType: feedbackOperationType || reviewActionResult || (files.length ? 'attachment_review' : 'assistant_round')
})
: null
const assistantMessage = createMessage('assistant', resolveAssistantResultText(payload, fallbackAnswer), [], {
meta: buildMessageMeta(payload, effectiveFileNames),
citations: Array.isArray(payload?.result?.citations) ? payload.result.citations : [],
suggestedActions: Array.isArray(payload?.result?.suggested_actions)
@@ -981,7 +1019,8 @@ export function useTravelReimbursementSubmitComposer(ctx) {
fileCount: files.length,
rawText
}),
riskFlags: Array.isArray(payload?.result?.risk_flags) ? payload.result.risk_flags : []
riskFlags: Array.isArray(payload?.result?.risk_flags) ? payload.result.risk_flags : [],
operationFeedback: buildOperationFeedbackState(operationFeedbackContext)
})
replaceMessage(pendingMessage.id, assistantMessage)
const nextInsight = buildAgentInsight(
@@ -996,12 +1035,17 @@ export function useTravelReimbursementSubmitComposer(ctx) {
completeFlowResult(payload, flowRunDetail)
persistSessionState()
nextTick(scrollToBottom)
const resolvedDraftClaimId = String(payload?.result?.draft_payload?.claim_id || draftClaimId.value || '').trim()
if (!isKnowledgeSession.value && resolvedDraftClaimId && files.length) {
void syncComposerFilesToDraft(resolvedDraftClaimId, files)
.then(() => {
.then((syncResult) => {
persistSessionState()
if (detailScopedUpload && Number(syncResult?.uploadedCount || 0) > 0) {
emitRequestUpdated?.({
claimId: resolvedDraftClaimId,
source: 'detail-smart-entry-attachment-sync'
})
}
})
.catch((error) => {
console.warn('Failed to persist composer attachments to draft claim:', error)