feat: 重构报销单服务并完善前端提交与审核交互
重构 expense_claims 服务模块结构并优化差旅票据审核逻辑, 增强用户代理服务的票据类型识别,前端报销创建页面拆分为 附件模型和会话模型模块,重构提交编排器和草稿关联确认流 程,更新知识库索引,补充单元测试。
This commit is contained in:
@@ -37,6 +37,7 @@ function resolveStatusTone(status) {
|
||||
export const MAX_ATTACHMENTS = 10
|
||||
export const MAX_OCR_DOCUMENTS = 10
|
||||
export const VISIBLE_ATTACHMENT_CHIPS = 2
|
||||
export const ATTACHMENT_ASSOCIATION_CONFIRM_HREF = '#confirm-attachment-association'
|
||||
|
||||
export function normalizeOcrDocuments(payload) {
|
||||
const documents = Array.isArray(payload?.documents) ? payload.documents : []
|
||||
@@ -85,6 +86,88 @@ export function buildOcrSummaryFromDocuments(documents) {
|
||||
.join(';')
|
||||
}
|
||||
|
||||
function resolveAssociationDocumentTypeLabel(document) {
|
||||
const explicitLabel = String(document?.document_type_label || '').trim()
|
||||
if (explicitLabel) {
|
||||
return explicitLabel
|
||||
}
|
||||
|
||||
const sceneLabel = String(document?.scene_label || '').trim()
|
||||
if (sceneLabel) {
|
||||
return sceneLabel
|
||||
}
|
||||
|
||||
const typeLabel = resolveDocumentTypeLabel(document?.document_type)
|
||||
return String(typeLabel || '').trim() || '其他票据'
|
||||
}
|
||||
|
||||
function buildAssociationDocumentContentLines(document) {
|
||||
const fields = Array.isArray(document?.document_fields) ? document.document_fields : []
|
||||
const fieldLines = fields
|
||||
.map((field) => {
|
||||
const label = String(field?.label || '').trim()
|
||||
const value = String(field?.value || '').trim()
|
||||
return label && value ? `- ${label}:${value}` : ''
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
if (fieldLines.length) {
|
||||
return fieldLines.slice(0, 8)
|
||||
}
|
||||
|
||||
const summary = String(document?.summary || document?.text || '').trim()
|
||||
if (summary) {
|
||||
return [`- 识别内容:${summary}`]
|
||||
}
|
||||
|
||||
return ['- 识别内容:暂未提取到结构化字段,请以票据原件为准。']
|
||||
}
|
||||
|
||||
export function buildAttachmentAssociationConfirmationMessage({
|
||||
claimNo = '',
|
||||
claimTitle = '',
|
||||
fileNames = [],
|
||||
ocrDocuments = []
|
||||
} = {}) {
|
||||
const documents = Array.isArray(ocrDocuments) && ocrDocuments.length
|
||||
? ocrDocuments
|
||||
: (Array.isArray(fileNames) ? fileNames : [])
|
||||
.map((filename) => ({ filename }))
|
||||
.filter((item) => String(item.filename || '').trim())
|
||||
const targetLines = [
|
||||
claimNo ? `- 草稿单号:${claimNo}` : '',
|
||||
claimTitle ? `- 单据说明:${claimTitle}` : '',
|
||||
`- 本次待归集附件:${documents.length || fileNames.length || 0} 份`
|
||||
].filter(Boolean)
|
||||
|
||||
const documentBlocks = documents.map((document, index) => {
|
||||
const filename = String(document?.filename || '').trim() || `附件 ${index + 1}`
|
||||
const typeLabel = resolveAssociationDocumentTypeLabel(document)
|
||||
const contentLines = buildAssociationDocumentContentLines(document)
|
||||
return [
|
||||
`附件 ${index + 1}:${filename}`,
|
||||
'',
|
||||
`附件类型:${typeLabel}`,
|
||||
'',
|
||||
...contentLines
|
||||
].join('\n')
|
||||
})
|
||||
|
||||
return [
|
||||
'已识别附件信息:',
|
||||
'',
|
||||
documentBlocks.join('\n\n'),
|
||||
'',
|
||||
'请问是否确定将票据信息归集到单据:',
|
||||
'',
|
||||
targetLines.join('\n'),
|
||||
'',
|
||||
`如果 [确认](${ATTACHMENT_ASSOCIATION_CONFIRM_HREF}) 该信息,我将直接将票据进行归集。`
|
||||
]
|
||||
.filter((part) => String(part || '').trim())
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
export function normalizeReviewDocumentFieldKey(label) {
|
||||
const compact = String(label || '').replace(/\s+/g, '').toLowerCase()
|
||||
if (!compact) return ''
|
||||
|
||||
Reference in New Issue
Block a user