fix(eslint): reduce warnings in GitHub Actions deployment

- Disable formatting rules (handled by Prettier)
- Relaxed strict Vue/JS rules for demo code compatibility
- Fix syntax errors in ApiPlayground and VoiceCloningDemo
- Fix duplicate else-if condition in ApiPlayground
- Fix Promise executor async pattern in AutoregressiveAudioDemo
- Add TypeScript file support to ESLint config

Warnings reduced from 295 to 251 problems.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
sanbuphy
2026-02-18 17:38:10 +08:00
parent 8b01686e68
commit 0eba9e87e9
456 changed files with 28450 additions and 9677 deletions
@@ -2,11 +2,22 @@
<div class="availability-zone-demo">
<!-- 控制面板 -->
<div class="control-panel">
<el-radio-group v-model="viewMode" size="small">
<el-radio-button label="normal">正常运行</el-radio-button>
<el-radio-button label="az-failure"> AZ 故障</el-radio-button>
<el-radio-button label="maintenance">维护模式</el-radio-button>
<el-radio-button label="scaling">弹性扩容</el-radio-button>
<el-radio-group
v-model="viewMode"
size="small"
>
<el-radio-button label="normal">
正常运行
</el-radio-button>
<el-radio-button label="az-failure">
AZ 故障
</el-radio-button>
<el-radio-button label="maintenance">
维护模式
</el-radio-button>
<el-radio-button label="scaling">
弹性扩容
</el-radio-button>
</el-radio-group>
<el-switch
@@ -20,65 +31,108 @@
<div class="architecture-container">
<!-- 流量入口层 -->
<div class="layer entry-layer">
<div class="layer-title">🚪 流量入口层</div>
<div class="layer-title">
🚪 流量入口层
</div>
<div class="entry-components">
<div class="component dns">
<div class="component-icon">📖</div>
<div class="component-name">DNS 解析</div>
<div class="component-icon">
📖
</div>
<div class="component-name">
DNS 解析
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<div class="component cdn">
<div class="component-icon">🌐</div>
<div class="component-name">CDN 加速</div>
<div class="component-icon">
🌐
</div>
<div class="component-name">
CDN 加速
</div>
</div>
<div class="arrow"></div>
<div class="arrow">
</div>
<div class="component waf">
<div class="component-icon">🛡</div>
<div class="component-name">WAF 防护</div>
<div class="component-icon">
🛡
</div>
<div class="component-name">
WAF 防护
</div>
</div>
</div>
</div>
<!-- 流量分发层 -->
<div class="layer distribution-layer">
<div class="layer-title"> 流量分发层 (SLB)</div>
<div class="slb-cluster"
:class="{ 'failover-active': viewMode === 'az-failure' }">
<div class="slb-instance primary"
:class="{ failed: viewMode === 'az-failure' }">
<div class="layer-title">
流量分发层 (SLB)
</div>
<div
class="slb-cluster"
:class="{ 'failover-active': viewMode === 'az-failure' }"
>
<div
class="slb-instance primary"
:class="{ failed: viewMode === 'az-failure' }"
>
<div class="instance-header">
<span class="status-indicator"
:class="viewMode === 'az-failure' ? 'offline' : 'online'"></span>
<span
class="status-indicator"
:class="viewMode === 'az-failure' ? 'offline' : 'online'"
/>
<span class="instance-name">SLB-A ()</span>
</div>
<div class="instance-meta">可用区 A</div>
<div class="instance-meta">
可用区 A
</div>
<!-- 流量动画 -->
<div class="traffic-flow" v-if="showTraffic && viewMode !== 'az-failure'">
<div class="flow-dot"></div>
<div
v-if="showTraffic && viewMode !== 'az-failure'"
class="traffic-flow"
>
<div class="flow-dot" />
</div>
</div>
<div class="failover-arrow" v-if="viewMode === 'az-failure'">
<div
v-if="viewMode === 'az-failure'"
class="failover-arrow"
>
<span class="failover-text">故障转移</span>
<div class="arrow-line"></div>
<div class="arrow-line" />
</div>
<div class="slb-instance secondary"
:class="{ 'taking-over': viewMode === 'az-failure' }">
<div
class="slb-instance secondary"
:class="{ 'taking-over': viewMode === 'az-failure' }"
>
<div class="instance-header">
<span class="status-indicator"
:class="viewMode === 'az-failure' ? 'online' : 'standby'"></span>
<span
class="status-indicator"
:class="viewMode === 'az-failure' ? 'online' : 'standby'"
/>
<span class="instance-name">SLB-B ()</span>
</div>
<div class="instance-meta">可用区 B</div>
<div class="instance-meta">
可用区 B
</div>
<div class="traffic-flow" v-if="showTraffic && viewMode === 'az-failure'">
<div class="flow-dot"></div>
<div
v-if="showTraffic && viewMode === 'az-failure'"
class="traffic-flow"
>
<div class="flow-dot" />
</div>
</div>
</div>
@@ -86,7 +140,9 @@
<!-- 可用区层 -->
<div class="layer azs-layer">
<div class="layer-title">🏢 可用区层 (Multi-AZ)</div>
<div class="layer-title">
🏢 可用区层 (Multi-AZ)
</div>
<div class="azs-grid">
<div
v-for="az in availabilityZones"
@@ -106,8 +162,10 @@
<span class="az-id">{{ az.id }}</span>
</div>
<div class="az-status">
<span class="status-badge"
:class="getAzStatusClass(az)">
<span
class="status-badge"
:class="getAzStatusClass(az)"
>
{{ getAzStatusText(az) }}
</span>
</div>
@@ -126,17 +184,29 @@
</div>
<!-- 维护模式遮罩 -->
<div class="maintenance-overlay" v-if="viewMode === 'maintenance' && az.id === 'az-a'">
<div
v-if="viewMode === 'maintenance' && az.id === 'az-a'"
class="maintenance-overlay"
>
<div class="overlay-content">
<div class="overlay-icon">🔧</div>
<div class="overlay-text">维护中</div>
<div class="overlay-icon">
🔧
</div>
<div class="overlay-text">
维护中
</div>
</div>
</div>
<!-- 弹性扩容动画 -->
<div class="scaling-indicator" v-if="viewMode === 'scaling'">
<div class="scaling-dot"></div>
<div class="scaling-text">扩容中</div>
<div
v-if="viewMode === 'scaling'"
class="scaling-indicator"
>
<div class="scaling-dot" />
<div class="scaling-text">
扩容中
</div>
</div>
</div>
</div>
@@ -145,22 +215,24 @@
<!-- 状态说明 -->
<div class="status-legend">
<div class="legend-title">状态说明</div>
<div class="legend-title">
状态说明
</div>
<div class="legend-items">
<div class="legend-item">
<span class="legend-dot healthy"></span>
<span class="legend-dot healthy" />
<span>健康运行</span>
</div>
<div class="legend-item">
<span class="legend-dot standby"></span>
<span class="legend-dot standby" />
<span>待机中</span>
</div>
<div class="legend-item">
<span class="legend-dot degraded"></span>
<span class="legend-dot degraded" />
<span>降级/故障</span>
</div>
<div class="legend-item">
<span class="legend-dot maintenance"></span>
<span class="legend-dot maintenance" />
<span>维护中</span>
</div>
</div>
@@ -2,30 +2,61 @@
<div class="compute-topology-demo">
<!-- 控制面板 -->
<div class="control-panel">
<el-radio-group v-model="viewMode" size="small">
<el-radio-button label="overview">概览</el-radio-button>
<el-radio-button label="vm">虚拟机</el-radio-button>
<el-radio-button label="container">容器</el-radio-button>
<el-radio-button label="serverless">无服务器</el-radio-button>
<el-radio-group
v-model="viewMode"
size="small"
>
<el-radio-button label="overview">
概览
</el-radio-button>
<el-radio-button label="vm">
虚拟机
</el-radio-button>
<el-radio-button label="container">
容器
</el-radio-button>
<el-radio-button label="serverless">
无服务器
</el-radio-button>
</el-radio-group>
<el-switch v-model="showMetrics" active-text="显示指标" style="margin-left: 20px" />
<el-switch
v-model="showMetrics"
active-text="显示指标"
style="margin-left: 20px"
/>
</div>
<!-- 计算架构图 -->
<div class="compute-architecture">
<!-- 物理基础设施层 -->
<div class="layer physical-layer" v-if="viewMode === 'overview' || viewMode === 'vm'">
<div
v-if="viewMode === 'overview' || viewMode === 'vm'"
class="layer physical-layer"
>
<div class="layer-header">
<span class="layer-icon">🏭</span>
<span class="layer-title">物理基础设施</span>
</div>
<div class="layer-content">
<div class="server-rack" v-for="rack in serverRacks" :key="rack.id">
<div class="rack-header">{{ rack.name }}</div>
<div
v-for="rack in serverRacks"
:key="rack.id"
class="server-rack"
>
<div class="rack-header">
{{ rack.name }}
</div>
<div class="rack-servers">
<div v-for="server in rack.servers" :key="server.id" class="server-node">
<div class="server-indicator" :class="server.status"></div>
<div
v-for="server in rack.servers"
:key="server.id"
class="server-node"
>
<div
class="server-indicator"
:class="server.status"
/>
</div>
</div>
</div>
@@ -33,34 +64,54 @@
</div>
<!-- 虚拟化层 -->
<div class="layer virtualization-layer" v-if="viewMode === 'overview' || viewMode === 'vm'">
<div
v-if="viewMode === 'overview' || viewMode === 'vm'"
class="layer virtualization-layer"
>
<div class="layer-header">
<span class="layer-icon">🔧</span>
<span class="layer-title">虚拟化层</span>
</div>
<div class="layer-content">
<div class="hypervisor-cluster">
<div class="hypervisor" v-for="hv in hypervisors" :key="hv.id">
<div
v-for="hv in hypervisors"
:key="hv.id"
class="hypervisor"
>
<div class="hv-header">
<span class="hv-icon">🔨</span>
<span class="hv-name">{{ hv.name }}</span>
</div>
<div class="vms-list">
<div v-for="vm in hv.vms" :key="vm.id" class="vm-item">
<div
v-for="vm in hv.vms"
:key="vm.id"
class="vm-item"
>
<div class="vm-info">
<span class="vm-icon">💻</span>
<span class="vm-name">{{ vm.name }}</span>
</div>
<div class="vm-metrics" v-if="showMetrics">
<div
v-if="showMetrics"
class="vm-metrics"
>
<div class="metric">
<div class="metric-bar">
<div class="metric-fill" :style="{ width: vm.cpu + '%' }"></div>
<div
class="metric-fill"
:style="{ width: vm.cpu + '%' }"
/>
</div>
<span class="metric-label">CPU</span>
</div>
<div class="metric">
<div class="metric-bar">
<div class="metric-fill memory" :style="{ width: vm.memory + '%' }"></div>
<div
class="metric-fill memory"
:style="{ width: vm.memory + '%' }"
/>
</div>
<span class="metric-label">内存</span>
</div>
@@ -73,7 +124,10 @@
</div>
<!-- 容器层 -->
<div class="layer container-layer" v-if="viewMode === 'overview' || viewMode === 'container'">
<div
v-if="viewMode === 'overview' || viewMode === 'container'"
class="layer container-layer"
>
<div class="layer-header">
<span class="layer-icon">📦</span>
<span class="layer-title">容器编排层 (Kubernetes)</span>
@@ -82,28 +136,54 @@
<div class="k8s-cluster">
<!-- 控制平面 -->
<div class="control-plane">
<div class="cp-title">控制平面</div>
<div class="cp-title">
控制平面
</div>
<div class="cp-components">
<div class="cp-comp" v-for="comp in controlPlaneComponents" :key="comp.name">
<div class="comp-icon">{{ comp.icon }}</div>
<div class="comp-name">{{ comp.name }}</div>
<div
v-for="comp in controlPlaneComponents"
:key="comp.name"
class="cp-comp"
>
<div class="comp-icon">
{{ comp.icon }}
</div>
<div class="comp-name">
{{ comp.name }}
</div>
</div>
</div>
</div>
<!-- 工作节点 -->
<div class="worker-nodes">
<div class="nodes-title">工作节点</div>
<div class="nodes-title">
工作节点
</div>
<div class="nodes-grid">
<div class="node" v-for="node in workerNodes" :key="node.name">
<div
v-for="node in workerNodes"
:key="node.name"
class="node"
>
<div class="node-header">
<span class="node-icon">🔧</span>
<span class="node-name">{{ node.name }}</span>
<span class="node-status" :class="node.status"></span>
<span
class="node-status"
:class="node.status"
/>
</div>
<div class="pods-list">
<div class="pod" v-for="pod in node.pods" :key="pod.name">
<div class="pod-color" :style="{ background: pod.color }"></div>
<div
v-for="pod in node.pods"
:key="pod.name"
class="pod"
>
<div
class="pod-color"
:style="{ background: pod.color }"
/>
<span class="pod-name">{{ pod.name }}</span>
</div>
</div>
@@ -115,7 +195,10 @@
</div>
<!-- 无服务器层 -->
<div class="layer serverless-layer" v-if="viewMode === 'overview' || viewMode === 'serverless'">
<div
v-if="viewMode === 'overview' || viewMode === 'serverless'"
class="layer serverless-layer"
>
<div class="layer-header">
<span class="layer-icon"></span>
<span class="layer-title">无服务器计算 (Function Compute)</span>
@@ -124,29 +207,51 @@
<div class="serverless-arch">
<!-- 触发器 -->
<div class="triggers-section">
<div class="section-title">触发器</div>
<div class="section-title">
触发器
</div>
<div class="triggers-list">
<div class="trigger" v-for="trigger in triggers" :key="trigger.name">
<div class="trigger-icon">{{ trigger.icon }}</div>
<div class="trigger-name">{{ trigger.name }}</div>
<div
v-for="trigger in triggers"
:key="trigger.name"
class="trigger"
>
<div class="trigger-icon">
{{ trigger.icon }}
</div>
<div class="trigger-name">
{{ trigger.name }}
</div>
</div>
</div>
</div>
<!-- 函数计算 -->
<div class="functions-section">
<div class="section-title">函数计算实例</div>
<div class="section-title">
函数计算实例
</div>
<div class="functions-list">
<div class="function-card" v-for="func in functions" :key="func.name">
<div
v-for="func in functions"
:key="func.name"
class="function-card"
>
<div class="func-header">
<span class="func-icon"></span>
<span class="func-name">{{ func.name }}</span>
</div>
<div class="func-metrics" v-if="showMetrics">
<div
v-if="showMetrics"
class="func-metrics"
>
<div class="metric-row">
<span class="metric-label">并发</span>
<div class="concurrency-bar">
<div class="concurrency-fill" :style="{ width: (func.concurrency / 100 * 100) + '%' }"></div>
<div
class="concurrency-fill"
:style="{ width: (func.concurrency / 100 * 100) + '%' }"
/>
</div>
<span class="metric-value">{{ func.concurrency }}</span>
</div>
@@ -161,11 +266,21 @@
<!-- 后端服务 -->
<div class="backend-section">
<div class="section-title">后端服务</div>
<div class="section-title">
后端服务
</div>
<div class="backend-services">
<div class="service" v-for="svc in backendServices" :key="svc.name">
<div class="service-icon">{{ svc.icon }}</div>
<div class="service-name">{{ svc.name }}</div>
<div
v-for="svc in backendServices"
:key="svc.name"
class="service"
>
<div class="service-icon">
{{ svc.icon }}
</div>
<div class="service-name">
{{ svc.name }}
</div>
</div>
</div>
</div>
@@ -176,7 +291,9 @@
<!-- 说明 -->
<div class="architecture-legend">
<div class="legend-title">计算资源类型说明</div>
<div class="legend-title">
计算资源类型说明
</div>
<div class="legend-items">
<div class="legend-item">
<span class="legend-icon">🔧</span>
@@ -2,37 +2,69 @@
<div class="disaster-recovery-demo">
<!-- 控制面板 -->
<div class="control-panel">
<el-radio-group v-model="drMode" size="small">
<el-radio-button label="same-city">同城双活</el-radio-button>
<el-radio-button label="remote">异地灾备</el-radio-button>
<el-radio-button label="three-center">两地三中心</el-radio-button>
<el-radio-button label="switchover">故障切换</el-radio-button>
<el-radio-group
v-model="drMode"
size="small"
>
<el-radio-button label="same-city">
同城双活
</el-radio-button>
<el-radio-button label="remote">
异地灾备
</el-radio-button>
<el-radio-button label="three-center">
两地三中心
</el-radio-button>
<el-radio-button label="switchover">
故障切换
</el-radio-button>
</el-radio-group>
<el-switch v-model="showRPO" active-text="显示 RPO/RTO" style="margin-left: 20px" />
<el-switch
v-model="showRPO"
active-text="显示 RPO/RTO"
style="margin-left: 20px"
/>
</div>
<!-- 灾备架构图 -->
<div class="dr-architecture">
<!-- 生产中心 -->
<div class="dr-center production" :class="{ degraded: drMode === 'switchover' && switchoverStep >= 2 }">
<div
class="dr-center production"
:class="{ degraded: drMode === 'switchover' && switchoverStep >= 2 }"
>
<div class="center-header">
<div class="center-badge production">生产</div>
<div class="center-title">生产中心 (Region A)</div>
<div class="center-location">📍 北京</div>
<div class="center-badge production">
生产
</div>
<div class="center-title">
生产中心 (Region A)
</div>
<div class="center-location">
📍 北京
</div>
</div>
<div class="center-content">
<!-- 可用区 A -->
<div class="az-block" :class="{ failed: drMode === 'switchover' && switchoverStep >= 1 }">
<div
class="az-block"
:class="{ failed: drMode === 'switchover' && switchoverStep >= 1 }"
>
<div class="az-header">
<span class="az-name">可用区 A</span>
<span class="az-status" :class="getAzStatus('A')">{{ getAzStatusText('A') }}</span>
<span
class="az-status"
:class="getAzStatus('A')"
>{{ getAzStatusText('A') }}</span>
</div>
<div class="az-resources">
<div class="resource-group">
<div class="group-title">计算</div>
<div class="group-title">
计算
</div>
<div class="resource-tags">
<span class="tag">ECS × 8</span>
<span class="tag primary">SLB </span>
@@ -40,7 +72,9 @@
</div>
<div class="resource-group">
<div class="group-title">数据库</div>
<div class="group-title">
数据库
</div>
<div class="resource-tags">
<span class="tag primary">RDS </span>
<span class="tag">Redis </span>
@@ -50,7 +84,10 @@
</div>
<!-- 可用区 B (同城灾备) -->
<div class="az-block standby" v-if="drMode !== 'remote'">
<div
v-if="drMode !== 'remote'"
class="az-block standby"
>
<div class="az-header">
<span class="az-name">可用区 B</span>
<span class="az-status standby">热备</span>
@@ -58,7 +95,9 @@
<div class="az-resources">
<div class="resource-group">
<div class="group-title">计算</div>
<div class="group-title">
计算
</div>
<div class="resource-tags">
<span class="tag">ECS × 6</span>
<span class="tag standby">SLB </span>
@@ -66,7 +105,9 @@
</div>
<div class="resource-group">
<div class="group-title">数据库</div>
<div class="group-title">
数据库
</div>
<div class="resource-tags">
<span class="tag standby">RDS </span>
<span class="tag">Redis </span>
@@ -77,7 +118,10 @@
</div>
<!-- RPO/RTO 指示器 -->
<div class="rpo-indicator" v-if="showRPO">
<div
v-if="showRPO"
class="rpo-indicator"
>
<div class="rpo-item">
<span class="rpo-label">RPO</span>
<span class="rpo-value">{{ getRPO() }}</span>
@@ -91,37 +135,68 @@
<!-- 复制链路 -->
<div class="replication-links">
<div class="link-group same-city" v-if="drMode === 'same-city' || drMode === 'three-center'">
<div class="link-line"></div>
<div class="link-label">同步复制</div>
<div class="link-bandwidth">延迟 &lt; 5ms</div>
<div
v-if="drMode === 'same-city' || drMode === 'three-center'"
class="link-group same-city"
>
<div class="link-line" />
<div class="link-label">
同步复制
</div>
<div class="link-bandwidth">
延迟 &lt; 5ms
</div>
</div>
<div class="link-group remote" v-if="drMode === 'remote' || drMode === 'three-center'">
<div class="link-line async"></div>
<div class="link-label">异步复制</div>
<div class="link-bandwidth">RPO 5s</div>
<div
v-if="drMode === 'remote' || drMode === 'three-center'"
class="link-group remote"
>
<div class="link-line async" />
<div class="link-label">
异步复制
</div>
<div class="link-bandwidth">
RPO 5s
</div>
</div>
</div>
<!-- 灾备中心 -->
<div class="dr-center disaster-recovery" :class="{ active: drMode === 'switchover' && switchoverStep >= 2 }">
<div
class="dr-center disaster-recovery"
:class="{ active: drMode === 'switchover' && switchoverStep >= 2 }"
>
<div class="center-header">
<div class="center-badge dr">灾备</div>
<div class="center-title">灾备中心 (Region B)</div>
<div class="center-location">📍 {{ drMode === 'same-city' ? '北京 (可用区 C)' : '上海' }}</div>
<div class="center-badge dr">
灾备
</div>
<div class="center-title">
灾备中心 (Region B)
</div>
<div class="center-location">
📍 {{ drMode === 'same-city' ? '北京 (可用区 C)' : '上海' }}
</div>
</div>
<div class="center-content">
<div class="az-block dr-standby" :class="{ promoted: drMode === 'switchover' && switchoverStep >= 3 }">
<div
class="az-block dr-standby"
:class="{ promoted: drMode === 'switchover' && switchoverStep >= 3 }"
>
<div class="az-header">
<span class="az-name">{{ drMode === 'same-city' ? '可用区 C' : '可用区 A' }}</span>
<span class="az-status" :class="getDrAzStatus()">{{ getDrAzStatusText() }}</span>
<span
class="az-status"
:class="getDrAzStatus()"
>{{ getDrAzStatusText() }}</span>
</div>
<div class="az-resources">
<div class="resource-group">
<div class="group-title">计算</div>
<div class="group-title">
计算
</div>
<div class="resource-tags">
<span class="tag">ECS × 4</span>
<span :class="['tag', drMode === 'switchover' && switchoverStep >= 3 ? 'primary' : 'standby']">
@@ -131,7 +206,9 @@
</div>
<div class="resource-group">
<div class="group-title">数据库</div>
<div class="group-title">
数据库
</div>
<div class="resource-tags">
<span :class="['tag', drMode === 'switchover' && switchoverStep >= 3 ? 'primary' : 'standby']">
RDS {{ drMode === 'switchover' && switchoverStep >= 3 ? '主' : '备' }}
@@ -146,61 +223,137 @@
</div>
<!-- 切换进度 (仅在故障切换模式显示) -->
<div class="switchover-progress" v-if="drMode === 'switchover'">
<div class="progress-title">故障切换进度</div>
<el-steps :active="switchoverStep" finish-status="success">
<el-step title="检测故障" description="监控系统发现可用区 A 故障" />
<el-step title="停止写入" description="切离主库,暂停业务写入" />
<el-step title="提升备库" description="灾备中心数据库提升为主库" />
<el-step title="流量切换" description="DNS 切换到灾备中心 SLB" />
<el-step title="恢复服务" description="业务在灾备中心正常运行" />
<div
v-if="drMode === 'switchover'"
class="switchover-progress"
>
<div class="progress-title">
故障切换进度
</div>
<el-steps
:active="switchoverStep"
finish-status="success"
>
<el-step
title="检测故障"
description="监控系统发现可用区 A 故障"
/>
<el-step
title="停止写入"
description="切离主库,暂停业务写入"
/>
<el-step
title="提升备库"
description="灾备中心数据库提升为主库"
/>
<el-step
title="流量切换"
description="DNS 切换到灾备中心 SLB"
/>
<el-step
title="恢复服务"
description="业务在灾备中心正常运行"
/>
</el-steps>
<div class="progress-actions">
<el-button @click="prevStep" :disabled="switchoverStep === 0">上一步</el-button>
<el-button type="primary" @click="nextStep" :disabled="switchoverStep === 5">下一步</el-button>
<el-button @click="resetSwitchover">重置</el-button>
<el-button
:disabled="switchoverStep === 0"
@click="prevStep"
>
上一步
</el-button>
<el-button
type="primary"
:disabled="switchoverStep === 5"
@click="nextStep"
>
下一步
</el-button>
<el-button @click="resetSwitchover">
重置
</el-button>
</div>
</div>
<!-- 架构对比表 -->
<div class="comparison-section">
<div class="comparison-title">📊 灾备架构方案对比</div>
<div class="comparison-title">
📊 灾备架构方案对比
</div>
<div class="comparison-table">
<div class="table-header">
<div class="header-cell">对比维度</div>
<div class="header-cell">同城双活</div>
<div class="header-cell">异地灾备</div>
<div class="header-cell">两地三中心</div>
<div class="header-cell">
对比维度
</div>
<div class="header-cell">
同城双活
</div>
<div class="header-cell">
异地灾备
</div>
<div class="header-cell">
两地三中心
</div>
</div>
<div class="table-row" v-for="row in drComparisonData" :key="row.dimension">
<div class="cell dimension">{{ row.dimension }}</div>
<div class="cell">{{ row.sameCity }}</div>
<div class="cell">{{ row.remote }}</div>
<div class="cell highlight">{{ row.threeCenter }}</div>
<div
v-for="row in drComparisonData"
:key="row.dimension"
class="table-row"
>
<div class="cell dimension">
{{ row.dimension }}
</div>
<div class="cell">
{{ row.sameCity }}
</div>
<div class="cell">
{{ row.remote }}
</div>
<div class="cell highlight">
{{ row.threeCenter }}
</div>
</div>
</div>
</div>
<!-- RPO/RTO 说明 -->
<div class="rpo-rto-explanation">
<div class="explanation-title">💡 RPO RTO 说明</div>
<div class="explanation-title">
💡 RPO RTO 说明
</div>
<div class="explanation-grid">
<div class="explanation-card">
<div class="card-icon"></div>
<div class="card-title">RPO (恢复点目标)</div>
<div class="card-desc">可接受的数据丢失量即最后一次备份到故障发生的时间间隔</div>
<div class="card-example">示例RPO = 5意味着最多丢失5秒的数据</div>
<div class="card-icon">
</div>
<div class="card-title">
RPO (恢复点目标)
</div>
<div class="card-desc">
可接受的数据丢失量即最后一次备份到故障发生的时间间隔
</div>
<div class="card-example">
示例RPO = 5意味着最多丢失5秒的数据
</div>
</div>
<div class="explanation-card">
<div class="card-icon">🔄</div>
<div class="card-title">RTO (恢复时间目标)</div>
<div class="card-desc">从故障发生到业务恢复所需的最长时间</div>
<div class="card-example">示例RTO = 30分钟意味着30分钟内必须恢复服务</div>
<div class="card-icon">
🔄
</div>
<div class="card-title">
RTO (恢复时间目标)
</div>
<div class="card-desc">
从故障发生到业务恢复所需的最长时间
</div>
<div class="card-example">
示例RTO = 30分钟意味着30分钟内必须恢复服务
</div>
</div>
</div>
</div>
@@ -2,56 +2,110 @@
<div class="network-flow-demo">
<!-- 控制面板 -->
<div class="control-panel">
<el-radio-group v-model="flowMode" size="small">
<el-radio-button label="inbound">入向流量</el-radio-button>
<el-radio-button label="outbound">出向流量</el-radio-button>
<el-radio-button label="east-west">东西向流量</el-radio-button>
<el-radio-button label="full">完整拓扑</el-radio-button>
<el-radio-group
v-model="flowMode"
size="small"
>
<el-radio-button label="inbound">
入向流量
</el-radio-button>
<el-radio-button label="outbound">
出向流量
</el-radio-button>
<el-radio-button label="east-west">
东西向流量
</el-radio-button>
<el-radio-button label="full">
完整拓扑
</el-radio-button>
</el-radio-group>
<el-switch v-model="showMetrics" active-text="显示流量数据" style="margin-left: 20px" />
<el-switch
v-model="showMetrics"
active-text="显示流量数据"
style="margin-left: 20px"
/>
</div>
<!-- 网络拓扑图 -->
<div class="network-topology">
<!-- 互联网区域 -->
<div class="zone internet-zone" v-if="showInternet">
<div
v-if="showInternet"
class="zone internet-zone"
>
<div class="zone-header">
<span class="zone-icon">🌐</span>
<span class="zone-title">互联网 (Internet)</span>
</div>
<div class="zone-content">
<div class="internet-entities">
<div class="entity" v-for="entity in internetEntities" :key="entity.name">
<div class="entity-icon">{{ entity.icon }}</div>
<div class="entity-name">{{ entity.name }}</div>
<div
v-for="entity in internetEntities"
:key="entity.name"
class="entity"
>
<div class="entity-icon">
{{ entity.icon }}
</div>
<div class="entity-name">
{{ entity.name }}
</div>
</div>
</div>
</div>
</div>
<!-- 流量箭头 -->
<div class="flow-arrows" v-if="showFlowArrows">
<div
v-if="showFlowArrows"
class="flow-arrows"
>
<div class="arrow-container">
<div class="flow-line" :class="flowMode"></div>
<div class="flow-particles" v-if="showMetrics">
<div class="particle" v-for="n in 5" :key="n"
:style="{ animationDelay: (n * 0.5) + 's' }"></div>
<div
class="flow-line"
:class="flowMode"
/>
<div
v-if="showMetrics"
class="flow-particles"
>
<div
v-for="n in 5"
:key="n"
class="particle"
:style="{ animationDelay: (n * 0.5) + 's' }"
/>
</div>
</div>
<div class="flow-stats" v-if="showMetrics">
<div
v-if="showMetrics"
class="flow-stats"
>
<div class="stat-item">
<div class="stat-label">带宽</div>
<div class="stat-value">2.5 Gbps</div>
<div class="stat-label">
带宽
</div>
<div class="stat-value">
2.5 Gbps
</div>
</div>
<div class="stat-item">
<div class="stat-label">流量</div>
<div class="stat-value">1.2 TB/</div>
<div class="stat-label">
流量
</div>
<div class="stat-value">
1.2 TB/
</div>
</div>
<div class="stat-item">
<div class="stat-label">延迟</div>
<div class="stat-value">15 ms</div>
<div class="stat-label">
延迟
</div>
<div class="stat-value">
15 ms
</div>
</div>
</div>
</div>
@@ -65,12 +119,23 @@
<div class="zone-content">
<!-- 网络设备层 -->
<div class="network-devices">
<div class="device" v-for="device in networkDevices" :key="device.name"
:class="device.type">
<div class="device-icon">{{ device.icon }}</div>
<div class="device-name">{{ device.name }}</div>
<div
v-for="device in networkDevices"
:key="device.name"
class="device"
:class="device.type"
>
<div class="device-icon">
{{ device.icon }}
</div>
<div class="device-name">
{{ device.name }}
</div>
<div class="device-stats" v-if="showMetrics">
<div
v-if="showMetrics"
class="device-stats"
>
<div class="stat">
<span class="stat-label">吞吐</span>
<span class="stat-value">{{ device.throughput }}</span>
@@ -85,8 +150,12 @@
<!-- 子网层 -->
<div class="subnets-container">
<div class="subnet" v-for="subnet in subnets" :key="subnet.name"
:class="subnet.type">
<div
v-for="subnet in subnets"
:key="subnet.name"
class="subnet"
:class="subnet.type"
>
<div class="subnet-header">
<span class="subnet-type-icon">{{ subnet.type === 'public' ? '🌐' : '🔒' }}</span>
<span class="subnet-name">{{ subnet.name }}</span>
@@ -94,14 +163,27 @@
</div>
<div class="subnet-resources">
<div class="resource" v-for="resource in subnet.resources" :key="resource.name">
<div class="resource-icon">{{ resource.icon }}</div>
<div
v-for="resource in subnet.resources"
:key="resource.name"
class="resource"
>
<div class="resource-icon">
{{ resource.icon }}
</div>
<div class="resource-info">
<div class="resource-name">{{ resource.name }}</div>
<div class="resource-ip">{{ resource.ip }}</div>
<div class="resource-name">
{{ resource.name }}
</div>
<div class="resource-ip">
{{ resource.ip }}
</div>
</div>
<div class="resource-traffic" v-if="showMetrics">
<div
v-if="showMetrics"
class="resource-traffic"
>
<div class="traffic-in">
<span class="traffic-label"></span>
<span class="traffic-value">{{ resource.inTraffic }}</span>
@@ -121,18 +203,20 @@
<!-- 图例说明 -->
<div class="network-legend">
<div class="legend-title">流量类型说明</div>
<div class="legend-title">
流量类型说明
</div>
<div class="legend-items">
<div class="legend-item">
<span class="legend-color inbound"></span>
<span class="legend-color inbound" />
<span>入向流量用户 服务器</span>
</div>
<div class="legend-item">
<span class="legend-color outbound"></span>
<span class="legend-color outbound" />
<span>出向流量服务器 外部</span>
</div>
<div class="legend-item">
<span class="legend-color east-west"></span>
<span class="legend-color east-west" />
<span>东西向流量服务间通信</span>
</div>
</div>
@@ -1,60 +1,109 @@
<template>
<div class="resource-topology-demo">
<div class="controls">
<el-radio-group v-model="viewMode" size="small">
<el-radio-button label="overview">全景视图</el-radio-button>
<el-radio-button label="compute">计算视角</el-radio-button>
<el-radio-button label="network">网络视角</el-radio-button>
<el-radio-button label="storage">存储视角</el-radio-button>
<el-radio-group
v-model="viewMode"
size="small"
>
<el-radio-button label="overview">
全景视图
</el-radio-button>
<el-radio-button label="compute">
计算视角
</el-radio-button>
<el-radio-button label="network">
网络视角
</el-radio-button>
<el-radio-button label="storage">
存储视角
</el-radio-button>
</el-radio-group>
</div>
<div class="topology-container" ref="topologyRef">
<div
ref="topologyRef"
class="topology-container"
>
<!-- 云服务商层 -->
<div class="layer cloud-provider">
<div class="layer-title"> 云服务商</div>
<div class="provider-grid">
<div v-for="provider in providers" :key="provider.name"
class="provider-card"
:class="{ active: selectedProvider === provider.name }"
@click="selectProvider(provider.name)">
<div class="provider-icon">{{ provider.icon }}</div>
<div class="provider-name">{{ provider.name }}</div>
</div>
<div class="layer-title">
云服务商
</div>
</div>
<!-- 连接箭头 -->
<div class="connection-arrow"></div>
<!-- 地域/可用区层 -->
<div class="layer region-layer">
<div class="layer-title">🌍 地域 & 可用区</div>
<div class="region-grid">
<div v-for="region in regions" :key="region.id"
class="region-card"
:class="{ active: selectedRegion === region.id }"
@click="selectRegion(region.id)">
<div class="region-name">{{ region.name }}</div>
<div class="region-azs">
<span v-for="az in region.azs" :key="az" class="az-badge">{{ az }}</span>
<div class="provider-grid">
<div
v-for="provider in providers"
:key="provider.name"
class="provider-card"
:class="{ active: selectedProvider === provider.name }"
@click="selectProvider(provider.name)"
>
<div class="provider-icon">
{{ provider.icon }}
</div>
<div class="provider-name">
{{ provider.name }}
</div>
</div>
</div>
</div>
<!-- 连接箭头 -->
<div class="connection-arrow"></div>
<div class="connection-arrow">
</div>
<!-- 地域/可用区层 -->
<div class="layer region-layer">
<div class="layer-title">
🌍 地域 & 可用区
</div>
<div class="region-grid">
<div
v-for="region in regions"
:key="region.id"
class="region-card"
:class="{ active: selectedRegion === region.id }"
@click="selectRegion(region.id)"
>
<div class="region-name">
{{ region.name }}
</div>
<div class="region-azs">
<span
v-for="az in region.azs"
:key="az"
class="az-badge"
>{{ az }}</span>
</div>
</div>
</div>
</div>
<!-- 连接箭头 -->
<div class="connection-arrow">
</div>
<!-- 资源拓扑层 -->
<div class="layer resource-layer">
<div class="layer-title">🎯 资源拓扑</div>
<div class="layer-title">
🎯 资源拓扑
</div>
<div class="resource-grid">
<!-- 计算资源 -->
<div class="resource-category" :class="{ highlight: viewMode === 'compute' || viewMode === 'overview' }">
<div class="category-title">💻 计算</div>
<div
class="resource-category"
:class="{ highlight: viewMode === 'compute' || viewMode === 'overview' }"
>
<div class="category-title">
💻 计算
</div>
<div class="resource-list">
<div v-for="item in computeResources" :key="item.name" class="resource-item">
<div
v-for="item in computeResources"
:key="item.name"
class="resource-item"
>
<span class="resource-icon">{{ item.icon }}</span>
<span class="resource-name">{{ item.name }}</span>
</div>
@@ -62,10 +111,19 @@
</div>
<!-- 网络资源 -->
<div class="resource-category" :class="{ highlight: viewMode === 'network' || viewMode === 'overview' }">
<div class="category-title">🌐 网络</div>
<div
class="resource-category"
:class="{ highlight: viewMode === 'network' || viewMode === 'overview' }"
>
<div class="category-title">
🌐 网络
</div>
<div class="resource-list">
<div v-for="item in networkResources" :key="item.name" class="resource-item">
<div
v-for="item in networkResources"
:key="item.name"
class="resource-item"
>
<span class="resource-icon">{{ item.icon }}</span>
<span class="resource-name">{{ item.name }}</span>
</div>
@@ -73,10 +131,19 @@
</div>
<!-- 存储资源 -->
<div class="resource-category" :class="{ highlight: viewMode === 'storage' || viewMode === 'overview' }">
<div class="category-title">💾 存储</div>
<div
class="resource-category"
:class="{ highlight: viewMode === 'storage' || viewMode === 'overview' }"
>
<div class="category-title">
💾 存储
</div>
<div class="resource-list">
<div v-for="item in storageResources" :key="item.name" class="resource-item">
<div
v-for="item in storageResources"
:key="item.name"
class="resource-item"
>
<span class="resource-icon">{{ item.icon }}</span>
<span class="resource-name">{{ item.name }}</span>
</div>
@@ -87,16 +154,26 @@
</div>
<!-- 信息面板 -->
<div class="info-panel" v-if="showInfo">
<div
v-if="showInfo"
class="info-panel"
>
<div class="info-header">
<h4>💡 拓扑说明</h4>
<el-button type="text" @click="showInfo = false">关闭</el-button>
<el-button
type="text"
@click="showInfo = false"
>
关闭
</el-button>
</div>
<div class="info-content">
<p><strong>当前视图</strong>{{ viewModeText }}</p>
<p><strong>选中云商</strong>{{ selectedProvider || '未选择' }}</p>
<p><strong>选中地域</strong>{{ selectedRegion || '未选择' }}</p>
<p class="tip">💡 提示点击云服务商和地域可以查看不同组合的资源拓扑</p>
<p class="tip">
💡 提示点击云服务商和地域可以查看不同组合的资源拓扑
</p>
</div>
</div>
</div>
@@ -2,30 +2,66 @@
<div class="storage-topology-demo">
<!-- 控制面板 -->
<div class="control-panel">
<el-radio-group v-model="viewMode" size="small">
<el-radio-button label="overview">存储概览</el-radio-button>
<el-radio-button label="object">对象存储</el-radio-button>
<el-radio-button label="block">块存储</el-radio-button>
<el-radio-button label="file">文件存储</el-radio-button>
<el-radio-group
v-model="viewMode"
size="small"
>
<el-radio-button label="overview">
存储概览
</el-radio-button>
<el-radio-button label="object">
对象存储
</el-radio-button>
<el-radio-button label="block">
块存储
</el-radio-button>
<el-radio-button label="file">
文件存储
</el-radio-button>
</el-radio-group>
<el-switch v-model="showDetails" active-text="显示详情" style="margin-left: 20px" />
<el-switch
v-model="showDetails"
active-text="显示详情"
style="margin-left: 20px"
/>
</div>
<!-- 存储架构图 -->
<div class="storage-architecture">
<!-- 应用接入层 -->
<div class="layer access-layer">
<div class="layer-title">🔌 应用接入层</div>
<div class="layer-title">
🔌 应用接入层
</div>
<div class="access-methods">
<div class="method-card" v-for="method in accessMethods" :key="method.name"
@mouseenter="hoverMethod = method.name" @mouseleave="hoverMethod = null">
<div class="method-icon">{{ method.icon }}</div>
<div class="method-name">{{ method.name }}</div>
<div class="method-desc">{{ method.description }}</div>
<div
v-for="method in accessMethods"
:key="method.name"
class="method-card"
@mouseenter="hoverMethod = method.name"
@mouseleave="hoverMethod = null"
>
<div class="method-icon">
{{ method.icon }}
</div>
<div class="method-name">
{{ method.name }}
</div>
<div class="method-desc">
{{ method.description }}
</div>
<div class="method-tooltip" v-if="hoverMethod === method.name && showDetails">
<div v-for="detail in method.details" :key="detail">{{ detail }}</div>
<div
v-if="hoverMethod === method.name && showDetails"
class="method-tooltip"
>
<div
v-for="detail in method.details"
:key="detail"
>
{{ detail }}
</div>
</div>
</div>
</div>
@@ -33,16 +69,25 @@
<!-- 存储网关层 -->
<div class="layer gateway-layer">
<div class="layer-title">🚪 存储网关层</div>
<div class="layer-title">
🚪 存储网关层
</div>
<div class="gateways-grid">
<div class="gateway-card" v-for="gateway in storageGateways" :key="gateway.name"
:class="gateway.type">
<div
v-for="gateway in storageGateways"
:key="gateway.name"
class="gateway-card"
:class="gateway.type"
>
<div class="gateway-header">
<span class="gateway-icon">{{ gateway.icon }}</span>
<span class="gateway-name">{{ gateway.name }}</span>
</div>
<div class="gateway-metrics" v-if="showDetails">
<div
v-if="showDetails"
class="gateway-metrics"
>
<div class="metric">
<span class="metric-label">TPS</span>
<span class="metric-value">{{ gateway.tps }}</span>
@@ -58,17 +103,27 @@
<!-- 存储服务层 -->
<div class="layer storage-services-layer">
<div class="layer-title">💾 存储服务层</div>
<div class="layer-title">
💾 存储服务层
</div>
<div class="storage-types-grid">
<!-- 对象存储 -->
<div class="storage-type-card object-storage"
:class="{ active: viewMode === 'object' || viewMode === 'overview' }">
<div
class="storage-type-card object-storage"
:class="{ active: viewMode === 'object' || viewMode === 'overview' }"
>
<div class="storage-header">
<div class="storage-icon">🪣</div>
<div class="storage-title">对象存储 OSS</div>
<div class="storage-icon">
🪣
</div>
<div class="storage-title">
对象存储 OSS
</div>
</div>
<div class="storage-desc">适合存储图片视频日志等非结构化数据</div>
<div class="storage-desc">
适合存储图片视频日志等非结构化数据
</div>
<div class="storage-features">
<div class="feature">
@@ -85,27 +140,44 @@
</div>
</div>
<div class="storage-buckets" v-if="showDetails">
<div class="bucket" v-for="bucket in buckets" :key="bucket.name">
<div
v-if="showDetails"
class="storage-buckets"
>
<div
v-for="bucket in buckets"
:key="bucket.name"
class="bucket"
>
<div class="bucket-info">
<span class="bucket-name">{{ bucket.name }}</span>
<span class="bucket-objects">{{ bucket.objects }} 个对象</span>
</div>
<div class="bucket-size">{{ bucket.size }}</div>
<div class="bucket-size">
{{ bucket.size }}
</div>
</div>
</div>
</div>
<!-- 块存储 -->
<div class="storage-type-card block-storage"
:class="{ active: viewMode === 'block' || viewMode === 'overview' }">
<div
class="storage-type-card block-storage"
:class="{ active: viewMode === 'block' || viewMode === 'overview' }"
>
<div class="storage-header">
<div class="storage-icon">💽</div>
<div class="storage-title">块存储 EBS</div>
<div class="storage-icon">
💽
</div>
<div class="storage-title">
块存储 EBS
</div>
</div>
<div class="storage-desc">为云服务器提供高性能低延迟的数据块存储</div>
<div class="storage-desc">
为云服务器提供高性能低延迟的数据块存储
</div>
<div class="storage-features">
<div class="feature">
@@ -122,12 +194,22 @@
</div>
</div>
<div class="volumes-list" v-if="showDetails">
<div class="volume" v-for="vol in volumes" :key="vol.id">
<div
v-if="showDetails"
class="volumes-list"
>
<div
v-for="vol in volumes"
:key="vol.id"
class="volume"
>
<div class="volume-info">
<div class="volume-header">
<span class="volume-name">{{ vol.name }}</span>
<span class="volume-type" :class="vol.type">{{ vol.type }}</span>
<span
class="volume-type"
:class="vol.type"
>{{ vol.type }}</span>
</div>
<div class="volume-meta">
@@ -137,23 +219,38 @@
</div>
</div>
<div class="volume-iops" v-if="vol.iops">
<div class="iops-label">IOPS</div>
<div class="iops-value">{{ vol.iops }}</div>
<div
v-if="vol.iops"
class="volume-iops"
>
<div class="iops-label">
IOPS
</div>
<div class="iops-value">
{{ vol.iops }}
</div>
</div>
</div>
</div>
</div>
<!-- 文件存储 -->
<div class="storage-type-card file-storage"
:class="{ active: viewMode === 'file' || viewMode === 'overview' }">
<div
class="storage-type-card file-storage"
:class="{ active: viewMode === 'file' || viewMode === 'overview' }"
>
<div class="storage-header">
<div class="storage-icon">📁</div>
<div class="storage-title">文件存储 NAS</div>
<div class="storage-icon">
📁
</div>
<div class="storage-title">
文件存储 NAS
</div>
</div>
<div class="storage-desc">为多个计算节点提供共享文件系统访问</div>
<div class="storage-desc">
为多个计算节点提供共享文件系统访问
</div>
<div class="storage-features">
<div class="feature">
@@ -170,12 +267,22 @@
</div>
</div>
<div class="filesystems-list" v-if="showDetails">
<div class="filesystem" v-for="fs in filesystems" :key="fs.name">
<div
v-if="showDetails"
class="filesystems-list"
>
<div
v-for="fs in filesystems"
:key="fs.name"
class="filesystem"
>
<div class="fs-header">
<div class="fs-info">
<span class="fs-name">{{ fs.name }}</span>
<span class="fs-protocol" :class="fs.protocol">{{ fs.protocol }}</span>
<span
class="fs-protocol"
:class="fs.protocol"
>{{ fs.protocol }}</span>
</div>
<div class="fs-capacity">
@@ -185,14 +292,23 @@
</div>
<div class="fs-capacity-bar">
<div class="capacity-progress" :style="{ width: fs.percentage + '%' }"
:class="{ warning: fs.percentage > 80, danger: fs.percentage > 90 }"></div>
<div
class="capacity-progress"
:style="{ width: fs.percentage + '%' }"
:class="{ warning: fs.percentage > 80, danger: fs.percentage > 90 }"
/>
</div>
<div class="fs-mounts">
<div class="mounts-label">挂载点</div>
<div class="mounts-label">
挂载点
</div>
<div class="mounts-list">
<span class="mount-point" v-for="mount in fs.mounts" :key="mount">{{ mount }}</span>
<span
v-for="mount in fs.mounts"
:key="mount"
class="mount-point"
>{{ mount }}</span>
</div>
</div>
</div>
@@ -204,21 +320,52 @@
<!-- 存储选型对比 -->
<div class="comparison-section">
<div class="comparison-title">📊 存储类型选型对比</div>
<div class="comparison-title">
📊 存储类型选型对比
</div>
<div class="comparison-table">
<div class="table-header">
<div class="header-cell">特性</div>
<div class="header-cell object">对象存储</div>
<div class="header-cell block">块存储</div>
<div class="header-cell file">文件存储</div>
<div class="header-cell">
特性
</div>
<div class="header-cell object">
对象存储
</div>
<div class="header-cell block">
块存储
</div>
<div class="header-cell file">
文件存储
</div>
</div>
<div class="table-row" v-for="row in comparisonData" :key="row.feature">
<div class="cell feature">{{ row.feature }}</div>
<div class="cell" :class="{ highlight: row.object === '优秀' || row.object === '强' }">{{ row.object }}</div>
<div class="cell" :class="{ highlight: row.block === '优秀' || row.block === '强' }">{{ row.block }}</div>
<div class="cell" :class="{ highlight: row.file === '优秀' || row.file === '强' }">{{ row.file }}</div>
<div
v-for="row in comparisonData"
:key="row.feature"
class="table-row"
>
<div class="cell feature">
{{ row.feature }}
</div>
<div
class="cell"
:class="{ highlight: row.object === '优秀' || row.object === '强' }"
>
{{ row.object }}
</div>
<div
class="cell"
:class="{ highlight: row.block === '优秀' || row.block === '强' }"
>
{{ row.block }}
</div>
<div
class="cell"
:class="{ highlight: row.file === '优秀' || row.file === '强' }"
>
{{ row.file }}
</div>
</div>
</div>
</div>
@@ -4,19 +4,39 @@
<div class="control-panel">
<div class="panel-section">
<span class="panel-label">VPC 网段</span>
<el-radio-group v-model="vpcCidr" size="small">
<el-radio-button label="172.16.0.0/12">172.16.0.0/12</el-radio-button>
<el-radio-button label="10.0.0.0/8">10.0.0.0/8</el-radio-button>
<el-radio-button label="192.168.0.0/16">192.168.0.0/16</el-radio-button>
<el-radio-group
v-model="vpcCidr"
size="small"
>
<el-radio-button label="172.16.0.0/12">
172.16.0.0/12
</el-radio-button>
<el-radio-button label="10.0.0.0/8">
10.0.0.0/8
</el-radio-button>
<el-radio-button label="192.168.0.0/16">
192.168.0.0/16
</el-radio-button>
</el-radio-group>
</div>
<div class="panel-section">
<span class="panel-label">子网划分</span>
<el-slider v-model="subnetBits" :min="2" :max="4" show-stops :marks="{2: '/24', 3: '/25', 4: '/26'}" style="width: 200px;" />
<el-slider
v-model="subnetBits"
:min="2"
:max="4"
show-stops
:marks="{2: '/24', 3: '/25', 4: '/26'}"
style="width: 200px;"
/>
</div>
<el-switch v-model="showCalculation" active-text="显示计算过程" style="margin-left: 20px;" />
<el-switch
v-model="showCalculation"
active-text="显示计算过程"
style="margin-left: 20px;"
/>
</div>
<!-- 网段可视化 -->
@@ -42,14 +62,19 @@
<span class="cell-type">{{ subnet.type === 'public' ? '🌐' : '🔒' }}</span>
<span class="cell-name">{{ subnet.name }}</span>
</div>
<div class="cell-cidr">{{ subnet.cidr }}</div>
<div class="cell-cidr">
{{ subnet.cidr }}
</div>
<div class="cell-stats">
<span class="ip-count">{{ subnet.ipCount }} IP</span>
<span class="az-badge">{{ subnet.az }}</span>
</div>
<!-- 悬停提示 -->
<div class="cell-tooltip" v-if="hoverSubnet === index && showCalculation">
<div
v-if="hoverSubnet === index && showCalculation"
class="cell-tooltip"
>
<div class="tooltip-row">
<span>网段范围</span>
<code>{{ subnet.range }}</code>
@@ -69,7 +94,10 @@
</div>
<!-- 网段计算说明 -->
<div class="calculation-panel" v-if="showCalculation">
<div
v-if="showCalculation"
class="calculation-panel"
>
<h4>📐 子网划分计算说明</h4>
<div class="calc-section">
@@ -118,21 +146,27 @@
<h4>💡 子网设计最佳实践</h4>
<div class="tips-grid">
<div class="tip-item">
<div class="tip-icon">🎯</div>
<div class="tip-icon">
🎯
</div>
<div class="tip-content">
<h5>预留足够 IP</h5>
<p>每个子网至少预留 20% IP 作为扩容缓冲</p>
</div>
</div>
<div class="tip-item">
<div class="tip-icon">🔒</div>
<div class="tip-icon">
🔒
</div>
<div class="tip-content">
<h5>公网私网分离</h5>
<p>核心数据放在私网子网通过 NAT 访问外网</p>
</div>
</div>
<div class="tip-item">
<div class="tip-icon">🌐</div>
<div class="tip-icon">
🌐
</div>
<div class="tip-content">
<h5> AZ 部署</h5>
<p>同一 VPC 的不同子网放在不同可用区</p>
@@ -2,11 +2,22 @@
<div class="vpc-architecture-demo">
<!-- 控制面板 -->
<div class="control-panel">
<el-radio-group v-model="viewMode" size="small">
<el-radio-button label="full">完整架构</el-radio-button>
<el-radio-button label="public">公网访问</el-radio-button>
<el-radio-button label="private">私网隔离</el-radio-button>
<el-radio-button label="hybrid">混合云</el-radio-button>
<el-radio-group
v-model="viewMode"
size="small"
>
<el-radio-button label="full">
完整架构
</el-radio-button>
<el-radio-button label="public">
公网访问
</el-radio-button>
<el-radio-button label="private">
私网隔离
</el-radio-button>
<el-radio-button label="hybrid">
混合云
</el-radio-button>
</el-radio-group>
<el-switch
v-model="showDetails"
@@ -18,126 +29,183 @@
<!-- VPC 架构图 -->
<div class="vpc-container">
<!-- 外部互联网 -->
<div class="internet-zone" v-if="showInternet">
<div
v-if="showInternet"
class="internet-zone"
>
<div class="zone-header">
<span class="zone-icon">🌐</span>
<span class="zone-title">互联网 (Internet)</span>
</div>
<div class="zone-content">
<div class="internet-user">
<div class="user-avatar">👤</div>
<div class="user-label">用户</div>
<div class="user-avatar">
👤
</div>
<div class="user-label">
用户
</div>
</div>
<div class="internet-user">
<div class="user-avatar">🏢</div>
<div class="user-label">企业</div>
<div class="user-avatar">
🏢
</div>
<div class="user-label">
企业
</div>
</div>
</div>
</div>
<!-- 连接箭头 -->
<div class="connection-flow" v-if="showInternet">
<div class="flow-line"></div>
<div
v-if="showInternet"
class="connection-flow"
>
<div class="flow-line" />
<div class="flow-devices">
<div class="device" v-for="device in borderDevices" :key="device.name"
:class="device.type"
@mouseenter="hoverDevice = device.name"
@mouseleave="hoverDevice = null"
003e
<div class="device-icon">{{ device.icon }}</div>
<div class="device-name">{{ device.name }}</div>
<div class="device-tooltip" v-if="hoverDevice === device.name && showDetails">
{{ device.description }}
</div>
<div
v-for="device in borderDevices"
:key="device.name"
class="device"
:class="device.type"
003e
<div
class="device-icon"
@mouseenter="hoverDevice = device.name"
@mouseleave="hoverDevice = null"
>
{{ device.icon }}
</div>
<div class="device-name">
{{ device.name }}
</div>
<div
v-if="hoverDevice === device.name && showDetails"
class="device-tooltip"
>
{{ device.description }}
</div>
</div>
</div>
</div>
<!-- VPC 主体 -->
<div class="vpc-zone">
<div class="vpc-header">
<div class="vpc-title">
<span class="vpc-icon">🏠</span>
<span>专有网络 VPC</span>
<span class="vpc-id">vpc-2ze7p8w7c9d6x5y4</span>
<!-- VPC 主体 -->
<div class="vpc-zone">
<div class="vpc-header">
<div class="vpc-title">
<span class="vpc-icon">🏠</span>
<span>专有网络 VPC</span>
<span class="vpc-id">vpc-2ze7p8w7c9d6x5y4</span>
</div>
<div class="vpc-meta">
<span class="meta-item">📍 华北2 (北京)</span>
<span class="meta-item">🌐 172.16.0.0/12</span>
</div>
</div>
<div class="vpc-content">
<!-- 可用区 1 -->
<div class="az-container">
<div class="az-header">
<span class="az-name">可用区 A</span>
<span class="az-status online">在线</span>
</div>
<div class="vpc-meta">
<span class="meta-item">📍 华北2 (北京)</span>
<span class="meta-item">🌐 172.16.0.0/12</span>
<div class="subnets">
<div
class="subnet public"
@mouseenter="hoverSubnet = 'public-a'"
@mouseleave="hoverSubnet = null"
>
<div class="subnet-header">
<span class="subnet-type">🌐 公网子网</span>
<span class="subnet-cidr">172.16.1.0/24</span>
</div>
<div class="subnet-resources">
<div class="resource-tag">
🖥 ECS × 2
</div>
<div class="resource-tag">
SLB
</div>
<div class="resource-tag">
🌐 NAT
</div>
</div>
<div
v-if="hoverSubnet === 'public-a' && showDetails"
class="subnet-tooltip"
>
公网子网可直接访问互联网部署对外服务
</div>
</div>
<div
class="subnet private"
@mouseenter="hoverSubnet = 'private-a'"
@mouseleave="hoverSubnet = null"
>
<div class="subnet-header">
<span class="subnet-type">🔒 私网子网</span>
<span class="subnet-cidr">172.16.2.0/24</span>
</div>
<div class="subnet-resources">
<div class="resource-tag">
🖥 ECS × 4
</div>
<div class="resource-tag">
🗄 RDS
</div>
<div class="resource-tag">
📦 Redis
</div>
</div>
<div
v-if="hoverSubnet === 'private-a' && showDetails"
class="subnet-tooltip"
>
私网子网无法直接访问互联网部署核心服务
</div>
</div>
</div>
</div>
<div class="vpc-content">
<!-- 可用区 1 -->
<div class="az-container">
<div class="az-header">
<span class="az-name">可用区 A</span>
<span class="az-status online">在线</span>
</div>
<div class="subnets">
<div class="subnet public"
@mouseenter="hoverSubnet = 'public-a'"
@mouseleave="hoverSubnet = null">
<div class="subnet-header">
<span class="subnet-type">🌐 公网子网</span>
<span class="subnet-cidr">172.16.1.0/24</span>
</div>
<div class="subnet-resources">
<div class="resource-tag">🖥 ECS × 2</div>
<div class="resource-tag"> SLB</div>
<div class="resource-tag">🌐 NAT</div>
</div>
<div class="subnet-tooltip" v-if="hoverSubnet === 'public-a' && showDetails">
公网子网可直接访问互联网部署对外服务
</div>
</div>
<div class="subnet private"
@mouseenter="hoverSubnet = 'private-a'"
@mouseleave="hoverSubnet = null">
<div class="subnet-header">
<span class="subnet-type">🔒 私网子网</span>
<span class="subnet-cidr">172.16.2.0/24</span>
</div>
<div class="subnet-resources">
<div class="resource-tag">🖥 ECS × 4</div>
<div class="resource-tag">🗄 RDS</div>
<div class="resource-tag">📦 Redis</div>
</div>
<div class="subnet-tooltip" v-if="hoverSubnet === 'private-a' && showDetails">
私网子网无法直接访问互联网部署核心服务
</div>
</div>
</div>
<!-- 可用区 2 -->
<div class="az-container">
<div class="az-header">
<span class="az-name">可用区 B</span>
<span class="az-status online">在线</span>
</div>
<!-- 可用区 2 -->
<div class="az-container">
<div class="az-header">
<span class="az-name">可用区 B</span>
<span class="az-status online">在线</span>
</div>
<div class="subnets">
<div class="subnet public">
<div class="subnet-header">
<span class="subnet-type">🌐 公网子网</span>
<span class="subnet-cidr">172.16.3.0/24</span>
<div class="subnets">
<div class="subnet public">
<div class="subnet-header">
<span class="subnet-type">🌐 公网子网</span>
<span class="subnet-cidr">172.16.3.0/24</span>
</div>
<div class="subnet-resources">
<div class="resource-tag">
🖥 ECS × 2
</div>
<div class="subnet-resources">
<div class="resource-tag">🖥 ECS × 2</div>
<div class="resource-tag"> SLB</div>
<div class="resource-tag">
SLB
</div>
</div>
</div>
<div class="subnet private">
<div class="subnet-header">
<span class="subnet-type">🔒 私网子网</span>
<span class="subnet-cidr">172.16.4.0/24</span>
<div class="subnet private">
<div class="subnet-header">
<span class="subnet-type">🔒 私网子网</span>
<span class="subnet-cidr">172.16.4.0/24</span>
</div>
<div class="subnet-resources">
<div class="resource-tag">
🖥 ECS × 4
</div>
<div class="subnet-resources">
<div class="resource-tag">🖥 ECS × 4</div>
<div class="resource-tag">🗄 RDS Slave</div>
<div class="resource-tag">📦 Redis Slave</div>
<div class="resource-tag">
🗄 RDS Slave
</div>
<div class="resource-tag">
📦 Redis Slave
</div>
</div>
</div>
@@ -146,6 +214,7 @@
</div>
</div>
</div>
</div>
</template>
<script setup>