feat(web): 优化差旅详情、风险建议卡片与文档中心交互
- 拆分阶段风险建议卡片样式到独立文件 - 完善差旅申请审批对话框与详情视图交互 - 调整文档中心列表共享样式与状态筛选 - 同步应用外壳、视图初始化与系统状态 composables
This commit is contained in:
@@ -107,6 +107,25 @@ export function isAttachmentRequiredExpenseItem(source) {
|
||||
return !isSystemGeneratedExpenseItemSource({ ...source, itemType }) && !OPTIONAL_ATTACHMENT_EXPENSE_TYPES.has(itemType)
|
||||
}
|
||||
|
||||
export function hasUploadedReceiptReference(source) {
|
||||
const invoiceId = String(source?.invoiceId ?? source?.invoice_id ?? '').trim()
|
||||
if (!isPlaceholderValue(invoiceId)) {
|
||||
return true
|
||||
}
|
||||
return Array.isArray(source?.attachments) && source.attachments.some((item) => !isPlaceholderValue(item))
|
||||
}
|
||||
|
||||
export function isIgnorableExpenseDraftPlaceholder(item) {
|
||||
if (!item || isSystemGeneratedExpenseItemSource(item) || hasUploadedReceiptReference(item)) {
|
||||
return false
|
||||
}
|
||||
const amount = Number(item?.itemAmount ?? item?.item_amount ?? 0)
|
||||
const missingAmount = !Number.isFinite(amount) || amount <= 0
|
||||
const missingReason = isPlaceholderValue(item?.itemReason ?? item?.item_reason)
|
||||
const missingLocation = isPlaceholderValue(item?.itemLocation ?? item?.item_location)
|
||||
return missingAmount && missingReason && missingLocation
|
||||
}
|
||||
|
||||
export function isLocationRequiredExpenseType(value) {
|
||||
return LOCATION_REQUIRED_EXPENSE_TYPES.has(normalizeExpenseType(value))
|
||||
}
|
||||
@@ -568,6 +587,7 @@ export function buildExpenseItemViewModel(source, index, requestModel, travelTim
|
||||
|
||||
export function rebuildExpenseItems(items, requestModel) {
|
||||
const sortedItems = [...items]
|
||||
.filter((item) => !isIgnorableExpenseDraftPlaceholder(item))
|
||||
.sort((left, right) => Number(isSystemGeneratedExpenseItemSource(left)) - Number(isSystemGeneratedExpenseItemSource(right)))
|
||||
const travelTimeLabelMap = buildTravelTimeLabelMap(sortedItems, requestModel)
|
||||
return sortedItems.map((item, index) => buildExpenseItemViewModel(item, index, requestModel, travelTimeLabelMap))
|
||||
@@ -575,29 +595,33 @@ export function rebuildExpenseItems(items, requestModel) {
|
||||
|
||||
export function buildExpenseDraftIssues(item) {
|
||||
const issues = []
|
||||
if (item.isSystemGenerated) {
|
||||
if (item.isSystemGenerated || isSystemGeneratedExpenseItemSource(item)) {
|
||||
return issues
|
||||
}
|
||||
if (isIgnorableExpenseDraftPlaceholder(item)) {
|
||||
return issues
|
||||
}
|
||||
const locationRequired = isLocationRequiredExpenseType(item.itemType)
|
||||
const hasUploadedReceipt = hasUploadedReceiptReference(item)
|
||||
|
||||
if (!isValidIsoDate(item.itemDate)) {
|
||||
if (!hasUploadedReceipt && !isValidIsoDate(item.itemDate)) {
|
||||
issues.push('缺少日期')
|
||||
}
|
||||
if (isPlaceholderValue(item.itemType)) {
|
||||
issues.push('缺少费用项目')
|
||||
}
|
||||
if (isPlaceholderValue(item.itemReason)) {
|
||||
if (!hasUploadedReceipt && isPlaceholderValue(item.itemReason)) {
|
||||
issues.push('缺少说明')
|
||||
} else if (isRouteDescriptionExpenseType(item.itemType) && !isValidRouteDescription(item.itemReason)) {
|
||||
} else if (!hasUploadedReceipt && isRouteDescriptionExpenseType(item.itemType) && !isValidRouteDescription(item.itemReason)) {
|
||||
issues.push('行程说明格式错误')
|
||||
}
|
||||
if (locationRequired && isPlaceholderValue(item.itemLocation)) {
|
||||
if (!hasUploadedReceipt && locationRequired && isPlaceholderValue(item.itemLocation)) {
|
||||
issues.push('缺少地点')
|
||||
}
|
||||
if (!Number.isFinite(Number(item.itemAmount)) || Number(item.itemAmount) <= 0) {
|
||||
if (!hasUploadedReceipt && (!Number.isFinite(Number(item.itemAmount)) || Number(item.itemAmount) <= 0)) {
|
||||
issues.push('缺少金额')
|
||||
}
|
||||
if (isAttachmentRequiredExpenseItem(item) && isPlaceholderValue(item.invoiceId)) {
|
||||
if (isAttachmentRequiredExpenseItem(item) && !hasUploadedReceipt) {
|
||||
issues.push('缺少票据标识')
|
||||
}
|
||||
|
||||
@@ -609,14 +633,15 @@ export function buildDraftBlockingIssues(request, expenseItems) {
|
||||
const isApplication = isApplicationDocumentRequest(request)
|
||||
const locationRequired = isLocationRequiredExpenseType(request.typeCode)
|
||||
const normalizedItems = Array.isArray(expenseItems) ? expenseItems : []
|
||||
const itemAmountTotal = normalizedItems.reduce((sum, item) => {
|
||||
const effectiveItems = normalizedItems.filter((item) => !isIgnorableExpenseDraftPlaceholder(item))
|
||||
const itemAmountTotal = effectiveItems.reduce((sum, item) => {
|
||||
const amount = Number(item?.itemAmount || 0)
|
||||
return Number.isFinite(amount) && amount > 0 ? sum + amount : sum
|
||||
}, 0)
|
||||
const hasValidItemDate = normalizedItems.some((item) => isValidIsoDate(item?.itemDate))
|
||||
const hasValidItemType = normalizedItems.some((item) => !isPlaceholderValue(item?.itemType))
|
||||
const hasValidItemReason = normalizedItems.some((item) => !isPlaceholderValue(item?.itemReason))
|
||||
const hasValidItemLocation = normalizedItems.some((item) => !isPlaceholderValue(item?.itemLocation))
|
||||
const hasValidItemDate = effectiveItems.some((item) => isValidIsoDate(item?.itemDate))
|
||||
const hasValidItemType = effectiveItems.some((item) => !isPlaceholderValue(item?.itemType))
|
||||
const hasValidItemReason = effectiveItems.some((item) => !isPlaceholderValue(item?.itemReason))
|
||||
const hasValidItemLocation = effectiveItems.some((item) => !isPlaceholderValue(item?.itemLocation))
|
||||
|
||||
if (isPlaceholderValue(request.profileName)) {
|
||||
issues.push('申请人未完善')
|
||||
@@ -655,7 +680,7 @@ export function buildDraftBlockingIssues(request, expenseItems) {
|
||||
if ((!Number.isFinite(Number(request.amountValue)) || Number(request.amountValue) <= 0) && itemAmountTotal <= 0) {
|
||||
issues.push('报销金额未完善')
|
||||
}
|
||||
if (!normalizedItems.length) {
|
||||
if (!effectiveItems.length) {
|
||||
issues.push('费用明细不能为空')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user