feat: 新增预算费控模型与报销审批流引擎
后端新增预算费控服务和报销单审批流模块,引入申请人费用画像 算法,优化知识库 RAG 运行时和同步逻辑,完善报销单工作流常 量和明细同步,更新差旅报销规则电子表格,前端新增预算分析 组件和数字员工模型,完善审批对话框和洞察面板交互,优化侧 边栏和顶栏样式,补充单元测试。
This commit is contained in:
@@ -5,6 +5,7 @@ import { useToast } from '../../composables/useToast.js'
|
||||
import EnterpriseSelect from '../../components/shared/EnterpriseSelect.vue'
|
||||
import ConfirmDialog from '../../components/shared/ConfirmDialog.vue'
|
||||
import TravelRequestApprovalDialog from '../../components/travel/TravelRequestApprovalDialog.vue'
|
||||
import TravelRequestBudgetAnalysis from '../../components/travel/TravelRequestBudgetAnalysis.vue'
|
||||
import TravelRequestDeleteDialog from '../../components/travel/TravelRequestDeleteDialog.vue'
|
||||
import TravelRequestReturnDialog from '../../components/travel/TravelRequestReturnDialog.vue'
|
||||
import {
|
||||
@@ -22,6 +23,7 @@ import {
|
||||
updateExpenseClaimItem
|
||||
} from '../../services/reimbursements.js'
|
||||
import {
|
||||
canApproveBudgetExpenseApplications,
|
||||
canApproveLeaderExpenseClaims,
|
||||
canDeleteArchivedExpenseClaims,
|
||||
canManageExpenseClaims,
|
||||
@@ -369,6 +371,7 @@ export default {
|
||||
ConfirmDialog,
|
||||
EnterpriseSelect,
|
||||
TravelRequestApprovalDialog,
|
||||
TravelRequestBudgetAnalysis,
|
||||
TravelRequestDeleteDialog,
|
||||
TravelRequestReturnDialog
|
||||
},
|
||||
@@ -490,6 +493,10 @@ export default {
|
||||
const node = String(request.value.node || request.value.approvalStage || '').trim()
|
||||
return node === '财务审批'
|
||||
})
|
||||
const isBudgetApprovalStage = computed(() => {
|
||||
const node = String(request.value.node || request.value.approvalStage || '').trim()
|
||||
return node === '预算管理者审批'
|
||||
})
|
||||
const isCurrentApplicant = computed(() => isCurrentRequestApplicant(request.value, currentUser.value))
|
||||
const isCurrentDirectManagerApprover = computed(() => (
|
||||
canApproveLeaderExpenseClaims(currentUser.value)
|
||||
@@ -501,6 +508,18 @@ export default {
|
||||
&& isFinanceUser(currentUser.value)
|
||||
&& !isCurrentApplicant.value
|
||||
))
|
||||
const canProcessBudgetApprovalStage = computed(() => (
|
||||
isApplicationDocument.value
|
||||
&& isBudgetApprovalStage.value
|
||||
&& canApproveBudgetExpenseApplications(currentUser.value, request.value)
|
||||
&& !isCurrentApplicant.value
|
||||
))
|
||||
const showBudgetAnalysis = computed(() => (
|
||||
isApplicationDocument.value
|
||||
&& isBudgetApprovalStage.value
|
||||
&& canApproveBudgetExpenseApplications(currentUser.value, request.value)
|
||||
&& !isCurrentApplicant.value
|
||||
))
|
||||
const canReturnRequest = computed(() => {
|
||||
if (request.value.approvalKey !== 'in_progress' || !request.value.claimId || !canReturnExpenseClaims(currentUser.value)) {
|
||||
return false
|
||||
@@ -508,6 +527,9 @@ export default {
|
||||
if (isDirectManagerApprovalStage.value) {
|
||||
return isCurrentDirectManagerApprover.value
|
||||
}
|
||||
if (isBudgetApprovalStage.value) {
|
||||
return canProcessBudgetApprovalStage.value
|
||||
}
|
||||
return canProcessFinanceApprovalStage.value
|
||||
})
|
||||
const canApproveRequest = computed(() =>
|
||||
@@ -520,6 +542,7 @@ export default {
|
||||
&& isCurrentDirectManagerApprover.value
|
||||
)
|
||||
|| canProcessFinanceApprovalStage.value
|
||||
|| canProcessBudgetApprovalStage.value
|
||||
)
|
||||
)
|
||||
const leaderApprovalInfo = computed(() => buildLeaderApprovalInfo(request.value))
|
||||
@@ -536,39 +559,43 @@ export default {
|
||||
isApplicationDocument.value
|
||||
&& hasLeaderApprovalEvents.value
|
||||
))
|
||||
const requiresApprovalOpinion = computed(() => isDirectManagerApprovalStage.value)
|
||||
const approvalOpinionTitle = computed(() => (isFinanceApprovalStage.value ? '财务意见' : '领导意见'))
|
||||
const requiresApprovalOpinion = computed(() => false)
|
||||
const approvalOpinionTitle = computed(() => (isFinanceApprovalStage.value ? '财务意见' : '附加意见'))
|
||||
const approvalOpinionPlaceholder = computed(() => {
|
||||
if (isFinanceApprovalStage.value) {
|
||||
return '请输入财务终审意见,可补充票据核验、金额一致性或入账关注点。'
|
||||
}
|
||||
if (isApplicationDocument.value) {
|
||||
return '请输入审批意见,可补充业务必要性、预算合理性或执行要求。'
|
||||
return '可选填审批补充说明,例如业务必要性、预算合理性或执行要求;不填写默认为同意。'
|
||||
}
|
||||
return '请输入审批意见,可补充核实情况、费用合理性或后续财务关注点。'
|
||||
return '可选填审批补充说明,例如核实情况、费用合理性或后续财务关注点;不填写默认为同意。'
|
||||
})
|
||||
const approvalOpinionHint = computed(() => {
|
||||
if (isFinanceApprovalStage.value) {
|
||||
return '审核通过后将进入归档入账。'
|
||||
}
|
||||
return isApplicationDocument.value ? '领导意见为必填,确认后会生成报销草稿。' : '领导意见为必填,审批通过后将流转至财务审批。'
|
||||
if (isBudgetApprovalStage.value) {
|
||||
return '不填写附加意见则默认同意,确认后会归档申请单并生成报销草稿。'
|
||||
}
|
||||
return isApplicationDocument.value ? '不填写附加意见则默认同意,确认后会流转至预算管理者审批。' : '不填写附加意见则默认同意,审批通过后将流转至财务审批。'
|
||||
})
|
||||
const approvalConfirmBadge = computed(() => {
|
||||
if (isFinanceApprovalStage.value) {
|
||||
return '财务终审'
|
||||
}
|
||||
return isBudgetApprovalStage.value ? '预算审核' : '领导审批'
|
||||
})
|
||||
const approvalConfirmBadge = computed(() => (isFinanceApprovalStage.value ? '财务终审' : '领导审批'))
|
||||
const approvalConfirmDescription = computed(() => {
|
||||
if (isFinanceApprovalStage.value) {
|
||||
return '确认后该报销单会完成财务终审并进入归档入账,请确认票据、金额与财务意见无误。'
|
||||
}
|
||||
if (isApplicationDocument.value) {
|
||||
return '确认后该申请单会完成直属领导审批,并自动进入申请人的报销草稿中。'
|
||||
return isBudgetApprovalStage.value
|
||||
? '确认后该申请单会完成预算审核,归档申请单,并自动进入申请人的报销草稿中。'
|
||||
: '确认后该申请单会完成直属领导审批,并流转给预算管理者进一步审核。'
|
||||
}
|
||||
return '确认后该报销单会从直属领导审批流转到财务审批,请确认申请信息与领导意见无误。'
|
||||
})
|
||||
const approvalNextStage = computed(() => {
|
||||
if (isFinanceApprovalStage.value) {
|
||||
return '归档入账'
|
||||
}
|
||||
return isApplicationDocument.value ? '报销草稿' : '财务审批'
|
||||
})
|
||||
const approveActionLabel = computed(() => (isApplicationDocument.value ? '确认审核' : '审批通过'))
|
||||
const approveBusyLabel = computed(() => (isApplicationDocument.value ? '确认中' : '通过中'))
|
||||
const approveConfirmTitle = computed(() => (
|
||||
@@ -581,15 +608,14 @@ export default {
|
||||
? '退回后该申请单会回到待提交状态,申请人需要调整后重新提交。'
|
||||
: '退回后该单据会回到待提交状态,申请人需要调整后重新提交并再次经过 AI 预审。'
|
||||
))
|
||||
const approvalConfirmSummaryLabel = computed(() => (
|
||||
isApplicationDocument.value ? '生成结果' : '下一节点'
|
||||
))
|
||||
const approvalSuccessToast = computed(() => {
|
||||
if (isFinanceApprovalStage.value) {
|
||||
return `${request.value.id} 已完成财务终审,进入归档入账。`
|
||||
}
|
||||
return isApplicationDocument.value
|
||||
? `${request.value.id} 已确认审核,正在生成报销草稿。`
|
||||
? isBudgetApprovalStage.value
|
||||
? `${request.value.id} 已完成预算审核,正在生成报销草稿。`
|
||||
: `${request.value.id} 已确认审核,已流转至预算管理者审批。`
|
||||
: `${request.value.id} 已审批通过,流转至财务审批。`
|
||||
})
|
||||
const deleteActionLabel = computed(() => (isDraftRequest.value ? '删除草稿' : '删除单据'))
|
||||
@@ -1751,15 +1777,10 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
if (requiresApprovalOpinion.value && !leaderOpinion.value.trim()) {
|
||||
toast('请先填写领导意见,填写后才能确认审核。')
|
||||
return
|
||||
}
|
||||
|
||||
approveBusy.value = true
|
||||
try {
|
||||
const responsePayload = await approveExpenseClaim(request.value.claimId, {
|
||||
opinion: leaderOpinion.value.trim()
|
||||
opinion: leaderOpinion.value.trim() || '同意'
|
||||
})
|
||||
const generatedDraftClaimNo = resolveGeneratedDraftClaimNo(responsePayload)
|
||||
approveConfirmDialogOpen.value = false
|
||||
@@ -1805,7 +1826,7 @@ export default {
|
||||
emit, actionBusy, aiAdvice, aiAdviceHint, aiAdviceTitle, attachmentPreviewError, attachmentPreviewIndexLabel,
|
||||
attachmentPreviewLoading, attachmentPreviewMediaType, attachmentPreviewName, attachmentPreviewOpen,
|
||||
attachmentPreviewUrl, approveBusy, approveConfirmDialogOpen, approvalConfirmBadge,
|
||||
approvalConfirmDescription, approvalConfirmSummaryLabel, approvalNextStage, approvalOpinionHint,
|
||||
approvalConfirmDescription, approvalOpinionHint,
|
||||
approvalOpinionPlaceholder, approvalOpinionTitle, approveActionLabel, approveBusyLabel,
|
||||
applicationDetailFactItems,
|
||||
approveBusyText, approveConfirmText, approveConfirmTitle, canDeleteRequest, canManageCurrentClaim,
|
||||
@@ -1836,6 +1857,7 @@ export default {
|
||||
requiresApprovalOpinion,
|
||||
riskOverrideReasons, saveDetailNote, savingDetailNote, savingExpenseId,
|
||||
showAiAdvicePanel, showApplicationLeaderOpinion,
|
||||
showBudgetAnalysis,
|
||||
showExpenseRisk, startExpenseEdit, submitBusy, submitConfirmDialogOpen,
|
||||
submitRiskWarnings,
|
||||
triggerExpenseUpload, uploadedExpenseCount, uploadingExpenseId, saveExpenseEdit
|
||||
|
||||
Reference in New Issue
Block a user