Files
cma-management/frontend/src/api/index.ts
T
Hermes CI Fix 61936302b2 feat(KR): KR完整修复 — krs表打通+方向符号operator+权重自由输入
- 后端okr.py: KR读取从ActionPlan改为krs表, 新增KR CRUD API(POST/PUT/DELETE /okr/{objective_id}/krs) + 批量sync
- operator方向符号: krs表加operator/tolerance/weight/sort_order/monthly_milestones列
- progress方向感知计算(>=/>: current/target, <=/<: target/current, =: 容差), 达成→status=achieved
- 关联KPI自动继承方向(threshold_green解析: F_COST_RATIO<=18等)
- maps.py: 保存地图时自动同步objectives+krs表, JSON→krs数据迁移脚本
- 前端: 权重下拉改自由数字输入(可小数33.33) + 方向选择器(≥/≤/>/</=) + 自动平分按钮 + KPI方向继承提示
- pytest: 10个新测试(krs CRUD/方向感知/权重校验/多租户隔离) + 更新旧KR测试
- 迁移: 现有strategic_maps JSON 12条KR已写入krs表
2026-08-27 10:59:56 +08:00

415 lines
20 KiB
TypeScript

import axios from 'axios'
const api = axios.create({
baseURL: '/api/cma',
timeout: 15000,
})
api.interceptors.request.use((config) => {
const token = localStorage.getItem('cma_token')
if (token) config.headers.Authorization = `Bearer ${token}`
// 账套模式:entity_id 由 token 绑定,前端不再自动附加 X-Entity-Id / entity_id
return config
})
api.interceptors.response.use(
(response) => response.data,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('cma_token')
localStorage.removeItem('cma_user')
window.location.href = '/login'
}
return Promise.reject(error)
}
)
export const authApi = {
login: (data: any) => api.post('/auth/login', data),
register: (data: any) => api.post('/auth/register', data),
switchEntity: (data: any) => api.post('/auth/switch-entity', data),
myEntities: () => api.get('/auth/my-entities'),
loginEntities: (username: string) => api.get('/auth/login-entities', { params: { username } }),
}
export const kpiApi = {
list: (params?: any) => api.get('/kpis', { params }),
get: (id: number) => api.get(`/kpis/${id}`),
create: (data: any) => api.post('/kpis', data),
update: (id: number, data: any) => api.put(`/kpis/${id}`, data),
delete: (id: number) => api.delete(`/kpis/${id}`),
restore: (id: number) => api.put(`/kpis/${id}/restore`),
listCategories: () => api.get('/kpis/categories'),
associateMap: (id: number, data: any) => api.put(`/kpis/${id}/associate-map`, data),
// KPI-5: 五档评分
score: (params?: any) => api.get('/kpis/score', { params }),
// KPI-6: 三级分解树
hierarchy: (params?: any) => api.get('/kpis/hierarchy', { params }),
// KPI-8: 因果链追踪
causalityChain: (id: number) => api.get(`/kpis/${id}/causality-chain`),
}
export const mapApi = {
list: () => api.get('/maps'),
create: (data: any) => api.post('/maps', data),
update: (id: number, data: any) => api.put(`/maps/${id}`, data),
delete: (id: number) => api.delete(`/maps/${id}`),
batchDelete: (ids: number[]) => api.post('/maps/batch-delete', { ids }),
createWithTemplate: (data: any) => api.post('/maps/create-with-template', data),
}
export const dashboardApi = {
summary: (role: string) => api.get('/dashboard/summary', { params: { role } }),
kpis: (params: any) => api.get('/dashboard/kpis', { params }),
myKpis: (params?: any) => api.get('/dashboard/my-kpis', { params }),
financeAnalysis: (params?: any) => api.get('/dashboard/finance-analysis', { params }),
predict: (params?: any) => api.get('/dashboard/predict', { params }),
}
export const templateApi = {
list: (params?: any) => api.get('/templates', { params }),
get: (id: number) => api.get(`/templates/${id}`),
instantiate: (id: number, data: any) => api.post(`/templates/${id}/instantiate`, data),
create: (data: any) => api.post('/templates', data),
update: (id: number, data: any) => api.put(`/templates/${id}`, data),
delete: (id: number) => api.delete(`/templates/${id}`),
}
export const okrTemplateApi = {
list: (params?: any) => api.get('/okr-templates', { params }),
get: (id: number) => api.get(`/okr-templates/${id}`),
create: (data: any) => api.post('/okr-templates', data),
incrementUse: (id: number) => api.post(`/okr-templates/${id}/use`),
applyTemplate: (id: number, data: any) => api.post(`/okr-templates/${id}/apply`, data),
}
export const okrApi = {
list: (params?: any) => api.get('/okr', { params }),
get: (id: number) => api.get(`/okr/${id}`),
create: (data: any) => api.post('/okr', data),
update: (id: number) => api.patch(`/okr/${id}`),
decomposition: (id: number) => api.get(`/okr/${id}/decomposition`),
saveMilestones: (okrId: number, krId: number, milestones: any[]) =>
api.put(`/okr/${okrId}/decomposition/milestones/${krId}`, { milestones }),
generateMilestones: (okrId: number, krId: number) =>
api.post(`/okr/${okrId}/decomposition/milestones/generate`, { kr_id: krId }),
// KR完整修复(2026-08-27): krs表CRUD
createKr: (objectiveId: number, data: any) => api.post(`/okr/${objectiveId}/krs`, data),
updateKr: (objectiveId: number, krId: number, data: any) =>
api.put(`/okr/${objectiveId}/krs/${krId}`, data),
deleteKr: (objectiveId: number, krId: number) =>
api.delete(`/okr/${objectiveId}/krs/${krId}`),
syncKrs: (objectiveId: number, krs: any[]) =>
api.put(`/okr/${objectiveId}/krs/sync`, { krs }),
}
// ── 本体三支柱追溯链 (科目↔KPI↔OKR) ──
export const ontologyApi = {
trace: (objectiveId: number) => api.get('/ontology/trace', { params: { objective_id: objectiveId } }),
objectives: (params?: any) => api.get('/ontology/objectives', { params }),
}
export const dataApi = {
importExcel: (file: File, qs?: string) => {
const form = new FormData()
form.append('file', file)
return api.post(`/data/import-excel${qs ? '?' + qs : ''}`, form)
},
importExcelSmart: (file: File) => {
const form = new FormData()
form.append('file', file)
return api.post('/data/import-excel-smart', form, { timeout: 60000 })
},
listSources: () => api.get('/data/sources'),
createSource: (data: any) => api.post('/data/sources', data),
updateSource: (id: number, data: any) => api.put(`/data/sources/${id}`, data),
deleteSource: (id: number) => api.delete(`/data/sources/${id}`),
}
export const alertApi = {
list: (params?: any) => api.get('/alerts', { params }),
resolve: (id: number, data: any) => api.post(`/alerts/${id}/resolve`, data),
riskMatrix: (params?: any) => api.get('/alerts/risk-matrix', { params }),
}
export const alertRulesApi = {
list: (params?: any) => api.get('/alert-rules', { params }),
getKpiRules: (kpiId: number) => api.get(`/alert-rules/kpi/${kpiId}`),
create: (data: any) => api.post('/alert-rules', data),
update: (id: number, data: any) => api.put(`/alert-rules/${id}`, data),
delete: (id: number) => api.delete(`/alert-rules/${id}`),
batchCreate: (data: any) => api.post('/alert-rules/batch', data),
generateDefaults: () => api.post('/alert-rules/generate-defaults'),
checkAll: () => api.post('/alert-rules/check-all'),
calculateDynamic: () => api.post('/alert-rules/calculate-dynamic'),
dynamicThresholds: (params?: any) => api.get('/alert-rules/dynamic-thresholds', { params }),
// AI事前预警
checkForecast: () => api.post('/alert-rules/check-forecast'),
generateSuggestions: () => api.post('/alert-rules/generate-suggestions'),
}
export const userApi = {
list: () => api.get('/users'),
create: (data: any) => api.post('/users', data),
update: (id: number, data: any) => api.put(`/users/${id}`, data),
delete: (id: number) => api.delete(`/users/${id}`),
}
export const orgApi = {
nodes: () => api.get('/org/nodes'),
tree: () => api.get('/org/tree'),
}
export const notificationApi = {
list: () => api.get('/notifications/channels'),
create: (data: any) => api.post('/notifications/channels', data),
update: (id: number, data: any) => api.put(`/notifications/channels/${id}`, data),
delete: (id: number) => api.delete(`/notifications/channels/${id}`),
test: (id: number) => api.post(`/notifications/channels/${id}/test`),
logs: (params?: any) => api.get('/notifications/logs', { params }),
}
export const actionPlanApi = {
list: (params?: any) => api.get('/action-plans', { params }),
create: (data: any) => api.post('/action-plans', data),
update: (id: number, data: any) => api.put(`/action-plans/${id}`, data),
delete: (id: number) => api.delete(`/action-plans/${id}`),
cosoChecklist: (params?: any) => api.get('/action-plans/coso-checklist', { params }),
stats: () => api.get('/action-plans/stats'),
}
export const budgetApi = {
list: (params?: any) => api.get('/budget/plans', { params }),
create: (data: any) => api.post('/budget/plans', data),
update: (id: number, data: any) => api.put(`/budget/plans/${id}`, data),
delete: (id: number) => api.delete(`/budget/plans/${id}`),
autoDecompose: (data: any) => api.post('/budget/auto-decompose', data),
deviationReport: (params?: any) => api.get('/budget/deviation-report', { params }),
methodComparison: (data: any) => api.post('/budget/method-comparison', data),
applyMethod: (data: any) => api.post('/budget/apply-method', data),
// 版本管理
versions: (params?: any) => api.get('/budget/versions', { params }),
versionSubmit: (data: any) => api.post('/budget/versions/submit', data),
versionApprove: (data: any) => api.post('/budget/versions/approve', data),
versionDiff: (data: any) => api.post('/budget/versions/diff', data),
// 持续规划
getConfig: () => api.get('/budget/config'),
setConfig: (data: any) => api.post('/budget/config', data),
rollForward: () => api.post('/budget/roll-forward'),
getComparison: (params?: any) => api.get('/budget/comparison', { params }),
getKpiComparison: (kpiId: number, params?: any) => api.get(`/budget/comparison/kpi/${kpiId}`, { params }),
deviationCheck: (data: any) => api.post('/budget/deviation-check', data),
listDeviationAlerts: (params?: any) => api.get('/budget/deviation-alerts', { params }),
updateDeviationAlert: (id: number, data: any) => api.put(`/budget/deviation-alerts/${id}`, data),
}
export const costApi = {
dashboard: (params?: any) => api.get('/cost/dashboard', { params }),
overview: (params?: any) => api.get('/cost/overview', { params }),
variance: (params?: any) => api.get('/cost/variance', { params }),
breakdown: (params?: any) => api.get('/cost/breakdown', { params }),
comparison: (params?: any) => api.get('/cost/comparison', { params }),
listStandardCosts: (params?: any) => api.get('/cost/standard-costs', { params }),
createStandardCost: (data: any) => api.post('/cost/standard-costs', data),
updateStandardCost: (id: number, data: any) => api.put(`/cost/standard-costs/${id}`, data),
deleteStandardCost: (id: number) => api.delete(`/cost/standard-costs/${id}`),
listActualCosts: (params?: any) => api.get('/cost/actual-costs', { params }),
createActualCost: (data: any) => api.post('/cost/actual-costs', data),
listAbcActivities: () => api.get('/cost/abc/activities'),
createAbcActivity: (data: any) => api.post('/cost/abc/activities', data),
doAbcAllocate: (data: any) => api.post('/cost/abc/allocate', data),
listAbcAllocations: (params?: any) => api.get('/cost/abc/allocations', { params }),
}
export const predictApi = {
cvp: (data: any) => api.post('/predict/cvp', data),
cvpDetailed: (data: any) => api.post('/predict/cvp-detailed', data),
investment: (data: any) => api.post('/predict/investment', data),
sensitivity: (data: any) => api.post('/predict/sensitivity', data),
scenario: (data: any) => api.post('/predict/scenario', data),
relevantDecision: (data: any) => api.post('/predict/relevant-decision', data),
growthQuality: (data: any) => api.post('/predict/growth-quality', data),
// AI事前预警
cashForecast: (data: any) => api.post('/predict/cash-forecast', data),
cashForecastHistory: (params?: any) => api.get('/predict/cash-forecast/history', { params }),
forecastAccuracy: (params?: any) => api.get('/predict/accuracy', { params }),
scenarioSuggestions: (params?: any) => api.get('/predict/scenario-suggestions', { params }),
generateSuggestion: (data: any) => api.post('/predict/scenario-suggestion/generate', data),
// KPI趋势预测(预测性成本智能)
kpiForecast: (params?: any) => api.get('/predict/kpi-forecast', { params }),
kpiForecastFinance: (params?: any) => api.get('/predict/kpi-forecast/finance', { params }),
kpiForecastSensitivity: (params?: any) => api.get('/predict/kpi-forecast/sensitivity', { params }),
}
export const deviationPushApi = {
pushToMap: (data: any) => api.post('/deviation-push/push-to-map', data),
getMapNodes: (mapId: number) => api.get(`/deviation-push/map-nodes/${mapId}`),
}
export const driverBudgetApi = {
// 驱动因子模式切换
getMode: () => api.get('/budget/driver/mode'),
setMode: (data: any) => api.post('/budget/driver/mode', data),
// 行业包
getIndustries: () => api.get('/budget/driver/industries'),
getTemplates: (params?: any) => api.get('/budget/driver/templates', { params }),
// 驱动因子计算
calculate: (data: any) => api.post('/budget/driver/calculate', data),
// 敏感性分析
sensitivity: (data: any) => api.post('/budget/driver/sensitivity', data),
// 历史记录
getHistory: (params?: any) => api.get('/budget/driver/history', { params }),
}
export const budgetGenerateApi = {
getCandidates: () => api.get('/budget/kpi-budget-candidates'),
generateFromKpis: (data: any) => api.post('/budget/generate-from-kpis', data),
}
export const knowledgeArticleApi = {
list: (params?: any) => api.get('/knowledge-articles', { params }),
get: (id: number) => api.get(`/knowledge-articles/${id}`),
}
export const roleApi = {
list: () => api.get('/roles'),
create: (data: any) => api.post('/roles', data),
update: (id: number, data: any) => api.put(`/roles/${id}`, data),
delete: (id: number) => api.delete(`/roles/${id}`),
}
export const permissionApi = {
getMenuTree: () => api.get('/permissions/menu-tree'),
getUserRoles: () => api.get('/user-roles'),
setUserRoles: (data: any) => api.post('/user-roles', data),
}
export const kpiCausalityApi = {
list: (params?: any) => api.get('/kpi-causality', { params }),
get: (id: number) => api.get(`/kpi-causality/${id}`),
create: (data: any) => api.post('/kpi-causality', data),
update: (id: number, data: any) => api.put(`/kpi-causality/${id}`, data),
delete: (id: number) => api.delete(`/kpi-causality/${id}`),
getNetwork: (kpiId: number) => api.get(`/kpi-causality/kpi/${kpiId}/network`),
getFullNetwork: () => api.get('/kpi-causality/full-network'),
simulate: (data: any) => api.post('/kpi-causality/simulate', data),
}
export const dataQualityApi = {
check: () => api.get('/data-quality/check'),
stats: () => api.get('/data-quality/stats'),
logs: (params?: any) => api.get('/data-quality/logs', { params }),
updateLog: (id: number, data: any) => api.put(`/data-quality/logs/${id}`, data),
deleteLog: (id: number) => api.delete(`/data-quality/logs/${id}`),
}
export const biReportApi = {
listTemplates: () => api.get('/bi-reports/templates'),
list: () => api.get('/bi-reports'),
get: (id: number) => api.get(`/bi-reports/${id}`),
create: (data: any) => api.post('/bi-reports', data),
update: (id: number, data: any) => api.put(`/bi-reports/${id}`, data),
delete: (id: number) => api.delete(`/bi-reports/${id}`),
templates: () => api.get('/bi-reports/templates'),
seedTemplates: () => api.post('/bi-reports/templates/seed'),
analyze: (data: any) => api.post('/bi-reports/analyze', data),
exportReport: (data: any) => api.post('/bi-reports/export', data),
}
export const entityApi = {
list: () => api.get('/entities'),
create: (data: any) => api.post('/entities', data),
update: (id: number, data: any) => api.put(`/entities/${id}`, data),
}
export const ethicsQuizApi = {
getQuestions: () => api.get('/knowledge/ethics-quiz'),
}
export const botKpiApi = {
list: (params?: any) => api.get('/bot-kpis', { params }),
updateValue: (id: number, data: any) => api.post(`/bot-kpis/${id}/value`, data),
}
export const analysisApi = {
getResults: (params?: any) => api.get('/analysis/result', { params }),
createResult: (params: any) => api.post('/analysis/result', null, { params }),
deleteResult: (id: number) => api.delete(`/analysis/result/${id}`),
autoCalculate: (params?: any) => api.post('/analysis/auto-calculate', null, { params }),
}
export const expenseApi = {
// 规则配置
listRules: (params?: any) => api.get('/expenses/rules', { params }),
createRule: (data: any) => api.post('/expenses/rules', data),
updateRule: (id: number, data: any) => api.put(`/expenses/rules/${id}`, data),
deleteRule: (id: number) => api.delete(`/expenses/rules/${id}`),
seedRules: () => api.post('/expenses/rules/seed'),
// 报销单
listReimbursements: (params?: any) => api.get('/expenses/reimbursements', { params }),
getReimbursement: (id: number) => api.get(`/expenses/reimbursements/${id}`),
submitReimbursement: (data: any) => api.post('/expenses/reimbursements', data),
approveReimbursement: (id: number, comment?: string) => api.post(`/expenses/reimbursements/${id}/approve`, { comment }),
rejectReimbursement: (id: number, comment: string) => api.post(`/expenses/reimbursements/${id}/reject`, { comment }),
returnReimbursement: (id: number, comment?: string) => api.post(`/expenses/reimbursements/${id}/return`, { comment }),
resubmitReimbursement: (id: number, data?: any) => api.post(`/expenses/reimbursements/${id}/resubmit`, data),
// 看板统计
stats: (params?: any) => api.get('/expenses/stats', { params }),
}
// ── 资金管理智能体:资金缺口预测 + 收付款计划 + 预警 ──
export const cashApi = {
// 资金缺口预测
gapForecast: (params?: any) => api.get('/cash/gap-forecast', { params }),
// 当前现金余额(预测基线)
getBalance: (params?: any) => api.get('/cash/balance', { params }),
setBalance: (data: any) => api.post('/cash/balance', data),
// 收付款计划 CRUD
listPlans: (params?: any) => api.get('/cash/plans', { params }),
createPlan: (data: any) => api.post('/cash/plans', data),
updatePlan: (id: number, data: any) => api.put(`/cash/plans/${id}`, data),
deletePlan: (id: number) => api.delete(`/cash/plans/${id}`),
completePlan: (id: number) => api.post(`/cash/plans/${id}/complete`),
// 应收款催收
receivables: (params?: any) => api.get('/cash/receivables', { params }),
registerPayment: (id: number, data: any) => api.post(`/cash/receivables/${id}/payment`, data),
importBohaiAR: () => api.post('/cash/import/bohai-ar', {}),
// 到期提醒
upcoming: (params?: any) => api.get('/cash/upcoming', { params }),
// 页面看板(日历+预测+提醒)
dashboard: (params?: any) => api.get('/cash/dashboard', { params }),
// 资金预警
checkAlerts: (params?: any) => api.post('/cash/check-alerts', null, { params }),
alertStatus: (params?: any) => api.get('/cash/alerts/status', { params }),
}
// ── 税务合规智能体:税负监控 + 发票校验 + 社保比对 ──
export const taxApi = {
// ① 税负监控
listTaxRecords: (params?: any) => api.get('/tax/records', { params }),
createTaxRecord: (data: any) => api.post('/tax/records', data),
updateTaxRecord: (id: number, data: any) => api.put(`/tax/records/${id}`, data),
deleteTaxRecord: (id: number) => api.delete(`/tax/records/${id}`),
burdenAnalysis: (params?: any) => api.get('/tax/burden', { params }),
runTaxCheck: (params?: any) => api.post('/tax/check', null, { params }),
// ② 发票校验
listInvoices: (params?: any) => api.get('/tax/invoices', { params }),
createInvoice: (data: any) => api.post('/tax/invoices', data),
updateInvoice: (id: number, data: any) => api.put(`/tax/invoices/${id}`, data),
deleteInvoice: (id: number) => api.delete(`/tax/invoices/${id}`),
batchCheckInvoices: (params?: any) => api.post('/tax/invoices/check', null, { params }),
abnormalInvoices: (params?: any) => api.get('/tax/invoices/abnormal', { params }),
// ③ 社保比对
listSsRecords: (params?: any) => api.get('/tax/ss', { params }),
createSsRecord: (data: any) => api.post('/tax/ss', data),
updateSsRecord: (id: number, data: any) => api.put(`/tax/ss/${id}`, data),
deleteSsRecord: (id: number) => api.delete(`/tax/ss/${id}`),
batchCheckSs: (params?: any) => api.post('/tax/ss/check', null, { params }),
abnormalSs: (params?: any) => api.get('/tax/ss/abnormal', { params }),
// 看板聚合 + 演示数据
dashboard: (params?: any) => api.get('/tax/dashboard', { params }),
seedDemo: (params?: any) => api.post('/tax/demo-data', null, { params }),
}
export default api