Commit 1fe9a380 by Jony.L

大屏数据:大地图 真实数据 管理端调整

parent 4ffe89c8
......@@ -16,6 +16,7 @@ export interface ResourceSpu {
nic?: string; // 网卡配置
ip?: string; // 服务器ip
location?: string; // 位置
areaId?: number; // 地区ID
initUsername?: string; // 初始用户名
initPassword?: string; // 初始密码
intro?: string; // 商品简介
......
......@@ -34,20 +34,18 @@
<div class="statistical-item">
<i></i>
<div>
<div class="label">算力利用率</div>
<div class="value">{{ dashboardData.overallSituation.computeUtilizationRate }}%</div>
<!-- 42.37%-->
<div class="label">闲置算力</div>
<div class="value">
{{ dashboardData.overallSituation.idleCompute }} TOPS
</div>
</div>
</div>
<div class="statistical-item">
<i></i>
<div>
<div class="label">运行中任务数</div>
<div class="value">
{{ dashboardData.overallSituation.runningTaskCount }}
<!-- 29
<animation-count :end-val="0.83" decimals :range-min="40" :range-max="42" />-->
</div>
<div class="label">算力利用率</div>
<div class="value">{{ dashboardData.overallSituation.computeUtilizationRate }}%</div>
<!-- 42.37%-->
</div>
</div>
</div>
......@@ -268,6 +266,11 @@ const fetchRealData = async () => {
if (res.carouselItems) {
dashboardData.value.carouselItems = res.carouselItems
}
// 地图数据
if (res.mapData) {
dashboardData.value.mapData = res.mapData
}
}
} catch (error) {
console.error('获取真实数据失败:', error)
......
......@@ -21,10 +21,7 @@
</div>
</el-card>
<!-- 第一行:平台总体态势 + API请求趋势 -->
<el-row :gutter="20">
<el-col :span="12">
<!-- 平台总体态势 -->
<!-- 平台总体态势 -->
<el-card class="config-card" shadow="never">
<template #header>
<div class="card-header">
......@@ -33,35 +30,34 @@
<el-button type="primary" size="small" @click="saveOverallSituation">保存</el-button>
</div>
</template>
<el-form :model="overallSituation" label-width="140px" class="config-form">
<el-row :gutter="20">
<el-form :model="overallSituation" label-width="130px" class="config-form">
<el-row :gutter="0">
<el-col :span="12">
<el-form-item label="算力总规模(P)">
<el-input-number v-model="overallSituation.allCompute" :precision="2" :min="0" />
<el-form-item label="算力总规模(TOPS)">
<el-input-number v-model="overallSituation.allCompute" :precision="2" :min="0" :controls="false" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="已租赁算力(P)">
<el-input-number v-model="overallSituation.leaseCompute" :precision="2" :min="0" />
<el-form-item label="已租赁算力(TOPS)">
<el-input-number v-model="overallSituation.leaseCompute" :precision="2" :min="0" :controls="false" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="算力利用率(%)">
<el-input-number v-model="overallSituation.computeUtilizationRate" :precision="2" :min="0" :max="100" />
<el-form-item label="闲置算力(TOPS)">
<el-input-number v-model="overallSituation.idleCompute" :precision="2" :min="0" :controls="false" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="运行中任务数">
<el-input-number v-model="overallSituation.runningTaskCount" :min="0" />
<el-form-item label="算力利用率(%)">
<el-input-number v-model="overallSituation.computeUtilizationRate" :precision="2" :min="0" :max="100" :controls="false" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</el-col>
<!-- 第二行:API请求趋势 + 算力资源分布 -->
<el-row :gutter="20">
<el-col :span="12">
<!-- API请求趋势 -->
<el-card class="config-card" shadow="never">
......@@ -72,50 +68,247 @@
<el-button type="primary" size="small" @click="saveApiCalls">保存</el-button>
</div>
</template>
<div class="table-section">
<el-button type="primary" size="small" @click="addApiCallItem" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="apiCallsList.length > 0">
<thead>
<tr>
<th>日期</th>
<th>调用次数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in apiCallsList" :key="index">
<td>
<el-date-picker
v-model="item.countDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
size="small"
/>
</td>
<td>
<el-input-number v-model="item.callsCount" :min="0" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeApiCallItem(index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
<el-tabs v-model="apiCallsTab" type="border-card">
<!-- 日维度 -->
<el-tab-pane label="日" name="d">
<div class="table-section">
<el-button type="primary" size="small" @click="addApiCallItem('d')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="apiCallsData.d && apiCallsData.d.length > 0">
<thead>
<tr>
<th>日期</th>
<th>调用次数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in apiCallsData.d" :key="index">
<td>
<el-date-picker
v-model="item.countDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
size="small"
/>
</td>
<td>
<el-input-number v-model="item.callsCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeApiCallItem('d', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
<!-- 月维度 -->
<el-tab-pane label="月" name="m">
<div class="table-section">
<el-button type="primary" size="small" @click="addApiCallItem('m')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="apiCallsData.m && apiCallsData.m.length > 0">
<thead>
<tr>
<th>日期</th>
<th>调用次数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in apiCallsData.m" :key="index">
<td>
<el-date-picker
v-model="item.countDate"
type="month"
placeholder="选择月份"
format="YYYY-MM"
value-format="YYYY-MM"
size="small"
/>
</td>
<td>
<el-input-number v-model="item.callsCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeApiCallItem('m', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
<!-- 年维度 -->
<el-tab-pane label="年" name="y">
<div class="table-section">
<el-button type="primary" size="small" @click="addApiCallItem('y')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="apiCallsData.y && apiCallsData.y.length > 0">
<thead>
<tr>
<th>年份</th>
<th>调用次数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in apiCallsData.y" :key="index">
<td>
<el-input v-model="item.countDate" placeholder="如:2025" size="small" />
</td>
<td>
<el-input-number v-model="item.callsCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeApiCallItem('y', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
<el-col :span="12">
<!-- 算力资源分布 -->
<el-card class="config-card" shadow="never">
<template #header>
<div class="card-header">
<Icon icon="ep:pie-chart" :size="20" />
<span class="title">算力资源分布</span>
<el-button type="primary" size="small" @click="saveComputeDistribution">保存</el-button>
</div>
</template>
<el-tabs v-model="activeTab" type="border-card">
<!-- GPU型号 -->
<el-tab-pane label="GPU型号" name="gpu">
<div class="table-section">
<el-button type="primary" size="small" @click="addComputeItem('gpu')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加GPU型号
</el-button>
<table class="data-table" v-if="computeDistribution.gpu && computeDistribution.gpu.length > 0">
<thead>
<tr>
<th>型号名称</th>
<th>占比</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in computeDistribution.gpu" :key="index">
<td>
<el-input v-model="item.name" placeholder="如:4090" size="small" />
</td>
<td>
<el-input-number v-model="item.value" :precision="2" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeComputeItem('gpu', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
<!-- 算力来源 -->
<el-tab-pane label="算力来源" name="source">
<div class="table-section">
<el-button type="primary" size="small" @click="addComputeItem('source')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加来源
</el-button>
<table class="data-table" v-if="computeDistribution.source && computeDistribution.source.length > 0">
<thead>
<tr>
<th>来源名称</th>
<th>占比</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in computeDistribution.source" :key="index">
<td>
<el-input v-model="item.name" placeholder="如:自有" size="small" />
</td>
<td>
<el-input-number v-model="item.value" :precision="2" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeComputeItem('source', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
<!-- 计算资源 -->
<el-tab-pane label="计算资源" name="resource">
<div class="table-section">
<el-button type="primary" size="small" @click="addComputeItem('resource')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加资源类型
</el-button>
<table class="data-table" v-if="computeDistribution.resource && computeDistribution.resource.length > 0">
<thead>
<tr>
<th>资源名称</th>
<th>占比</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in computeDistribution.resource" :key="index">
<td>
<el-input v-model="item.name" placeholder="如:裸金属" size="small" />
</td>
<td>
<el-input-number v-model="item.value" :precision="2" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeComputeItem('resource', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
<!-- 第二行:算力资源分布 + 用户管理 -->
<!-- 第三行:用户管理 + 服务能力 -->
<el-row :gutter="20">
<el-col :span="12">
<!-- 用户管理 -->
<!-- 算力资源分布 -->
<el-card class="config-card" shadow="never">
<template #header>
......@@ -146,7 +339,7 @@
<el-input v-model="item.name" placeholder="如:4090" size="small" />
</td>
<td>
<el-input-number v-model="item.value" :precision="2" :min="0" size="small" />
<el-input-number v-model="item.value" :precision="2" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeComputeItem('gpu', index)">
......@@ -180,7 +373,7 @@
<el-input v-model="item.name" placeholder="如:自有" size="small" />
</td>
<td>
<el-input-number v-model="item.value" :precision="2" :min="0" size="small" />
<el-input-number v-model="item.value" :precision="2" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeComputeItem('source', index)">
......@@ -214,7 +407,7 @@
<el-input v-model="item.name" placeholder="如:裸金属" size="small" />
</td>
<td>
<el-input-number v-model="item.value" :precision="2" :min="0" size="small" />
<el-input-number v-model="item.value" :precision="2" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeComputeItem('resource', index)">
......@@ -241,43 +434,189 @@
<el-button type="primary" size="small" @click="saveUsers">保存</el-button>
</div>
</template>
<el-tabs v-model="usersTab" type="border-card">
<!-- 日维度 -->
<el-tab-pane label="日" name="d">
<div class="table-section">
<el-button type="primary" size="small" @click="addUserItem('d')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="usersData.d && usersData.d.length > 0">
<thead>
<tr>
<th>日期</th>
<th>用户总数</th>
<th>增长用户数</th>
<th>活跃用户数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in usersData.d" :key="index">
<td>
<el-date-picker
v-model="item.countDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
size="small"
/>
</td>
<td>
<el-input-number v-model="item.usersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.growthUsersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.activeUsersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeUserItem('d', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
<!-- 月维度 -->
<el-tab-pane label="月" name="m">
<div class="table-section">
<el-button type="primary" size="small" @click="addUserItem('m')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="usersData.m && usersData.m.length > 0">
<thead>
<tr>
<th>日期</th>
<th>用户总数</th>
<th>增长用户数</th>
<th>活跃用户数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in usersData.m" :key="index">
<td>
<el-date-picker
v-model="item.countDate"
type="month"
placeholder="选择月份"
format="YYYY-MM"
value-format="YYYY-MM"
size="small"
/>
</td>
<td>
<el-input-number v-model="item.usersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.growthUsersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.activeUsersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeUserItem('m', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
<!-- 年维度 -->
<el-tab-pane label="年" name="y">
<div class="table-section">
<el-button type="primary" size="small" @click="addUserItem('y')" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="usersData.y && usersData.y.length > 0">
<thead>
<tr>
<th>年份</th>
<th>用户总数</th>
<th>增长用户数</th>
<th>活跃用户数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in usersData.y" :key="index">
<td>
<el-input v-model="item.countDate" placeholder="如:2025" size="small" />
</td>
<td>
<el-input-number v-model="item.usersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.growthUsersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.activeUsersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeUserItem('y', index)">
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty v-else description="暂无数据,请添加" :image-size="80" />
</div>
</el-tab-pane>
</el-tabs>
</el-card>
</el-col>
</el-row>
<!-- 第三行:服务能力 + 订单管理 -->
<el-row :gutter="20">
<el-col :span="12">
<!-- 服务能力 -->
<el-card class="config-card" shadow="never">
<template #header>
<div class="card-header">
<Icon icon="ep:trend-charts" :size="20" />
<span class="title">服务能力</span>
<el-button type="primary" size="small" @click="saveServiceCapability">保存</el-button>
</div>
</template>
<div class="table-section">
<el-button type="primary" size="small" @click="addUserItem" style="margin-bottom: 10px;">
<el-button type="primary" size="small" @click="addServiceCapabilityItem" style="margin-bottom: 10px;">
<Icon icon="ep:plus" class="mr-5px" />添加数据项
</el-button>
<table class="data-table" v-if="usersList.length > 0">
<table class="data-table" v-if="serviceCapabilityList.length > 0">
<thead>
<tr>
<th>日期</th>
<th>用户总数</th>
<th>增长用户数</th>
<th>活跃用户数</th>
<th>年份</th>
<th>上线应用数</th>
<th>上线API数</th>
<th style="width: 80px">操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in usersList" :key="index">
<tr v-for="(item, index) in serviceCapabilityList" :key="index">
<td>
<el-date-picker
v-model="item.countDate"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
size="small"
/>
<el-input v-model="item.year" placeholder="如:2018" size="small" />
</td>
<td>
<el-input-number v-model="item.usersCount" :min="0" size="small" />
<el-input-number v-model="item.appOnline" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.growthUsersCount" :min="0" size="small" />
<el-input-number v-model="item.apiOnline" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.activeUsersCount" :min="0" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeUserItem(index)">
<el-button type="danger" size="small" @click="removeServiceCapabilityItem(index)">
删除
</el-button>
</td>
......@@ -288,33 +627,6 @@
</div>
</el-card>
</el-col>
</el-row>
<!-- 第三行:服务能力 + 订单管理 -->
<el-row :gutter="20">
<el-col :span="12">
<!-- 服务能力 -->
<el-card class="config-card" shadow="never">
<template #header>
<div class="card-header">
<Icon icon="ep:trend-charts" :size="20" />
<span class="title">服务能力</span>
<el-button type="primary" size="small" @click="saveServiceCapability">保存</el-button>
</div>
</template>
<el-form :model="serviceCapability" label-width="120px" class="config-form">
<el-form-item label="年份">
<el-input v-model="serviceCapability.yearsStr" placeholder="如:2018,2019,2020" />
</el-form-item>
<el-form-item label="上线应用">
<el-input v-model="serviceCapability.appOnlineStr" placeholder="如:10,20,30,40,50(逗号分隔)" />
</el-form-item>
<el-form-item label="上线API">
<el-input v-model="serviceCapability.apiOnlineStr" placeholder="如:100,200,300,400,500(逗号分隔)" />
</el-form-item>
</el-form>
</el-card>
</el-col>
<el-col :span="12">
<!-- 订单管理 -->
......@@ -357,16 +669,16 @@
/>
</td>
<td>
<el-input-number v-model="item.computeOrdersCount" :min="0" size="small" />
<el-input-number v-model="item.computeOrdersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.apiOrdersCount" :min="0" size="small" />
<el-input-number v-model="item.apiOrdersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.computeOrdersAmount" :min="0" size="small" />
<el-input-number v-model="item.computeOrdersAmount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.apiOrdersAmount" :min="0" size="small" />
<el-input-number v-model="item.apiOrdersAmount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeOrderItem('d', index)">
......@@ -410,16 +722,16 @@
/>
</td>
<td>
<el-input-number v-model="item.computeOrdersCount" :min="0" size="small" />
<el-input-number v-model="item.computeOrdersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.apiOrdersCount" :min="0" size="small" />
<el-input-number v-model="item.apiOrdersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.computeOrdersAmount" :min="0" size="small" />
<el-input-number v-model="item.computeOrdersAmount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.apiOrdersAmount" :min="0" size="small" />
<el-input-number v-model="item.apiOrdersAmount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeOrderItem('m', index)">
......@@ -456,16 +768,16 @@
<el-input v-model="item.countDate" placeholder="如:2025" size="small" />
</td>
<td>
<el-input-number v-model="item.computeOrdersCount" :min="0" size="small" />
<el-input-number v-model="item.computeOrdersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.apiOrdersCount" :min="0" size="small" />
<el-input-number v-model="item.apiOrdersCount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.computeOrdersAmount" :min="0" size="small" />
<el-input-number v-model="item.computeOrdersAmount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-input-number v-model="item.apiOrdersAmount" :min="0" size="small" />
<el-input-number v-model="item.apiOrdersAmount" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeOrderItem('y', index)">
......@@ -485,7 +797,7 @@
<!-- 地图数据 -->
<el-row :gutter="20">
<el-col :span="24">
<el-col :span="12">
<el-card class="config-card" shadow="never">
<template #header>
<div class="card-header">
......@@ -514,7 +826,7 @@
</el-select>
</td>
<td>
<el-input-number v-model="item.value" :precision="4" :min="0" size="small" />
<el-input-number v-model="item.value" :precision="4" :min="0" :controls="false" size="small" />
</td>
<td>
<el-button type="danger" size="small" @click="removeMapDataItem(index)">
......@@ -551,21 +863,27 @@ const overallSituation = ref({
allCompute: 432.58,
leaseCompute: 139.94,
computeUtilizationRate: 42.37,
runningTaskCount: 29
idleCompute: 292.64
})
// API请求趋势
const apiCallsList = ref([])
const apiCallsTab = ref('d')
const apiCallsData = ref({
d: [],
m: [],
y: []
})
// 用户管理
const usersList = ref([])
const usersTab = ref('d')
const usersData = ref({
d: [],
m: [],
y: []
})
// 服务能力
const serviceCapability = ref({
yearsStr: '',
appOnlineStr: '',
apiOnlineStr: ''
})
const serviceCapabilityList = ref([])
// 算力资源分布
const activeTab = ref('gpu')
......@@ -611,7 +929,9 @@ const loadAllMockData = async () => {
}
} else if (item.configKey === 'mock_api_calls') {
try {
apiCallsList.value = JSON.parse(item.configValue)
const data = JSON.parse(item.configValue)
// API请求趋势数据是对象格式,包含 d/m/y 三个维度
apiCallsData.value = data
} catch (e) {
console.error('解析API请求趋势失败', e)
}
......@@ -623,18 +943,21 @@ const loadAllMockData = async () => {
}
} else if (item.configKey === 'mock_users') {
try {
usersList.value = JSON.parse(item.configValue)
const data = JSON.parse(item.configValue)
// 用户管理数据是对象格式,包含 d/m/y 三个维度
usersData.value = data
} catch (e) {
console.error('解析用户管理失败', e)
}
} else if (item.configKey === 'mock_service_capability') {
try {
const data = JSON.parse(item.configValue)
serviceCapability.value = {
yearsStr: data.years ? data.years.join(',') : '',
appOnlineStr: data.appOnline ? data.appOnline.join(',') : '',
apiOnlineStr: data.apiOnline ? data.apiOnline.join(',') : ''
}
// 将原来分开的数组合并成表格行
serviceCapabilityList.value = (data.years || []).map((year, index) => ({
year: year,
appOnline: data.appOnline ? data.appOnline[index] || 0 : 0,
apiOnline: data.apiOnline ? data.apiOnline[index] || 0 : 0
}))
} catch (e) {
console.error('解析服务能力失败', e)
}
......@@ -701,7 +1024,7 @@ const saveApiCalls = async () => {
if (res && res.list) {
const config = res.list.find(item => item.configKey === 'mock_api_calls')
if (config) {
const updateData = { ...config, configValue: JSON.stringify(apiCallsList.value) }
const updateData = { ...config, configValue: JSON.stringify(apiCallsData.value) }
await HomeDashboardMockApi.updateHomeDashboardMock(updateData)
message.success('保存成功')
}
......@@ -712,17 +1035,20 @@ const saveApiCalls = async () => {
}
}
// 添加API请求数据项
const addApiCallItem = () => {
apiCallsList.value.push({
// API请求趋势 - 添加数据项
const addApiCallItem = (type: 'd' | 'm' | 'y') => {
if (!apiCallsData.value[type]) {
apiCallsData.value[type] = []
}
apiCallsData.value[type].push({
countDate: '',
callsCount: 0
})
}
// 删除API请求数据项
const removeApiCallItem = (index: number) => {
apiCallsList.value.splice(index, 1)
// API请求趋势 - 删除数据项
const removeApiCallItem = (type: 'd' | 'm' | 'y', index: number) => {
apiCallsData.value[type].splice(index, 1)
}
// 保存算力资源分布
......@@ -766,7 +1092,7 @@ const saveUsers = async () => {
if (res && res.list) {
const config = res.list.find(item => item.configKey === 'mock_users')
if (config) {
const updateData = { ...config, configValue: JSON.stringify(usersList.value) }
const updateData = { ...config, configValue: JSON.stringify(usersData.value) }
await HomeDashboardMockApi.updateHomeDashboardMock(updateData)
message.success('保存成功')
}
......@@ -777,9 +1103,12 @@ const saveUsers = async () => {
}
}
// 添加用户数据项
const addUserItem = () => {
usersList.value.push({
// 用户管理 - 添加数据项
const addUserItem = (type: 'd' | 'm' | 'y') => {
if (!usersData.value[type]) {
usersData.value[type] = []
}
usersData.value[type].push({
countDate: '',
usersCount: 0,
growthUsersCount: 0,
......@@ -787,9 +1116,9 @@ const addUserItem = () => {
})
}
// 删除用户数据项
const removeUserItem = (index: number) => {
usersList.value.splice(index, 1)
// 用户管理 - 删除数据项
const removeUserItem = (type: 'd' | 'm' | 'y', index: number) => {
usersData.value[type].splice(index, 1)
}
// 保存服务能力
......@@ -798,10 +1127,11 @@ const saveServiceCapability = async () => {
const res = await HomeDashboardMockApi.getHomeDashboardMockPage({ pageNo: 1, pageSize: 100 })
if (res && res.list) {
const config = res.list.find(item => item.configKey === 'mock_service_capability')
// 将表格数据转换成原来的格式(分开的数组)
const data = {
years: serviceCapability.value.yearsStr.split(',').map(s => s.trim()),
appOnline: serviceCapability.value.appOnlineStr.split(',').map(s => parseFloat(s.trim()) || 0),
apiOnline: serviceCapability.value.apiOnlineStr.split(',').map(s => parseFloat(s.trim()) || 0)
years: serviceCapabilityList.value.map(item => item.year),
appOnline: serviceCapabilityList.value.map(item => item.appOnline),
apiOnline: serviceCapabilityList.value.map(item => item.apiOnline)
}
if (config) {
const updateData = { ...config, configValue: JSON.stringify(data) }
......@@ -823,6 +1153,20 @@ const saveServiceCapability = async () => {
}
}
// 服务能力 - 添加数据项
const addServiceCapabilityItem = () => {
serviceCapabilityList.value.push({
year: '',
appOnline: 0,
apiOnline: 0
})
}
// 服务能力 - 删除数据项
const removeServiceCapabilityItem = (index: number) => {
serviceCapabilityList.value.splice(index, 1)
}
// 订单管理 - 保存
const saveOrders = async () => {
try {
......
......@@ -130,15 +130,30 @@
<!-- 5. 服务器信息 -->
<div style="display: flex; margin-bottom: 24px;">
<el-form-item label="选择地区" prop="areaId" style="margin-bottom: 0;">
<el-cascader
v-if="areaList.length > 0"
v-model="formData.areaId"
:options="areaList"
:props="{
value: 'id',
label: 'name',
children: 'children',
expandTrigger: 'click'
}"
placeholder="请选择省市区"
clearable
filterable
style="width: 300px;"
:disabled="isDetailMode"
@change="handleAreaChange"
/>
<el-text v-else type="info">加载中...</el-text>
</el-form-item>
</div>
<div style="display: flex; margin-bottom: 24px;">
<el-form-item label="服务器所在地" prop="location" style="margin-right: 20px; margin-bottom: 0;">
<el-select v-model="formData.location" placeholder="请选择服务器所在地" clearable style="width: 180px;" :disabled="isDetailMode">
<el-option
v-for="option in resourceConfigStore.getOptionsByType('location')"
:key="option.id"
:label="option.configOption"
:value="option.configOption"
/>
</el-select>
<el-input v-model="formData.location" placeholder="选择地区后自动显示" style="width: 180px;" disabled />
</el-form-item>
<el-form-item label="服务器IP" prop="ip" style="margin-bottom: 0;">
<el-input v-model="formData.ip" placeholder="请输入服务器IP" style="width: 180px;" :disabled="isDetailMode" />
......@@ -217,6 +232,7 @@ import { UploadImg } from '@/components/UploadFile'
import { useTagsViewStore } from '@/store/modules/tagsView'
import { useResourceConfigStore } from '@/store/modules/compute/hardwareConfig'
import { ResourceSpu, ResourceSpuApi } from '@/api/compute/resourcespu'
import * as AreaApi from '@/api/system/area'
defineOptions({ name: 'ResourceSpuAdd' })
......@@ -239,6 +255,7 @@ const resourceConfigStore = useResourceConfigStore() // 资源配置store
const formLoading = ref(false) // 表单的加载中
const formRef = ref() // 表单 Ref
const categoryList = ref<any[]>([])
const areaList = ref<any[]>([]) // 地区树数据
// 从store获取硬件配置选项
const cpuOptions = computed(() => resourceConfigStore.getOptionsByType('cpu'))
......@@ -271,6 +288,7 @@ const formData = ref<ResourceSpu>({
memoryCapacity: undefined,
sales: undefined,
location: undefined,
areaId: undefined,
status: undefined
})
......@@ -292,10 +310,41 @@ const formRules = reactive({
categoryId: [{ required: true, message: '算力资源分类编号不能为空', trigger: 'blur' }],
picUrl: [{ required: true, message: '商品封面图不能为空', trigger: 'blur' }],
sales: [{ required: true, message: '商品销量不能为空', trigger: 'blur' }],
location: [{ required: true, message: '服务器所在地不能为空', trigger: 'blur' }],
areaId: [{ required: true, message: '服务器所在地不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
})
/** 地区选择变化时,自动设置 location 为市级名称(第二级) */
const handleAreaChange = (value: number[]) => {
if (!value || value.length === 0) {
formData.value.location = undefined
formData.value.areaId = undefined
return
}
// el-cascader 返回的是数组 [省级id, 市级id, 区县级id]
// 取区县级id(最后一个元素)作为 areaId 的值
const districtId = value[value.length - 1]
formData.value.areaId = districtId
// 获取市级id(第二个元素)
const cityId = value[1]
// 查找市级名称
const findCityName = (list: any[], cityId: number): string | null => {
for (const item of list) {
if (item.children) {
for (const city of item.children) {
if (city.id === cityId) {
return city.name
}
}
}
}
return null
}
formData.value.location = findCityName(areaList.value, cityId) || undefined
}
/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
......@@ -330,12 +379,14 @@ const close = () => {
/** 初始化 */
onMounted(async () => {
try {
// 并行加载分类列表和硬件配置选项
const [categoryResponse] = await Promise.all([
// 并行加载分类列表、硬件配置选项和地区树
const [categoryResponse, _, areaResponse] = await Promise.all([
ResourceSpuApi.listSimpleCategory(),
resourceConfigStore.loadConfigOptions()
resourceConfigStore.loadConfigOptions(),
AreaApi.getAreaTree()
])
categoryList.value = categoryResponse
areaList.value = areaResponse
// 编辑模式或详情模式需要获取数据
if (isEditMode.value || isDetailMode.value) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment