feat(frontend): make mock panels follow business line

This commit is contained in:
mac
2026-07-17 19:28:19 +08:00
parent a112cf742c
commit 981e9557fe
12 changed files with 383 additions and 241 deletions
+113
View File
@@ -0,0 +1,113 @@
import { computed } from 'vue'
import { useBusinessLineStore } from '@/stores/businessLine'
export const BUSINESS_LINE_NAMES = ['kodo', 'linxi', 'xinfra', 'las'] as const
export type BusinessLineName = (typeof BUSINESS_LINE_NAMES)[number]
interface BusinessLineMockProfile {
name: BusinessLineName
clusters: number
nodes: number
physicalMachines: number
virtualMachines: number
cpuAllocated: number
components: number
mysql: number
redis: number
alertsP0: number
alertsP1: number
tasksRunning: number
primaryZone: string
secondaryZone: string
servicePrefix: string
}
const profiles: Record<BusinessLineName, BusinessLineMockProfile> = {
kodo: {
name: 'kodo',
clusters: 3,
nodes: 128,
physicalMachines: 186,
virtualMachines: 512,
cpuAllocated: 61,
components: 214,
mysql: 38,
redis: 92,
alertsP0: 1,
alertsP1: 5,
tasksRunning: 2,
primaryZone: 'IDC-华北机房',
secondaryZone: 'IDC-华东机房',
servicePrefix: 'kodo',
},
linxi: {
name: 'linxi',
clusters: 2,
nodes: 74,
physicalMachines: 96,
virtualMachines: 238,
cpuAllocated: 47,
components: 128,
mysql: 21,
redis: 46,
alertsP0: 0,
alertsP1: 2,
tasksRunning: 1,
primaryZone: 'IDC-华东机房',
secondaryZone: '阿里云-华南',
servicePrefix: 'linxi',
},
xinfra: {
name: 'xinfra',
clusters: 2,
nodes: 52,
physicalMachines: 68,
virtualMachines: 156,
cpuAllocated: 39,
components: 84,
mysql: 12,
redis: 31,
alertsP0: 0,
alertsP1: 1,
tasksRunning: 1,
primaryZone: 'IDC-华北机房',
secondaryZone: '香港 IDC',
servicePrefix: 'xinfra',
},
las: {
name: 'las',
clusters: 1,
nodes: 34,
physicalMachines: 42,
virtualMachines: 118,
cpuAllocated: 31,
components: 66,
mysql: 8,
redis: 18,
alertsP0: 0,
alertsP1: 3,
tasksRunning: 0,
primaryZone: '七牛-新加坡',
secondaryZone: 'AWS-美国',
servicePrefix: 'las',
},
}
export function normalizeBusinessLineName(name?: string | null): BusinessLineName {
const normalized = String(name || '').trim().toLowerCase()
if (BUSINESS_LINE_NAMES.includes(normalized as BusinessLineName)) {
return normalized as BusinessLineName
}
return 'kodo'
}
export function useBusinessLineMockProfile() {
const businessLineStore = useBusinessLineStore()
const currentName = computed(() => normalizeBusinessLineName(businessLineStore.current?.name))
const profile = computed(() => profiles[currentName.value])
return {
currentName,
profile,
}
}
+43 -7
View File
@@ -24,7 +24,7 @@
</tr>
</thead>
<tbody>
<tr v-for="cluster in clusters" :key="cluster.name" class="tr-hover">
<tr v-for="cluster in businessLineClusters" :key="cluster.name" class="tr-hover">
<td class="strong">{{ cluster.name }}</td>
<td><span class="tag" :class="cluster.zoneClass">{{ cluster.zone }}</span></td>
<td :class="['status-text', cluster.statusClass]">● {{ cluster.status }}</td>
@@ -43,7 +43,7 @@
<div class="panel">
<div class="panel-head">
<h3>rke2-bj-prod-01 · 节点列表(节选)</h3>
<h3>{{ businessLineClusters[0]?.name }} · 节点列表(节选)</h3>
<span class="meta">node-label 多租户隔离</span>
</div>
<div class="panel-body">
@@ -60,7 +60,7 @@
</tr>
</thead>
<tbody>
<tr v-for="node in nodes" :key="node.name" class="tr-hover">
<tr v-for="node in businessLineNodes" :key="node.name" class="tr-hover">
<td class="strong mono">{{ node.name }}</td>
<td class="mono">{{ node.ip }}</td>
<td><span class="tag biz" :style="{ color: node.labelColor, borderColor: node.labelBorder }">{{ node.label }}</span></td>
@@ -77,7 +77,10 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName, profile } = useBusinessLineMockProfile()
const clusters = ref([
{ name: 'rke2-bj-prod-01', zone: '华北 · IDC', zoneClass: 'zone-a', status: '健康', statusClass: 'ok', nodes: 46, cpu: 64, cpuClass: '', version: 'v1.28.9+rke2r1', calico: 'BGP AS64512' },
@@ -87,10 +90,43 @@ const clusters = ref([
const nodes = ref([
{ name: 'bj-node-014', ip: '10.21.4.14', label: 'business-line=kodo', labelColor: 'var(--tag-blue-text)', labelBorder: 'var(--tag-blue-border)', taint: 'kodo:NoSchedule', spec: '64C/256G', cpu: 58, cpuClass: '', status: 'Ready', statusClass: 'ok' },
{ name: 'bj-node-015', ip: '10.21.4.15', label: 'business-line=kodo', labelColor: 'var(--tag-blue-text)', labelBorder: 'var(--tag-blue-border)', taint: 'kodo:NoSchedule', spec: '64C/256G', cpu: 62, cpuClass: '', status: 'Ready', statusClass: 'ok' },
{ name: 'bj-node-031', ip: '10.21.4.31', label: 'business-line=las', labelColor: 'var(--tag-purple-text)', labelBorder: 'var(--tag-purple-border)', taint: 'las:NoSchedule', spec: '32C/128G', cpu: 88, cpuClass: 'warn', status: '资源告警', statusClass: 'warn' },
{ name: 'bj-node-048', ip: '10.21.4.48', label: '未分配', labelColor: 'var(--text-dim)', labelBorder: 'var(--line)', taint: '—', spec: '32C/128G', cpu: 4, cpuClass: '', status: 'Ready · 空闲', statusClass: 'ok' },
{ name: 'bj-node-015', ip: '10.21.4.15', label: 'business-line=linxi', labelColor: 'var(--tag-blue-text)', labelBorder: 'var(--tag-blue-border)', taint: 'linxi:NoSchedule', spec: '64C/256G', cpu: 62, cpuClass: '', status: 'Ready', statusClass: 'ok' },
{ name: 'bj-node-031', ip: '10.21.4.31', label: 'business-line=xinfra', labelColor: 'var(--tag-purple-text)', labelBorder: 'var(--tag-purple-border)', taint: 'xinfra:NoSchedule', spec: '32C/128G', cpu: 88, cpuClass: 'warn', status: '资源告警', statusClass: 'warn' },
{ name: 'bj-node-048', ip: '10.21.4.48', label: 'business-line=las', labelColor: 'var(--text-dim)', labelBorder: 'var(--line)', taint: 'las:NoSchedule', spec: '32C/128G', cpu: 4, cpuClass: '', status: 'Ready · 空闲', statusClass: 'ok' },
])
const businessLineClusters = computed(() => {
const cpu = profile.value.cpuAllocated
return clusters.value.map((cluster, index) => ({
...cluster,
name: `${cluster.name}-${currentName.value}`,
nodes: Math.max(1, Math.round(profile.value.nodes * ([0.42, 0.36, 0.22][index] || 0.2))),
cpu: Math.min(96, Math.max(8, cpu + (index - 1) * 7)),
cpuClass: cpu > 75 ? 'warn' : '',
status: profile.value.alertsP1 && index === 2 ? `${profile.value.alertsP1} 节点告警` : '健康',
statusClass: profile.value.alertsP1 && index === 2 ? 'warn' : 'ok',
}))
})
const businessLineNodes = computed(() => {
const selected = nodes.value.filter((node) => node.label === `business-line=${currentName.value}`)
if (selected.length) return selected
return [
{
name: `${currentName.value}-node-001`,
ip: '10.21.4.14',
label: `business-line=${currentName.value}`,
labelColor: 'var(--tag-blue-text)',
labelBorder: 'var(--tag-blue-border)',
taint: `${currentName.value}:NoSchedule`,
spec: '64C/256G',
cpu: profile.value.cpuAllocated,
cpuClass: profile.value.cpuAllocated > 75 ? 'warn' : '',
status: profile.value.alertsP1 ? '资源告警' : 'Ready',
statusClass: profile.value.alertsP1 ? 'warn' : 'ok',
},
]
})
</script>
<style scoped>
+15 -9
View File
@@ -21,13 +21,13 @@
</div>
<div class="stat-card">
<div class="label">配置项总数</div>
<div class="value">1,260</div>
<div class="delta">Namespace 38 个</div>
<div class="value">{{ configItemCount }}</div>
<div class="delta">Namespace {{ Math.max(1, Math.round(configItemCount / 32)) }} 个</div>
</div>
<div class="stat-card">
<div class="label">接入业务线</div>
<div class="value">2 / 5</div>
<div class="delta">kodo · las 已接入</div>
<div class="value">1 / 1</div>
<div class="delta">{{ currentName }} 已接入</div>
</div>
<div class="stat-card">
<div class="label">同步状态</div>
@@ -78,7 +78,7 @@
</tr>
</thead>
<tbody>
<tr v-for="cluster in clusters" :key="cluster.name" class="tr-hover">
<tr v-for="cluster in currentClusters" :key="cluster.name" class="tr-hover">
<td><span class="tag" :class="cluster.zoneClass">{{ cluster.name }}</span></td>
<td class="mono">cluster={{ cluster.cluster }}</td>
<td class="mono text-xs">{{ cluster.address }}</td>
@@ -95,17 +95,23 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName } = useBusinessLineMockProfile()
const clusters = ref([
{ name: 'YZH 机房', zoneClass: 'zone-a', cluster: 'yzh', address: 'config-yzh.xinfra.internal:8080', type: '容器化 · K8s Service', biz: 'kodo', items: 486, status: '运行中', statusClass: 'ok' },
{ name: 'XS 机房', zoneClass: 'zone-b', cluster: 'xs', address: 'config-xs.xinfra.internal:8080', type: '容器化 · K8s Service', biz: 'las', items: 398, status: '运行中', statusClass: 'ok' },
{ name: 'JF 机房', zoneClass: 'zone-c', cluster: 'jf', address: 'config-jf.xinfra.internal:8080', type: '容器化 · K8s Service', biz: '灵矽', items: 376, status: '灰度接入中', statusClass: 'warn' },
{ name: '达拉斯 IDC', zoneClass: '', cluster: 'dallas', address: '—', type: '容器化 · K8s Service', biz: '—', items: 0, status: '建设中', statusClass: 'idle' },
{ name: 'XS 机房', zoneClass: 'zone-b', cluster: 'xs', address: 'config-xs.xinfra.internal:8080', type: '容器化 · K8s Service', biz: 'linxi', items: 398, status: '运行中', statusClass: 'ok' },
{ name: 'JF 机房', zoneClass: 'zone-c', cluster: 'jf', address: 'config-jf.xinfra.internal:8080', type: '容器化 · K8s Service', biz: 'xinfra', items: 376, status: '灰度接入中', statusClass: 'warn' },
{ name: '达拉斯 IDC', zoneClass: '', cluster: 'dallas', address: 'config-dallas.xinfra.internal:8080', type: '容器化 · K8s Service', biz: 'las', items: 128, status: '建设中', statusClass: 'idle' },
{ name: '新加坡 IDC', zoneClass: '', cluster: 'singapore', address: '—', type: '容器化 · K8s Service', biz: '—', items: 0, status: '建设中', statusClass: 'idle' },
{ name: '香港 IDC', zoneClass: '', cluster: 'hk', address: '—', type: '容器化 · K8s Service', biz: '—', items: 0, status: '待启动', statusClass: 'idle' },
{ name: '东南亚 IDC', zoneClass: '', cluster: 'sea', address: '—', type: '容器化 · K8s Service', biz: '—', items: 0, status: '待启动', statusClass: 'idle' },
])
const currentClusters = computed(() => clusters.value.filter((cluster) => cluster.biz === currentName.value))
const configItemCount = computed(() => currentClusters.value.reduce((sum, cluster) => sum + cluster.items, 0))
</script>
<style scoped>
+27 -23
View File
@@ -11,28 +11,28 @@
<div class="stat-row">
<div class="stat-card">
<div class="label">RKE2 集群</div>
<div class="value">3</div>
<div class="delta">3 机房在线</div>
<div class="value">{{ profile.clusters }}</div>
<div class="delta">{{ profile.clusters }} 机房在线</div>
</div>
<div class="stat-card">
<div class="label">节点总数</div>
<div class="value">128</div>
<div class="delta up">↑ 6 本周新增</div>
<div class="value">{{ profile.nodes }}</div>
<div class="delta up">↑ {{ Math.max(1, Math.round(profile.nodes / 24)) }} 本周新增</div>
</div>
<div class="stat-card">
<div class="label">CPU 已分配</div>
<div class="value">61%</div>
<div class="delta">2,048 / 3,360 核</div>
<div class="value">{{ profile.cpuAllocated }}%</div>
<div class="delta">{{ Math.round(profile.nodes * 16 * profile.cpuAllocated / 100) }} / {{ profile.nodes * 16 }} 核</div>
</div>
<div class="stat-card">
<div class="label">组件实例</div>
<div class="value">214</div>
<div class="delta">MySQL 38 · Redis 92 · 其他 84</div>
<div class="value">{{ profile.components }}</div>
<div class="delta">MySQL {{ profile.mysql }} · Redis {{ profile.redis }} · 其他 {{ profile.components - profile.mysql - profile.redis }}</div>
</div>
<div class="stat-card">
<div class="label">进行中任务</div>
<div class="value warn">2</div>
<div class="delta warn">1 个待关注</div>
<div class="value warn">{{ profile.tasksRunning }}</div>
<div class="delta warn">{{ Math.min(profile.tasksRunning, 1) }} 个待关注</div>
</div>
</div>
@@ -45,8 +45,8 @@
<div class="topo">
<div class="topo-cluster">
<div class="tname">
<span class="tag zone-a">IDC-华北机房</span>
<span class="mono text-dim">46节点</span>
<span class="tag zone-a">{{ profile.primaryZone }}</span>
<span class="mono text-dim">{{ Math.round(profile.nodes * 0.42) }}节点</span>
</div>
<div class="node-grid">
<div v-for="i in 24" :key="i" :class="['node-cell', i <= 18 ? 'a' : '']"></div>
@@ -54,8 +54,8 @@
</div>
<div class="topo-cluster">
<div class="tname">
<span class="tag zone-b">IDC-华东机房</span>
<span class="mono text-dim">52节点</span>
<span class="tag zone-b">{{ profile.secondaryZone }}</span>
<span class="mono text-dim">{{ Math.round(profile.nodes * 0.36) }}节点</span>
</div>
<div class="node-grid">
<div v-for="i in 24" :key="i" :class="['node-cell', i <= 20 ? 'b' : '']"></div>
@@ -63,8 +63,8 @@
</div>
<div class="topo-cluster">
<div class="tname">
<span class="tag zone-c">阿里云-华南</span>
<span class="mono text-dim">30节点</span>
<span class="tag zone-c">弹性云资源池</span>
<span class="mono text-dim">{{ Math.max(1, profile.nodes - Math.round(profile.nodes * 0.42) - Math.round(profile.nodes * 0.36)) }}节点</span>
</div>
<div class="node-grid">
<div v-for="i in 18" :key="i" :class="['node-cell', i <= 12 ? 'c' : '']"></div>
@@ -72,9 +72,9 @@
</div>
</div>
<div class="legend">
<span><span class="node-cell a inline"></span>Kodo业务线</span>
<span><span class="node-cell b inline"></span>LAS业务线</span>
<span><span class="node-cell c inline"></span>灵矽业务线</span>
<span><span class="node-cell a inline"></span>{{ currentName }}主资源池</span>
<span><span class="node-cell b inline"></span>{{ currentName }}扩展池</span>
<span><span class="node-cell c inline"></span>{{ currentName }}弹性池</span>
<span><span class="node-cell empty inline"></span>空闲</span>
</div>
</div>
@@ -89,22 +89,22 @@
<tbody>
<tr class="tr-hover">
<td class="status-text ok">● 成功</td>
<td class="strong">MySQL 主从部署</td>
<td class="strong">{{ profile.servicePrefix }} MySQL 主从部署</td>
<td class="mono">2m14s</td>
</tr>
<tr class="tr-hover">
<td class="status-text warn">● 执行中</td>
<td class="strong">RKE2 节点加入</td>
<td class="strong">{{ profile.servicePrefix }} RKE2 节点加入</td>
<td class="mono">38s</td>
</tr>
<tr class="tr-hover">
<td class="status-text ok">● 成功</td>
<td class="strong">Redis Cluster 部署</td>
<td class="strong">{{ profile.servicePrefix }} Redis Cluster 部署</td>
<td class="mono">3m02s</td>
</tr>
<tr class="tr-hover">
<td class="status-text err">● 失败</td>
<td class="strong">openresty 网关部署</td>
<td class="strong">{{ profile.servicePrefix }} openresty 网关部署</td>
<td class="mono">41s</td>
</tr>
<tr class="tr-hover">
@@ -121,6 +121,10 @@
</template>
<script setup lang="ts">
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName, profile } = useBusinessLineMockProfile()
const refresh = () => {
// 刷新数据
}
+35 -63
View File
@@ -10,17 +10,17 @@
<div class="stat-row">
<div class="stat-card">
<div class="label">P0 / Disaster 告警</div>
<div class="value" style="color: var(--err)">1</div>
<div class="value" style="color: var(--err)">{{ profile.alertsP0 }}</div>
<div class="delta" style="color: var(--err)">来自 VictoriaMetrics</div>
</div>
<div class="stat-card">
<div class="label">P1 / High 告警</div>
<div class="value" style="color: var(--warn)">5</div>
<div class="delta warn">来自 Zabbix · 4 条 / VM · 1 条</div>
<div class="value" style="color: var(--warn)">{{ profile.alertsP1 }}</div>
<div class="delta warn">来自 Zabbix · {{ Math.max(0, profile.alertsP1 - 1) }} 条 / VM · {{ profile.alertsP1 ? 1 : 0 }} 条</div>
</div>
<div class="stat-card">
<div class="label">今日已推送</div>
<div class="value">5</div>
<div class="value">{{ profile.alertsP0 + profile.alertsP1 }}</div>
<div class="delta">qpass 统一告警通道</div>
</div>
</div>
@@ -69,53 +69,13 @@
<th>告警内容</th>
<th>时间</th>
</tr>
<tr class="tr-hover">
<td><span class="tag sev-p0">P0</span></td>
<td class="mono">VictoriaMetrics</td>
<td class="mono">disaster</td>
<td class="strong mono">sg-las-overseas-007</td>
<td>磁盘只读 / IO 错误,节点不可写</td>
<td class="mono">07:38:55</td>
</tr>
<tr class="tr-hover">
<td><span class="tag sev-p1">P1</span></td>
<td class="mono">Zabbix</td>
<td class="mono">high</td>
<td class="strong mono">yzh-las-014</td>
<td>风扇转速低于阈值(FAN_6: 1920 RPM)</td>
<td class="mono">07:35:12</td>
</tr>
<tr class="tr-hover">
<td><span class="tag sev-p1">P1</span></td>
<td class="mono">Zabbix</td>
<td class="mono">high</td>
<td class="strong mono">xs-bm-291</td>
<td>电源冗余丢失(PSU2 离线)</td>
<td class="mono">07:21:40</td>
</tr>
<tr class="tr-hover">
<td><span class="tag sev-p1">P1</span></td>
<td class="mono">VictoriaMetrics</td>
<td class="mono">high</td>
<td class="strong mono">redis-ads-feature-cluster-02</td>
<td>慢查询比例超阈值(>5%,持续5分钟)</td>
<td class="mono">07:18:03</td>
</tr>
<tr class="tr-hover">
<td><span class="tag sev-avg">average</span></td>
<td class="mono">Zabbix</td>
<td class="mono">average</td>
<td class="strong mono">overseas-dallas-idc</td>
<td>专线延迟抖动超基线(WireGuard ↔ AWS US)</td>
<td class="mono">07:10:22</td>
</tr>
<tr class="tr-hover">
<td><span class="tag sev-avg">average</span></td>
<td class="mono">Zabbix</td>
<td class="mono">average</td>
<td class="strong mono">jf-bm-118</td>
<td>CPU 温度接近阈值(76℃ / 80℃)</td>
<td class="mono">06:58:47</td>
<tr v-for="alert in alertRows" :key="alert.object" class="tr-hover">
<td><span :class="['tag', alert.sevClass]">{{ alert.level }}</span></td>
<td class="mono">{{ alert.source }}</td>
<td class="mono">{{ alert.rawLevel }}</td>
<td class="strong mono">{{ alert.object }}</td>
<td>{{ alert.message }}</td>
<td class="mono">{{ alert.time }}</td>
</tr>
</table>
</div>
@@ -127,7 +87,7 @@
<span class="meta">近 24h · qpass</span>
</div>
<div class="panel-body log-stream">
<div v-for="(alert, index) in alerts" :key="index" :class="['task-log-line', alert.class]">
<div v-for="(alert, index) in alerts" :key="index" :class="['task-log-line', alert.class]">
<span class="t">{{ alert.time }}</span>{{ alert.message }}
</div>
</div>
@@ -136,18 +96,30 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const alerts = ref([
{ time: '07:38:55', message: '[qpass] P0 告警推送:sg-las-overseas-007 磁盘只读 / IO 错误', class: 'err' },
{ time: '07:35:12', message: '[qpass] P1 告警推送:yzh-las-014 风扇转速低于阈值(FAN_6: 1920 RPM)', class: '' },
{ time: '07:21:40', message: '[qpass] P1 告警推送:xs-bm-291 电源冗余丢失(PSU2 离线)', class: '' },
{ time: '07:18:03', message: '[qpass] P1 告警推送:redis-ads-feature-cluster-02 慢查询比例超阈值', class: '' },
{ time: '07:10:22', message: '[qpass] average 告警推送:overseas-dallas-idc 专线延迟抖动超基线', class: '' },
{ time: '06:58:47', message: '[qpass] average 告警推送:jf-bm-118 CPU 温度接近阈值(76℃ / 80℃)', class: '' },
{ time: '06:15:22', message: '[Nightingale] sg-las-007 CPU 使用率恢复(当前 42%)', class: 'ok' },
{ time: '05:48:10', message: '[Nightingale] sg-las-007 CPU 使用率超过 90% 持续 5 分钟', class: '' },
])
const { currentName, profile } = useBusinessLineMockProfile()
const alertRows = computed(() => {
const rows = []
if (profile.value.alertsP0) {
rows.push({ level: 'P0', sevClass: 'sev-p0', source: 'VictoriaMetrics', rawLevel: 'disaster', object: `${currentName.value}-node-critical-007`, message: '磁盘只读 / IO 错误,节点不可写', time: '07:38:55' })
}
for (let i = 0; i < profile.value.alertsP1; i += 1) {
rows.push({ level: 'P1', sevClass: 'sev-p1', source: i % 2 ? 'VictoriaMetrics' : 'Zabbix', rawLevel: 'high', object: `${currentName.value}-svc-${String(i + 1).padStart(2, '0')}`, message: i % 2 ? '慢查询比例超阈值(>5%,持续5分钟)' : '节点硬件健康指标异常', time: `07:${35 - i * 4}:12` })
}
if (!rows.length) {
rows.push({ level: 'average', sevClass: 'sev-avg', source: 'Zabbix', rawLevel: 'average', object: `${currentName.value}-baseline`, message: '当前无 P0/P1,仅保留基线观察项', time: '07:10:22' })
}
return rows
})
const alerts = computed(() => alertRows.value.map((alert) => ({
time: alert.time,
message: `[qpass] ${alert.level} 告警推送:${alert.object} ${alert.message}`,
class: alert.level === 'P0' ? 'err' : '',
})))
</script>
<style scoped>
+22 -46
View File
@@ -11,18 +11,18 @@
<div class="stat-row">
<div class="stat-card">
<div class="label">物理机总数</div>
<div class="value">186</div>
<div class="delta">186 / 186 监控覆盖</div>
<div class="value">{{ profile.physicalMachines }}</div>
<div class="delta">{{ profile.physicalMachines }} / {{ profile.physicalMachines }} 监控覆盖</div>
</div>
<div class="stat-card">
<div class="label">虚机总数(LAS)</div>
<div class="value">512</div>
<div class="delta up">↑ 14 本周新增</div>
<div class="label">虚机总数</div>
<div class="value">{{ profile.virtualMachines }}</div>
<div class="delta up">↑ {{ Math.max(1, Math.round(profile.virtualMachines / 36)) }} 本周新增</div>
</div>
<div class="stat-card">
<div class="label">基础组件实例</div>
<div class="value">214</div>
<div class="delta">MySQL 38 · Redis 92 · 其他 84</div>
<div class="value">{{ profile.components }}</div>
<div class="delta">MySQL {{ profile.mysql }} · Redis {{ profile.redis }} · 其他 {{ profile.components - profile.mysql - profile.redis }}</div>
</div>
</div>
@@ -87,7 +87,7 @@
<div class="panel">
<div class="panel-head">
<h3>虚机状态 · LAS 资源池</h3>
<h3>虚机状态 · 按业务线</h3>
<span class="meta">数据源:VictoriaMetrics</span>
</div>
<div class="panel-body">
@@ -99,40 +99,13 @@
<th>状态</th>
</tr>
<tr class="tr-hover">
<td class="strong mono">Kodo</td>
<td class="mono">218</td>
<td class="strong mono">{{ currentName }}</td>
<td class="mono">{{ profile.virtualMachines }}</td>
<td>
<span class="bar-wrap"><span class="bar-fill" style="width: 64%"></span></span>
64%
<span class="bar-wrap"><span class="bar-fill" :class="{ warn: profile.cpuAllocated > 75 }" :style="{ width: `${profile.cpuAllocated}%` }"></span></span>
{{ profile.cpuAllocated }}%
</td>
<td class="status-text ok">● 正常</td>
</tr>
<tr class="tr-hover">
<td class="strong mono">LAS</td>
<td class="mono">164</td>
<td>
<span class="bar-wrap"><span class="bar-fill warn" style="width: 82%"></span></span>
82%
</td>
<td class="status-text warn">● 1 条告警</td>
</tr>
<tr class="tr-hover">
<td class="strong mono">灵矽</td>
<td class="mono">96</td>
<td>
<span class="bar-wrap"><span class="bar-fill" style="width: 57%"></span></span>
57%
</td>
<td class="status-text ok">● 正常</td>
</tr>
<tr class="tr-hover">
<td class="strong mono">共享池 / 未分配</td>
<td class="mono">34</td>
<td>
<span class="bar-wrap"><span class="bar-fill" style="width: 31%"></span></span>
31%
</td>
<td class="status-text ok">● 正常</td>
<td :class="['status-text', profile.alertsP1 ? 'warn' : 'ok']">● {{ profile.alertsP1 ? `${profile.alertsP1} 条告警` : '正常' }}</td>
</tr>
</table>
</div>
@@ -155,17 +128,17 @@
</tr>
<tr class="tr-hover">
<td class="strong">MySQL</td>
<td class="mono">38</td>
<td class="mono">{{ profile.mysql }}</td>
<td class="mono">0</td>
<td class="mono">100%</td>
<td class="status-text ok">● 正常</td>
</tr>
<tr class="tr-hover">
<td class="strong">Redis(CacheCloud)</td>
<td class="mono">92</td>
<td class="mono">1</td>
<td class="mono">98.9%</td>
<td class="status-text warn">● 1 条告警</td>
<td class="mono">{{ profile.redis }}</td>
<td class="mono">{{ profile.alertsP1 ? 1 : 0 }}</td>
<td class="mono">{{ profile.alertsP1 ? '98.9%' : '100%' }}</td>
<td :class="['status-text', profile.alertsP1 ? 'warn' : 'ok']">● {{ profile.alertsP1 ? '1 条告警' : '正常' }}</td>
</tr>
<tr class="tr-hover">
<td class="strong">PostgreSQL</td>
@@ -183,7 +156,7 @@
</tr>
<tr class="tr-hover">
<td class="strong">其他中间件</td>
<td class="mono">46</td>
<td class="mono">{{ profile.components - profile.mysql - profile.redis - 12 - 26 }}</td>
<td class="mono">0</td>
<td class="mono">100%</td>
<td class="status-text ok">● 正常</td>
@@ -196,6 +169,9 @@
</template>
<script setup lang="ts">
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName, profile } = useBusinessLineMockProfile()
</script>
<style scoped>
+22 -17
View File
@@ -11,8 +11,8 @@
<div class="stat-row">
<div class="stat-card">
<div class="label">资源总数</div>
<div class="value">658</div>
<div class="delta">物理机 146 · 虚机 512</div>
<div class="value">{{ filteredResources.length }}</div>
<div class="delta">物理机 {{ physicalCount }} · 虚机 {{ vmCount }}</div>
</div>
<div class="stat-card">
<div class="label">SINA CMDB</div>
@@ -25,9 +25,9 @@
<div class="delta">ECS · 增量同步</div>
</div>
<div class="stat-card">
<div class="label">AWS / 七牛 LAS 同步</div>
<div class="label">AWS / 七牛同步</div>
<div class="value">136</div>
<div class="delta">AWS 58 · 七牛 LAS 78</div>
<div class="delta">AWS 58 · 七牛 78</div>
</div>
<div class="stat-card">
<div class="label">最近一次同步</div>
@@ -47,16 +47,14 @@
<el-option label="SINA CMDB" value="cmdb" />
<el-option label="阿里云同步" value="aliyun" />
<el-option label="AWS 同步" value="aws" />
<el-option label="七牛 LAS 同步" value="qiniu" />
<el-option label="七牛同步" value="qiniu" />
</el-select>
<el-select placeholder="全部业务线">
<el-option label="全部业务线" value="" />
<el-option label="kodo" value="kodo" />
<el-option label="linxi" value="linxi" />
<el-option label="xinfra" value="xinfra" />
<el-option label="las" value="las" />
<el-option label="lingxi" value="lingxi" />
<el-option label="ltoken" value="ltoken" />
<el-option label="maas" value="maas" />
<el-option label="未分配" value="unassigned" />
</el-select>
<el-input placeholder="搜索 hostname / asset_number / IP" class="search-input" />
</div>
@@ -82,7 +80,7 @@
</tr>
</thead>
<tbody>
<tr v-for="item in resources" :key="item.hostname" class="tr-hover">
<tr v-for="item in filteredResources" :key="item.hostname" class="tr-hover">
<td class="strong mono">{{ item.hostname }}</td>
<td class="mono text-xs">{{ item.asset_number }}</td>
<td><span class="tag" :class="item.type === '物理机' ? '' : 'vm'">{{ item.type }}</span></td>
@@ -96,7 +94,7 @@
</tbody>
</table>
<div class="pagination">
<span>共 658 条 · 每页 7 条</span>
<span>共 {{ filteredResources.length }} 条 · 当前业务线:{{ currentName }}</span>
<div class="pg-btns">
<span class="pg-btn disabled">‹</span>
<span class="pg-btn active">1</span>
@@ -113,17 +111,24 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName } = useBusinessLineMockProfile()
const resources = ref([
{ hostname: 'xs291', asset_number: 'SERV00003502', type: '物理机', location: '华东·杭州下沙', ip: '10.34.37.52', spec: '20C/192G/13.52T', business_line: 'kodo', source: 'SINA CMDB', status: 'production' },
{ hostname: 'yzh-las-014', asset_number: 'SERV00004187', type: '虚机', location: '华北·YZH', ip: '10.21.4.214', spec: '32C/128G/4.0T', business_line: 'las', source: 'SINA CMDB', status: 'production' },
{ hostname: 'jf-bm-118', asset_number: 'SERV00004290', type: '物理机', location: '华南·JF', ip: '10.45.2.18', spec: '16C/64G/2.0T', business_line: 'lingxi', source: 'SINA CMDB', status: 'production' },
{ hostname: 'ali-ecs-sz-0231', asset_number: '—', type: '虚机', location: '阿里云·华南', ip: '172.18.4.31', spec: '16C/64G/500G', business_line: 'ltoken', source: '阿里云同步', status: 'production' },
{ hostname: 'aws-us-i-0a13fe2', asset_number: '—', type: '虚机', location: 'AWS · 美国', ip: '10.66.2.12', spec: '8C/32G/200G', business_line: 'maas', source: 'AWS 同步', status: 'production' },
{ hostname: 'sg-las-007', asset_number: 'SERV00004511', type: '虚机', location: '七牛 LAS · 新加坡', ip: '10.88.1.07', spec: '16C/64G/2.0T', business_line: 'las', source: '七牛 LAS 同步', status: 'idle' },
{ hostname: 'hk-bm-001', asset_number: 'SERV00004602', type: '物理机', location: '香港 IDC', ip: '10.90.0.11', spec: '8C/32G/1.0T', business_line: '未分配', source: 'SINA CMDB', status: 'production' },
{ hostname: 'jf-bm-118', asset_number: 'SERV00004290', type: '物理机', location: '华南·JF', ip: '10.45.2.18', spec: '16C/64G/2.0T', business_line: 'linxi', source: 'SINA CMDB', status: 'production' },
{ hostname: 'ali-ecs-sz-0231', asset_number: '—', type: '虚机', location: '阿里云·华南', ip: '172.18.4.31', spec: '16C/64G/500G', business_line: 'xinfra', source: '阿里云同步', status: 'production' },
{ hostname: 'aws-us-i-0a13fe2', asset_number: '—', type: '虚机', location: 'AWS · 美国', ip: '10.66.2.12', spec: '8C/32G/200G', business_line: 'las', source: 'AWS 同步', status: 'production' },
{ hostname: 'sg-las-007', asset_number: 'SERV00004511', type: '虚机', location: '七牛 · 新加坡', ip: '10.88.1.07', spec: '16C/64G/2.0T', business_line: 'las', source: '七牛同步', status: 'idle' },
{ hostname: 'hk-bm-001', asset_number: 'SERV00004602', type: '物理机', location: '香港 IDC', ip: '10.90.0.11', spec: '8C/32G/1.0T', business_line: 'xinfra', source: 'SINA CMDB', status: 'production' },
])
const filteredResources = computed(() => resources.value.filter((item) => item.business_line === currentName.value))
const physicalCount = computed(() => filteredResources.value.filter((item) => item.type === '物理机').length)
const vmCount = computed(() => filteredResources.value.filter((item) => item.type === '虚机').length)
</script>
<style scoped>
+19 -33
View File
@@ -11,28 +11,28 @@
<div class="stat-row">
<div class="stat-card">
<div class="label">物理机总数</div>
<div class="value">186</div>
<div class="delta">186 / 186 监控覆盖</div>
<div class="value">{{ profile.physicalMachines }}</div>
<div class="delta">{{ profile.physicalMachines }} / {{ profile.physicalMachines }} 监控覆盖</div>
</div>
<div class="stat-card">
<div class="label">虚机总数(LAS)</div>
<div class="value">512</div>
<div class="delta up">↑ 14 本周新增</div>
<div class="label">虚机总数({{ currentName }})</div>
<div class="value">{{ profile.virtualMachines }}</div>
<div class="delta up">↑ {{ Math.max(1, Math.round(profile.virtualMachines / 36)) }} 本周新增</div>
</div>
<div class="stat-card">
<div class="label">基础组件实例</div>
<div class="value">214</div>
<div class="delta">MySQL 38 · Redis 92 · 其他 84</div>
<div class="value">{{ profile.components }}</div>
<div class="delta">MySQL {{ profile.mysql }} · Redis {{ profile.redis }} · 其他 {{ profile.components - profile.mysql - profile.redis }}</div>
</div>
<div class="stat-card">
<div class="label">P0 / Disaster 告警</div>
<div class="value err">1</div>
<div class="value err">{{ profile.alertsP0 }}</div>
<div class="delta err">来自 VictoriaMetrics</div>
</div>
<div class="stat-card">
<div class="label">P1 / High 告警</div>
<div class="value warn">5</div>
<div class="delta warn">来自 Zabbix · 4 条 / VM · 1 条</div>
<div class="value warn">{{ profile.alertsP1 }}</div>
<div class="delta warn">来自 Zabbix · {{ Math.max(0, profile.alertsP1 - 1) }} 条 / VM · {{ profile.alertsP1 ? 1 : 0 }} 条</div>
</div>
</div>
@@ -83,7 +83,7 @@
<div class="panel">
<div class="panel-head">
<h3>虚机状态 · LAS 资源池</h3>
<h3>虚机状态 · 业务线资源池</h3>
<span class="meta">数据源:VictoriaMetrics</span>
</div>
<div class="panel-body">
@@ -93,28 +93,10 @@
</thead>
<tbody>
<tr class="tr-hover">
<td class="strong mono">Kodo</td>
<td class="mono">218</td>
<td><span class="bar-wrap"><span class="bar-fill" style="width: 64%"></span></span>64%</td>
<td class="status-text ok">● 正常</td>
</tr>
<tr class="tr-hover">
<td class="strong mono">LAS</td>
<td class="mono">164</td>
<td><span class="bar-wrap"><span class="bar-fill warn" style="width: 82%"></span></span>82%</td>
<td class="status-text warn">● 1 条告警</td>
</tr>
<tr class="tr-hover">
<td class="strong mono">灵矽</td>
<td class="mono">96</td>
<td><span class="bar-wrap"><span class="bar-fill" style="width: 57%"></span></span>57%</td>
<td class="status-text ok">● 正常</td>
</tr>
<tr class="tr-hover">
<td class="strong mono">共享池 / 未分配</td>
<td class="mono">34</td>
<td><span class="bar-wrap"><span class="bar-fill" style="width: 31%"></span></span>31%</td>
<td class="status-text ok">● 正常</td>
<td class="strong mono">{{ currentName }}</td>
<td class="mono">{{ profile.virtualMachines }}</td>
<td><span class="bar-wrap"><span class="bar-fill" :class="{ warn: profile.cpuAllocated > 75 }" :style="{ width: `${profile.cpuAllocated}%` }"></span></span>{{ profile.cpuAllocated }}%</td>
<td :class="['status-text', profile.alertsP1 ? 'warn' : 'ok']">● {{ profile.alertsP1 ? `${profile.alertsP1} 条告警` : '正常' }}</td>
</tr>
</tbody>
</table>
@@ -125,6 +107,10 @@
</template>
<script setup lang="ts">
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName, profile } = useBusinessLineMockProfile()
const refresh = () => {
// 刷新数据
}
+39 -21
View File
@@ -28,7 +28,7 @@
</tr>
</thead>
<tbody>
<tr v-for="tenant in tenants" :key="tenant.key" class="tr-hover">
<tr v-for="tenant in currentTenants" :key="tenant.key" class="tr-hover">
<td class="strong">{{ tenant.name }}</td>
<td class="mono">{{ tenant.key }}</td>
<td class="mono">{{ tenant.namespace }}</td>
@@ -63,23 +63,14 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName, profile } = useBusinessLineMockProfile()
const tenants = ref([
{
name: 'LAS',
key: 'las',
namespace: 'ns-las-prod',
nodes: 12,
cpuPct: 64,
cpuClass: '',
memPct: 71,
memClass: '',
status: '正常',
statusClass: 'ok',
},
{
name: 'KODO',
name: 'kodo',
key: 'kodo',
namespace: 'ns-kodo-prod',
nodes: 8,
@@ -91,9 +82,9 @@ const tenants = ref([
statusClass: 'ok',
},
{
name: 'PILI',
key: 'pili',
namespace: 'ns-pili-prod',
name: 'linxi',
key: 'linxi',
namespace: 'ns-linxi-prod',
nodes: 6,
cpuPct: 82,
cpuClass: 'warn',
@@ -103,9 +94,9 @@ const tenants = ref([
statusClass: 'warn',
},
{
name: 'QVM',
key: 'qvm',
namespace: 'ns-qvm-prod',
name: 'xinfra',
key: 'xinfra',
namespace: 'ns-xinfra-prod',
nodes: 4,
cpuPct: 23,
cpuClass: '',
@@ -114,7 +105,34 @@ const tenants = ref([
status: '正常',
statusClass: 'ok',
},
{
name: 'las',
key: 'las',
namespace: 'ns-las-prod',
nodes: 12,
cpuPct: 64,
cpuClass: '',
memPct: 71,
memClass: '',
status: '正常',
statusClass: 'ok',
},
])
const currentTenants = computed(() => {
const tenant = tenants.value.find((item) => item.key === currentName.value)
if (!tenant) return []
return [{
...tenant,
nodes: Math.max(1, Math.round(profile.value.nodes / 12)),
cpuPct: profile.value.cpuAllocated,
cpuClass: profile.value.cpuAllocated > 75 ? 'warn' : '',
memPct: Math.min(96, profile.value.cpuAllocated + 8),
memClass: profile.value.cpuAllocated > 75 ? 'warn' : '',
status: profile.value.alertsP1 ? '资源告警' : '正常',
statusClass: profile.value.alertsP1 ? 'warn' : 'ok',
}]
})
</script>
<style scoped>
+13 -4
View File
@@ -77,8 +77,10 @@
<div class="field">
<label>业务线</label>
<select v-model="mysqlForm.bl">
<option value="las">las(当前)</option>
<option value="kodo">kodo</option>
<option value="linxi">linxi</option>
<option value="xinfra">xinfra</option>
<option value="las">las</option>
</select>
</div>
<div class="field">
@@ -128,12 +130,14 @@
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { ref, reactive, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import { subsystemApi } from '@/api/subsystem'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const router = useRouter()
const { currentName } = useBusinessLineMockProfile()
interface Service {
name: string
@@ -210,11 +214,16 @@ const basicServices = ref<Service[]>([
const showMysqlModal = ref(false)
const mysqlForm = reactive({
bl: 'las',
bl: currentName.value,
topology: '1m2r',
spec: '8C32G',
version: '8.0.36',
instanceName: 'mysql-las-billing-02',
instanceName: `mysql-${currentName.value}-billing-02`,
})
watch(currentName, (name) => {
mysqlForm.bl = name
mysqlForm.instanceName = `mysql-${name}-billing-02`
})
const handleCardClick = (service: Service) => {
+15 -11
View File
@@ -16,12 +16,12 @@
</div>
<div class="stat-card">
<div class="label">服务总数</div>
<div class="value">186</div>
<div class="value">{{ filteredServices.length }}</div>
<div class="delta">去重后唯一服务名</div>
</div>
<div class="stat-card">
<div class="label">服务实例总数</div>
<div class="value">842</div>
<div class="value">{{ serviceInstances }}</div>
<div class="delta">所有机房注册 IP 汇总</div>
</div>
<div class="stat-card">
@@ -50,10 +50,9 @@
<el-select placeholder="全部业务标签">
<el-option label="全部业务标签" value="" />
<el-option label="kodo" value="kodo" />
<el-option label="linxi" value="linxi" />
<el-option label="xinfra" value="xinfra" />
<el-option label="las" value="las" />
<el-option label="lingxi" value="lingxi" />
<el-option label="ltoken" value="ltoken" />
<el-option label="maas" value="maas" />
</el-select>
<el-select placeholder="全部状态">
<el-option label="全部状态" value="" />
@@ -83,7 +82,7 @@
</tr>
</thead>
<tbody>
<tr v-for="service in services" :key="service.name" class="tr-hover">
<tr v-for="service in filteredServices" :key="service.name" class="tr-hover">
<td class="strong mono">{{ service.name }}</td>
<td><span class="tag" :class="service.dcClass">{{ service.dc }}</span></td>
<td class="mono">{{ service.biz }}</td>
@@ -95,7 +94,7 @@
</tbody>
</table>
<div class="pagination">
<span>共 186 条 · 每页 7 条</span>
<span>共 {{ filteredServices.length }} 条 · 当前业务线:{{ currentName }}</span>
<div class="pg-btns">
<span class="pg-btn disabled">‹</span>
<span class="pg-btn active">1</span>
@@ -112,17 +111,22 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName } = useBusinessLineMockProfile()
const services = ref([
{ name: 'kodo-gateway-svc', dc: 'YZH', dcClass: 'zone-a', biz: 'kodo', instances: 12, healthy: '12 / 12', ip: '10.21.4.51', status: '健康', statusClass: 'ok' },
{ name: 'kodo-upload-svc', dc: 'XS', dcClass: 'zone-b', biz: 'kodo', instances: 10, healthy: '10 / 10', ip: '10.34.37.66', status: '健康', statusClass: 'ok' },
{ name: 'linxi-render-svc', dc: 'JF', dcClass: 'zone-c', biz: 'linxi', instances: 6, healthy: '6 / 6', ip: '10.45.2.30', status: '健康', statusClass: 'ok' },
{ name: 'xinfra-portal-svc', dc: 'YZH', dcClass: 'zone-a', biz: 'xinfra', instances: 8, healthy: '8 / 8', ip: '10.21.4.88', status: '健康', statusClass: 'ok' },
{ name: 'las-search-api', dc: 'XS', dcClass: 'zone-b', biz: 'las', instances: 18, healthy: '17 / 18', ip: '10.34.37.20', status: '部分异常', statusClass: 'warn' },
{ name: 'las-order-svc', dc: '达拉斯 IDC', dcClass: '', biz: 'las', instances: 5, healthy: '5 / 5', ip: '10.66.2.20', status: '健康', statusClass: 'ok' },
{ name: 'lingxi-render-svc', dc: 'JF', dcClass: 'zone-c', biz: 'lingxi', instances: 6, healthy: '6 / 6', ip: '10.45.2.30', status: '健康', statusClass: 'ok' },
{ name: 'ltoken-wallet-svc', dc: 'YZH', dcClass: 'zone-a', biz: 'ltoken', instances: 8, healthy: '8 / 8', ip: '10.21.4.88', status: '健康', statusClass: 'ok' },
{ name: 'maas-infer-svc', dc: '新加坡 IDC', dcClass: '', biz: 'maas', instances: 4, healthy: '3 / 4', ip: '10.88.1.40', status: '部分异常', statusClass: 'warn' },
])
const filteredServices = computed(() => services.value.filter((service) => service.biz === currentName.value))
const serviceInstances = computed(() => filteredServices.value.reduce((sum, service) => sum + service.instances, 0))
</script>
<style scoped>
+20 -7
View File
@@ -15,7 +15,7 @@
<div class="panel-body">
<table>
<tbody>
<tr v-for="task in tasks" :key="task.id" class="tr-hover" :class="{ active: task.id === selectedTask }" @click="selectedTask = task.id">
<tr v-for="task in visibleTasks" :key="task.id" class="tr-hover" :class="{ active: task.id === selectedTask }" @click="selectedTask = task.id">
<td :class="['status-text', task.statusClass]">● {{ task.status }}</td>
<td class="strong">{{ task.name }}</td>
<td class="mono text-xs text-dim">{{ task.playbook }}</td>
@@ -23,7 +23,7 @@
</tbody>
</table>
<div class="pagination">
<span>共 86 条 · 每页 6 条</span>
<span>共 {{ visibleTasks.length }} 条 · 当前业务线:{{ currentName }}</span>
<div class="pg-btns">
<span class="pg-btn disabled">‹</span>
<span class="pg-btn active">1</span>
@@ -39,11 +39,11 @@
<div class="panel">
<div class="panel-head">
<h3>实时日志 · RKE2 节点加入</h3>
<h3>实时日志 · {{ currentName }} RKE2 节点加入</h3>
<span class="meta">WebSocket 流式输出</span>
</div>
<div class="panel-body log-stream">
<div v-for="(log, index) in logs" :key="index" :class="['task-log-line', log.class]">
<div v-for="(log, index) in visibleLogs" :key="index" :class="['task-log-line', log.class]">
<span class="t">{{ log.time }}</span>{{ log.message }}
</div>
<div class="task-log-line">
@@ -57,17 +57,20 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref } from 'vue'
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
const { currentName } = useBusinessLineMockProfile()
const selectedTask = ref(1)
const tasks = ref([
{ id: 1, name: 'RKE2 节点加入 · bj-node-061', playbook: 'roles/rke2-node-join', status: '执行中', statusClass: 'warn' },
{ id: 2, name: 'MySQL 主从部署 · kodo', playbook: 'roles/mysql-deploy', status: '成功', statusClass: 'ok' },
{ id: 3, name: 'Redis Cluster 部署 · las', playbook: 'roles/redis-deploy', status: '成功', statusClass: 'ok' },
{ id: 3, name: 'Redis Cluster 部署 · linxi', playbook: 'roles/redis-deploy', status: '成功', statusClass: 'ok' },
{ id: 4, name: 'openresty 网关部署', playbook: 'roles/openresty-deploy', status: '失败', statusClass: 'err' },
{ id: 5, name: '业务线标签同步 · LDAP', playbook: 'internal/label-sync', status: '成功', statusClass: 'ok' },
{ id: 6, name: 'MySQL 主从部署 · ltoken', playbook: 'roles/mysql-deploy', status: '成功', statusClass: 'ok' },
{ id: 6, name: 'MySQL 主从部署 · xinfra', playbook: 'roles/mysql-deploy', status: '成功', statusClass: 'ok' },
])
const logs = ref([
@@ -80,6 +83,16 @@ const logs = ref([
{ time: '10:42:20', message: 'changed: [bj-node-061] => labels applied', class: 'tag-ok' },
{ time: '10:42:21', message: 'TASK [加入集群 rke2-bj-prod-01] ...', class: '' },
])
const visibleTasks = computed(() => tasks.value.map((task) => ({
...task,
name: task.name.replace(/ · (kodo|linxi|xinfra|las)|$/, ` · ${currentName.value}`),
})))
const visibleLogs = computed(() => logs.value.map((log) => ({
...log,
message: log.message.replace(/business-line=(kodo|linxi|xinfra|las)/, `business-line=${currentName.value}`),
})))
</script>
<style scoped>