拆分系统监测模块并统一运维化文案

This commit is contained in:
Cheng Zhou
2026-06-11 11:06:59 +08:00
parent b7484c8e01
commit 1886765db8
21 changed files with 222 additions and 143 deletions
@@ -59,7 +59,8 @@ describe("ApiPermissions.vue", () => {
const source = readFileSync(resolve(__dirname, "./ApiPermissions.vue"), "utf8");
expect(source).toContain('label="角色权限"');
expect(source).toContain('label="权限监控"');
expect(source).not.toContain('label="权限监控"');
expect(source).not.toContain("<PermissionMonitoring");
});
it("has save button disabled when not dirty", () => {
+2 -70
View File
@@ -19,10 +19,6 @@
</span>
</div>
<div class="permission-actions">
<el-button @click="resetMetrics" :loading="resetting">
<el-icon><RefreshRight /></el-icon>
刷新指标
</el-button>
<el-button type="primary" :loading="saving" :disabled="!dirty" @click="save">
<el-icon><Check /></el-icon>
保存
@@ -46,17 +42,6 @@
@update="onApiMatrixUpdate"
/>
</el-tab-pane>
<!-- 权限监控 -->
<el-tab-pane label="权限监控" name="monitoring">
<PermissionMonitoring
:is-admin="isAdmin"
:metrics="metrics"
:health="health"
:alerts="alerts"
@refresh="loadMonitoringData"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
@@ -66,39 +51,24 @@
import { ref, computed, onMounted } from "vue";
import { useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import { Key, RefreshRight, Check } from "@element-plus/icons-vue";
import { Key, Check } from "@element-plus/icons-vue";
import type {
ApiEndpointPermissionsResponse,
PermissionMetricsResponse,
CacheStatsResponse,
AlertsResponse,
HealthResponse,
} from "@/types/api";
import {
fetchApiEndpointPermissions,
updateApiEndpointPermissions,
fetchPermissionMetrics,
fetchCacheStats,
fetchPermissionAlerts,
fetchPermissionHealth,
resetPermissionMetrics,
} from "@/api/projectPermissions";
import { useStudyStore } from "@/store/study";
import { useAuthStore } from "@/store/auth";
import { isSystemAdmin } from "@/utils/roles";
import ApiEndpointPermissions from "@/components/ApiEndpointPermissions.vue";
import PermissionMonitoring from "@/components/PermissionMonitoring.vue";
import PermissionTemplateSelector from "@/components/PermissionTemplateSelector.vue";
const route = useRoute();
const studyStore = useStudyStore();
const auth = useAuthStore();
const isAdmin = computed(() => isSystemAdmin(auth.user));
const activeTab = ref<"api" | "monitoring">("api");
const activeTab = ref<"api">("api");
const loading = ref(false);
const saving = ref(false);
const resetting = ref(false);
const project = computed(() => studyStore.currentStudy);
const studyId = computed(() => {
@@ -109,11 +79,6 @@ const studyId = computed(() => {
// 权限数据
const apiMatrix = ref<ApiEndpointPermissionsResponse | null>(null);
// 监控数据
const metrics = ref<PermissionMetricsResponse | null>(null);
const health = ref<HealthResponse | null>(null);
const alerts = ref<AlertsResponse | null>(null);
// 脏值检测
const dirty = ref(false);
@@ -133,25 +98,6 @@ const loadPermissionData = async () => {
}
};
const loadMonitoringData = async () => {
if (!studyId.value) return;
try {
const [metricsRes, healthRes, alertsRes] = await Promise.all([
fetchPermissionMetrics(),
fetchPermissionHealth(),
fetchPermissionAlerts(undefined, 20),
]);
metrics.value = metricsRes.data;
health.value = healthRes.data;
alerts.value = alertsRes.data;
} catch (error) {
ElMessage.error("加载监控数据失败");
console.error(error);
}
};
const onApiMatrixUpdate = (newMatrix: ApiEndpointPermissionsResponse) => {
apiMatrix.value = newMatrix;
dirty.value = true;
@@ -209,20 +155,6 @@ const save = async () => {
}
};
const resetMetrics = async () => {
resetting.value = true;
try {
await resetPermissionMetrics();
await loadMonitoringData();
ElMessage.success("指标已重置");
} catch (error) {
ElMessage.error("重置指标失败");
console.error(error);
} finally {
resetting.value = false;
}
};
onMounted(() => {
loadPermissionData();
});
@@ -351,7 +351,9 @@ describe("permission management custom roles", () => {
it("does not render the duplicated monitoring header", () => {
const source = readSource();
expect(source).toContain('<PermissionMonitoring :is-admin="isAdmin" />');
expect(source).not.toContain("<PermissionMonitoring");
expect(source).not.toContain('activeTab === "monitoring"');
expect(source).not.toContain("/admin/permissions/monitoring");
expect(source).not.toContain("实时监控权限使用情况、趋势分析与异常告警");
expect(source).not.toContain("重置指标");
expect(source).not.toContain("refreshMonitoring");
@@ -215,18 +215,6 @@
</div>
</template>
<!--
权限监控
-->
<template v-else-if="activeTab === 'monitoring'">
<div class="perm-body">
<div class="perm-body-padded">
<PermissionMonitoring :is-admin="isAdmin" />
</div>
</div>
</template>
<!--
角色管理抽屉
-->
@@ -612,7 +600,6 @@ import {
} from "@/utils/projectPermissionModules";
import { useRoleTemplateMeta } from "@/composables/useRoleTemplateMeta";
import ApiEndpointPermissions from "@/components/ApiEndpointPermissions.vue";
import PermissionMonitoring from "@/components/PermissionMonitoring.vue";
import PermissionTemplateSelector from "@/components/PermissionTemplateSelector.vue";
const route = useRoute();
@@ -657,16 +644,15 @@ const memberRoleLabels = (row: MemberRoleRow) => {
};
// ── 顶层标签 ──
const tabFromPath = (): "project" | "system" | "monitoring" => {
const tabFromPath = (): "project" | "system" => {
const p = route.path;
if (p.endsWith("/system")) return "system";
if (p.endsWith("/monitoring")) return "monitoring";
return "project";
};
const activeTab = computed({
get: () => tabFromPath(),
set: (tab: "project" | "system" | "monitoring") => {
const pathMap = { system: "/admin/permissions/system", project: "/admin/permissions/project", monitoring: "/admin/permissions/monitoring" };
set: (tab: "project" | "system") => {
const pathMap = { system: "/admin/permissions/system", project: "/admin/permissions/project" };
router.push({ path: pathMap[tab], query: route.query });
},
});
@@ -0,0 +1,18 @@
<template>
<div class="system-monitoring-page">
<PermissionMonitoring :is-admin="true" />
</div>
</template>
<script setup lang="ts">
import PermissionMonitoring from "@/components/PermissionMonitoring.vue";
</script>
<style scoped>
.system-monitoring-page {
margin: -6px -8px;
min-height: calc(100vh - 52px);
min-height: calc(100dvh - 52px);
background: #f5f7fa;
}
</style>