feat: 增加差旅报销标准测算和财务终审流程
新增差旅报销测算接口及 Spreadsheet 规则解析,审批流程拆分 直属领导审批与财务终审两阶段并细分权限,修复 PDF 文本层 缺失时自动回退 OCR,提交后清理关联会话,前端适配审批流 交互并补充单元测试。
This commit is contained in:
@@ -21,7 +21,7 @@ const LOCATION_REQUIRED_EXPENSE_TYPES = new Set([
|
||||
])
|
||||
|
||||
const REIMBURSEMENT_PROGRESS_LABELS = [
|
||||
'保存草稿',
|
||||
'创建单据',
|
||||
'待提交',
|
||||
'AI预审',
|
||||
'直属领导审批',
|
||||
@@ -270,6 +270,21 @@ function normalizeText(value) {
|
||||
return String(value || '').trim()
|
||||
}
|
||||
|
||||
function isEmailLike(value) {
|
||||
return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(normalizeText(value))
|
||||
}
|
||||
|
||||
function resolveDisplayName(...values) {
|
||||
for (const value of values) {
|
||||
const normalized = normalizeText(value)
|
||||
if (normalized && !isEmailLike(normalized)) {
|
||||
return normalized
|
||||
}
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
function getRiskFlags(claim) {
|
||||
return Array.isArray(claim?.risk_flags_json) ? claim.risk_flags_json : []
|
||||
}
|
||||
@@ -344,7 +359,7 @@ function buildCompletedStepMeta(claim, label) {
|
||||
const stepLabel = normalizeText(label)
|
||||
const employeeName = normalizeText(claim?.employee_name) || '申请人'
|
||||
|
||||
if (stepLabel === '保存草稿') {
|
||||
if (stepLabel === '创建单据') {
|
||||
const createdAt = formatDateTime(claim?.created_at)
|
||||
return buildProgressStepMeta(`${employeeName}创建`, createdAt)
|
||||
}
|
||||
@@ -362,7 +377,12 @@ function buildCompletedStepMeta(claim, label) {
|
||||
if (stepLabel === '直属领导审批' || stepLabel === '财务审批') {
|
||||
const approvalEvent = findApprovalEventForStep(claim, stepLabel)
|
||||
if (approvalEvent) {
|
||||
const operator = normalizeText(approvalEvent.operator) || (stepLabel === '财务审批' ? '财务' : '审批人')
|
||||
const operator = resolveDisplayName(
|
||||
approvalEvent.operator,
|
||||
approvalEvent.operator_name,
|
||||
approvalEvent.operatorName,
|
||||
stepLabel === '直属领导审批' ? claim?.manager_name : ''
|
||||
) || (stepLabel === '财务审批' ? '财务' : '直属领导')
|
||||
const approvedAt = formatDateTime(approvalEvent.created_at || approvalEvent.createdAt)
|
||||
return buildProgressStepMeta(`${operator}通过`, approvedAt, `${operator}审批通过 ${approvedAt}`.trim())
|
||||
}
|
||||
@@ -383,7 +403,7 @@ function buildCompletedStepMeta(claim, label) {
|
||||
|
||||
function resolveCurrentStepStartedAt(claim, label) {
|
||||
const stepLabel = normalizeText(label)
|
||||
if (stepLabel === '保存草稿') {
|
||||
if (stepLabel === '创建单据') {
|
||||
return claim?.created_at
|
||||
}
|
||||
if (stepLabel === '待提交') {
|
||||
@@ -539,7 +559,7 @@ export function mapExpenseClaimToRequest(claim) {
|
||||
employeeName: String(claim?.employee_name || '').trim() || '待补充',
|
||||
employeePosition: String(claim?.employee_position || '').trim(),
|
||||
employeeGrade: String(claim?.employee_grade || '').trim(),
|
||||
managerName: String(claim?.manager_name || '').trim(),
|
||||
managerName: resolveDisplayName(claim?.manager_name),
|
||||
roleLabels: Array.isArray(claim?.role_labels) ? claim.role_labels.filter(Boolean) : [],
|
||||
entity: '',
|
||||
typeCode,
|
||||
|
||||
Reference in New Issue
Block a user