Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
1fe9a380
authored
Mar 05, 2026
by
Jony.L
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
大屏数据:大地图 真实数据 管理端调整
parent
4ffe89c8
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
509 additions
and
110 deletions
+509
-110
src/api/compute/resourcespu/index.ts
+1
-0
src/views/Home/Home.vue
+12
-9
src/views/biz/home/index.vue
+433
-89
src/views/compute/resourcespu/form/index.vue
+63
-12
No files found.
src/api/compute/resourcespu/index.ts
View file @
1fe9a380
...
...
@@ -16,6 +16,7 @@ export interface ResourceSpu {
nic
?:
string
;
// 网卡配置
ip
?:
string
;
// 服务器ip
location
?:
string
;
// 位置
areaId
?:
number
;
// 地区ID
initUsername
?:
string
;
// 初始用户名
initPassword
?:
string
;
// 初始密码
intro
?:
string
;
// 商品简介
...
...
src/views/Home/Home.vue
View file @
1fe9a380
...
...
@@ -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
)
...
...
src/views/biz/home/index.vue
View file @
1fe9a380
...
...
@@ -21,9 +21,6 @@
</div>
</el-card>
<!-- 第一行:平台总体态势 + API请求趋势 -->
<el-row
:gutter=
"20"
>
<el-col
:span=
"12"
>
<!-- 平台总体态势 -->
<el-card
class=
"config-card"
shadow=
"never"
>
<
template
#
header
>
...
...
@@ -33,35 +30,34 @@
<el-button
type=
"primary"
size=
"small"
@
click=
"saveOverallSituation"
>
保存
</el-button>
</div>
</
template
>
<el-form
:model=
"overallSituation"
label-width=
"1
4
0px"
class=
"config-form"
>
<el-row
:gutter=
"
2
0"
>
<el-form
:model=
"overallSituation"
label-width=
"1
3
0px"
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,11 +68,14 @@
<el-button
type=
"primary"
size=
"small"
@
click=
"saveApiCalls"
>
保存
</el-button>
</div>
</
template
>
<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
"
style=
"margin-bottom: 10px;"
>
<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=
"apiCallsList
.length > 0"
>
<table
class=
"data-table"
v-if=
"apiCallsData.d && apiCallsData.d
.length > 0"
>
<thead>
<tr>
<th>
日期
</th>
...
...
@@ -85,7 +84,7 @@
</tr>
</thead>
<tbody>
<tr
v-for=
"(item, index) in apiCallsList
"
:key=
"index"
>
<tr
v-for=
"(item, index) in apiCallsData.d
"
:key=
"index"
>
<td>
<el-date-picker
v-model=
"item.countDate"
...
...
@@ -97,10 +96,201 @@
/>
</td>
<td>
<el-input-number
v-model=
"item.callsCount"
:min=
"0"
size=
"small"
/>
<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=
"removeApiCallItem(
index)"
>
<el-button
type=
"danger"
size=
"small"
@
click=
"removeComputeItem('resource',
index)"
>
删除
</el-button>
</td>
...
...
@@ -109,13 +299,16 @@
</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,11 +434,14 @@
<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
"
style=
"margin-bottom: 10px;"
>
<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=
"usersList
.length > 0"
>
<table
class=
"data-table"
v-if=
"usersData.d && usersData.d
.length > 0"
>
<thead>
<tr>
<th>
日期
</th>
...
...
@@ -256,7 +452,7 @@
</tr>
</thead>
<tbody>
<tr
v-for=
"(item, index) in usersList
"
:key=
"index"
>
<tr
v-for=
"(item, index) in usersData.d
"
:key=
"index"
>
<td>
<el-date-picker
v-model=
"item.countDate"
...
...
@@ -268,16 +464,16 @@
/>
</td>
<td>
<el-input-number
v-model=
"item.usersCount"
:min=
"0
"
size=
"small"
/>
<el-input-number
v-model=
"item.usersCount"
: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.growthUsersCount"
:min=
"0"
:controls=
"false
"
size=
"small"
/>
</td>
<td>
<el-input-number
v-model=
"item.activeUsersCount"
:min=
"0
"
size=
"small"
/>
<el-input-number
v-model=
"item.activeUsersCount"
:min=
"0"
:controls=
"false
"
size=
"small"
/>
</td>
<td>
<el-button
type=
"danger"
size=
"small"
@
click=
"removeUserItem(
index)"
>
<el-button
type=
"danger"
size=
"small"
@
click=
"removeUserItem('d',
index)"
>
删除
</el-button>
</td>
...
...
@@ -286,6 +482,99 @@
</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>
...
...
@@ -302,17 +591,40 @@
<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>
<div
class=
"table-section"
>
<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=
"serviceCapabilityList.length > 0"
>
<thead>
<tr>
<th>
年份
</th>
<th>
上线应用数
</th>
<th>
上线API数
</th>
<th
style=
"width: 80px"
>
操作
</th>
</tr>
</thead>
<tbody>
<tr
v-for=
"(item, index) in serviceCapabilityList"
:key=
"index"
>
<td>
<el-input
v-model=
"item.year"
placeholder=
"如:2018"
size=
"small"
/>
</td>
<td>
<el-input-number
v-model=
"item.appOnline"
:min=
"0"
:controls=
"false"
size=
"small"
/>
</td>
<td>
<el-input-number
v-model=
"item.apiOnline"
:min=
"0"
:controls=
"false"
size=
"small"
/>
</td>
<td>
<el-button
type=
"danger"
size=
"small"
@
click=
"removeServiceCapabilityItem(index)"
>
删除
</el-button>
</td>
</tr>
</tbody>
</table>
<el-empty
v-else
description=
"暂无数据,请添加"
:image-size=
"80"
/>
</div>
</el-card>
</el-col>
...
...
@@ -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
(
apiCalls
List
.
value
)
}
const
updateData
=
{
...
config
,
configValue
:
JSON
.
stringify
(
apiCalls
Data
.
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
)
=>
{
apiCalls
List
.
value
.
splice
(
index
,
1
)
//
API请求趋势 - 删除
数据项
const
removeApiCallItem
=
(
type
:
'd'
|
'm'
|
'y'
,
index
:
number
)
=>
{
apiCalls
Data
.
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
(
users
List
.
value
)
}
const
updateData
=
{
...
config
,
configValue
:
JSON
.
stringify
(
users
Data
.
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
)
=>
{
users
List
.
value
.
splice
(
index
,
1
)
//
用户管理 - 删除
数据项
const
removeUserItem
=
(
type
:
'd'
|
'm'
|
'y'
,
index
:
number
)
=>
{
users
Data
.
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
:
serviceCapability
List
.
value
.
map
(
item
=>
item
.
year
),
appOnline
:
serviceCapability
List
.
value
.
map
(
item
=>
item
.
appOnline
),
apiOnline
:
serviceCapability
List
.
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
{
...
...
src/views/compute/resourcespu/form/index.vue
View file @
1fe9a380
...
...
@@ -130,15 +130,30 @@
<!-- 5. 服务器信息 -->
<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-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-select>
<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-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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment