Commit 5d3142e4 by renyizhao

动态规格(未完成)

parent ccbdbc30
...@@ -26,6 +26,9 @@ export interface ResourceSpu { ...@@ -26,6 +26,9 @@ export interface ResourceSpu {
sliderPicUrls?: string; // 商品轮播图地址,以逗号分隔,最多15张 sliderPicUrls?: string; // 商品轮播图地址,以逗号分隔,最多15张
sales?: number; // 商品销量 sales?: number; // 商品销量
status?: number; // 状态(0 下架,1 上架,2 回收) status?: number; // 状态(0 下架,1 上架,2 回收)
specConfigIds?: number[]; // 规格配置项 ID 列表(关联 compute_resource_config.id)
specMap?: Record<string, string>; // 规格展示 Map(key=configCategory, value=configOption)
specConfigIdsByCategory: Record<string, number[]>; // 前端辅助字段:按 configCategory 分组的多选绑定(提交时扁平化为 specConfigIds)
} }
// 算力资源SPU表(基础配置信息) API // 算力资源SPU表(基础配置信息) API
......
<template> <template>
<ContentWrap v-loading="formLoading"> <ContentWrap v-loading="formLoading">
<el-form ref="formRef" :model="formData" :rules="!isDetailMode ? formRules : {}" label-width="120px"> <el-form
ref="formRef"
:model="formData"
:rules="!isDetailMode ? formRules : {}"
label-width="120px"
>
<!-- 1. 算力资源名称 --> <!-- 1. 算力资源名称 -->
<el-form-item label="算力资源名称" prop="name"> <el-form-item label="算力资源名称" prop="name">
<el-input <el-input
...@@ -20,7 +25,13 @@ ...@@ -20,7 +25,13 @@
<!-- 3. 算力资源分类 --> <!-- 3. 算力资源分类 -->
<el-form-item label="算力资源分类" prop="categoryId"> <el-form-item label="算力资源分类" prop="categoryId">
<el-select v-model="formData.categoryId" placeholder="请选择算力资源分类" clearable style="width: 200px;" :disabled="isDetailMode"> <el-select
v-model="formData.categoryId"
placeholder="请选择算力资源分类"
clearable
style="width: 200px"
:disabled="isDetailMode"
>
<el-option <el-option
v-for="category in categoryList" v-for="category in categoryList"
:key="category.id" :key="category.id"
...@@ -32,7 +43,13 @@ ...@@ -32,7 +43,13 @@
<!-- 3.1 算力来源 --> <!-- 3.1 算力来源 -->
<el-form-item label="算力来源" prop="source"> <el-form-item label="算力来源" prop="source">
<el-select v-model="formData.source" placeholder="请选择算力来源" clearable style="width: 200px;" :disabled="isDetailMode"> <el-select
v-model="formData.source"
placeholder="请选择算力来源"
clearable
style="width: 200px"
:disabled="isDetailMode"
>
<el-option <el-option
v-for="dict in getStrDictOptions(DICT_TYPE.COMPUTE_RESOURCE_SOURCE)" v-for="dict in getStrDictOptions(DICT_TYPE.COMPUTE_RESOURCE_SOURCE)"
:key="dict.value" :key="dict.value"
...@@ -42,95 +59,32 @@ ...@@ -42,95 +59,32 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 4. 硬件配置 - inline布局 --> <!-- 4. 规格配置 - 按 configCategory 分组多选 -->
<div style="display: flex; margin-bottom: 16px;"> <el-form-item label="规格配置" prop="specConfigIds">
<el-form-item label="CPU配置" prop="cpu" style="margin-right: 20px; margin-bottom: 0;"> <div class="spec-config-wrapper">
<el-select v-model="formData.cpu" placeholder="请选择CPU配置" clearable style="width: 180px;" :disabled="isDetailMode"> <div v-for="category in specCategories" :key="category.value" class="spec-category-row">
<el-option <span class="spec-category-label">{{ category.label }}</span>
v-for="option in cpuOptions" <el-checkbox-group
:key="option.id" v-model="formData.specConfigIdsByCategory[category.value]"
:label="option.configOption" :disabled="isDetailMode"
:value="option.configOption" >
/> <el-checkbox v-for="opt in category.options" :key="opt.id" :value="opt.id">
</el-select> {{ opt.configOption }}
</el-form-item> <el-tooltip v-if="opt.detailRemark" :content="opt.detailRemark" placement="top">
<el-form-item label="GPU配置" prop="gpu" style="margin-bottom: 0;"> <Icon icon="ep:info-filled" class="ml-1" />
<el-select v-model="formData.gpu" placeholder="请选择GPU配置" clearable style="width: 180px;" :disabled="isDetailMode"> </el-tooltip>
<el-option </el-checkbox>
v-for="option in gpuOptions" </el-checkbox-group>
:key="option.id"
:label="option.configOption"
:value="option.configOption"
/>
</el-select>
</el-form-item>
</div> </div>
<div v-if="!specCategories.length" class="spec-empty"
<div style="display: flex; margin-bottom: 16px;"> >暂无规格类别,请在「系统管理 → 字典管理」配置</div
<el-form-item label="CPU核心数" prop="coreCount" style="margin-bottom: 0;"> >
<el-input v-model="formData.coreCount" placeholder="请输入CPU核心数" style="width: 180px;" :disabled="isDetailMode" />
</el-form-item>
<el-form-item label="算力" prop="compute" style="margin-bottom: 0;">
<el-input v-model="formData.compute" placeholder="请输入算力值(TFLOPS)" style="width: 180px;" :disabled="isDetailMode" />
</el-form-item>
<el-form-item label="GPU卡数量" prop="gpuCount" style="margin-bottom: 0;">
<el-input v-model="formData.gpuCount" placeholder="请输入GPU卡数量" style="width: 180px;" :disabled="isDetailMode" />
</el-form-item>
</div> </div>
<div style="display: flex; margin-bottom: 24px;">
<el-form-item label="内存配置" prop="ram" style="margin-right: 20px; margin-bottom: 0;">
<el-select v-model="formData.ram" placeholder="请选择内存配置" clearable style="width: 180px;" :disabled="isDetailMode">
<el-option
v-for="option in ramOptions"
:key="option.id"
:label="option.configOption"
:value="option.configOption"
/>
</el-select>
</el-form-item>
<el-form-item label="内存容量" prop="memoryCapacity" style="margin-bottom: 0;">
<el-input v-model="formData.memoryCapacity" placeholder="请输入内存容量" style="width: 180px;" :disabled="isDetailMode" />
</el-form-item>
<el-form-item label="存储配置" prop="storage" style="margin-bottom: 0;">
<el-select v-model="formData.storage" placeholder="请选择存储配置" clearable style="width: 180px;" :disabled="isDetailMode">
<el-option
v-for="option in storageOptions"
:key="option.id"
:label="option.configOption"
:value="option.configOption"
/>
</el-select>
</el-form-item> </el-form-item>
</div>
<!-- 新增:电源和网卡配置 --> <!-- 5. 选择地区 / 服务器所在地 -->
<div style="display: flex; margin-bottom: 24px;"> <div style="display: flex; margin-bottom: 24px">
<el-form-item label="电源配置" prop="powerSupply" style="margin-right: 20px; margin-bottom: 0;"> <el-form-item label="选择地区" prop="areaId" style="margin-bottom: 0">
<el-select v-model="formData.powerSupply" placeholder="请选择电源配置" clearable style="width: 180px;" :disabled="isDetailMode">
<el-option
v-for="option in powerSupplyOptions"
:key="option.id"
:label="option.configOption"
:value="option.configOption"
/>
</el-select>
</el-form-item>
<el-form-item label="网卡配置" prop="nic" style="margin-bottom: 0;">
<el-select v-model="formData.nic" placeholder="请选择网卡配置" clearable style="width: 180px;" :disabled="isDetailMode">
<el-option
v-for="option in nicOptions"
:key="option.id"
:label="option.configOption"
:value="option.configOption"
/>
</el-select>
</el-form-item>
</div>
<!-- 5. 服务器信息 -->
<div style="display: flex; margin-bottom: 24px;">
<el-form-item label="选择地区" prop="areaId" style="margin-bottom: 0;">
<el-cascader <el-cascader
v-if="areaList.length > 0" v-if="areaList.length > 0"
v-model="formData.areaId" v-model="formData.areaId"
...@@ -144,52 +98,49 @@ ...@@ -144,52 +98,49 @@
placeholder="请选择省市区" placeholder="请选择省市区"
clearable clearable
filterable filterable
style="width: 300px;" style="width: 300px"
:disabled="isDetailMode" :disabled="isDetailMode"
@change="handleAreaChange" @change="handleAreaChange"
/> />
<el-text v-else type="info">加载中...</el-text> <el-text v-else type="info">加载中...</el-text>
</el-form-item> </el-form-item>
</div> </div>
<div style="display: flex; margin-bottom: 24px;"> <div style="display: flex; margin-bottom: 24px">
<el-form-item label="服务器所在地" prop="location" style="margin-right: 20px; margin-bottom: 0;"> <el-form-item label="服务器所在地" prop="location" style="margin-bottom: 0">
<el-input v-model="formData.location" placeholder="选择地区后自动显示" style="width: 180px;" disabled /> <el-input
</el-form-item> v-model="formData.location"
<el-form-item label="服务器IP" prop="ip" style="margin-bottom: 0;"> placeholder="选择地区后自动显示"
<el-input v-model="formData.ip" placeholder="请输入服务器IP" style="width: 180px;" :disabled="isDetailMode" /> style="width: 180px"
</el-form-item> disabled
</div> />
<div style="display: flex; margin-bottom: 24px;">
<el-form-item label="初始用户名" prop="initUsername" style="margin-right: 20px; margin-bottom: 0;">
<el-input v-model="formData.initUsername" placeholder="请输入初始用户名" style="width: 180px;" autocomplete="off" :disabled="isDetailMode" />
</el-form-item>
<el-form-item label="初始密码" prop="initPassword" style="margin-bottom: 0;">
<el-input v-model="formData.initPassword" placeholder="请输入初始密码" style="width: 180px;" autocomplete="off" :disabled="isDetailMode" />
</el-form-item> </el-form-item>
</div> </div>
<!-- 6. 商品销量 --> <!-- 9. 商品销量 -->
<div style="display: flex; margin-bottom: 24px;"> <div style="display: flex; margin-bottom: 24px">
<el-form-item label="商品销量" prop="sales" style="margin-bottom: 0;"> <el-form-item label="商品销量" prop="sales" style="margin-bottom: 0">
<el-input v-model="formData.sales" placeholder="请输入商品销量" style="width: 150px;" :disabled="isDetailMode" /> <el-input
v-model="formData.sales"
placeholder="请输入商品销量"
style="width: 150px"
:disabled="isDetailMode"
/>
</el-form-item> </el-form-item>
</div> </div>
<!-- 10. 商品简介 -->
<!-- 7. 商品简介 -->
<el-form-item label="商品简介" prop="intro"> <el-form-item label="商品简介" prop="intro">
<el-input <el-input
v-model="formData.intro" v-model="formData.intro"
placeholder="请输入商品简介" placeholder="请输入商品简介"
type="textarea" type="textarea"
rows="3" :rows="3"
style="width: 400px;" style="width: 400px"
:disabled="isDetailMode" :disabled="isDetailMode"
/> />
</el-form-item> </el-form-item>
<!-- 8. 轮播图地址 - 已隐藏 --> <!-- 11. 轮播图地址 - 已隐藏 -->
<!-- <el-form-item label="轮播图地址" prop="sliderPicUrls"> <!-- <el-form-item label="轮播图地址" prop="sliderPicUrls">
<el-input <el-input
v-model="formData.sliderPicUrls" v-model="formData.sliderPicUrls"
...@@ -200,7 +151,7 @@ ...@@ -200,7 +151,7 @@
/> />
</el-form-item> --> </el-form-item> -->
<!-- 9. 状态 --> <!-- 12. 状态 -->
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status" :disabled="isDetailMode"> <el-radio-group v-model="formData.status" :disabled="isDetailMode">
<el-radio <el-radio
...@@ -214,11 +165,17 @@ ...@@ -214,11 +165,17 @@
</el-form-item> </el-form-item>
<!-- 操作按钮 --> <!-- 操作按钮 -->
<el-form-item style="text-align: center; margin-top: 30px;"> <el-form-item style="text-align: center; margin-top: 30px">
<el-button v-if="!isDetailMode" :loading="formLoading" type="primary" size="large" @click="submitForm"> <el-button
v-if="!isDetailMode"
:loading="formLoading"
type="primary"
size="large"
@click="submitForm"
>
保存 保存
</el-button> </el-button>
<el-button size="large" style="margin-left: 20px;" @click="close"> <el-button size="large" style="margin-left: 20px" @click="close">
{{ isDetailMode ? '返回' : '取消' }} {{ isDetailMode ? '返回' : '取消' }}
</el-button> </el-button>
</el-form-item> </el-form-item>
...@@ -230,8 +187,8 @@ ...@@ -230,8 +187,8 @@
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict' 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 { useResourceConfigStore } from '@/store/modules/compute/hardwareConfig'
import { ResourceSpu, ResourceSpuApi } from '@/api/compute/resourcespu' import { ResourceSpu, ResourceSpuApi } from '@/api/compute/resourcespu'
import { ResourceConfigApi } from '@/api/compute/resourceconfig'
import * as AreaApi from '@/api/system/area' import * as AreaApi from '@/api/system/area'
defineOptions({ name: 'ResourceSpuAdd' }) defineOptions({ name: 'ResourceSpuAdd' })
...@@ -242,7 +199,7 @@ const { push, currentRoute } = useRouter() // 路由 ...@@ -242,7 +199,7 @@ const { push, currentRoute } = useRouter() // 路由
const { params, name } = useRoute() // 查询参数 const { params, name } = useRoute() // 查询参数
// 获取路由参数 // 获取路由参数
const { mode, id } = params as { mode?: string, id?: string } const { mode, id } = params as { mode?: string; id?: string }
// 判断当前模式 // 判断当前模式
const currentMode = computed(() => mode || 'add') const currentMode = computed(() => mode || 'add')
...@@ -250,70 +207,97 @@ const isDetailMode = computed(() => currentMode.value === 'detail') ...@@ -250,70 +207,97 @@ const isDetailMode = computed(() => currentMode.value === 'detail')
const isEditMode = computed(() => currentMode.value === 'edit') const isEditMode = computed(() => currentMode.value === 'edit')
const isAddMode = computed(() => currentMode.value === 'add') const isAddMode = computed(() => currentMode.value === 'add')
const { delView } = useTagsViewStore() // 视图操作 const { delView } = useTagsViewStore() // 视图操作
const resourceConfigStore = useResourceConfigStore() // 资源配置store
const formLoading = ref(false) // 表单的加载中 const formLoading = ref(false) // 表单的加载中
const formRef = ref() // 表单 Ref const formRef = ref() // 表单 Ref
const categoryList = ref<any[]>([]) const categoryList = ref<any[]>([])
const areaList = ref<any[]>([]) // 地区树数据 const areaList = ref<any[]>([]) // 地区树数据
// 从store获取硬件配置选项 // 规格分组(按 configCategory 分组多选)
const cpuOptions = computed(() => resourceConfigStore.getOptionsByType('cpu')) interface SpecOption {
const gpuOptions = computed(() => resourceConfigStore.getOptionsByType('gpu')) id: number
const ramOptions = computed(() => resourceConfigStore.getOptionsByType('ram')) configOption: string
const storageOptions = computed(() => resourceConfigStore.getOptionsByType('storage')) detailRemark?: string
const powerSupplyOptions = computed(() => resourceConfigStore.getOptionsByType('powerSupply')) }
const nicOptions = computed(() => resourceConfigStore.getOptionsByType('nic')) interface SpecCategory {
value: string // 字典 value(对应 configCategory)
label: string // 字典 label
options: SpecOption[]
}
const specCategories = ref<SpecCategory[]>([])
const formData = ref<ResourceSpu>({ const formData = ref<ResourceSpu>({
id: undefined, id: undefined,
name: undefined, name: undefined,
cpu: undefined,
gpu: undefined,
ram: undefined,
storage: undefined,
powerSupply: undefined,
nic: undefined,
ip: undefined,
initUsername: undefined,
initPassword: undefined,
intro: undefined, intro: undefined,
categoryId: undefined, categoryId: undefined,
source: undefined, source: undefined,
picUrl: undefined, picUrl: undefined,
sliderPicUrls: undefined, sliderPicUrls: undefined,
compute: undefined,
gpuCount: undefined,
coreCount: undefined,
memoryCapacity: undefined,
sales: undefined, sales: undefined,
location: undefined, status: undefined,
areaId: undefined, // 规格相关
status: undefined specConfigIds: [],
specConfigIdsByCategory: {}
}) })
const formRules = reactive({ const formRules = reactive({
name: [{ required: true, message: '算力资源名称不能为空', trigger: 'blur' }], name: [{ required: true, message: '算力资源名称不能为空', trigger: 'blur' }],
cpu: [{ required: true, message: 'CPU配置不能为空', trigger: 'blur' }],
gpu: [{ required: true, message: 'GPU配置不能为空', trigger: 'blur' }],
ram: [{ required: true, message: '内存配置不能为空', trigger: 'blur' }],
compute: [{ required: true, message: '算力不能为空', trigger: 'blur' }],
gpuCount: [{ required: true, message: 'GPU卡数量不能为空', trigger: 'blur' }],
coreCount: [{ required: true, message: 'CPU数量不能为空', trigger: 'blur' }],
memoryCapacity: [{ required: true, message: '内存大小不能为空', trigger: 'blur' }],
storage: [{ required: true, message: '存储配置不能为空', trigger: 'blur' }],
powerSupply: [{ required: true, message: '电源配置不能为空', trigger: 'blur' }],
nic: [{ required: true, message: '网卡配置不能为空', trigger: 'blur' }],
ip: [{ required: true, message: '服务器ip不能为空', trigger: 'blur' }],
initUsername: [{ required: true, message: '初始用户名不能为空', trigger: 'blur' }],
initPassword: [{ required: true, message: '初始密码不能为空', trigger: 'blur' }],
categoryId: [{ required: true, message: '算力资源分类编号不能为空', trigger: 'blur' }], categoryId: [{ required: true, message: '算力资源分类编号不能为空', trigger: 'blur' }],
picUrl: [{ required: true, message: '商品封面图不能为空', trigger: 'blur' }], picUrl: [{ required: true, message: '商品封面图不能为空', trigger: 'blur' }],
sales: [{ required: true, message: '商品销量不能为空', trigger: 'blur' }], sales: [{ required: true, message: '商品销量不能为空', trigger: 'blur' }],
areaId: [{ required: true, message: '服务器所在地不能为空', trigger: 'blur' }],
status: [{ required: true, message: '状态不能为空', trigger: 'blur' }] status: [{ required: true, message: '状态不能为空', trigger: 'blur' }]
}) })
/**
* 加载规格分组选项:
* 1. 从字典 compute_resource_config_category 读取所有类别
* 2. 对每个类别调 listSimpleConfigByCategory 拿该类别的所有规格项
*/
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 分布到各分组
*/
const distributeSpecConfigIds = () => {
const flat = new Set(formData.value.specConfigIds || [])
// 先清空所有分组
for (const cat of specCategories.value) {
formData.value.specConfigIdsByCategory[cat.value] = []
}
// 再按 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)
}
}
}
}
/** 地区选择变化时,自动设置 location 为市级名称(第二级) */ /** 地区选择变化时,自动设置 location 为市级名称(第二级) */
const handleAreaChange = (value: number[]) => { const handleAreaChange = (value: number[]) => {
if (!value || value.length === 0) { if (!value || value.length === 0) {
...@@ -345,14 +329,24 @@ const handleAreaChange = (value: number[]) => { ...@@ -345,14 +329,24 @@ const handleAreaChange = (value: number[]) => {
formData.value.location = findCityName(areaList.value, cityId) || undefined formData.value.location = findCityName(areaList.value, cityId) || undefined
} }
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
const submitForm = async () => { const submitForm = async () => {
await formRef.value.validate() await formRef.value.validate()
// 校验:至少选 1 个规格
const allSpecIds = (Object.values(formData.value.specConfigIdsByCategory || {}).flat() ||
[]) as number[]
if (!allSpecIds.length) {
message.error('请至少选择 1 个规格')
return
}
// 扁平化写入 formData.specConfigIds
formData.value.specConfigIds = allSpecIds
formLoading.value = true formLoading.value = true
try { try {
const data = formData.value as unknown as ResourceSpu const data = { ...formData.value } as unknown as ResourceSpu
// 提交时不发送 specConfigIdsByCategory(仅前端辅助字段)
delete (data as any).specConfigIdsByCategory
if (isEditMode.value) { if (isEditMode.value) {
// 编辑 // 编辑
await ResourceSpuApi.updateResourceSpu(data) await ResourceSpuApi.updateResourceSpu(data)
...@@ -379,11 +373,11 @@ const close = () => { ...@@ -379,11 +373,11 @@ const close = () => {
/** 初始化 */ /** 初始化 */
onMounted(async () => { onMounted(async () => {
try { try {
// 并行加载分类列表、硬件配置选项和地区树 // 并行加载分类列表、地区树和规格分组
const [categoryResponse, _, areaResponse] = await Promise.all([ const [categoryResponse, areaResponse] = await Promise.all([
ResourceSpuApi.listSimpleCategory(), ResourceSpuApi.listSimpleCategory(),
resourceConfigStore.loadConfigOptions(), AreaApi.getAreaTree(),
AreaApi.getAreaTree() loadSpecOptions()
]) ])
categoryList.value = categoryResponse categoryList.value = categoryResponse
areaList.value = areaResponse areaList.value = areaResponse
...@@ -393,6 +387,12 @@ onMounted(async () => { ...@@ -393,6 +387,12 @@ onMounted(async () => {
formLoading.value = true formLoading.value = true
try { try {
formData.value = await ResourceSpuApi.getResourceSpu(Number(id)) formData.value = await ResourceSpuApi.getResourceSpu(Number(id))
// 初始化 specConfigIdsByCategory 为空对象(接口可能不返回)
if (!formData.value.specConfigIdsByCategory) {
formData.value.specConfigIdsByCategory = {}
}
// 把 specConfigIds 分布到各分组
distributeSpecConfigIds()
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
...@@ -402,3 +402,27 @@ onMounted(async () => { ...@@ -402,3 +402,27 @@ onMounted(async () => {
} }
}) })
</script> </script>
<style scoped>
.spec-config-wrapper {
width: 100%;
}
.spec-category-row {
display: flex;
align-items: flex-start;
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>
...@@ -18,12 +18,7 @@ ...@@ -18,12 +18,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="CPU" prop="cpu"> <el-form-item label="CPU" prop="cpu">
<el-select <el-select v-model="queryParams.cpu" placeholder="请选择CPU配置" clearable class="!w-240px">
v-model="queryParams.cpu"
placeholder="请选择CPU配置"
clearable
class="!w-240px"
>
<el-option <el-option
v-for="option in resourceConfigStore.getOptionsByType('cpu')" v-for="option in resourceConfigStore.getOptionsByType('cpu')"
:key="option.id" :key="option.id"
...@@ -33,12 +28,7 @@ ...@@ -33,12 +28,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="GPU" prop="gpu"> <el-form-item label="GPU" prop="gpu">
<el-select <el-select v-model="queryParams.gpu" placeholder="请选择GPU配置" clearable class="!w-240px">
v-model="queryParams.gpu"
placeholder="请选择GPU配置"
clearable
class="!w-240px"
>
<el-option <el-option
v-for="option in resourceConfigStore.getOptionsByType('gpu')" v-for="option in resourceConfigStore.getOptionsByType('gpu')"
:key="option.id" :key="option.id"
...@@ -77,33 +67,33 @@ ...@@ -77,33 +67,33 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- <el-form-item label="服务器ip" prop="ip">--> <!-- <el-form-item label="服务器ip" prop="ip">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.ip"--> <!-- v-model="queryParams.ip"-->
<!-- placeholder="请输入服务器ip"--> <!-- placeholder="请输入服务器ip"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
<!-- <el-form-item label="初始用户名" prop="initUsername">--> <!-- <el-form-item label="初始用户名" prop="initUsername">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.initUsername"--> <!-- v-model="queryParams.initUsername"-->
<!-- placeholder="请输入初始用户名"--> <!-- placeholder="请输入初始用户名"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
<!-- <el-form-item label="初始密码" prop="initPassword">--> <!-- <el-form-item label="初始密码" prop="initPassword">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.initPassword"--> <!-- v-model="queryParams.initPassword"-->
<!-- placeholder="请输入初始密码"--> <!-- placeholder="请输入初始密码"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </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"
...@@ -158,49 +148,44 @@ ...@@ -158,49 +148,44 @@
/> />
</el-select> </el-select>
</el-form-item> </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"-->
<!-- placeholder="请输入商品封面图"--> <!-- placeholder="请输入商品封面图"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
<!-- <el-form-item label="商品轮播图地址" prop="sliderPicUrls">--> <!-- <el-form-item label="商品轮播图地址" prop="sliderPicUrls">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.sliderPicUrls"--> <!-- v-model="queryParams.sliderPicUrls"-->
<!-- placeholder="请输入商品轮播图地址"--> <!-- placeholder="请输入商品轮播图地址"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
<!-- <el-form-item label="总库存数量" prop="stock">--> <!-- <el-form-item label="总库存数量" prop="stock">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.stock"--> <!-- v-model="queryParams.stock"-->
<!-- placeholder="请输入总库存数量"--> <!-- placeholder="请输入总库存数量"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
<!-- <el-form-item label="商品销量" prop="sales">--> <!-- <el-form-item label="商品销量" prop="sales">-->
<!-- <el-input--> <!-- <el-input-->
<!-- v-model="queryParams.sales"--> <!-- v-model="queryParams.sales"-->
<!-- placeholder="请输入商品销量"--> <!-- placeholder="请输入商品销量"-->
<!-- clearable--> <!-- clearable-->
<!-- @keyup.enter="handleQuery"--> <!-- @keyup.enter="handleQuery"-->
<!-- class="!w-240px"--> <!-- class="!w-240px"-->
<!-- />--> <!-- />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
<el-form-item label="状态" prop="status"> <el-form-item label="状态" prop="status">
<el-select <el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
v-model="queryParams.status"
placeholder="请选择状态"
clearable
class="!w-240px"
>
<el-option <el-option
v-for="dict in statusOptions" v-for="dict in statusOptions"
:key="dict.value" :key="dict.value"
...@@ -264,7 +249,7 @@ ...@@ -264,7 +249,7 @@
@selection-change="handleRowCheckboxChange" @selection-change="handleRowCheckboxChange"
> >
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<!-- <el-table-column label="主键ID" align="center" prop="id" />--> <!-- <el-table-column label="主键ID" align="center" prop="id" />-->
<el-table-column label="算力资源名称" min-width="200"> <el-table-column label="算力资源名称" min-width="200">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex"> <div class="flex">
...@@ -285,6 +270,18 @@ ...@@ -285,6 +270,18 @@
<!-- 硬件配置字段已隐藏 --> <!-- 硬件配置字段已隐藏 -->
<!-- <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">
<template #default="{ row }">
<el-tag
v-for="(value, key) in row.specMap"
:key="key"
size="small"
class="!mr-1"
>
{{ key }}: {{ value }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="算力来源" align="center" prop="source" min-width="120"> <el-table-column label="算力来源" align="center" prop="source" min-width="120">
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.COMPUTE_RESOURCE_SOURCE" :value="scope.row.source" /> <dict-tag :type="DICT_TYPE.COMPUTE_RESOURCE_SOURCE" :value="scope.row.source" />
...@@ -353,7 +350,7 @@ import { dateFormatter } from '@/utils/formatTime' ...@@ -353,7 +350,7 @@ import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download' 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' import { useResourceConfigStore } from '@/store/modules/compute/hardwareConfig'
const { push } = useRouter() const { push } = useRouter()
...@@ -393,7 +390,6 @@ const queryParams = reactive({ ...@@ -393,7 +390,6 @@ const queryParams = reactive({
const queryFormRef = ref() // 搜索的表单 const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中 const exportLoading = ref(false) // 导出的加载中
const statusOptions = getIntDictOptions(DICT_TYPE.COMPUTE_RESOURCE_SPU_STATUS) const statusOptions = getIntDictOptions(DICT_TYPE.COMPUTE_RESOURCE_SPU_STATUS)
/** 查询列表 */ /** 查询列表 */
const getList = async () => { const getList = async () => {
...@@ -453,15 +449,15 @@ const handleDeleteBatch = async () => { ...@@ -453,15 +449,15 @@ const handleDeleteBatch = async () => {
try { try {
// 删除的二次确认 // 删除的二次确认
await message.delConfirm() await message.delConfirm()
await ResourceSpuApi.deleteResourceSpuList(checkedIds.value); await ResourceSpuApi.deleteResourceSpuList(checkedIds.value)
message.success(t('common.delSuccess')) message.success(t('common.delSuccess'))
await getList(); await getList()
} catch {} } catch {}
} }
const checkedIds = ref<number[]>([]) const checkedIds = ref<number[]>([])
const handleRowCheckboxChange = (records: ResourceSpu[]) => { const handleRowCheckboxChange = (records: ResourceSpu[]) => {
checkedIds.value = records.map((item) => item.id); checkedIds.value = records.map((item) => item.id)
} }
/** 商品图预览 */ /** 商品图预览 */
......
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