feat: 新增预算后端服务与差旅风险规则库
后端新增预算模型、端点和服务模块,支持预算 CRUD 和余额 查询,清理旧生成规则文件并替换为按严重等级分类的差旅风 险规则库,优化认证权限和报销单访问策略,新增财务规则目 录和演示数据构建脚本,前端预算中心增加对话框交互,完善 审计页面运行时模型和元数据展示,补充单元测试。
This commit is contained in:
@@ -46,11 +46,13 @@ function readCurrentUserHeaders() {
|
||||
const username = String(payload?.username || '').trim()
|
||||
const name = String(payload?.name || username).trim()
|
||||
const roleCodes = Array.isArray(payload?.roleCodes) ? payload.roleCodes.filter(Boolean) : []
|
||||
const isAdmin = Boolean(payload?.isAdmin)
|
||||
const isAdmin = resolveStoredUserAdminFlag(payload, roleCodes)
|
||||
const department = String(payload?.department || payload?.departmentName || '').trim()
|
||||
const costCenter = String(payload?.costCenter || payload?.cost_center || '').trim()
|
||||
const safeUsername = pickSafeHeaderValue(username)
|
||||
const safeName = pickSafeHeaderValue(name)
|
||||
const safeDepartment = pickSafeHeaderValue(department)
|
||||
const safeCostCenter = pickSafeHeaderValue(costCenter)
|
||||
|
||||
if (!safeUsername && !safeName) {
|
||||
return {}
|
||||
@@ -73,11 +75,30 @@ function readCurrentUserHeaders() {
|
||||
headers['x-auth-department'] = safeDepartment
|
||||
}
|
||||
|
||||
if (safeCostCenter) {
|
||||
headers['x-auth-cost-center'] = safeCostCenter
|
||||
}
|
||||
|
||||
return headers
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveStoredUserAdminFlag(payload, roleCodes = []) {
|
||||
const username = String(payload?.username || payload?.account || '').trim().toLowerCase()
|
||||
const role = String(payload?.role || '').trim().toLowerCase()
|
||||
const normalizedRoleCodes = roleCodes.map((item) => String(item || '').trim().toLowerCase()).filter(Boolean)
|
||||
|
||||
return (
|
||||
Boolean(payload?.isAdmin)
|
||||
|| username === 'admin'
|
||||
|| role === 'admin'
|
||||
|| role === '管理员'
|
||||
|| role === '系统管理员'
|
||||
|| normalizedRoleCodes.includes('admin')
|
||||
)
|
||||
}
|
||||
|
||||
function normalizeApiBaseUrl(value) {
|
||||
return String(value || '/api/v1').replace(/\/$/, '')
|
||||
|
||||
30
web/src/services/budgets.js
Normal file
30
web/src/services/budgets.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { apiRequest } from './api.js'
|
||||
|
||||
function buildQuery(params = {}) {
|
||||
const search = new URLSearchParams()
|
||||
Object.entries(params || {}).forEach(([key, value]) => {
|
||||
if (typeof value === 'undefined' || value === null || value === '') return
|
||||
search.set(key, String(value))
|
||||
})
|
||||
const query = search.toString()
|
||||
return query ? `?${query}` : ''
|
||||
}
|
||||
|
||||
export function fetchBudgetSummary(params = {}) {
|
||||
return apiRequest(`/budgets/summary${buildQuery(params)}`)
|
||||
}
|
||||
|
||||
export function fetchBudgetAllocations(params = {}) {
|
||||
return apiRequest(`/budgets/allocations${buildQuery(params)}`)
|
||||
}
|
||||
|
||||
export function createBudgetAllocation(payload = {}) {
|
||||
return apiRequest('/budgets/allocations', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchBudgetTransactions(allocationId) {
|
||||
return apiRequest(`/budgets/allocations/${encodeURIComponent(String(allocationId || '').trim())}/transactions`)
|
||||
}
|
||||
Reference in New Issue
Block a user