feat: 本体字段治理与风险规则模板执行器重构

- 新增本体字段注册表与字段治理审计脚本
- 重构风险规则模板执行器、DSL 验证与清单分类器
- 完善票据夹服务与差旅请求详情页交互
- 优化趋势图表与总览页数据展示
- 增强报销平台风险分级与模拟公司筛选
- 补充本体字段、风险规则生成与票据夹服务测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-03 15:46:56 +08:00
parent e12b140508
commit 34457f9c3e
81 changed files with 4858 additions and 1073 deletions

View File

@@ -18,6 +18,7 @@ import { waitForMockApplicationTransportQuote } from '../../utils/expenseApplica
import { fetchOntologyParse } from '../../services/ontology.js'
import { buildExpenseApplicationOntologyContext } from '../../utils/expenseApplicationOntology.js'
import { calculateTravelReimbursement } from '../../services/reimbursements.js'
import { fetchReceiptFolderItems } from '../../services/receiptFolder.js'
import {
handleBudgetCompileReportSubmit,
shouldUseBudgetCompileReport
@@ -171,6 +172,78 @@ export function useTravelReimbursementSubmitComposer(ctx) {
}
}
function hasReceiptFolderSourceFile(files) {
return files.some((file) => String(file?.receiptId || '').trim())
}
async function promptUnlinkedReceiptFolderIfNeeded({
detailScopedClaimId,
files,
fileNames,
options,
rawText,
resolvedUploadDisposition,
reviewAction,
systemGenerated,
userText
}) {
if (
isKnowledgeSession.value ||
systemGenerated ||
!files.length ||
detailScopedClaimId ||
resolvedUploadDisposition ||
options.skipReceiptFolderUnlinkedPrompt ||
options.skipDraftAssociationPrompt ||
reviewAction ||
hasReceiptFolderSourceFile(files)
) {
return false
}
let unlinkedReceipts = []
try {
unlinkedReceipts = await fetchReceiptFolderItems('unlinked')
} catch (error) {
console.warn('Failed to load unlinked receipt folder items before attachment upload:', error)
return false
}
const count = Array.isArray(unlinkedReceipts) ? unlinkedReceipts.length : 0
if (!count) {
return false
}
resetFlowRun()
if (!options.skipUserMessage) {
messages.value.push(createMessage('user', userText, fileNames))
}
messages.value.push(createMessage(
'assistant',
`票据夹中还有 ${count} 份未关联票据。建议先处理这些票据再上传新附件,避免重复保存或遗漏关联。`,
[],
{
meta: ['票据夹待关联'],
suggestedActions: [
{
action_type: 'open_receipt_folder',
label: '去票据夹关联',
icon: 'mdi mdi-folder-open-outline',
payload: { target_view: 'receiptFolder' }
},
{
action_type: 'continue_upload_with_unlinked_receipts',
label: '继续上传新附件',
icon: 'mdi mdi-upload-outline',
payload: { raw_text: rawText }
}
]
}
))
nextTick(scrollToBottom)
persistSessionState()
return true
}
function buildConfirmedAssociationText(message) {
return String(message?.text || '')
.replace(`[确认](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF})`, '已确认')
@@ -653,6 +726,20 @@ export function useTravelReimbursementSubmitComposer(ctx) {
return null
}
if (await promptUnlinkedReceiptFolderIfNeeded({
detailScopedClaimId,
files,
fileNames,
options,
rawText,
resolvedUploadDisposition,
reviewAction,
systemGenerated,
userText
})) {
return null
}
const hasUnsavedReviewDraft = Boolean(
!isKnowledgeSession.value &&
files.length &&