feat(web): AI 文档详情引用解析与查询卡片增强
- 新增 aiDocumentDetailReference,统一解析 #ai-open-document-detail / #ai-open-application-detail 引用,兼容 A/R/D 短格式与 AP-/RE-/AD- 旧格式单号,提供 isBusinessDocumentReference 判定 - aiDocumentQueryModel 文档卡片接入详情引用,按申请单/报销单生成对应 href,HTML 渲染器识别单据记录表格并生成卡片链接 - PersonalWorkbenchAiMode 处理文档详情点击跳转,卡片样式重构为结构化布局并更新背景资源 - expenseApplicationPreview 补充事由字段,同步新增/更新 ai-document-detail-reference、document-query-model、html-renderer、workbench-ai-mode 等测试 - 更新公司通信费报销规则表
This commit is contained in:
141
web/src/utils/aiDocumentDetailReference.js
Normal file
141
web/src/utils/aiDocumentDetailReference.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import { isApplicationDocumentNo } from './documentClassification.js'
|
||||
|
||||
export const AI_DOCUMENT_DETAIL_HREF_PREFIX = '#ai-open-document-detail:'
|
||||
export const AI_APPLICATION_DETAIL_HREF_PREFIX = '#ai-open-application-detail:'
|
||||
|
||||
const SHORT_BUSINESS_DOCUMENT_NO_PATTERN = /^(?:A|R|D)[A-HJ-NP-Z2-9]{8}$/
|
||||
const LEGACY_BUSINESS_DOCUMENT_NO_PATTERN = /^(?:AP|APP|RE|AD|EXP|CL|BX)-/
|
||||
|
||||
function normalizeText(value = '') {
|
||||
return String(value ?? '').trim()
|
||||
}
|
||||
|
||||
export function isBusinessDocumentReference(value = '') {
|
||||
const text = normalizeText(value)
|
||||
return Boolean(
|
||||
text &&
|
||||
(
|
||||
SHORT_BUSINESS_DOCUMENT_NO_PATTERN.test(text) ||
|
||||
LEGACY_BUSINESS_DOCUMENT_NO_PATTERN.test(text)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function parseDetailReferencePayload(reference = '', options = {}) {
|
||||
const text = normalizeText(reference)
|
||||
if (!text) {
|
||||
return null
|
||||
}
|
||||
|
||||
const params = new URLSearchParams(text)
|
||||
const claimId = normalizeText(params.get('claim_id') || params.get('claimId'))
|
||||
const claimNo = normalizeText(
|
||||
params.get('claim_no') ||
|
||||
params.get('claimNo') ||
|
||||
params.get('document_no') ||
|
||||
params.get('documentNo')
|
||||
)
|
||||
const documentType = normalizeText(options.documentType)
|
||||
|
||||
if (claimId || claimNo) {
|
||||
return {
|
||||
reference: claimNo || claimId,
|
||||
claimId,
|
||||
claimNo,
|
||||
...(documentType ? { documentType } : {})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
reference: text,
|
||||
...(documentType ? { documentType } : {})
|
||||
}
|
||||
}
|
||||
|
||||
function parseAiDetailHref(href = '', prefix = '', options = {}) {
|
||||
const value = normalizeText(href)
|
||||
if (!value.startsWith(prefix)) {
|
||||
return null
|
||||
}
|
||||
const encodedReference = value.slice(prefix.length)
|
||||
if (!encodedReference) {
|
||||
return null
|
||||
}
|
||||
try {
|
||||
return parseDetailReferencePayload(decodeURIComponent(encodedReference), options)
|
||||
} catch {
|
||||
return parseDetailReferencePayload(encodedReference, options)
|
||||
}
|
||||
}
|
||||
|
||||
export function parseAiDocumentDetailHref(href = '') {
|
||||
return parseAiDetailHref(href, AI_DOCUMENT_DETAIL_HREF_PREFIX)
|
||||
}
|
||||
|
||||
export function parseAiApplicationDetailHref(href = '') {
|
||||
return parseAiDetailHref(href, AI_APPLICATION_DETAIL_HREF_PREFIX, { documentType: 'application' })
|
||||
}
|
||||
|
||||
function resolveExplicitClaimId(source = {}) {
|
||||
const claimNo = normalizeText(source.claimNo || source.claim_no || source.documentNo || source.document_no)
|
||||
const rawClaimId = normalizeText(source.claimId || source.claim_id || source.id)
|
||||
if (!rawClaimId || rawClaimId === claimNo || isBusinessDocumentReference(rawClaimId)) {
|
||||
return ''
|
||||
}
|
||||
return rawClaimId
|
||||
}
|
||||
|
||||
export function buildAiDocumentDetailHref(source = {}, options = {}) {
|
||||
const prefix = normalizeText(options.prefix) || AI_DOCUMENT_DETAIL_HREF_PREFIX
|
||||
const claimId = resolveExplicitClaimId(source)
|
||||
const claimNo = normalizeText(source.claimNo || source.claim_no || source.documentNo || source.document_no)
|
||||
const fallback = normalizeText(source.reference)
|
||||
|
||||
if (claimId || claimNo) {
|
||||
const params = new URLSearchParams()
|
||||
if (claimId) {
|
||||
params.set('claim_id', claimId)
|
||||
}
|
||||
if (claimNo) {
|
||||
params.set('claim_no', claimNo)
|
||||
}
|
||||
return `${prefix}${encodeURIComponent(params.toString())}`
|
||||
}
|
||||
|
||||
return fallback ? `${prefix}${encodeURIComponent(fallback)}` : ''
|
||||
}
|
||||
|
||||
export function buildAiDocumentDetailRequest(detailReference = {}) {
|
||||
const reference = normalizeText(detailReference.reference)
|
||||
const explicitClaimId = resolveExplicitClaimId(detailReference)
|
||||
const explicitClaimNo = normalizeText(
|
||||
detailReference.claimNo ||
|
||||
detailReference.claim_no ||
|
||||
detailReference.documentNo ||
|
||||
detailReference.document_no
|
||||
)
|
||||
const referenceIsBusinessNo = isBusinessDocumentReference(reference)
|
||||
const claimId = explicitClaimId || (!referenceIsBusinessNo ? reference : '')
|
||||
const claimNo = explicitClaimNo || (referenceIsBusinessNo ? reference : '')
|
||||
const lookupReference = claimId || claimNo || reference
|
||||
const displayReference = claimNo || reference || lookupReference
|
||||
const documentTypeCode = normalizeText(
|
||||
detailReference.documentTypeCode ||
|
||||
detailReference.document_type_code ||
|
||||
detailReference.documentType ||
|
||||
detailReference.document_type
|
||||
).toLowerCase()
|
||||
const isApplication = documentTypeCode === 'application' || isApplicationDocumentNo(displayReference)
|
||||
|
||||
return {
|
||||
id: lookupReference,
|
||||
claimId,
|
||||
claimNo,
|
||||
documentNo: displayReference,
|
||||
documentType: isApplication ? 'application' : 'reimbursement',
|
||||
documentTypeCode: isApplication ? 'application' : 'reimbursement',
|
||||
detailLookupOnly: true,
|
||||
source: 'workbench',
|
||||
returnTo: 'workbench'
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user