+ AI建议 @@ -393,10 +393,10 @@ 返回报销列表 - + - {{ deleteBusy ? '删除中' : '删除草稿' }} + {{ deleteBusy ? '删除中' : deleteActionLabel }} @@ -500,7 +500,7 @@ badge="退回单据" badge-tone="warning" :title="`确认退回 ${request.id} 吗?`" - description="退回后该单据会进入待补充状态,申请人需要补充后重新提交。" + description="退回后该单据会回到待提交状态,申请人需要调整后重新提交并再次经过 AI 预审。" cancel-text="取消" confirm-text="确认退回" busy-text="退回中..." diff --git a/web/src/views/scripts/ApprovalCenterView.js b/web/src/views/scripts/ApprovalCenterView.js index dfdcaa7..c67db2d 100644 --- a/web/src/views/scripts/ApprovalCenterView.js +++ b/web/src/views/scripts/ApprovalCenterView.js @@ -428,9 +428,9 @@ export default { actionBusy.value = true try { await returnExpenseClaim(row.claimId, { - reason: '审批中心退回,请申请人补充后重新提交。' + reason: '审批中心退回,请申请人调整后重新提交。' }) - toast(`${row.id} 已退回待补充。`) + toast(`${row.id} 已退回待提交。`) returnDialogOpen.value = false selectedClaimId.value = '' await reload() diff --git a/web/src/views/scripts/EmployeeManagementView.js b/web/src/views/scripts/EmployeeManagementView.js index 6504090..d2f6fe9 100644 --- a/web/src/views/scripts/EmployeeManagementView.js +++ b/web/src/views/scripts/EmployeeManagementView.js @@ -264,21 +264,21 @@ function formatEmployeeHistoryTime(value) { return '' } - const matched = raw.match( - /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/ + const chineseMatched = raw.match( + /^(\d{4})年(\d{1,2})月(\d{1,2})日(\d{1,2})时(\d{1,2})分(?:\d{1,2}秒)?$/ ) - if (!matched) { - return raw + if (chineseMatched) { + const [, year, month, day, hour, minute] = chineseMatched + return `${year}年${Number(month)}月${Number(day)}日${Number(hour)}时${Number(minute)}分` } - const year = Number.parseInt(matched[1], 10) - const month = Number.parseInt(matched[2], 10) - const day = Number.parseInt(matched[3], 10) - const hour = Number.parseInt(matched[4] || '0', 10) - const minute = Number.parseInt(matched[5] || '0', 10) - const second = Number.parseInt(matched[6] || '0', 10) + const isoMatched = raw.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}))?/) + if (isoMatched) { + const [, year, month, day, hour = '0', minute = '0'] = isoMatched + return `${year}年${Number(month)}月${Number(day)}日${Number(hour)}时${Number(minute)}分` + } - return `${year}年${month}月${day}日${hour}时${minute}分${second}秒` + return raw.replace(/(\d{1,2}分)\d{1,2}秒$/, '$1') } function resolveOrganizationUnitCode(employee) { diff --git a/web/src/views/scripts/TravelRequestDetailView.js b/web/src/views/scripts/TravelRequestDetailView.js index 126670d..00e9d1d 100644 --- a/web/src/views/scripts/TravelRequestDetailView.js +++ b/web/src/views/scripts/TravelRequestDetailView.js @@ -454,8 +454,9 @@ export default { const isTravelRequest = computed(() => request.value.detailVariant === 'travel') const isDraftRequest = computed(() => request.value.approvalKey === 'draft') + const isEditableRequest = computed(() => ['draft', 'supplement'].includes(request.value.approvalKey)) const canManageCurrentClaim = computed(() => canManageExpenseClaims(currentUser.value)) - const canDeleteRequest = computed(() => isDraftRequest.value || canManageCurrentClaim.value) + const canDeleteRequest = computed(() => isEditableRequest.value || canManageCurrentClaim.value) const canReturnRequest = computed(() => canManageCurrentClaim.value && request.value.approvalKey === 'in_progress' @@ -584,7 +585,7 @@ export default { const uploadedExpenseCount = computed(() => expenseItems.value.filter((item) => item.attachments.length).length) const hasExpenseRiskColumn = computed(() => expenseItems.value.some((item) => item.attachments.length)) const expenseTableColumnCount = computed( - () => 5 + (hasExpenseRiskColumn.value ? 1 : 0) + (isDraftRequest.value ? 1 : 0) + () => 5 + (hasExpenseRiskColumn.value ? 1 : 0) + (isEditableRequest.value ? 1 : 0) ) const expenseSummaryText = computed( () => request.value.expenseTableSummary || '请继续补充票据、说明和系统校验结果。' @@ -595,9 +596,9 @@ export default { || '暂无附加说明。可在这里补充特殊背景、例外原因、补件计划或其他需要财务和审批人重点关注的信息。' ) const draftBlockingIssues = computed(() => - isDraftRequest.value ? buildDraftBlockingIssues(request.value, expenseItems.value) : [] + isEditableRequest.value ? buildDraftBlockingIssues(request.value, expenseItems.value) : [] ) - const canSubmit = computed(() => isDraftRequest.value && draftBlockingIssues.value.length === 0 && !actionBusy.value) + const canSubmit = computed(() => isEditableRequest.value && draftBlockingIssues.value.length === 0 && !actionBusy.value) const locationInputPlaceholder = computed(() => resolveLocationInputPlaceholder(expenseEditor.itemType)) function applyLocalExpenseItemPatch(itemId, patch) { @@ -807,7 +808,7 @@ export default { }) function startExpenseEdit(item) { - if (!isDraftRequest.value || actionBusy.value) { + if (!isEditableRequest.value || actionBusy.value) { return } @@ -850,7 +851,7 @@ export default { } async function handleAddExpenseItem() { - if (!isDraftRequest.value || actionBusy.value) { + if (!isEditableRequest.value || actionBusy.value) { return } @@ -884,7 +885,7 @@ export default { } function triggerExpenseUpload(item) { - if (!isDraftRequest.value || actionBusy.value) { + if (!isEditableRequest.value || actionBusy.value) { return } @@ -1198,10 +1199,10 @@ export default { returnBusy.value = true try { await returnExpenseClaim(request.value.claimId, { - reason: '详情页退回,请申请人补充后重新提交。' + reason: '详情页退回,请申请人调整后重新提交。' }) returnDialogOpen.value = false - toast(`${request.value.id} 已退回待补充。`) + toast(`${request.value.id} 已退回待提交。`) emit('request-updated', { claimId: request.value.claimId }) } catch (error) { toast(error?.message || '退回单据失败,请稍后重试。') @@ -1270,6 +1271,7 @@ export default { hasExpenseRiskColumn, heroFactItems, isDraftRequest, + isEditableRequest, isTravelRequest, locationInputPlaceholder, openAiEntry,
AI建议 @@ -393,10 +393,10 @@ 返回报销列表 - + - {{ deleteBusy ? '删除中' : '删除草稿' }} + {{ deleteBusy ? '删除中' : deleteActionLabel }} @@ -500,7 +500,7 @@ badge="退回单据" badge-tone="warning" :title="`确认退回 ${request.id} 吗?`" - description="退回后该单据会进入待补充状态,申请人需要补充后重新提交。" + description="退回后该单据会回到待提交状态,申请人需要调整后重新提交并再次经过 AI 预审。" cancel-text="取消" confirm-text="确认退回" busy-text="退回中..." diff --git a/web/src/views/scripts/ApprovalCenterView.js b/web/src/views/scripts/ApprovalCenterView.js index dfdcaa7..c67db2d 100644 --- a/web/src/views/scripts/ApprovalCenterView.js +++ b/web/src/views/scripts/ApprovalCenterView.js @@ -428,9 +428,9 @@ export default { actionBusy.value = true try { await returnExpenseClaim(row.claimId, { - reason: '审批中心退回,请申请人补充后重新提交。' + reason: '审批中心退回,请申请人调整后重新提交。' }) - toast(`${row.id} 已退回待补充。`) + toast(`${row.id} 已退回待提交。`) returnDialogOpen.value = false selectedClaimId.value = '' await reload() diff --git a/web/src/views/scripts/EmployeeManagementView.js b/web/src/views/scripts/EmployeeManagementView.js index 6504090..d2f6fe9 100644 --- a/web/src/views/scripts/EmployeeManagementView.js +++ b/web/src/views/scripts/EmployeeManagementView.js @@ -264,21 +264,21 @@ function formatEmployeeHistoryTime(value) { return '' } - const matched = raw.match( - /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/ + const chineseMatched = raw.match( + /^(\d{4})年(\d{1,2})月(\d{1,2})日(\d{1,2})时(\d{1,2})分(?:\d{1,2}秒)?$/ ) - if (!matched) { - return raw + if (chineseMatched) { + const [, year, month, day, hour, minute] = chineseMatched + return `${year}年${Number(month)}月${Number(day)}日${Number(hour)}时${Number(minute)}分` } - const year = Number.parseInt(matched[1], 10) - const month = Number.parseInt(matched[2], 10) - const day = Number.parseInt(matched[3], 10) - const hour = Number.parseInt(matched[4] || '0', 10) - const minute = Number.parseInt(matched[5] || '0', 10) - const second = Number.parseInt(matched[6] || '0', 10) + const isoMatched = raw.match(/^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}))?/) + if (isoMatched) { + const [, year, month, day, hour = '0', minute = '0'] = isoMatched + return `${year}年${Number(month)}月${Number(day)}日${Number(hour)}时${Number(minute)}分` + } - return `${year}年${month}月${day}日${hour}时${minute}分${second}秒` + return raw.replace(/(\d{1,2}分)\d{1,2}秒$/, '$1') } function resolveOrganizationUnitCode(employee) { diff --git a/web/src/views/scripts/TravelRequestDetailView.js b/web/src/views/scripts/TravelRequestDetailView.js index 126670d..00e9d1d 100644 --- a/web/src/views/scripts/TravelRequestDetailView.js +++ b/web/src/views/scripts/TravelRequestDetailView.js @@ -454,8 +454,9 @@ export default { const isTravelRequest = computed(() => request.value.detailVariant === 'travel') const isDraftRequest = computed(() => request.value.approvalKey === 'draft') + const isEditableRequest = computed(() => ['draft', 'supplement'].includes(request.value.approvalKey)) const canManageCurrentClaim = computed(() => canManageExpenseClaims(currentUser.value)) - const canDeleteRequest = computed(() => isDraftRequest.value || canManageCurrentClaim.value) + const canDeleteRequest = computed(() => isEditableRequest.value || canManageCurrentClaim.value) const canReturnRequest = computed(() => canManageCurrentClaim.value && request.value.approvalKey === 'in_progress' @@ -584,7 +585,7 @@ export default { const uploadedExpenseCount = computed(() => expenseItems.value.filter((item) => item.attachments.length).length) const hasExpenseRiskColumn = computed(() => expenseItems.value.some((item) => item.attachments.length)) const expenseTableColumnCount = computed( - () => 5 + (hasExpenseRiskColumn.value ? 1 : 0) + (isDraftRequest.value ? 1 : 0) + () => 5 + (hasExpenseRiskColumn.value ? 1 : 0) + (isEditableRequest.value ? 1 : 0) ) const expenseSummaryText = computed( () => request.value.expenseTableSummary || '请继续补充票据、说明和系统校验结果。' @@ -595,9 +596,9 @@ export default { || '暂无附加说明。可在这里补充特殊背景、例外原因、补件计划或其他需要财务和审批人重点关注的信息。' ) const draftBlockingIssues = computed(() => - isDraftRequest.value ? buildDraftBlockingIssues(request.value, expenseItems.value) : [] + isEditableRequest.value ? buildDraftBlockingIssues(request.value, expenseItems.value) : [] ) - const canSubmit = computed(() => isDraftRequest.value && draftBlockingIssues.value.length === 0 && !actionBusy.value) + const canSubmit = computed(() => isEditableRequest.value && draftBlockingIssues.value.length === 0 && !actionBusy.value) const locationInputPlaceholder = computed(() => resolveLocationInputPlaceholder(expenseEditor.itemType)) function applyLocalExpenseItemPatch(itemId, patch) { @@ -807,7 +808,7 @@ export default { }) function startExpenseEdit(item) { - if (!isDraftRequest.value || actionBusy.value) { + if (!isEditableRequest.value || actionBusy.value) { return } @@ -850,7 +851,7 @@ export default { } async function handleAddExpenseItem() { - if (!isDraftRequest.value || actionBusy.value) { + if (!isEditableRequest.value || actionBusy.value) { return } @@ -884,7 +885,7 @@ export default { } function triggerExpenseUpload(item) { - if (!isDraftRequest.value || actionBusy.value) { + if (!isEditableRequest.value || actionBusy.value) { return } @@ -1198,10 +1199,10 @@ export default { returnBusy.value = true try { await returnExpenseClaim(request.value.claimId, { - reason: '详情页退回,请申请人补充后重新提交。' + reason: '详情页退回,请申请人调整后重新提交。' }) returnDialogOpen.value = false - toast(`${request.value.id} 已退回待补充。`) + toast(`${request.value.id} 已退回待提交。`) emit('request-updated', { claimId: request.value.claimId }) } catch (error) { toast(error?.message || '退回单据失败,请稍后重试。') @@ -1270,6 +1271,7 @@ export default { hasExpenseRiskColumn, heroFactItems, isDraftRequest, + isEditableRequest, isTravelRequest, locationInputPlaceholder, openAiEntry,