From b700863d56753621e1629f0b42aa1ab235380fe0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E5=90=AF=E8=88=AA?=
<12344192+zhangsetsail@user.noreply.gitee.com>
Date: Mon, 16 Mar 2026 15:10:42 +0800
Subject: [PATCH 001/147] feat: add platform resource API service and DVA model
---
src/models/platformResources.js | 97 +++++++++++++++++++++++++++++++
src/services/platformResource.js | 98 ++++++++++++++++++++++++++++++++
2 files changed, 195 insertions(+)
create mode 100644 src/models/platformResources.js
create mode 100644 src/services/platformResource.js
diff --git a/src/models/platformResources.js b/src/models/platformResources.js
new file mode 100644
index 000000000..f06770010
--- /dev/null
+++ b/src/models/platformResources.js
@@ -0,0 +1,97 @@
+import {
+ getPlatformResourcesOverview,
+ getPlatformStorageClasses,
+ getPlatformPersistentVolumes,
+ getPlatformResourceTypes,
+ getPlatformResourceMetrics,
+ getPlatformResourceAlerts,
+} from '../services/platformResources';
+
+export default {
+ namespace: 'platformResources',
+
+ state: {
+ overview: {},
+ storageClasses: [],
+ persistentVolumes: [],
+ resourceTypes: [],
+ metrics: {},
+ alerts: [],
+ },
+
+ effects: {
+ *fetchOverview({ payload, callback, handleError }, { call, put }) {
+ const response = yield call(getPlatformResourcesOverview, payload, handleError);
+ if (response) {
+ yield put({ type: 'saveOverview', payload: response });
+ if (callback) callback(response);
+ }
+ },
+
+ *fetchStorageClasses({ payload, callback, handleError }, { call, put }) {
+ const response = yield call(getPlatformStorageClasses, payload, handleError);
+ if (response) {
+ yield put({ type: 'saveStorageClasses', payload: response });
+ if (callback) callback(response);
+ }
+ },
+
+ *fetchPersistentVolumes({ payload, callback, handleError }, { call, put }) {
+ const response = yield call(getPlatformPersistentVolumes, payload, handleError);
+ if (response) {
+ yield put({ type: 'savePersistentVolumes', payload: response });
+ if (callback) callback(response);
+ }
+ },
+
+ *fetchResourceTypes({ payload, callback, handleError }, { call, put }) {
+ const response = yield call(getPlatformResourceTypes, payload, handleError);
+ if (response) {
+ yield put({ type: 'saveResourceTypes', payload: response });
+ if (callback) callback(response);
+ }
+ },
+
+ *fetchMetrics({ payload, callback, handleError }, { call, put }) {
+ const response = yield call(getPlatformResourceMetrics, payload, handleError);
+ if (response) {
+ yield put({ type: 'saveMetrics', payload: response });
+ if (callback) callback(response);
+ }
+ },
+
+ *fetchAlerts({ payload, callback, handleError }, { call, put }) {
+ const response = yield call(getPlatformResourceAlerts, payload, handleError);
+ if (response) {
+ yield put({ type: 'saveAlerts', payload: response });
+ if (callback) callback(response);
+ }
+ },
+ },
+
+ reducers: {
+ saveOverview(state, action) {
+ return { ...state, overview: action.payload };
+ },
+
+ saveStorageClasses(state, action) {
+ return { ...state, storageClasses: action.payload };
+ },
+
+ savePersistentVolumes(state, action) {
+ return { ...state, persistentVolumes: action.payload };
+ },
+
+ saveResourceTypes(state, action) {
+ return { ...state, resourceTypes: action.payload };
+ },
+
+ saveMetrics(state, action) {
+ return { ...state, metrics: action.payload };
+ },
+
+ saveAlerts(state, action) {
+ return { ...state, alerts: action.payload };
+ },
+ },
+};
diff --git a/src/services/platformResource.js b/src/services/platformResource.js
new file mode 100644
index 000000000..ac9158910
--- /dev/null
+++ b/src/services/platformResource.js
@@ -0,0 +1,98 @@
+import apiconfig from '../../config/api.config';
+import request from '../utils/request';
+
+/**
+ * Get storage overview information
+ */
+export async function getStorageOverview(body = {}) {
+ return request(
+ `${apiconfig.baseUrl}/console/platform/storage/overview`,
+ {
+ method: 'get',
+ params: {
+ cluster_id: body.cluster_id
+ }
+ }
+ );
+}
+
+/**
+ * Get available storage classes
+ */
+export async function getStorageClasses(body = {}) {
+ return request(
+ `${apiconfig.baseUrl}/console/platform/storage/classes`,
+ {
+ method: 'get',
+ params: {
+ cluster_id: body.cluster_id
+ }
+ }
+ );
+}
+
+/**
+ * Get persistent volumes
+ */
+export async function getPersistentVolumes(body = {}) {
+ return request(
+ `${apiconfig.baseUrl}/console/platform/storage/volumes`,
+ {
+ method: 'get',
+ params: {
+ cluster_id: body.cluster_id,
+ page: body.page,
+ page_size: body.page_size
+ }
+ }
+ );
+}
+
+/**
+ * Get cluster resource types
+ */
+export async function getClusterResourceTypes(body = {}) {
+ return request(
+ `${apiconfig.baseUrl}/console/platform/cluster/resource-types`,
+ {
+ method: 'get',
+ params: {
+ cluster_id: body.cluster_id
+ }
+ }
+ );
+}
+
+/**
+ * Get cluster resources
+ */
+export async function getClusterResources(body = {}) {
+ return request(
+ `${apiconfig.baseUrl}/console/platform/cluster/resources`,
+ {
+ method: 'get',
+ params: {
+ cluster_id: body.cluster_id,
+ resource_type: body.resource_type,
+ page: body.page,
+ page_size: body.page_size
+ }
+ }
+ );
+}
+
+/**
+ * Get cluster resource detail
+ */
+export async function getClusterResourceDetail(body = {}) {
+ return request(
+ `${apiconfig.baseUrl}/console/platform/cluster/resources/${body.resource_id}`,
+ {
+ method: 'get',
+ params: {
+ cluster_id: body.cluster_id,
+ resource_type: body.resource_type
+ }
+ }
+ );
+}
From 68fb0cb4609a45c53a1fccd63e7ae3a8f63afc18 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BC=A0=E5=90=AF=E8=88=AA?=
<12344192+zhangsetsail@user.noreply.gitee.com>
Date: Mon, 16 Mar 2026 15:10:42 +0800
Subject: [PATCH 002/147] feat: add storage page component
---
src/pages/PlatformResources/Storage/index.js | 337 ++++++++++++++++++
.../PlatformResources/Storage/index.less | 100 ++++++
2 files changed, 437 insertions(+)
create mode 100644 src/pages/PlatformResources/Storage/index.js
create mode 100644 src/pages/PlatformResources/Storage/index.less
diff --git a/src/pages/PlatformResources/Storage/index.js b/src/pages/PlatformResources/Storage/index.js
new file mode 100644
index 000000000..0356ebdee
--- /dev/null
+++ b/src/pages/PlatformResources/Storage/index.js
@@ -0,0 +1,337 @@
+import React, { PureComponent } from 'react';
+import { Card, Row, Col, Table, Spin, Button, Modal, notification } from 'antd';
+import { connect } from 'dva';
+import { formatMessage } from '@/utils/intl';
+import globalUtil from '@/utils/global';
+import styles from './index.less';
+
+@connect(({ loading, platformResources }) => ({
+ storageLoading: loading.effects['platformResources/fetchStorageData'],
+ storageClassList: platformResources.storageClassList || [],
+ pvList: platformResources.pvList || [],
+ storageStats: platformResources.storageStats || {}
+}))
+export default class StoragePage extends PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ selectedStorageClass: null,
+ selectedPV: null
+ };
+ }
+
+ componentDidMount() {
+ this.loadStorageData();
+ }
+
+ loadStorageData = () => {
+ const { dispatch } = this.props;
+ const regionName = globalUtil.getCurrRegionName();
+
+ dispatch({
+ type: 'platformResources/fetchStorageData',
+ payload: {
+ region_name: regionName
+ },
+ callback: res => {
+ if (res && res.status_code !== 200) {
+ notification.error({
+ message: formatMessage({ id: 'notification.error.load_storage' })
+ });
+ }
+ }
+ });
+ };
+
+ handleRefresh = () => {
+ this.loadStorageData();
+ };
+
+ handleDeleteStorageClass = (record) => {
+ const { dispatch } = this.props;
+ const regionName = globalUtil.getCurrRegionName();
+
+ Modal.confirm({
+ title: formatMessage({ id: 'modal.confirm.delete' }),
+ content: formatMessage({ id: 'modal.confirm.delete_storage_class' }),
+ okText: formatMessage({ id: 'button.confirm' }),
+ cancelText: formatMessage({ id: 'button.cancel' }),
+ onOk: () => {
+ dispatch({
+ type: 'platformResources/deleteStorageClass',
+ payload: {
+ region_name: regionName,
+ name: record.name
+ },
+ callback: res => {
+ if (res && res.status_code === 200) {
+ notification.success({
+ message: formatMessage({ id: 'notification.success.delete' })
+ });
+ this.loadStorageData();
+ }
+ }
+ });
+ }
+ });
+ };
+
+ handleDeletePV = (record) => {
+ const { dispatch } = this.props;
+ const regionName = globalUtil.getCurrRegionName();
+
+ Modal.confirm({
+ title: formatMessage({ id: 'modal.confirm.delete' }),
+ content: formatMessage({ id: 'modal.confirm.delete_pv' }),
+ okText: formatMessage({ id: 'button.confirm' }),
+ cancelText: formatMessage({ id: 'button.cancel' }),
+ onOk: () => {
+ dispatch({
+ type: 'platformResources/deletePV',
+ payload: {
+ region_name: regionName,
+ name: record.name
+ },
+ callback: res => {
+ if (res && res.status_code === 200) {
+ notification.success({
+ message: formatMessage({ id: 'notification.success.delete' })
+ });
+ this.loadStorageData();
+ }
+ }
+ });
+ }
+ });
+ };
+
+ renderStorageStats = () => {
+ const { storageStats } = this.props;
+
+ const stats = [
+ {
+ label: formatMessage({ id: 'storage.stats.total_capacity' }),
+ value: storageStats.totalCapacity || '0 Gi',
+ color: '#155aef'
+ },
+ {
+ label: formatMessage({ id: 'storage.stats.used_capacity' }),
+ value: storageStats.usedCapacity || '0 Gi',
+ color: '#18B633'
+ },
+ {
+ label: formatMessage({ id: 'storage.stats.available_capacity' }),
+ value: storageStats.availableCapacity || '0 Gi',
+ color: '#FF8D3C'
+ },
+ {
+ label: formatMessage({ id: 'storage.stats.storage_class_count' }),
+ value: storageStats.storageClassCount || 0,
+ color: '#FC481B'
+ }
+ ];
+
+ return (
+
全局资源与集群级公共资源管理
+集群资源概览(待实现)
+存储卷列表(待实现)
+ClusterRole / ClusterRoleBinding(待实现)
+CRD 列表(待实现)
+Namespace 列表(待实现)
+当前团队范围内的资源与 Helm 应用管理
+Pod 列表(待实现)
Service/Ingress(待实现)
ConfigMap/Secret(待实现)
PVC 列表(待实现)
{v},
+ },
+ { title: '回收策略', dataIndex: 'reclaim_policy', key: 'reclaim_policy', render: v => 当前团队范围内的资源与 Helm 应用管理
{gv};
- },
+ title: '名称',
+ key: 'name',
+ render: (_, r) => (
+ { e.preventDefault(); this.handleViewInstanceYaml(r); }}>
+ {(r.metadata && r.metadata.name) || '-'}
+
+ ),
},
{
- title: '支持操作',
- dataIndex: 'verbs',
- key: 'verbs',
- render: verbs => (Array.isArray(verbs) ? verbs : []).map(v =>