feat: 同步报销流程与工作台改动
This commit is contained in:
@@ -5,7 +5,7 @@ import { useNavigation, navItems } from './useNavigation.js'
|
||||
import { mapExpenseClaimToRequest, useRequests } from './useRequests.js'
|
||||
import { useSystemState } from './useSystemState.js'
|
||||
import { useToast } from './useToast.js'
|
||||
import { fetchExpenseClaimDetail } from '../services/reimbursements.js'
|
||||
import { fetchAllApprovalExpenseClaims, fetchExpenseClaimDetail } from '../services/reimbursements.js'
|
||||
import { fetchOntologyParse } from '../services/ontology.js'
|
||||
import { fetchLatestConversation } from '../services/orchestrator.js'
|
||||
import { clearAssistantSessionSnapshotForDraftClaim } from '../utils/assistantSessionSnapshot.js'
|
||||
@@ -18,20 +18,20 @@ import {
|
||||
} from '../utils/workbenchAssistantIntent.js'
|
||||
import { buildWorkbenchSummary } from '../utils/workbenchSummary.js'
|
||||
import { createCurrentYearDateRange } from '../utils/dateRangeDefaults.js'
|
||||
|
||||
|
||||
const SESSION_TYPE_EXPENSE = 'expense'
|
||||
const SMART_ENTRY_SOURCE_APPLICATION = 'application'
|
||||
const SMART_ENTRY_SOURCE_REIMBURSEMENT = 'topbar'
|
||||
|
||||
export function useAppShell() {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const smartEntryOpen = ref(false)
|
||||
const smartEntryContext = ref({
|
||||
prompt: '',
|
||||
|
||||
export function useAppShell() {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const smartEntryOpen = ref(false)
|
||||
const smartEntryContext = ref({
|
||||
prompt: '',
|
||||
source: 'documents',
|
||||
request: null,
|
||||
request: null,
|
||||
files: [],
|
||||
conversation: null,
|
||||
scope: null,
|
||||
@@ -45,16 +45,17 @@ export function useAppShell() {
|
||||
const smartEntryInvalidatedDraftClaimId = ref('')
|
||||
const selectedRequestSnapshot = ref(null)
|
||||
const documentCenterRefreshToken = ref(0)
|
||||
|
||||
const { activeView, currentView, setView } = useNavigation()
|
||||
const {
|
||||
requests,
|
||||
loading: requestsLoading,
|
||||
error: requestsError,
|
||||
search,
|
||||
filters,
|
||||
ranges,
|
||||
activeRange,
|
||||
const workbenchApprovalRequests = ref([])
|
||||
|
||||
const { activeView, currentView, setView } = useNavigation()
|
||||
const {
|
||||
requests,
|
||||
loading: requestsLoading,
|
||||
error: requestsError,
|
||||
search,
|
||||
filters,
|
||||
ranges,
|
||||
activeRange,
|
||||
filteredRequests,
|
||||
approveRequest,
|
||||
rejectRequest,
|
||||
@@ -65,7 +66,7 @@ export function useAppShell() {
|
||||
const { toast } = useToast()
|
||||
|
||||
const customRange = ref(createCurrentYearDateRange())
|
||||
|
||||
|
||||
const selectedRequest = computed(() => {
|
||||
const requestId = String(route.params.requestId || '')
|
||||
|
||||
@@ -105,6 +106,40 @@ export function useAppShell() {
|
||||
return reloadRequests()
|
||||
}
|
||||
|
||||
async function reloadWorkbenchApprovalRequests() {
|
||||
try {
|
||||
const payload = await fetchAllApprovalExpenseClaims()
|
||||
workbenchApprovalRequests.value = Array.isArray(payload)
|
||||
? payload.map((item) => mapExpenseClaimToRequest(item))
|
||||
: []
|
||||
} catch {
|
||||
workbenchApprovalRequests.value = []
|
||||
}
|
||||
}
|
||||
|
||||
async function reloadWorkbenchRequests() {
|
||||
const [payload] = await Promise.all([
|
||||
reloadRequests({ silent: true }),
|
||||
reloadWorkbenchApprovalRequests()
|
||||
])
|
||||
return payload
|
||||
}
|
||||
|
||||
function resolveWorkbenchRequestKey(request) {
|
||||
return String(request?.claimId || request?.id || request?.claimNo || '').trim()
|
||||
}
|
||||
|
||||
function mergeWorkbenchRequests(primaryRequests = [], approvalRequests = []) {
|
||||
const merged = new Map()
|
||||
for (const request of [...primaryRequests, ...approvalRequests]) {
|
||||
const key = resolveWorkbenchRequestKey(request)
|
||||
if (key) {
|
||||
merged.set(key, request)
|
||||
}
|
||||
}
|
||||
return Array.from(merged.values())
|
||||
}
|
||||
|
||||
function isSameRequestIdentity(request, requestId) {
|
||||
const normalizedId = String(requestId || '').trim()
|
||||
if (!request || !normalizedId) {
|
||||
@@ -185,16 +220,20 @@ export function useAppShell() {
|
||||
return
|
||||
}
|
||||
if (view === 'workbench') {
|
||||
void ensureRequestsLoaded()
|
||||
void reloadWorkbenchRequests()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const workbenchSummary = computed(() =>
|
||||
buildWorkbenchSummary(requests.value, currentUser.value)
|
||||
)
|
||||
|
||||
|
||||
const workbenchRequests = computed(() =>
|
||||
mergeWorkbenchRequests(requests.value, workbenchApprovalRequests.value)
|
||||
)
|
||||
|
||||
const workbenchSummary = computed(() =>
|
||||
buildWorkbenchSummary(workbenchRequests.value, currentUser.value)
|
||||
)
|
||||
|
||||
const topBarView = computed(() => {
|
||||
if (detailMode.value) {
|
||||
const request = selectedRequest.value || {}
|
||||
@@ -207,46 +246,46 @@ export function useAppShell() {
|
||||
: '查看报销明细、票据材料、审批进度与风险提示。'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return currentView.value
|
||||
})
|
||||
|
||||
const requestSummary = computed(() =>
|
||||
filteredRequests.value.reduce(
|
||||
(summary, item) => {
|
||||
const request = normalizeRequestForUi(item)
|
||||
if (!request) {
|
||||
return summary
|
||||
}
|
||||
|
||||
summary.total += 1
|
||||
|
||||
if (request.approvalKey === 'draft') {
|
||||
summary.draft += 1
|
||||
} else if (request.approvalKey === 'in_progress') {
|
||||
summary.inProgress += 1
|
||||
} else if (request.approvalKey === 'supplement') {
|
||||
summary.supplement += 1
|
||||
} else if (request.approvalKey === 'completed') {
|
||||
summary.completed += 1
|
||||
}
|
||||
|
||||
return summary
|
||||
},
|
||||
{ total: 0, draft: 0, inProgress: 0, supplement: 0, completed: 0 }
|
||||
)
|
||||
)
|
||||
|
||||
function handleApprove(request) {
|
||||
const message = approveRequest(request)
|
||||
toast(message)
|
||||
}
|
||||
|
||||
function handleReject(request) {
|
||||
const message = rejectRequest(request)
|
||||
toast(message)
|
||||
}
|
||||
|
||||
|
||||
const requestSummary = computed(() =>
|
||||
filteredRequests.value.reduce(
|
||||
(summary, item) => {
|
||||
const request = normalizeRequestForUi(item)
|
||||
if (!request) {
|
||||
return summary
|
||||
}
|
||||
|
||||
summary.total += 1
|
||||
|
||||
if (request.approvalKey === 'draft') {
|
||||
summary.draft += 1
|
||||
} else if (request.approvalKey === 'in_progress') {
|
||||
summary.inProgress += 1
|
||||
} else if (request.approvalKey === 'supplement') {
|
||||
summary.supplement += 1
|
||||
} else if (request.approvalKey === 'completed') {
|
||||
summary.completed += 1
|
||||
}
|
||||
|
||||
return summary
|
||||
},
|
||||
{ total: 0, draft: 0, inProgress: 0, supplement: 0, completed: 0 }
|
||||
)
|
||||
)
|
||||
|
||||
function handleApprove(request) {
|
||||
const message = approveRequest(request)
|
||||
toast(message)
|
||||
}
|
||||
|
||||
function handleReject(request) {
|
||||
const message = rejectRequest(request)
|
||||
toast(message)
|
||||
}
|
||||
|
||||
function handleNavigate(view) {
|
||||
smartEntryOpen.value = false
|
||||
const shouldRefreshCurrentDocumentCenter =
|
||||
@@ -258,7 +297,7 @@ export function useAppShell() {
|
||||
void reloadDocumentCenterRequests()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function openFinancialAssistantCreate(source) {
|
||||
if (smartEntryOpen.value) {
|
||||
smartEntryRevealToken.value += 1
|
||||
@@ -287,28 +326,28 @@ export function useAppShell() {
|
||||
function openExpenseApplicationCreate() {
|
||||
openFinancialAssistantCreate(SMART_ENTRY_SOURCE_APPLICATION)
|
||||
}
|
||||
|
||||
function resolveCurrentUserId() {
|
||||
const user = currentUser.value || {}
|
||||
return String(user.username || user.name || 'anonymous').trim() || 'anonymous'
|
||||
}
|
||||
|
||||
function resolveSmartEntryClaimScope(payload = {}) {
|
||||
const request = payload.request && typeof payload.request === 'object' ? payload.request : null
|
||||
const payloadScope = payload.scope && typeof payload.scope === 'object' ? payload.scope : null
|
||||
const claimId = String(
|
||||
payloadScope?.claimId ||
|
||||
payloadScope?.claim_id ||
|
||||
request?.claimId ||
|
||||
request?.claim_id ||
|
||||
''
|
||||
).trim()
|
||||
if (!claimId) {
|
||||
return null
|
||||
}
|
||||
return { type: 'claim', claimId }
|
||||
}
|
||||
|
||||
|
||||
function resolveCurrentUserId() {
|
||||
const user = currentUser.value || {}
|
||||
return String(user.username || user.name || 'anonymous').trim() || 'anonymous'
|
||||
}
|
||||
|
||||
function resolveSmartEntryClaimScope(payload = {}) {
|
||||
const request = payload.request && typeof payload.request === 'object' ? payload.request : null
|
||||
const payloadScope = payload.scope && typeof payload.scope === 'object' ? payload.scope : null
|
||||
const claimId = String(
|
||||
payloadScope?.claimId ||
|
||||
payloadScope?.claim_id ||
|
||||
request?.claimId ||
|
||||
request?.claim_id ||
|
||||
''
|
||||
).trim()
|
||||
if (!claimId) {
|
||||
return null
|
||||
}
|
||||
return { type: 'claim', claimId }
|
||||
}
|
||||
|
||||
function isDetailClaimScopedPayload(payload = {}) {
|
||||
return String(payload.source || '').trim() === 'detail' && Boolean(resolveSmartEntryClaimScope(payload))
|
||||
}
|
||||
@@ -451,7 +490,7 @@ export function useAppShell() {
|
||||
const status = String(payload.status || payload.claimStatus || '').trim()
|
||||
const approvalStage = String(payload.approvalStage || payload.approval_stage || '').trim()
|
||||
const isApplicationDocument = isApplicationDocumentPayload(payload, claimNo)
|
||||
await reloadRequests()
|
||||
await reloadWorkbenchRequests()
|
||||
if (status === 'submitted') {
|
||||
if (isApplicationDocument) {
|
||||
toast(`${claimNo || '该'}申请单已提交${approvalStage ? `,当前节点:${approvalStage}` : ',等待直属领导审批'}。`)
|
||||
@@ -505,7 +544,7 @@ export function useAppShell() {
|
||||
}
|
||||
|
||||
async function handleRequestUpdated() {
|
||||
await reloadRequests()
|
||||
await reloadWorkbenchRequests()
|
||||
await refreshSelectedRequestDetail(String(route.params.requestId || ''))
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ import {
|
||||
import {
|
||||
metricBlueprints,
|
||||
systemMetricBlueprints,
|
||||
systemDashboardTotals as fallbackSystemDashboardTotals,
|
||||
systemAgentDailyRatio as fallbackSystemAgentDailyRatio,
|
||||
systemLoginWave as fallbackSystemLoginWave,
|
||||
systemTokenDailyWave as fallbackSystemTokenDailyWave,
|
||||
systemUsageDurationSummary as fallbackSystemUsageDurationSummary,
|
||||
systemUserTokenUsage as fallbackSystemUserTokenUsage,
|
||||
@@ -78,6 +76,25 @@ const emptyFinanceBudgetMetrics = [
|
||||
{ label: '预警预算池', value: '0 个', detail: '超支 0 个', tone: 'success', icon: 'mdi mdi-alert-outline' }
|
||||
]
|
||||
|
||||
const emptySystemDashboardTotals = {
|
||||
toolCalls: 0,
|
||||
modelTokens: 0,
|
||||
onlineUsers: 0,
|
||||
avgOnlineMinutes: 0,
|
||||
executionSuccessRate: 0,
|
||||
positiveFeedback: 0,
|
||||
negativeFeedback: 0,
|
||||
failedRuns: 0,
|
||||
toolCallsChange: 0,
|
||||
modelTokensChange: 0
|
||||
}
|
||||
|
||||
const emptySystemLoginWave = {
|
||||
labels: Array.from({ length: 24 }, (_, hour) => `${String(hour).padStart(2, '0')}:00`),
|
||||
loginUsers: Array.from({ length: 24 }, () => 0),
|
||||
interactions: Array.from({ length: 24 }, () => 0)
|
||||
}
|
||||
|
||||
function parseLocalDate(value) {
|
||||
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(value || '').trim())
|
||||
if (!match) {
|
||||
@@ -439,13 +456,13 @@ export function useOverviewView(options = {}) {
|
||||
})
|
||||
|
||||
const systemDashboardTotals = computed(() => (
|
||||
systemDashboardPayload.value?.totals || fallbackSystemDashboardTotals
|
||||
systemDashboardPayload.value?.totals || emptySystemDashboardTotals
|
||||
))
|
||||
const systemAgentDailyRatio = computed(() => (
|
||||
systemDashboardPayload.value?.agentDailyRatio || fallbackSystemAgentDailyRatio
|
||||
))
|
||||
const systemLoginWave = computed(() => (
|
||||
systemDashboardPayload.value?.loginWave || fallbackSystemLoginWave
|
||||
systemDashboardPayload.value?.loginWave || emptySystemLoginWave
|
||||
))
|
||||
const systemTokenDailyWave = computed(() => (
|
||||
systemDashboardPayload.value?.tokenDailyWave || fallbackSystemTokenDailyWave
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
|
||||
import { fetchExpenseClaims } from '../services/reimbursements.js'
|
||||
import { fetchAllExpenseClaims } from '../services/reimbursements.js'
|
||||
import { filterActionableRiskFlags, normalizeRiskFlagTone } from '../utils/riskFlags.js'
|
||||
|
||||
const EXPENSE_TYPE_LABELS = {
|
||||
@@ -72,7 +72,6 @@ const APPLICATION_PROGRESS_LABELS = [
|
||||
'创建申请',
|
||||
'直属领导审批',
|
||||
'预算管理者审批',
|
||||
'审批完成',
|
||||
APPLICATION_LINK_STATUS_STEP_LABEL,
|
||||
ARCHIVED_STEP_LABEL
|
||||
]
|
||||
@@ -80,7 +79,6 @@ const APPLICATION_PROGRESS_LABELS = [
|
||||
const APPLICATION_PROGRESS_LABELS_WITHOUT_BUDGET = [
|
||||
'创建申请',
|
||||
'直属领导审批',
|
||||
'审批完成',
|
||||
APPLICATION_LINK_STATUS_STEP_LABEL,
|
||||
ARCHIVED_STEP_LABEL
|
||||
]
|
||||
@@ -595,17 +593,17 @@ function resolveApplicationProgressCurrentIndex(approvalMeta, workflowNode) {
|
||||
const normalizedNode = String(workflowNode || '').trim()
|
||||
|
||||
if (approvalMeta.key === 'completed') {
|
||||
return normalizedNode.includes(APPLICATION_ARCHIVE_STAGE_LABEL) ? 4 : 3
|
||||
return normalizedNode.includes(APPLICATION_ARCHIVE_STAGE_LABEL) ? 3 : 2
|
||||
}
|
||||
|
||||
if (normalizedNode.includes(APPLICATION_ARCHIVE_STAGE_LABEL) || normalizedNode.includes(ARCHIVED_STEP_LABEL)) {
|
||||
return 4
|
||||
return 3
|
||||
}
|
||||
if (normalizedNode.includes(APPLICATION_LINK_STATUS_STEP_LABEL)) {
|
||||
return 3
|
||||
return 2
|
||||
}
|
||||
if (normalizedNode.includes('审批完成') || normalizedNode.includes('申请完成')) {
|
||||
return 3
|
||||
return 2
|
||||
}
|
||||
if (normalizedNode.includes('预算')) {
|
||||
return 2
|
||||
@@ -693,6 +691,36 @@ function resolveApplicationApproverName(claim) {
|
||||
) || '直属领导'
|
||||
}
|
||||
|
||||
function resolveReimbursementApproverName(claim, label) {
|
||||
const stepLabel = normalizeText(label)
|
||||
if (stepLabel === '直属领导审批') {
|
||||
return resolveDisplayName(
|
||||
claim?.manager_name,
|
||||
claim?.managerName,
|
||||
claim?.profile_manager,
|
||||
claim?.profileManager,
|
||||
claim?.direct_manager_name,
|
||||
claim?.directManagerName
|
||||
) || '直属领导'
|
||||
}
|
||||
|
||||
if (stepLabel === '财务审批') {
|
||||
const routeEvent = findReimbursementFinanceRouteEvent(claim)
|
||||
return resolveDisplayName(
|
||||
claim?.finance_approver_name,
|
||||
claim?.financeApproverName,
|
||||
routeEvent?.next_approver_name,
|
||||
routeEvent?.nextApproverName,
|
||||
routeEvent?.finance_approver_name,
|
||||
routeEvent?.financeApproverName,
|
||||
claim?.finance_owner_name,
|
||||
claim?.financeOwnerName
|
||||
) || '财务'
|
||||
}
|
||||
|
||||
return stepLabel.replace(/审批$/, '') || '审批人'
|
||||
}
|
||||
|
||||
function resolveApplicationBudgetApproverName(claim) {
|
||||
const routeEvent = findApprovalEventForStep(claim, '直属领导审批')
|
||||
return resolveDisplayName(
|
||||
@@ -708,6 +736,15 @@ function resolveApplicationBudgetApproverName(claim) {
|
||||
function resolveProgressDisplayLabel(label, documentTypeCode, claim, approvalMeta) {
|
||||
const normalizedLabel = normalizeText(label)
|
||||
const workflowNode = normalizeText(claim?.approval_stage || claim?.workflowNode)
|
||||
if (
|
||||
documentTypeCode !== DOCUMENT_TYPE_APPLICATION
|
||||
&& approvalMeta.key !== 'completed'
|
||||
&& (normalizedLabel === '直属领导审批' || normalizedLabel === '财务审批')
|
||||
&& workflowNode.includes(normalizedLabel.replace(/审批$/, ''))
|
||||
) {
|
||||
return `等待 ${resolveReimbursementApproverName(claim, normalizedLabel)} 批复`
|
||||
}
|
||||
|
||||
if (
|
||||
documentTypeCode === DOCUMENT_TYPE_APPLICATION
|
||||
&& approvalMeta.key !== 'completed'
|
||||
@@ -796,6 +833,24 @@ function findApprovalEventForStep(claim, label) {
|
||||
return getLatestEvent(events)
|
||||
}
|
||||
|
||||
function findReimbursementFinanceRouteEvent(claim) {
|
||||
return getLatestEvent(
|
||||
getRiskFlags(claim).filter((flag) => {
|
||||
if (!flag || typeof flag !== 'object') {
|
||||
return false
|
||||
}
|
||||
|
||||
const source = normalizeText(flag.source)
|
||||
if (!['manual_approval', 'budget_approval'].includes(source)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const nextStage = normalizeText(flag.next_approval_stage || flag.nextApprovalStage)
|
||||
return nextStage.includes('财务')
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function findLatestReturnEvent(claim) {
|
||||
return getLatestEvent(
|
||||
getRiskFlags(claim).filter((flag) => (
|
||||
@@ -1066,13 +1121,39 @@ function findMergedApplicationBudgetApprovalEvent(claim) {
|
||||
source === 'manual_approval'
|
||||
&& eventType === 'expense_application_approval'
|
||||
&& previousStage.includes('直属领导')
|
||||
&& nextStage.includes('审批完成')
|
||||
&& (
|
||||
nextStage.includes('审批完成')
|
||||
|| nextStage.includes(APPLICATION_LINK_STATUS_STEP_LABEL)
|
||||
|| nextStage.includes('申请完成')
|
||||
)
|
||||
&& mergedFlag
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function resolveBudgetRouteResult(flag, routeDecision = {}) {
|
||||
if (routeDecision && typeof routeDecision === 'object') {
|
||||
const routeBudgetResult = routeDecision.budget_result || routeDecision.budgetResult
|
||||
if (routeBudgetResult && typeof routeBudgetResult === 'object') {
|
||||
return routeBudgetResult
|
||||
}
|
||||
}
|
||||
|
||||
const flagBudgetResult = flag?.budget_result || flag?.budgetResult
|
||||
return flagBudgetResult && typeof flagBudgetResult === 'object' ? flagBudgetResult : {}
|
||||
}
|
||||
|
||||
function applicationBudgetRouteMeetsThreshold(flag, routeDecision = {}) {
|
||||
const budgetResult = resolveBudgetRouteResult(flag, routeDecision)
|
||||
const metrics = budgetResult.metrics && typeof budgetResult.metrics === 'object' ? budgetResult.metrics : {}
|
||||
const overBudgetAmount = parseNumber(metrics.over_budget_amount ?? metrics.overBudgetAmount)
|
||||
const afterUsageRate = parseNumber(metrics.after_usage_rate ?? metrics.afterUsageRate)
|
||||
const claimAmountRatio = parseNumber(metrics.claim_amount_ratio ?? metrics.claimAmountRatio)
|
||||
|
||||
return overBudgetAmount > 0 || Math.max(afterUsageRate, claimAmountRatio) >= 90
|
||||
}
|
||||
|
||||
function applicationRequiresBudgetReviewStep(claim, workflowNode) {
|
||||
const node = normalizeText(workflowNode || claim?.approval_stage || claim?.workflowNode)
|
||||
if (node.includes('预算')) {
|
||||
@@ -1087,24 +1168,22 @@ function applicationRequiresBudgetReviewStep(claim, workflowNode) {
|
||||
const source = normalizeText(flag.source)
|
||||
const eventType = normalizeText(flag.event_type || flag.eventType)
|
||||
const previousStage = normalizeText(flag.previous_approval_stage || flag.previousApprovalStage)
|
||||
const nextStage = normalizeText(flag.next_approval_stage || flag.nextApprovalStage)
|
||||
const routeDecision = flag.route_decision || flag.routeDecision || {}
|
||||
|
||||
if (source === 'approval_routing' && flag.requires_budget_review === true) {
|
||||
return true
|
||||
return applicationBudgetRouteMeetsThreshold(flag, flag)
|
||||
}
|
||||
if (
|
||||
routeDecision
|
||||
&& typeof routeDecision === 'object'
|
||||
&& routeDecision.requires_budget_review === true
|
||||
) {
|
||||
return true
|
||||
return applicationBudgetRouteMeetsThreshold(flag, routeDecision)
|
||||
}
|
||||
return (
|
||||
source === 'budget_approval'
|
||||
|| eventType === 'expense_application_budget_approval'
|
||||
|| previousStage.includes('预算')
|
||||
|| nextStage.includes('预算')
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1273,7 +1352,7 @@ function buildProgressSteps(approvalMeta, workflowNode, claim = {}, options = {}
|
||||
? hasApplicationReturnStep
|
||||
? ['创建申请', '直属领导审批', '退回', '待提交']
|
||||
: hasMergedApplicationBudgetApproval
|
||||
? ['创建申请', '直属领导审批', '审批完成', APPLICATION_LINK_STATUS_STEP_LABEL, ARCHIVED_STEP_LABEL]
|
||||
? ['创建申请', '直属领导审批', APPLICATION_LINK_STATUS_STEP_LABEL, ARCHIVED_STEP_LABEL]
|
||||
: shouldShowApplicationBudgetStep
|
||||
? APPLICATION_PROGRESS_LABELS
|
||||
: APPLICATION_PROGRESS_LABELS_WITHOUT_BUDGET
|
||||
@@ -1512,6 +1591,8 @@ export function mapExpenseClaimToRequest(claim) {
|
||||
employeePosition: String(claim?.employee_position || '').trim(),
|
||||
employeeGrade: String(claim?.employee_grade || '').trim(),
|
||||
managerName: resolveDisplayName(claim?.manager_name),
|
||||
financeApproverName: resolveDisplayName(claim?.finance_approver_name, claim?.financeApproverName),
|
||||
financeOwnerName: resolveDisplayName(claim?.finance_owner_name, claim?.financeOwnerName),
|
||||
budgetApproverName: resolveDisplayName(claim?.budget_approver_name, claim?.budgetApproverName),
|
||||
budgetApproverGrade: String(claim?.budget_approver_grade || claim?.budgetApproverGrade || '').trim(),
|
||||
budgetApproverRoleCode: String(claim?.budget_approver_role_code || claim?.budgetApproverRoleCode || '').trim(),
|
||||
@@ -1665,19 +1746,26 @@ export function useRequests() {
|
||||
})
|
||||
})
|
||||
|
||||
async function reload() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
async function reload(options = {}) {
|
||||
const silent = Boolean(options?.silent)
|
||||
if (!silent) {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = await fetchExpenseClaims()
|
||||
const payload = await fetchAllExpenseClaims()
|
||||
requests.value = Array.isArray(payload) ? payload.map((item) => mapExpenseClaimToRequest(item)) : []
|
||||
loaded.value = true
|
||||
} catch (nextError) {
|
||||
requests.value = []
|
||||
if (!silent) {
|
||||
requests.value = []
|
||||
}
|
||||
error.value = nextError instanceof Error ? nextError.message : '个人报销列表加载失败。'
|
||||
} finally {
|
||||
loading.value = false
|
||||
if (!silent) {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user