新增前端归档中心视图及相关工具函数,扩充知识库文档分类和 提取器支持多种格式,增强编排器报销查询的多维度检索,优 化本体规则和用户代理审核消息,前端完善报销创建和审批详 情交互细节,补充单元测试覆盖。
157 lines
5.6 KiB
JavaScript
157 lines
5.6 KiB
JavaScript
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}`)
|
||
}
|
||
})
|
||
}
|