refactor(frontend): split large reimbursement and audit modules
This commit is contained in:
155
web/src/views/scripts/travelReimbursementReviewDocuments.js
Normal file
155
web/src/views/scripts/travelReimbursementReviewDocuments.js
Normal file
@@ -0,0 +1,155 @@
|
||||
import {
|
||||
DOCUMENT_TYPE_LABELS,
|
||||
EXPENSE_TYPE_LABELS
|
||||
} from './travelReimbursementReviewConstants.js'
|
||||
|
||||
export function cloneReviewDocumentDrafts(items) {
|
||||
return (Array.isArray(items) ? items : []).map((item) => ({
|
||||
...item,
|
||||
warnings: Array.isArray(item?.warnings) ? [...item.warnings] : [],
|
||||
fields: Array.isArray(item?.fields)
|
||||
? item.fields.map((field) => ({
|
||||
label: String(field?.label || '').trim(),
|
||||
value: String(field?.value || ''),
|
||||
source: String(field?.source || 'ocr').trim() || 'ocr'
|
||||
}))
|
||||
: []
|
||||
}))
|
||||
}
|
||||
|
||||
export function buildReviewDocumentDrafts(reviewPayload) {
|
||||
return buildReviewDocumentSummaries(reviewPayload).map((item) => ({
|
||||
index: Number(item.index || 0),
|
||||
filename: String(item.filename || '').trim(),
|
||||
document_type: String(item.document_type || 'other').trim() || 'other',
|
||||
suggested_expense_type: String(item.suggested_expense_type || 'other').trim() || 'other',
|
||||
scene_label: String(item.scene_label || '').trim(),
|
||||
summary: String(item.summary || '').trim(),
|
||||
confidenceLabel: String(item.confidenceLabel || '').trim(),
|
||||
documentTypeLabel: String(item.documentTypeLabel || '').trim(),
|
||||
expenseTypeLabel: String(item.expenseTypeLabel || '').trim(),
|
||||
preview_kind: String(item.preview_kind || '').trim(),
|
||||
preview_data_url: String(item.preview_data_url || '').trim(),
|
||||
warnings: Array.isArray(item.warnings) ? [...item.warnings] : [],
|
||||
fields: Array.isArray(item.fields)
|
||||
? item.fields.map((field) => ({
|
||||
label: String(field?.label || '').trim(),
|
||||
value: String(field?.value || ''),
|
||||
source: String(field?.source || 'ocr').trim() || 'ocr'
|
||||
}))
|
||||
: []
|
||||
}))
|
||||
}
|
||||
|
||||
export function normalizeReviewDocumentComparableValue(item) {
|
||||
return {
|
||||
index: Number(item?.index || 0),
|
||||
filename: String(item?.filename || '').trim(),
|
||||
scene_label: String(item?.scene_label || '').trim(),
|
||||
summary: String(item?.summary || '').trim(),
|
||||
fields: (Array.isArray(item?.fields) ? item.fields : []).map((field) => ({
|
||||
label: String(field?.label || '').trim(),
|
||||
value: String(field?.value || '').trim()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
export function buildReviewDocumentCorrectionLines(baseDrafts, nextDrafts) {
|
||||
const baseMap = new Map(
|
||||
cloneReviewDocumentDrafts(baseDrafts).map((item) => [`${item.index}:${item.filename}`, item])
|
||||
)
|
||||
|
||||
return cloneReviewDocumentDrafts(nextDrafts).reduce((lines, item) => {
|
||||
const key = `${item.index}:${item.filename}`
|
||||
const base = baseMap.get(key)
|
||||
const changes = []
|
||||
const nextSceneLabel = String(item.scene_label || '').trim()
|
||||
const baseSceneLabel = String(base?.scene_label || '').trim()
|
||||
const nextSummary = String(item.summary || '').trim()
|
||||
const baseSummary = String(base?.summary || '').trim()
|
||||
|
||||
if (nextSceneLabel !== baseSceneLabel) {
|
||||
changes.push(`票据场景:${nextSceneLabel || '待补充'}`)
|
||||
}
|
||||
|
||||
if (nextSummary !== baseSummary) {
|
||||
changes.push(`识别摘要:${nextSummary || '待补充'}`)
|
||||
}
|
||||
|
||||
const baseFieldMap = new Map(
|
||||
(Array.isArray(base?.fields) ? base.fields : []).map((field) => [
|
||||
String(field?.label || '').trim(),
|
||||
String(field?.value || '').trim()
|
||||
])
|
||||
)
|
||||
|
||||
for (const field of Array.isArray(item.fields) ? item.fields : []) {
|
||||
const label = String(field?.label || '').trim()
|
||||
if (!label) continue
|
||||
const nextValue = String(field?.value || '').trim()
|
||||
const baseValue = baseFieldMap.get(label) || ''
|
||||
if (nextValue !== baseValue) {
|
||||
changes.push(`${label}:${nextValue || '待补充'}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (changes.length) {
|
||||
lines.push(`第${item.index}张票据(${item.filename}):${changes.join(';')}`)
|
||||
}
|
||||
|
||||
return lines
|
||||
}, [])
|
||||
}
|
||||
|
||||
export function buildReviewDocumentCorrectionMessage(baseDrafts, nextDrafts) {
|
||||
const lines = buildReviewDocumentCorrectionLines(baseDrafts, nextDrafts)
|
||||
if (!lines.length) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return `请同步修正逐票据识别结果:\n${lines.join('\n')}`
|
||||
}
|
||||
|
||||
export function buildReviewDocumentCorrectionContext(drafts) {
|
||||
return cloneReviewDocumentDrafts(drafts).map((item) => ({
|
||||
index: item.index,
|
||||
filename: item.filename,
|
||||
scene_label: String(item.scene_label || '').trim(),
|
||||
summary: String(item.summary || '').trim(),
|
||||
fields: item.fields.map((field) => ({
|
||||
label: String(field.label || '').trim(),
|
||||
value: String(field.value || '').trim()
|
||||
}))
|
||||
}))
|
||||
}
|
||||
|
||||
export function formatConfidenceLabel(value) {
|
||||
const score = Number(value || 0)
|
||||
if (!score) return '待补充'
|
||||
return `${Math.round(score * 100)}%`
|
||||
}
|
||||
|
||||
export function resolveDocumentTypeLabel(type) {
|
||||
return DOCUMENT_TYPE_LABELS[String(type || '').trim()] || DOCUMENT_TYPE_LABELS.other
|
||||
}
|
||||
|
||||
export function resolveExpenseTypeLabel(type, fallbackLabel = '') {
|
||||
const normalized = String(type || '').trim()
|
||||
return EXPENSE_TYPE_LABELS[normalized] || String(fallbackLabel || '').trim() || EXPENSE_TYPE_LABELS.other
|
||||
}
|
||||
|
||||
export function buildReviewDocumentSummaries(reviewPayload) {
|
||||
const docs = Array.isArray(reviewPayload?.document_cards) ? reviewPayload.document_cards : []
|
||||
return docs.map((item) => {
|
||||
const fields = Array.isArray(item.fields) ? item.fields : []
|
||||
return {
|
||||
...item,
|
||||
documentTypeLabel: resolveDocumentTypeLabel(item.document_type),
|
||||
expenseTypeLabel: resolveExpenseTypeLabel(item.suggested_expense_type, item.scene_label),
|
||||
confidenceLabel: formatConfidenceLabel(item.avg_score),
|
||||
lines: fields
|
||||
.filter((field) => String(field?.value || '').trim())
|
||||
.map((field) => `${field.label}:${field.value}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user