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
04340bf7
authored
Aug 07, 2026
by
renyizhao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
动态规格
parent
5d3142e4
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
340 additions
and
216 deletions
+340
-216
src/views/compute/resourcespu/ResourceConfigSelectDialog.vue
+233
-0
src/views/compute/resourcespu/form/index.vue
+101
-94
src/views/compute/resourcespu/index.vue
+6
-122
No files found.
src/views/compute/resourcespu/ResourceConfigSelectDialog.vue
0 → 100644
View file @
04340bf7
<
template
>
<Dialog
:title=
"dialogTitle"
v-model=
"dialogVisible"
:width=
"1000"
>
<!-- 搜索区域 -->
<el-form
class=
"-mb-15px"
:model=
"queryParams"
ref=
"queryFormRef"
:inline=
"true"
label-width=
"82px"
>
<el-form-item
label=
"配置类别"
prop=
"configCategory"
>
<el-select
v-model=
"queryParams.configCategory"
placeholder=
"请选择配置类别"
clearable
class=
"!w-200px"
>
<el-option
v-for=
"dict in categoryOptions"
:key=
"dict.value"
:label=
"dict.label"
:value=
"dict.value"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"配置选项"
prop=
"configOption"
>
<el-input
v-model=
"queryParams.configOption"
placeholder=
"请输入配置选项"
clearable
@
keyup
.
enter=
"handleQuery"
class=
"!w-200px"
/>
</el-form-item>
<el-form-item>
<el-button
@
click=
"handleQuery"
><Icon
icon=
"ep:search"
class=
"mr-5px"
/>
搜索
</el-button>
<el-button
@
click=
"resetQuery"
><Icon
icon=
"ep:refresh"
class=
"mr-5px"
/>
重置
</el-button>
</el-form-item>
</el-form>
<!-- 规格配置列表 -->
<el-table
ref=
"tableRef"
v-loading=
"loading"
:data=
"list"
:stripe=
"true"
:show-overflow-tooltip=
"true"
row-key=
"id"
@
selection-change=
"handleSelectionChange"
height=
"400"
>
<el-table-column
type=
"selection"
width=
"55"
:reserve-selection=
"true"
/>
<el-table-column
label=
"配置类别"
align=
"center"
prop=
"configCategory"
min-width=
"160"
>
<template
#
default=
"scope"
>
<dict-tag
:type=
"DICT_TYPE.COMPUTE_RESOURCE_CONFIG_CATEGORY"
:value=
"scope.row.configCategory"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"配置选项"
align=
"center"
prop=
"configOption"
min-width=
"180"
/>
<el-table-column
label=
"详情备注"
align=
"center"
prop=
"detailRemark"
min-width=
"200"
/>
</el-table>
<!-- 分页 -->
<Pagination
:total=
"total"
v-model:page=
"queryParams.pageNo"
v-model:limit=
"queryParams.pageSize"
@
pagination=
"getList"
class=
"mt-4"
/>
<!-- 底部按钮 -->
<
template
#
footer
>
<el-button
@
click=
"dialogVisible = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleConfirm"
>
确定选择 (
{{
selectedCount
}}
)
</el-button>
</
template
>
</Dialog>
</template>
<
script
setup
lang=
"ts"
>
import
{
ref
,
reactive
,
computed
,
watch
,
nextTick
}
from
'vue'
import
{
DICT_TYPE
,
getStrDictOptions
}
from
'@/utils/dict'
import
{
ResourceConfigApi
,
ResourceConfig
}
from
'@/api/compute/resourceconfig'
interface
Props
{
modelValue
:
boolean
title
?:
string
/** 已选中的规格 ID 列表(用于回显勾选状态) */
selectedIds
?:
number
[]
}
interface
Emits
{
(
e
:
'update:modelValue'
,
value
:
boolean
):
void
(
e
:
'confirm'
,
selections
:
ResourceConfig
[]):
void
}
const
props
=
withDefaults
(
defineProps
<
Props
>
(),
{
title
:
'选择规格'
,
selectedIds
:
()
=>
[]
})
const
emit
=
defineEmits
<
Emits
>
()
const
dialogVisible
=
computed
({
get
:
()
=>
props
.
modelValue
,
set
:
(
val
)
=>
emit
(
'update:modelValue'
,
val
)
})
const
dialogTitle
=
computed
(()
=>
props
.
title
)
// 字典选项
const
categoryOptions
=
getStrDictOptions
(
DICT_TYPE
.
COMPUTE_RESOURCE_CONFIG_CATEGORY
)
const
loading
=
ref
(
false
)
const
list
=
ref
<
ResourceConfig
[]
>
([])
const
total
=
ref
(
0
)
const
tableRef
=
ref
()
// 跨分页的全量已选规格(key: id,value: 完整规格对象)
// 用于支持多选 + 翻页 + 取消勾选场景
const
allSelectedMap
=
reactive
(
new
Map
<
number
,
ResourceConfig
>
())
const
selectedCount
=
computed
(()
=>
allSelectedMap
.
size
)
const
queryParams
=
reactive
({
pageNo
:
1
,
pageSize
:
10
,
configCategory
:
undefined
,
configOption
:
undefined
,
status
:
0
// 默认只查询启用的规格
})
const
queryFormRef
=
ref
()
/** 查询列表 */
const
getList
=
async
()
=>
{
loading
.
value
=
true
try
{
const
data
=
await
ResourceConfigApi
.
getResourceConfigPage
(
queryParams
)
list
.
value
=
data
.
list
total
.
value
=
data
.
total
// 数据加载完后回显已选中的项
await
nextTick
()
restoreSelection
()
}
finally
{
loading
.
value
=
false
}
}
/** 回显已选中的规格(跨分页) */
const
restoreSelection
=
()
=>
{
if
(
!
props
.
selectedIds
?.
length
||
!
tableRef
.
value
)
return
const
idSet
=
new
Set
(
props
.
selectedIds
)
for
(
const
row
of
list
.
value
)
{
if
(
idSet
.
has
(
row
.
id
))
{
tableRef
.
value
.
toggleRowSelection
(
row
,
true
)
}
}
}
/** 搜索按钮操作 */
const
handleQuery
=
()
=>
{
queryParams
.
pageNo
=
1
getList
()
}
/** 重置按钮操作 */
const
resetQuery
=
()
=>
{
queryFormRef
.
value
?.
resetFields
()
queryParams
.
status
=
0
handleQuery
()
}
/** 处理表格多选变化
* el-table 的 selection-change 只会带当前页可见的已选行;
* 这里用 allSelectedMap 维护所有分页的全量已选规格。
* 策略:把当前页 id 全部从 map 中移除,再把 rows(当前页最新已选)写入 map,
* 这样能正确处理「取消勾选」和「翻页」两种场景。
*/
const
handleSelectionChange
=
(
rows
:
ResourceConfig
[])
=>
{
const
currentPageIds
=
list
.
value
.
map
((
r
)
=>
r
.
id
)
const
visibleSelectedIds
=
new
Set
(
rows
.
map
((
r
)
=>
r
.
id
))
for
(
const
id
of
currentPageIds
)
{
if
(
!
visibleSelectedIds
.
has
(
id
))
{
allSelectedMap
.
delete
(
id
)
}
}
for
(
const
row
of
rows
)
{
allSelectedMap
.
set
(
row
.
id
,
row
)
}
}
/** 确认选择 - 提交全量已选(跨分页) */
const
handleConfirm
=
()
=>
{
emit
(
'confirm'
,
Array
.
from
(
allSelectedMap
.
values
()))
dialogVisible
.
value
=
false
}
/** 打开弹窗时加载数据
* 弹窗只展示启用规格,但 props.selectedIds 里可能既有启用的也有禁用的;
* 跨分页的已选规格在第一页打开时不会触发 selection-change,所以这里要主动
* 预加载所有已选的启用规格到 allSelectedMap,让底部计数从一开始就是全量。
*/
const
handleOpen
=
async
()
=>
{
allSelectedMap
.
clear
()
if
(
props
.
selectedIds
?.
length
)
{
const
results
=
await
Promise
.
all
(
props
.
selectedIds
.
map
((
id
)
=>
ResourceConfigApi
.
getResourceConfig
(
id
).
catch
(()
=>
null
))
)
for
(
const
cfg
of
results
)
{
// 只统计启用规格(弹窗只展示启用规格,禁用的不在计数范围内)
if
(
cfg
&&
cfg
.
status
!==
1
)
{
allSelectedMap
.
set
(
cfg
.
id
,
cfg
)
}
}
}
getList
()
}
// 监听弹窗打开
watch
(
()
=>
props
.
modelValue
,
(
val
)
=>
{
if
(
val
)
{
handleOpen
()
}
else
{
// 关闭时清空全量选择
allSelectedMap
.
clear
()
}
},
{
immediate
:
true
}
)
</
script
>
src/views/compute/resourcespu/form/index.vue
View file @
04340bf7
...
@@ -59,26 +59,35 @@
...
@@ -59,26 +59,35 @@
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<!-- 4. 规格配置 -
按 configCategory 分组
多选 -->
<!-- 4. 规格配置 -
弹窗
多选 -->
<el-form-item
label=
"规格配置"
prop=
"specConfigIds"
>
<el-form-item
label=
"规格配置"
prop=
"specConfigIds"
>
<div
class=
"spec-config-wrapper"
>
<div
class=
"spec-config-wrapper"
>
<div
v-for=
"category in specCategories"
:key=
"category.value"
class=
"spec-category-row"
>
<div
v-if=
"selectedConfigs.length"
class=
"spec-tag-list"
>
<span
class=
"spec-category-label"
>
{{
category
.
label
}}
:
</span>
<el-tag
<el-checkbox-group
v-for=
"item in selectedConfigs"
v-model=
"formData.specConfigIdsByCategory[category.value]"
:key=
"item.id"
:disabled=
"isDetailMode"
:type=
"isDisabledConfig(item) ? 'danger' : 'primary'"
:effect=
"isDisabledConfig(item) ? 'dark' : 'light'"
closable
:disable-transitions=
"true"
class=
"!mr-2 !mb-2"
@
close=
"removeSpecConfig(item.id)"
>
>
<el-checkbox
v-for=
"opt in category.options"
:key=
"opt.id"
:value=
"opt.id"
>
{{
getCategoryLabel
(
item
.
configCategory
)
}}
:
{{
item
.
configOption
}}
{{
opt
.
configOption
}}
<el-text
v-if=
"isDisabledConfig(item)"
type=
"danger"
size=
"small"
class=
"!ml-1"
>
<el-tooltip
v-if=
"opt.detailRemark"
:content=
"opt.detailRemark"
placement=
"top"
>
(已禁用)
<Icon
icon=
"ep:info-filled"
class=
"ml-1"
/>
</el-text>
</el-tooltip>
</el-tag>
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<div
v-if=
"!specCategories.length"
class=
"spec-empty"
<el-text
v-else
type=
"info"
>
暂未选择规格
</el-text>
>
暂无规格类别,请在「系统管理 → 字典管理」配置
</div
<el-button
type=
"primary"
plain
:disabled=
"isDetailMode"
@
click=
"configDialogVisible = true"
>
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
选择规格
</el-button>
</div>
</div>
</el-form-item>
</el-form-item>
...
@@ -181,6 +190,13 @@
...
@@ -181,6 +190,13 @@
</el-form-item>
</el-form-item>
</el-form>
</el-form>
</ContentWrap>
</ContentWrap>
<!-- 规格选择弹窗 -->
<ResourceConfigSelectDialog
v-model=
"configDialogVisible"
:selected-ids=
"formData.specConfigIds || []"
@
confirm=
"handleConfigConfirm"
/>
</
template
>
</
template
>
<
script
lang=
"ts"
setup
>
<
script
lang=
"ts"
setup
>
...
@@ -188,8 +204,9 @@ import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
...
@@ -188,8 +204,9 @@ import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import
{
UploadImg
}
from
'@/components/UploadFile'
import
{
UploadImg
}
from
'@/components/UploadFile'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
{
useTagsViewStore
}
from
'@/store/modules/tagsView'
import
{
ResourceSpu
,
ResourceSpuApi
}
from
'@/api/compute/resourcespu'
import
{
ResourceSpu
,
ResourceSpuApi
}
from
'@/api/compute/resourcespu'
import
{
ResourceConfigApi
}
from
'@/api/compute/resourceconfig'
import
{
ResourceConfigApi
,
ResourceConfig
}
from
'@/api/compute/resourceconfig'
import
*
as
AreaApi
from
'@/api/system/area'
import
*
as
AreaApi
from
'@/api/system/area'
import
ResourceConfigSelectDialog
from
'../ResourceConfigSelectDialog.vue'
defineOptions
({
name
:
'ResourceSpuAdd'
})
defineOptions
({
name
:
'ResourceSpuAdd'
})
...
@@ -213,18 +230,22 @@ const formRef = ref() // 表单 Ref
...
@@ -213,18 +230,22 @@ const formRef = ref() // 表单 Ref
const
categoryList
=
ref
<
any
[]
>
([])
const
categoryList
=
ref
<
any
[]
>
([])
const
areaList
=
ref
<
any
[]
>
([])
// 地区树数据
const
areaList
=
ref
<
any
[]
>
([])
// 地区树数据
// 规格分组(按 configCategory 分组多选)
// 已选规格(仅前端用于回显 tag,需提交时只取 id 列表)
interface
SpecOption
{
const
selectedConfigs
=
ref
<
ResourceConfig
[]
>
([])
id
:
number
const
configDialogVisible
=
ref
(
false
)
// 规格选择弹窗可见性
configOption
:
string
// 类别字典:用于把 configCategory 转为中文 label
detailRemark
?:
string
const
categoryDictMap
=
computed
(()
=>
{
}
const
map
:
Record
<
string
,
string
>
=
{}
interface
SpecCategory
{
for
(
const
d
of
getStrDictOptions
(
DICT_TYPE
.
COMPUTE_RESOURCE_CONFIG_CATEGORY
))
{
value
:
string
// 字典 value(对应 configCategory)
map
[
d
.
value
as
string
]
=
d
.
label
label
:
string
// 字典 label
}
options
:
SpecOption
[]
return
map
}
})
const
specCategories
=
ref
<
SpecCategory
[]
>
([])
const
getCategoryLabel
=
(
category
?:
string
)
=>
(
category
&&
categoryDictMap
.
value
[
category
])
||
category
||
''
/** 判断已选规格是否已禁用 */
const
isDisabledConfig
=
(
item
:
ResourceConfig
)
=>
item
.
status
===
1
const
formData
=
ref
<
ResourceSpu
>
({
const
formData
=
ref
<
ResourceSpu
>
({
id
:
undefined
,
id
:
undefined
,
...
@@ -236,8 +257,9 @@ const formData = ref<ResourceSpu>({
...
@@ -236,8 +257,9 @@ const formData = ref<ResourceSpu>({
sliderPicUrls
:
undefined
,
sliderPicUrls
:
undefined
,
sales
:
undefined
,
sales
:
undefined
,
status
:
undefined
,
status
:
undefined
,
// 规格相关
// 规格相关
(提交时使用)
specConfigIds
:
[],
specConfigIds
:
[],
// 前端辅助字段(不再使用分组多选,但保留以兼容类型)
specConfigIdsByCategory
:
{}
specConfigIdsByCategory
:
{}
})
})
...
@@ -249,53 +271,42 @@ const formRules = reactive({
...
@@ -249,53 +271,42 @@ const formRules = reactive({
status
:
[{
required
:
true
,
message
:
'状态不能为空'
,
trigger
:
'blur'
}]
status
:
[{
required
:
true
,
message
:
'状态不能为空'
,
trigger
:
'blur'
}]
})
})
/**
/** 删除单个已选规格 */
* 加载规格分组选项:
const
removeSpecConfig
=
(
id
:
number
)
=>
{
* 1. 从字典 compute_resource_config_category 读取所有类别
selectedConfigs
.
value
=
selectedConfigs
.
value
.
filter
((
c
)
=>
c
.
id
!==
id
)
* 2. 对每个类别调 listSimpleConfigByCategory 拿该类别的所有规格项
formData
.
value
.
specConfigIds
=
selectedConfigs
.
value
.
map
((
c
)
=>
c
.
id
)
*/
const
loadSpecOptions
=
async
()
=>
{
const
categoryDicts
=
getStrDictOptions
(
DICT_TYPE
.
COMPUTE_RESOURCE_CONFIG_CATEGORY
)
if
(
!
categoryDicts
.
length
)
{
specCategories
.
value
=
[]
return
}
const
results
=
await
Promise
.
all
(
categoryDicts
.
map
(
async
(
cat
)
=>
{
const
options
=
await
ResourceConfigApi
.
listSimpleConfigByCategory
(
cat
.
value
as
string
)
return
{
value
:
cat
.
value
as
string
,
label
:
cat
.
label
,
options
:
(
options
||
[])
as
SpecOption
[]
}
})
)
specCategories
.
value
=
results
// 预填 specConfigIdsByCategory 键,确保 el-checkbox-group v-model 能正常绑定
for
(
const
cat
of
specCategories
.
value
)
{
if
(
!
formData
.
value
.
specConfigIdsByCategory
[
cat
.
value
])
{
formData
.
value
.
specConfigIdsByCategory
[
cat
.
value
]
=
[]
}
}
}
}
/**
/** 规格选择弹窗 - 确认回调
* 把后端返回的扁平 specConfigIds 按 configCategory 分布到各分组
* dialog 只展示启用规格,selections 是「全量已选的启用规格」;
* 表单里已有的禁用规格(status===1)需要保留,避免从弹窗走一圈就丢了。
*/
*/
const
distributeSpecConfigIds
=
()
=>
{
const
handleConfigConfirm
=
(
selections
:
ResourceConfig
[])
=>
{
const
flat
=
new
Set
(
formData
.
value
.
specConfigIds
||
[])
const
map
=
new
Map
<
number
,
ResourceConfig
>
()
// 先清空所有分组
// 先放禁用规格(保留)
for
(
const
cat
of
specCategories
.
value
)
{
for
(
const
c
of
selectedConfigs
.
value
)
{
formData
.
value
.
specConfigIdsByCategory
[
cat
.
value
]
=
[]
if
(
isDisabledConfig
(
c
))
{
map
.
set
(
c
.
id
,
c
)
}
}
// 再按 configId 匹配回填
for
(
const
cat
of
specCategories
.
value
)
{
for
(
const
opt
of
cat
.
options
)
{
if
(
flat
.
has
(
opt
.
id
))
{
formData
.
value
.
specConfigIdsByCategory
[
cat
.
value
].
push
(
opt
.
id
)
}
}
// 再用弹窗返回的启用规格覆盖(支持取消勾选、新增)
for
(
const
c
of
selections
)
{
map
.
set
(
c
.
id
,
c
)
}
}
selectedConfigs
.
value
=
Array
.
from
(
map
.
values
())
formData
.
value
.
specConfigIds
=
selectedConfigs
.
value
.
map
((
c
)
=>
c
.
id
)
}
/** 根据 id 列表加载完整规格对象(用于编辑模式回显) */
const
loadSelectedConfigs
=
async
(
ids
:
number
[])
=>
{
if
(
!
ids
?.
length
)
{
selectedConfigs
.
value
=
[]
return
}
}
const
results
=
await
Promise
.
all
(
ids
.
map
((
id
)
=>
ResourceConfigApi
.
getResourceConfig
(
id
).
catch
(()
=>
null
))
)
selectedConfigs
.
value
=
results
.
filter
(
Boolean
)
as
ResourceConfig
[]
}
}
/** 地区选择变化时,自动设置 location 为市级名称(第二级) */
/** 地区选择变化时,自动设置 location 为市级名称(第二级) */
...
@@ -334,14 +345,19 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成
...
@@ -334,14 +345,19 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成
const
submitForm
=
async
()
=>
{
const
submitForm
=
async
()
=>
{
await
formRef
.
value
.
validate
()
await
formRef
.
value
.
validate
()
// 校验:至少选 1 个规格
// 校验:至少选 1 个规格
const
allSpecIds
=
(
Object
.
values
(
formData
.
value
.
specConfigIdsByCategory
||
{}).
flat
()
||
if
(
!
formData
.
value
.
specConfigIds
?.
length
)
{
[])
as
number
[]
if
(
!
allSpecIds
.
length
)
{
message
.
error
(
'请至少选择 1 个规格'
)
message
.
error
(
'请至少选择 1 个规格'
)
return
return
}
}
// 扁平化写入 formData.specConfigIds
// 校验:所选规格不能包含已禁用的项
formData
.
value
.
specConfigIds
=
allSpecIds
const
disabledItems
=
selectedConfigs
.
value
.
filter
(
isDisabledConfig
)
if
(
disabledItems
.
length
)
{
const
names
=
disabledItems
.
map
((
c
)
=>
`
${
getCategoryLabel
(
c
.
configCategory
)}
:
${
c
.
configOption
}
`
)
.
join
(
'、'
)
message
.
error
(
`已选规格包含已禁用的项:
${
names
}
,请移除后重新选择`
)
return
}
formLoading
.
value
=
true
formLoading
.
value
=
true
try
{
try
{
const
data
=
{
...
formData
.
value
}
as
unknown
as
ResourceSpu
const
data
=
{
...
formData
.
value
}
as
unknown
as
ResourceSpu
...
@@ -373,11 +389,10 @@ const close = () => {
...
@@ -373,11 +389,10 @@ const close = () => {
/** 初始化 */
/** 初始化 */
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
try
{
try
{
// 并行加载分类列表、地区树
和规格分组
// 并行加载分类列表、地区树
const
[
categoryResponse
,
areaResponse
]
=
await
Promise
.
all
([
const
[
categoryResponse
,
areaResponse
]
=
await
Promise
.
all
([
ResourceSpuApi
.
listSimpleCategory
(),
ResourceSpuApi
.
listSimpleCategory
(),
AreaApi
.
getAreaTree
(),
AreaApi
.
getAreaTree
()
loadSpecOptions
()
])
])
categoryList
.
value
=
categoryResponse
categoryList
.
value
=
categoryResponse
areaList
.
value
=
areaResponse
areaList
.
value
=
areaResponse
...
@@ -391,8 +406,8 @@ onMounted(async () => {
...
@@ -391,8 +406,8 @@ onMounted(async () => {
if
(
!
formData
.
value
.
specConfigIdsByCategory
)
{
if
(
!
formData
.
value
.
specConfigIdsByCategory
)
{
formData
.
value
.
specConfigIdsByCategory
=
{}
formData
.
value
.
specConfigIdsByCategory
=
{}
}
}
//
把 specConfigIds 分布到各分组
//
加载已选规格的完整对象(用于回显 tag)
distributeSpecConfigIds
(
)
await
loadSelectedConfigs
(
formData
.
value
.
specConfigIds
||
[]
)
}
finally
{
}
finally
{
formLoading
.
value
=
false
formLoading
.
value
=
false
}
}
...
@@ -405,24 +420,16 @@ onMounted(async () => {
...
@@ -405,24 +420,16 @@ onMounted(async () => {
<
style
scoped
>
<
style
scoped
>
.spec-config-wrapper
{
.spec-config-wrapper
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-start
;
width
:
100%
;
width
:
100%
;
}
}
.spec-
category-row
{
.spec-
tag-list
{
display
:
flex
;
display
:
flex
;
align-items
:
flex-start
;
flex-wrap
:
wrap
;
align-items
:
center
;
width
:
100%
;
margin-bottom
:
12px
;
margin-bottom
:
12px
;
}
}
.spec-category-label
{
width
:
80px
;
text-align
:
right
;
padding-right
:
12px
;
color
:
#606266
;
line-height
:
32px
;
flex-shrink
:
0
;
}
.spec-empty
{
color
:
#909399
;
font-size
:
13px
;
padding
:
8px
0
;
}
</
style
>
</
style
>
src/views/compute/resourcespu/index.vue
View file @
04340bf7
...
@@ -17,83 +17,6 @@
...
@@ -17,83 +17,6 @@
class=
"!w-240px"
class=
"!w-240px"
/>
/>
</el-form-item>
</el-form-item>
<el-form-item
label=
"CPU"
prop=
"cpu"
>
<el-select
v-model=
"queryParams.cpu"
placeholder=
"请选择CPU配置"
clearable
class=
"!w-240px"
>
<el-option
v-for=
"option in resourceConfigStore.getOptionsByType('cpu')"
:key=
"option.id"
:label=
"option.configOption"
:value=
"option.configOption"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"GPU"
prop=
"gpu"
>
<el-select
v-model=
"queryParams.gpu"
placeholder=
"请选择GPU配置"
clearable
class=
"!w-240px"
>
<el-option
v-for=
"option in resourceConfigStore.getOptionsByType('gpu')"
:key=
"option.id"
:label=
"option.configOption"
:value=
"option.configOption"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"内存"
prop=
"ram"
>
<el-select
v-model=
"queryParams.ram"
placeholder=
"请选择内存配置"
clearable
class=
"!w-240px"
>
<el-option
v-for=
"option in resourceConfigStore.getOptionsByType('ram')"
:key=
"option.id"
:label=
"option.configOption"
:value=
"option.configOption"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"存储"
prop=
"storage"
>
<el-select
v-model=
"queryParams.storage"
placeholder=
"请选择存储配置"
clearable
class=
"!w-240px"
>
<el-option
v-for=
"option in resourceConfigStore.getOptionsByType('storage')"
:key=
"option.id"
:label=
"option.configOption"
:value=
"option.configOption"
/>
</el-select>
</el-form-item>
<!--
<el-form-item
label=
"服务器ip"
prop=
"ip"
>
-->
<!--
<el-input-->
<!-- v-model="queryParams.ip"-->
<!-- placeholder="请输入服务器ip"-->
<!-- clearable-->
<!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"-->
<!-- />-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"初始用户名"
prop=
"initUsername"
>
-->
<!--
<el-input-->
<!-- v-model="queryParams.initUsername"-->
<!-- placeholder="请输入初始用户名"-->
<!-- clearable-->
<!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"-->
<!-- />-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"初始密码"
prop=
"initPassword"
>
-->
<!--
<el-input-->
<!-- v-model="queryParams.initPassword"-->
<!-- placeholder="请输入初始密码"-->
<!-- clearable-->
<!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"-->
<!-- />-->
<!--
</el-form-item>
-->
<el-form-item
label=
"商品简介"
prop=
"intro"
>
<el-form-item
label=
"商品简介"
prop=
"intro"
>
<el-input
<el-input
v-model=
"queryParams.intro"
v-model=
"queryParams.intro"
...
@@ -133,21 +56,6 @@
...
@@ -133,21 +56,6 @@
/>
/>
</el-select>
</el-select>
</el-form-item>
</el-form-item>
<el-form-item
label=
"服务器所在地"
prop=
"location"
>
<el-select
v-model=
"queryParams.location"
placeholder=
"请选择服务器所在地"
clearable
class=
"!w-240px"
>
<el-option
v-for=
"option in resourceConfigStore.getOptionsByType('location')"
:key=
"option.id"
:label=
"option.configOption"
:value=
"option.configOption"
/>
</el-select>
</el-form-item>
<!--
<el-form-item
label=
"商品封面图"
prop=
"picUrl"
>
-->
<!--
<el-form-item
label=
"商品封面图"
prop=
"picUrl"
>
-->
<!--
<el-input-->
<!--
<el-input-->
<!-- v-model="queryParams.picUrl"-->
<!-- v-model="queryParams.picUrl"-->
...
@@ -216,7 +124,7 @@
...
@@ -216,7 +124,7 @@
>
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
</el-button>
<el-button
<
!--
<
el-button
type=
"success"
type=
"success"
plain
plain
@
click=
"handleExport"
@
click=
"handleExport"
...
@@ -224,7 +132,7 @@
...
@@ -224,7 +132,7 @@
v-hasPermi=
"['compute:resource-spu:export']"
v-hasPermi=
"['compute:resource-spu:export']"
>
>
<Icon
icon=
"ep:download"
class=
"mr-5px"
/>
导出
<Icon
icon=
"ep:download"
class=
"mr-5px"
/>
导出
</el-button>
</el-button>
-->
<el-button
<el-button
type=
"danger"
type=
"danger"
plain
plain
...
@@ -268,16 +176,11 @@
...
@@ -268,16 +176,11 @@
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<!-- 硬件配置字段已隐藏 -->
<!-- 硬件配置字段已隐藏 -->
<!-- <el-table-column label="算力资源分类编号" align="center" prop="categoryId" />-->
<!-- <el-table-column label="算力资源分类编号" align="center" prop="categoryId" />-->
<el-table-column
label=
"算力资源分类"
align=
"center"
prop=
"categoryName"
min-width=
"150"
/>
<el-table-column
label=
"算力资源分类"
align=
"center"
prop=
"categoryName"
min-width=
"150"
/>
<el-table-column
label=
"规格"
min-width=
"240"
>
<el-table-column
label=
"规格"
min-width=
"240"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<el-tag
<el-tag
v-for=
"(value, key) in row.specMap"
:key=
"key"
size=
"small"
class=
"!mr-1"
>
v-for=
"(value, key) in row.specMap"
:key=
"key"
size=
"small"
class=
"!mr-1"
>
{{
key
}}
:
{{
value
}}
{{
key
}}
:
{{
value
}}
</el-tag>
</el-tag>
</
template
>
</
template
>
...
@@ -351,10 +254,8 @@ import download from '@/utils/download'
...
@@ -351,10 +254,8 @@ import download from '@/utils/download'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
createImageViewer
}
from
'@/components/ImageViewer'
import
{
ResourceSpuApi
,
ResourceSpu
}
from
'@/api/compute/resourcespu'
import
{
ResourceSpuApi
,
ResourceSpu
}
from
'@/api/compute/resourcespu'
import
{
DICT_TYPE
,
getIntDictOptions
,
getStrDictOptions
}
from
'@/utils/dict'
import
{
DICT_TYPE
,
getIntDictOptions
,
getStrDictOptions
}
from
'@/utils/dict'
import
{
useResourceConfigStore
}
from
'@/store/modules/compute/hardwareConfig'
const
{
push
}
=
useRouter
()
const
{
push
}
=
useRouter
()
const
resourceConfigStore
=
useResourceConfigStore
()
/** 算力资源SPU表(基础配置信息) 列表 */
/** 算力资源SPU表(基础配置信息) 列表 */
defineOptions
({
name
:
'ResourceSpu'
})
defineOptions
({
name
:
'ResourceSpu'
})
...
@@ -370,20 +271,9 @@ const queryParams = reactive({
...
@@ -370,20 +271,9 @@ const queryParams = reactive({
pageNo
:
1
,
pageNo
:
1
,
pageSize
:
10
,
pageSize
:
10
,
name
:
undefined
,
name
:
undefined
,
cpu
:
undefined
,
gpu
:
undefined
,
ram
:
undefined
,
storage
:
undefined
,
ip
:
undefined
,
initUsername
:
undefined
,
initPassword
:
undefined
,
intro
:
undefined
,
intro
:
undefined
,
categoryId
:
undefined
,
categoryId
:
undefined
,
source
:
undefined
,
source
:
undefined
,
location
:
undefined
,
picUrl
:
undefined
,
sliderPicUrls
:
undefined
,
sales
:
undefined
,
status
:
undefined
,
status
:
undefined
,
createTime
:
[]
createTime
:
[]
})
})
...
@@ -485,15 +375,9 @@ const handleExport = async () => {
...
@@ -485,15 +375,9 @@ const handleExport = async () => {
/** 初始化 **/
/** 初始化 **/
onMounted
(
async
()
=>
{
onMounted
(
async
()
=>
{
try
{
try
{
// 并行加载数据
// 加载分类列表 + 列表数据
const
[
categoryResponse
]
=
await
Promise
.
all
([
const
[
categoryResponse
]
=
await
Promise
.
all
([
ResourceSpuApi
.
listSimpleCategory
(),
getList
()])
ResourceSpuApi
.
listSimpleCategory
(),
resourceConfigStore
.
loadConfigOptions
()
])
categoryList
.
value
=
categoryResponse
categoryList
.
value
=
categoryResponse
// 加载列表数据
getList
()
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'初始化失败:'
,
error
)
console
.
error
(
'初始化失败:'
,
error
)
}
}
...
...
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