Files
X-Financial/web/src/views/scripts/travelReimbursementReviewDocuments.js

157 lines
5.6 KiB
JavaScript
Raw Normal View History

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(),
preview_url: String(item.preview_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}`)
}
})
}