Commit 1f847553 by Jony.L

算力资源重构-算力资源SKU管理修改1.0

parent 9d78ba94
import { defineStore } from 'pinia'
import { ResourceConfigApi } from '@/api/compute/resourceconfig'
interface ResourceConfig {
cpuOptions: any[]
gpuOptions: any[]
ramOptions: any[]
storageOptions: any[]
locationOptions: any[]
lastFetched: number | null
}
export const useResourceConfigStore = defineStore('resourceConfig', {
state: (): ResourceConfig => ({
cpuOptions: [],
gpuOptions: [],
ramOptions: [],
storageOptions: [],
locationOptions: [],
lastFetched: null
}),
getters: {
// 判断是否需要重新获取数据(缓存5分钟)
needsRefresh(): boolean {
if (!this.lastFetched) return true
const now = Date.now()
const fiveMinutes = 5 * 60 * 1000
return now - this.lastFetched > fiveMinutes
},
// 获取所有配置选项
allOptions() {
return {
cpu: this.cpuOptions,
gpu: this.gpuOptions,
ram: this.ramOptions,
storage: this.storageOptions,
location: this.locationOptions
}
}
},
actions: {
// 加载硬件配置选项
async loadConfigOptions(forceRefresh = false) {
// 如果不需要刷新且不是强制刷新,直接返回缓存数据
if (!forceRefresh && !this.needsRefresh) {
return this.allOptions
}
try {
const [cpuRes, gpuRes, ramRes, storageRes, locationRes] = await Promise.all([
ResourceConfigApi.listSimpleConfigByCategory('cpu'),
ResourceConfigApi.listSimpleConfigByCategory('gpu'),
ResourceConfigApi.listSimpleConfigByCategory('ram'),
ResourceConfigApi.listSimpleConfigByCategory('storage'),
ResourceConfigApi.listSimpleConfigByCategory('location')
])
this.cpuOptions = cpuRes
this.gpuOptions = gpuRes
this.ramOptions = ramRes
this.storageOptions = storageRes
this.locationOptions = locationRes
this.lastFetched = Date.now()
return this.allOptions
} catch (error) {
console.error('加载资源配置选项失败:', error)
throw error
}
},
// 清除缓存
clearCache() {
this.cpuOptions = []
this.gpuOptions = []
this.ramOptions = []
this.storageOptions = []
this.locationOptions = []
this.lastFetched = null
},
// 根据类型获取选项
getOptionsByType(type: 'cpu' | 'gpu' | 'ram' | 'storage' | 'location') {
return this[type + 'Options']
}
}
})
\ No newline at end of file
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" :width="1000">
<!-- 搜索区域 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="资源名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入算力资源名称"
clearable
@keyup.enter="handleQuery"
class="!w-200px"
/>
</el-form-item>
<el-form-item label="CPU" prop="cpu">
<el-select
v-model="queryParams.cpu"
placeholder="请选择CPU配置"
clearable
class="!w-160px"
>
<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-160px"
>
<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="categoryId">
<el-select
v-model="queryParams.categoryId"
placeholder="请选择资源分类"
clearable
class="!w-160px"
>
<el-option
v-for="category in categoryList"
:key="category.id"
:label="category.name"
:value="category.id"
/>
</el-select>
</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>
<!-- SPU列表 -->
<el-table
ref="tableRef"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
@row-click="handleRowClick"
height="400"
highlight-current-row
>
<el-table-column width="55">
<template #default="{ row }">
<el-radio
v-model="selectedRowId"
:label="row.id"
@change="handleRadioChange(row)"
/>
</template>
</el-table-column>
<el-table-column label="算力资源" min-width="200">
<template #default="{ row }">
<div class="flex items-center">
<el-image
fit="cover"
:src="row.picUrl"
class="flex-none w-40px h-40px rounded"
:preview-src-list="[row.picUrl]"
/>
<div class="ml-3">
<div class="font-medium">{{ row.name }}</div>
<div class="text-gray-500 text-sm">{{ row.categoryName }}</div>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="硬件配置" min-width="300">
<template #default="{ row }">
<div class="space-y-1">
<div class="text-sm">CPU: {{ row.cpu || '-' }}</div>
<div class="text-sm">GPU: {{ row.gpu || '-' }}</div>
<div class="text-sm">内存: {{ row.ram || '-' }}</div>
<div class="text-sm">存储: {{ row.storage || '-' }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="服务器所在地" width="120" prop="location" />
<el-table-column label="库存" width="80" prop="stock" />
<el-table-column label="销量" width="80" prop="sales" />
<el-table-column label="状态" width="80" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.COMPUTE_RESOURCE_SPU_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
</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" :disabled="!selectedRows.length" @click="handleConfirm">
确定选择 ({{ selectedRows.length }})
</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { DICT_TYPE } from "@/utils/dict"
import { ResourceSpuApi, ResourceSpu } from '@/api/compute/resourcespu'
import { useResourceConfigStore } from '@/store/modules/compute/hardwareConfig'
interface Props {
modelValue: boolean
title?: string
multiple?: boolean
// 默认只显示上架的SPU
defaultStatus?: number
}
interface Emits {
(e: 'update:modelValue', value: boolean): void
(e: 'confirm', selections: ResourceSpu[]): void
}
const props = withDefaults(defineProps<Props>(), {
title: '选择算力资源SPU',
multiple: false,
defaultStatus: 1 // 默认只显示上架的
})
const emit = defineEmits<Emits>()
const dialogVisible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const dialogTitle = computed(() => props.title)
const resourceConfigStore = useResourceConfigStore()
const loading = ref(false)
const list = ref<ResourceSpu[]>([])
const total = ref(0)
const selectedRows = ref<ResourceSpu[]>([])
const selectedRowId = ref<number | null>(null)
const tableRef = ref()
const categoryList = ref<any[]>([])
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
name: undefined,
cpu: undefined,
gpu: undefined,
ram: undefined,
storage: undefined,
categoryId: undefined,
status: props.defaultStatus
})
const queryFormRef = ref()
/** 查询列表 */
const getList = async () => {
loading.value = true
try {
const data = await ResourceSpuApi.getResourceSpuPage(queryParams)
list.value = data.list
total.value = data.total
} finally {
loading.value = false
}
}
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.pageNo = 1
getList()
}
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields()
queryParams.status = props.defaultStatus
handleQuery()
}
/** 处理单选框变化 */
const handleRadioChange = (row: ResourceSpu) => {
selectedRows.value = [row]
selectedRowId.value = row.id
}
/** 处理行点击 */
const handleRowClick = (row: ResourceSpu) => {
selectedRowId.value = row.id
selectedRows.value = [row]
}
/** 确认选择 */
const handleConfirm = () => {
emit('confirm', selectedRows.value)
dialogVisible.value = false
}
/** 打开弹窗时加载数据 */
const handleOpen = async () => {
// 清除之前的选择状态
selectedRows.value = []
selectedRowId.value = null
// 加载分类列表
const categoryResponse = await ResourceSpuApi.listSimpleCategory()
categoryList.value = categoryResponse
// 预加载硬件配置
resourceConfigStore.loadConfigOptions().catch(error => {
console.error('预加载资源配置失败:', error)
})
// 加载列表数据
getList()
}
// 监听弹窗打开
watch(
() => props.modelValue,
(val) => {
if (val) {
handleOpen()
}
},
{ immediate: true }
)
</script>
<style scoped>
.text-orange-500 {
color: #f97316;
}
</style>
\ No newline at end of file
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