2026-07-14 15:40:21 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="page-head">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h1>服务管理</h1>
|
|
|
|
|
|
<p>同步全部机房 Consul 注册中心服务目录,统一查看服务名 / 服务 IP / 业务标签 / 实例数</p>
|
|
|
|
|
|
</div>
|
2026-07-17 16:00:06 +08:00
|
|
|
|
<el-button type="primary">同步</el-button>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="stat-row">
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="label">接入 Consul Datacenter</div>
|
|
|
|
|
|
<div class="value">7</div>
|
|
|
|
|
|
<div class="delta">国内 3 · 海外 4</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="label">服务总数</div>
|
2026-07-17 19:28:19 +08:00
|
|
|
|
<div class="value">{{ filteredServices.length }}</div>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<div class="delta">去重后唯一服务名</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="label">服务实例总数</div>
|
2026-07-17 19:28:19 +08:00
|
|
|
|
<div class="value">{{ serviceInstances }}</div>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<div class="delta">所有机房注册 IP 汇总</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="label">健康实例占比</div>
|
2026-07-15 15:11:55 +08:00
|
|
|
|
<div class="value accent">98.6%</div>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<div class="delta warn">12 个实例 critical</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="label">最近同步</div>
|
2026-07-15 15:11:55 +08:00
|
|
|
|
<div class="value accent-pill">● 正常</div>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<div class="delta">07:41:05 · 间隔 30s</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="las-toolbar">
|
|
|
|
|
|
<el-select placeholder="全部机房">
|
|
|
|
|
|
<el-option label="全部机房" value="" />
|
|
|
|
|
|
<el-option label="YZH" value="yzh" />
|
|
|
|
|
|
<el-option label="XS" value="xs" />
|
|
|
|
|
|
<el-option label="JF" value="jf" />
|
|
|
|
|
|
<el-option label="达拉斯" value="dallas" />
|
|
|
|
|
|
<el-option label="新加坡" value="singapore" />
|
|
|
|
|
|
<el-option label="香港" value="hk" />
|
|
|
|
|
|
<el-option label="东南亚" value="sea" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
<el-select placeholder="全部业务标签">
|
|
|
|
|
|
<el-option label="全部业务标签" value="" />
|
|
|
|
|
|
<el-option label="kodo" value="kodo" />
|
2026-07-17 19:28:19 +08:00
|
|
|
|
<el-option label="linxi" value="linxi" />
|
|
|
|
|
|
<el-option label="xinfra" value="xinfra" />
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<el-option label="las" value="las" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
<el-select placeholder="全部状态">
|
|
|
|
|
|
<el-option label="全部状态" value="" />
|
|
|
|
|
|
<el-option label="健康" value="healthy" />
|
|
|
|
|
|
<el-option label="部分异常" value="partial" />
|
|
|
|
|
|
<el-option label="全部下线" value="offline" />
|
|
|
|
|
|
</el-select>
|
2026-07-15 15:11:55 +08:00
|
|
|
|
<el-input placeholder="搜索服务名 / IP" class="search-input" />
|
2026-07-14 15:40:21 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<div class="panel-head">
|
|
|
|
|
|
<h3>服务台账 · 按 Consul Datacenter 同步</h3>
|
|
|
|
|
|
<span class="meta">数据源:Consul Catalog API</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="panel-body">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>服务名</th>
|
|
|
|
|
|
<th>机房 / Datacenter</th>
|
|
|
|
|
|
<th>业务标签</th>
|
|
|
|
|
|
<th>实例数</th>
|
|
|
|
|
|
<th>健康实例</th>
|
|
|
|
|
|
<th>示例 IP</th>
|
|
|
|
|
|
<th>状态</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
2026-07-17 19:28:19 +08:00
|
|
|
|
<tr v-for="service in filteredServices" :key="service.name" class="tr-hover">
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<td class="strong mono">{{ service.name }}</td>
|
|
|
|
|
|
<td><span class="tag" :class="service.dcClass">{{ service.dc }}</span></td>
|
|
|
|
|
|
<td class="mono">{{ service.biz }}</td>
|
|
|
|
|
|
<td class="mono">{{ service.instances }}</td>
|
|
|
|
|
|
<td class="mono">{{ service.healthy }}</td>
|
|
|
|
|
|
<td class="mono">{{ service.ip }}</td>
|
|
|
|
|
|
<td :class="['status-text', service.statusClass]">● {{ service.status }}</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="pagination">
|
2026-07-17 19:28:19 +08:00
|
|
|
|
<span>共 {{ filteredServices.length }} 条 · 当前业务线:{{ currentName }}</span>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
<div class="pg-btns">
|
|
|
|
|
|
<span class="pg-btn disabled">‹</span>
|
|
|
|
|
|
<span class="pg-btn active">1</span>
|
|
|
|
|
|
<span class="pg-btn">2</span>
|
|
|
|
|
|
<span class="pg-btn">3</span>
|
|
|
|
|
|
<span class="pg-sep">…</span>
|
|
|
|
|
|
<span class="pg-btn">27</span>
|
|
|
|
|
|
<span class="pg-btn">›</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-07-22 14:57:11 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<div class="panel-head">
|
|
|
|
|
|
<h3>容器化服务台账 · 按集群 / Namespace 同步</h3>
|
|
|
|
|
|
<span class="meta">{{ containerLoading ? '同步中...' : containerMetaText }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="panel-body">
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>服务名</th>
|
|
|
|
|
|
<th>集群</th>
|
|
|
|
|
|
<th>Namespace</th>
|
|
|
|
|
|
<th>工作负载</th>
|
|
|
|
|
|
<th>Pod Ready</th>
|
|
|
|
|
|
<th>镜像</th>
|
|
|
|
|
|
<th>业务标签</th>
|
|
|
|
|
|
<th>状态</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr v-if="!containerLoading && containerServices.length === 0">
|
|
|
|
|
|
<td colspan="8" class="text-dim">当前业务线暂无容器化服务</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr v-for="service in containerServices" :key="`${service.cluster}-${service.namespace}-${service.name}`" class="tr-hover">
|
|
|
|
|
|
<td class="strong mono">{{ service.name }}</td>
|
|
|
|
|
|
<td><span class="tag">{{ service.cluster }}</span></td>
|
|
|
|
|
|
<td class="mono">{{ service.namespace }}</td>
|
|
|
|
|
|
<td>{{ service.workload }}</td>
|
|
|
|
|
|
<td class="mono">{{ service.ready }}</td>
|
|
|
|
|
|
<td class="mono text-xs">{{ service.image || '-' }}</td>
|
|
|
|
|
|
<td class="mono">{{ service.biz }}</td>
|
|
|
|
|
|
<td :class="['status-text', service.statusClass]">● {{ service.status }}</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="pagination">
|
|
|
|
|
|
<span>共 {{ containerServices.length }} 条容器化服务 · 当前业务线:{{ currentName }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-07-14 15:40:21 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
2026-07-22 14:57:11 +08:00
|
|
|
|
import { computed, ref, watch } from 'vue'
|
|
|
|
|
|
import { containerServiceApi, emptyContainerServiceSummary, type ContainerServiceSummary, type ContainerWorkload } from '@/api/containerService'
|
|
|
|
|
|
import { useBusinessLineStore } from '@/stores/businessLine'
|
2026-07-17 19:28:19 +08:00
|
|
|
|
import { useBusinessLineMockProfile } from '@/utils/businessLineMock'
|
|
|
|
|
|
|
|
|
|
|
|
const { currentName } = useBusinessLineMockProfile()
|
2026-07-22 14:57:11 +08:00
|
|
|
|
const businessLineStore = useBusinessLineStore()
|
2026-07-14 15:40:21 +08:00
|
|
|
|
|
|
|
|
|
|
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' },
|
2026-07-17 19:28:19 +08:00
|
|
|
|
{ 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' },
|
2026-07-14 15:40:21 +08:00
|
|
|
|
{ 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' },
|
|
|
|
|
|
])
|
2026-07-17 19:28:19 +08:00
|
|
|
|
|
2026-07-22 14:57:11 +08:00
|
|
|
|
const containerServices = ref<ContainerWorkload[]>([])
|
|
|
|
|
|
const containerSummary = ref<ContainerServiceSummary>({ ...emptyContainerServiceSummary })
|
|
|
|
|
|
const containerLoading = ref(false)
|
|
|
|
|
|
const containerError = ref('')
|
|
|
|
|
|
|
2026-07-17 19:28:19 +08:00
|
|
|
|
const filteredServices = computed(() => services.value.filter((service) => service.biz === currentName.value))
|
|
|
|
|
|
const serviceInstances = computed(() => filteredServices.value.reduce((sum, service) => sum + service.instances, 0))
|
2026-07-22 14:57:11 +08:00
|
|
|
|
const containerMetaText = computed(() => {
|
|
|
|
|
|
if (containerError.value) {
|
|
|
|
|
|
return containerError.value
|
|
|
|
|
|
}
|
|
|
|
|
|
const errors = containerSummary.value.errors?.length || 0
|
|
|
|
|
|
return errors > 0 ? `数据源:Kubernetes Workload API · ${errors} 项同步失败` : '数据源:Kubernetes Workload API'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const loadContainerServices = async () => {
|
|
|
|
|
|
const businessLineId = businessLineStore.current?.id
|
|
|
|
|
|
if (!businessLineId) {
|
|
|
|
|
|
containerServices.value = []
|
|
|
|
|
|
containerSummary.value = { ...emptyContainerServiceSummary }
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
containerLoading.value = true
|
|
|
|
|
|
containerError.value = ''
|
|
|
|
|
|
try {
|
|
|
|
|
|
const data = await containerServiceApi.listWorkloads(businessLineId)
|
|
|
|
|
|
containerServices.value = data.items
|
|
|
|
|
|
containerSummary.value = data.summary
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
containerServices.value = []
|
|
|
|
|
|
containerSummary.value = { ...emptyContainerServiceSummary }
|
|
|
|
|
|
containerError.value = error instanceof Error ? error.message : '容器化服务数据同步失败'
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
containerLoading.value = false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => businessLineStore.current?.id,
|
|
|
|
|
|
() => {
|
|
|
|
|
|
loadContainerServices()
|
|
|
|
|
|
},
|
|
|
|
|
|
{ immediate: true },
|
|
|
|
|
|
)
|
2026-07-14 15:40:21 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2026-07-15 15:11:55 +08:00
|
|
|
|
/* 所有样式已在 global.css 中定义 */
|
2026-07-14 15:40:21 +08:00
|
|
|
|
</style>
|