在SKU管理中新增规格单位和规格数量字段,优化时间显示格式并调整列宽布局,同时修改分类属性类型接口路径以匹配后端枚举接口规范

This commit is contained in:
WUSIJIAN
2026-01-13 16:12:02 +08:00
parent eec9a72a1d
commit aae01669d0
3 changed files with 108 additions and 11 deletions

View File

@@ -154,3 +154,12 @@ export function deleteAssetSku(id: string) {
params: { id },
});
}
// 获取规格单位选项
export function getSpecsUnitOptions(assetType: string) {
return newService({
url: '/assets/enum/getSpecsUnit',
method: 'get',
params: { assetType },
});
}

View File

@@ -23,7 +23,7 @@ export function getCategory(id: string) {
// 获取属性类型选项
export function getCategoryAttrTypeOptions() {
return newService({
url: '/assets/category/getCategoryAttrTypeOptions',
url: '/assets/enum/getCategoryAttrType',
method: 'get',
});
}

View File

@@ -1,5 +1,5 @@
<template>
<el-dialog v-model="dialogVisible" :title="`SKU管理 - ${assetName}`" width="1000px" :close-on-click-modal="false" @close="onClose">
<el-dialog v-model="dialogVisible" :title="`SKU管理 - ${assetName}`" width="1200px" :close-on-click-modal="false" @close="onClose">
<!-- 搜索区域 -->
<div class="sku-search mb15">
<el-button type="primary" @click="onOpenAddSku">
@@ -21,7 +21,7 @@
<!-- SKU 列表 -->
<el-table :data="tableData" v-loading="loading" border style="width: 100%">
<el-table-column prop="skuName" label="SKU名称" min-width="120" show-overflow-tooltip />
<el-table-column prop="specValues" label="规格属性" min-width="150">
<el-table-column prop="specValues" label="规格属性" min-width="140">
<template #default="scope">
<span v-if="scope.row.specValues && Array.isArray(scope.row.specValues) && scope.row.specValues.length > 0">
<el-tag v-for="(item, idx) in scope.row.specValues" :key="idx" size="small" style="margin-right: 4px">
@@ -36,7 +36,17 @@
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="price" label="价格" width="100" align="center">
<el-table-column prop="specsUnit" label="规格单位" width="80" align="center">
<template #default="scope">
{{ scope.row.specsUnit?.value || getSpecsUnitLabel(scope.row.specsUnit) || '-' }}
</template>
</el-table-column>
<el-table-column prop="specsCount" label="规格数量" width="80" align="center">
<template #default="scope">
{{ scope.row.specsCount || '-' }}
</template>
</el-table-column>
<el-table-column prop="price" label="价格" width="90" align="center">
<template #default="scope">
¥{{ (scope.row.price / 100).toFixed(2) }}
</template>
@@ -53,9 +63,21 @@
</el-tag>
</template>
</el-table-column>
<el-table-column prop="sort" label="排序" width="80" align="center" />
<el-table-column prop="createdAt" label="创建时间" width="160" align="center" />
<el-table-column prop="updatedAt" label="修改时间" width="160" align="center" />
<el-table-column prop="sort" label="排序" width="60" align="center" />
<el-table-column prop="createdAt" label="创建时间" width="100" align="center">
<template #default="scope">
<el-tooltip :content="scope.row.createdAt" placement="top">
<span>{{ formatShortTime(scope.row.createdAt) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column prop="updatedAt" label="修改时间" width="100" align="center">
<template #default="scope">
<el-tooltip :content="scope.row.updatedAt" placement="top">
<span>{{ formatShortTime(scope.row.updatedAt) }}</span>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="scope">
<el-button size="small" text type="primary" @click="onEditSku(scope.row)">编辑</el-button>
@@ -86,7 +108,7 @@
<el-form-item label="SKU名称" prop="skuName">
<el-input v-model="skuForm.skuName" placeholder="请输入SKU名称" />
</el-form-item>
<el-form-item label="规格属性" v-if="assetSpecAttrs.length > 0">
<el-form-item v-if="assetSpecAttrs.length > 0">
<div class="spec-values-container">
<div v-for="attr in assetSpecAttrs" :key="attr.name" class="spec-item">
<span class="spec-label">{{ attr.name }}</span>
@@ -97,6 +119,14 @@
</div>
</div>
</el-form-item>
<el-form-item label="规格单位" prop="specsUnit">
<el-select v-model="skuForm.specsUnit" placeholder="请选择规格单位" style="width: 150px" clearable>
<el-option v-for="opt in specsUnitOptions" :key="opt.key" :label="opt.value" :value="opt.key" />
</el-select>
</el-form-item>
<el-form-item label="规格数量" prop="specsCount">
<el-input-number v-model="skuForm.specsCount" :min="1" controls-position="right" />
</el-form-item>
<el-form-item label="价格" prop="price">
<el-input-number v-model="skuForm.price" :min="0" :precision="2" :step="0.01" controls-position="right" />
<span style="margin-left: 8px"></span>
@@ -143,7 +173,7 @@
import { ref, reactive } from 'vue';
import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
import { ElMessageBox } from 'element-plus';
import { listAssetSkus, createAssetSku, updateAssetSku, deleteAssetSku, getAssetSku, getAsset, uploadAssetImage } from '/@/api/assets/asset';
import { listAssetSkus, createAssetSku, updateAssetSku, deleteAssetSku, getAssetSku, getAsset, uploadAssetImage, getSpecsUnitOptions } from '/@/api/assets/asset';
import type { UploadRequestOptions, UploadUserFile } from 'element-plus';
interface SpecValueItem {
@@ -167,9 +197,11 @@ const editSkuId = ref('');
const assetId = ref('');
const assetName = ref('');
const assetType = ref('');
const assetSpecAttrs = ref<AssetSpecAttr[]>([]);
const fileAddressPrefix = ref('');
const skuImagePreview = ref('');
const specsUnitOptions = ref<{ key: string; value: string }[]>([]);
const tableData = ref<any[]>([]);
const total = ref(0);
@@ -190,6 +222,8 @@ const skuForm = reactive({
sort: 0,
imageUrl: '',
description: '',
specsUnit: '',
specsCount: 1,
});
const specValuesList = ref<SpecValueItem[]>([{ key: '', value: '' }]);
@@ -197,6 +231,11 @@ const specValuesMap = reactive<Record<string, string>>({});
const skuRules: FormRules = {
skuName: [{ required: true, message: '请输入SKU名称', trigger: 'blur' }],
specsUnit: [{ required: true, message: '请选择规格单位', trigger: 'change' }],
specsCount: [
{ required: true, message: '请输入规格数量', trigger: 'blur' },
{ type: 'number', min: 1, message: '规格数量必须大于0', trigger: 'blur' }
],
price: [
{ required: true, message: '请输入价格', trigger: 'blur' },
{ type: 'number', min: 0.01, message: '价格必须大于0', trigger: 'blur' }
@@ -221,13 +260,41 @@ const skuRules: FormRules = {
};
// 打开弹窗
const openDialog = (row: { id: string; name: string }) => {
const openDialog = (row: { id: string; name: string; type?: string }) => {
assetId.value = row.id;
assetName.value = row.name;
assetType.value = row.type || '';
dialogVisible.value = true;
resetQuery();
getSkuList();
fetchAssetSpecAttrs();
fetchSpecsUnitOptions();
};
// 获取规格单位选项
const fetchSpecsUnitOptions = () => {
if (!assetType.value) return;
getSpecsUnitOptions(assetType.value)
.then((res: any) => {
specsUnitOptions.value = res.data?.options || [];
})
.catch(() => {
specsUnitOptions.value = [];
});
};
// 根据规格单位 key 获取对应的 label
const getSpecsUnitLabel = (key: string) => {
if (!key) return '';
const option = specsUnitOptions.value.find((opt) => opt.key === key);
return option?.value || key;
};
// 格式化时间为短格式(只显示日期)
const formatShortTime = (time: string) => {
if (!time) return '-';
// 只取日期部分 YYYY-MM-DD
return time.substring(0, 10);
};
// 获取资产规格属性(只获取多选类型)
@@ -328,6 +395,13 @@ const onEditSku = async (row: any) => {
skuForm.sort = data.sort || 0;
skuForm.imageUrl = data.imageUrl || '';
skuForm.description = data.description || '';
// specsUnit 可能是对象格式 { key, value } 或字符串
if (data.specsUnit && typeof data.specsUnit === 'object') {
skuForm.specsUnit = data.specsUnit.key || '';
} else {
skuForm.specsUnit = data.specsUnit || '';
}
skuForm.specsCount = data.specsCount || 1;
// 图片预览回显
if (data.imageUrl) {
skuImagePreview.value = formatImageUrl(data.imageUrl);
@@ -396,6 +470,8 @@ const resetSkuForm = () => {
skuForm.sort = 0;
skuForm.imageUrl = '';
skuForm.description = '';
skuForm.specsUnit = '';
skuForm.specsCount = 1;
specValuesList.value = [{ key: '', value: '' }];
// 清空 specValuesMap
Object.keys(specValuesMap).forEach((key) => delete specValuesMap[key]);
@@ -522,6 +598,16 @@ const onSubmitSku = async () => {
}
});
// 构建 specsUnit 对象格式
let specsUnitObj = undefined;
if (skuForm.specsUnit) {
const unitOption = specsUnitOptions.value.find((opt) => opt.key === skuForm.specsUnit);
specsUnitObj = {
key: skuForm.specsUnit,
value: unitOption?.value || skuForm.specsUnit,
};
}
const data = {
assetId: assetId.value,
assetName: assetName.value,
@@ -533,7 +619,9 @@ const onSubmitSku = async () => {
stock: skuForm.stock,
sort: skuForm.sort,
status: skuForm.status,
description:skuForm.description,
description: skuForm.description,
specsUnit: specsUnitObj,
specsCount: skuForm.specsCount || undefined,
};
try {