feat(expenses): add authoritative pre-review workflow

This commit is contained in:
caoxiaozhu
2026-07-16 11:42:08 +08:00
parent ae3f02c35a
commit 6bdf65bc24
52 changed files with 4300 additions and 1069 deletions

View File

@@ -187,6 +187,12 @@ function sanitizeHeaders(headers) {
function buildApiResponseError(response, payload, { auth, handleUnauthorized }) {
const error = new Error(resolveErrorMessage(payload))
error.status = response.status
error.payload = payload
error.detail = payload?.detail
if (payload?.detail && typeof payload.detail === 'object') {
error.code = String(payload.detail.code || '').trim()
error.review = payload.detail.review || null
}
if (response.status === 401 && auth && handleUnauthorized && readAuthAccessToken()) {
error.code = 'AUTH_SESSION_EXPIRED'
notifyAuthSessionExpired()

View File

@@ -224,10 +224,26 @@ export function updateExpenseClaimItem(claimId, itemId, payload) {
})
}
export function submitExpenseClaim(claimId) {
function createPreReviewRequestId() {
if (typeof globalThis.crypto?.randomUUID === 'function') {
return `pre-review:${globalThis.crypto.randomUUID()}`
}
return `pre-review:${Date.now()}:${Math.random().toString(16).slice(2)}`
}
export function preReviewExpenseClaim(claimId, requestId = '') {
const normalizedRequestId = String(requestId || '').trim() || createPreReviewRequestId()
return apiRequest(`/reimbursements/claims/${encodeURIComponent(String(claimId || '').trim())}/pre-review`, {
method: 'POST',
headers: { 'X-Request-ID': normalizedRequestId },
body: JSON.stringify({})
})
}
export function submitExpenseClaim(claimId, payload = {}) {
return apiRequest(`/reimbursements/claims/${encodeURIComponent(String(claimId || '').trim())}/submit`, {
method: 'POST',
body: JSON.stringify({})
body: JSON.stringify(payload || {})
})
}