refactor(cma-frontend): route all API calls through shared axios instance (cma-frontend-axios-unify-20260915)

api/index.ts: add permissionApi.getModules/getConfig/saveConfig + alignmentApi.config/tree.

views: replace 13 raw fetch calls and 6 local axios.create instances (each hand-building the Authorization header, without the shared 401 redirect / timeout toast) with the shared instance from api/index.ts.

KPIAlignment: fixes a live bug - the header value was the string literal 'Bearer ' + token, so /alignment/tree always returned 401 (reproduced against the production bundle).

Unwrap semantics preserved: the shared response interceptor returns response.data, so call sites that used res.data were adjusted accordingly.

Verified: scan-frontend-tokenless RAW-TOKENLESS=0; vite build ok; headless A/B (new dist vs production bundle, 8 affected pages, real login) -> identical rendered rows and identical pre-existing error profile, /alignment 401->200.

Push not executed: main is ahead 4 with other tickets' gated commits (see cma-main-ahead3-push-gate-notice-20260915).
This commit is contained in:
Hermes CI Fix
2026-09-15 22:21:56 +08:00
parent e5eb092d20
commit 7b74736980
9 changed files with 73 additions and 133 deletions
+14 -35
View File
@@ -141,6 +141,8 @@
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// 统一走 api/index.ts 的 axios 实例(拦截器自动带 Bearer / 401 跳登录)
import { permissionApi, alignmentApi } from '../api/index'
// ── Tab 控制 ──
const activeTab = ref('permissions')
@@ -200,14 +202,10 @@ function toggleAction(role: string, actionKey: string, value: boolean) {
async function savePermConfig() {
saving.value = true
try {
const token = localStorage.getItem('cma_token')
await fetch('/api/cma/permissions/config', {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({
route_permissions: routePerms.value,
action_permissions: actionPerms.value,
}),
// 统一走 api 实例(Bearer 由拦截器注入,不再手拼 header)
await permissionApi.saveConfig({
route_permissions: routePerms.value,
action_permissions: actionPerms.value,
})
ElMessage.success('权限配置已保存')
permSaved.value = true
@@ -217,13 +215,8 @@ async function savePermConfig() {
async function resetPermConfig() {
try { await ElMessageBox.confirm('确定恢复默认权限配置?', '确认', { center: true }) } catch { return }
const token = localStorage.getItem('cma_token')
try {
await fetch('/api/cma/permissions/config', {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({})
})
await permissionApi.saveConfig({})
ElMessage.success('已恢复默认')
loadPermData()
} catch { ElMessage.error('恢复失败') }
@@ -231,12 +224,9 @@ async function resetPermConfig() {
async function loadPermData() {
try {
// 鉴权收口(cma-api-auth-surface-audit-20260914):/permissions/* 已要求 Bearer,补 token
const token = localStorage.getItem('cma_token')
const authHeaders = { 'Authorization': `Bearer ${token}` }
const [modRes, cfgRes] = await Promise.all([
fetch('/api/cma/permissions/modules', { headers: authHeaders }).then(r => r.json()),
fetch('/api/cma/permissions/config', { headers: authHeaders }).then(r => r.json()),
const [modRes, cfgRes]: any[] = await Promise.all([
permissionApi.getModules(),
permissionApi.getConfig(),
])
modules.value = modRes.modules || []
actions.value = modRes.actions || []
@@ -275,11 +265,8 @@ function feedsLabel(feeds: string[] | null) {
async function loadAlignmentConfig() {
try {
// 鉴权收口(cma-api-auth-surface-audit-20260914):/alignment/* 已要求 Bearer,补 token
const token = localStorage.getItem('cma_token')
const r = await fetch('/api/cma/alignment/config', {
headers: { 'Authorization': `Bearer ${token}` },
}).then(r => r.json())
// 统一走 api 实例(Bearer 由拦截器注入)
const r: any = await alignmentApi.getConfig()
alignmentModes.value = r.modes || []
alignConfigured.value = r.configured || false
currentMode.value = null
@@ -295,12 +282,7 @@ async function saveAlignmentConfig() {
if (!selectedMode.value) return
savingAlign.value = true
try {
const token = localStorage.getItem('cma_token')
const r = await fetch('/api/cma/alignment/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ mode: selectedMode.value }),
}).then(r => r.json())
const r: any = await alignmentApi.saveConfig({ mode: selectedMode.value })
ElMessage.success(r.message || '对齐模式已设置')
loadAlignmentConfig()
showSelector.value = false
@@ -311,10 +293,7 @@ async function saveAlignmentConfig() {
async function previewTree() {
loadingTree.value = true
try {
const token = localStorage.getItem('cma_token')
const r = await fetch('/api/cma/alignment/tree', {
headers: { 'Authorization': `Bearer ${token}` },
}).then(r => r.json())
const r: any = await alignmentApi.getTree()
treeData.value = r
} catch (e: any) {
ElMessage.error(e.message || '加载失败')