feat(shopGoods): 支持商品分类多选及列表树形高度优化

- 商品模型增加 categoryIds 字段支持多分类,搜索参数同步支持多分类查询
- 商品列表新增分类列,展示商品所属分类名称
- 商品编辑及搜索组件商品分类选择改为多选,保持兼容单选主分类逻辑
- 商品分类树形列表SVG连线高度调小,提升界面紧凑度
- 优化分类图片尺寸,缩小预览图大小,提升视觉效果
- 更新用户推荐接口方法参数类型声明,增加类型安全保障
This commit is contained in:
2026-08-14 19:38:02 +08:00
parent 780606f05a
commit 053b776d9a
7 changed files with 71 additions and 28 deletions
@@ -32,18 +32,20 @@
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="商品分类" name="categoryId">
<a-form-item label="商品分类" name="categoryIds">
<a-tree-select
allow-clear
multiple
:max-tag-count="3"
:tree-data="navigationList"
tree-default-expand-all
style="width: 320px"
placeholder="请选择分类"
:value="form.categoryId || undefined"
placeholder="请选择分类(可多选)"
:value="form.categoryIds && form.categoryIds.length ? form.categoryIds : undefined"
:listHeight="700"
:dropdown-style="{ overflow: 'auto' }"
@update:value="(value?: number) => (form.categoryId = value)"
@change="onCategoryId"
@update:value="(value?: number[]) => (form.categoryIds = value || [])"
@change="onCategoryIds"
/>
</a-form-item>
<a-form-item label="商品编码" name="code">
@@ -928,12 +930,13 @@ const addEnsureTag = (item = '') => {
ensureTagItem.value = '';
};
// 选择栏目
const onCategoryId = (id: number) => {
form.categoryId = id;
// 选择栏目(方案B:支持多选,主分类取列表首个,向后兼容旧字段)
const onCategoryIds = (ids: number[]) => {
form.categoryIds = ids || [];
form.categoryId = ids && ids.length ? ids[0] : undefined;
// 💾 在新增模式下,用户手动选择栏目时也保存到本地存储
if (!isUpdate.value && id) {
saveLastCategory(id);
if (!isUpdate.value && ids && ids.length) {
saveLastCategory(ids[0]);
}
};
@@ -1204,6 +1207,7 @@ const form = reactive<ShopGoods>({
canExpress: 1,
unitName: '',
categoryId: undefined,
categoryIds: [],
parentName: undefined,
categoryName: undefined,
specs: 0,
@@ -1449,14 +1453,18 @@ const chooseSupplier = (item: ShopMerchant) => {
};
const chooseGoodsCategory = (item: ShopGoodsCategory, value: any) => {
form.categoryId = value[1].value;
const cid = value[1].value as number;
form.categoryId = cid;
form.categoryIds = [cid];
form.parentName = value[0].label;
form.categoryName = value[1].label;
};
const chooseTakeawayCategory = (item: ShopGoodsCategory, value: any) => {
const cid = item[0] as number;
form.categoryParent = '店铺分类';
form.categoryChildren = value[0].label;
form.categoryId = item[0];
form.categoryId = cid;
form.categoryIds = [cid];
};
const chooseImage = (data: FileRecord) => {
@@ -1788,6 +1796,11 @@ const save = () => {
if (form.specs === 1 && goodsSpec.value && spec.value.length) {
goodsSpec.value.specValue = JSON.stringify(spec.value);
}
// 方案B:主分类兜底取多分类第一个,保证旧字段/旧逻辑兼容
if (form.categoryIds && form.categoryIds.length && !form.categoryId) {
form.categoryId = form.categoryIds[0];
}
const formData: any = {
...form,
content: content.value,
@@ -2050,15 +2063,21 @@ watch(
if (form.ensureTag) {
ensureTag.value = form.ensureTag.split(',');
}
// 🎯 优先级设置栏目:
// 1. 如果传入了 categoryId(从栏目页面点击添加),使用传入的
// 2. 否则使用上次保存的栏目
if (props.data.categoryId) {
// 🎯 优先级设置栏目(方案B:支持多分类回填)
// 1. 如果传入了 categoryIds,使用多分类
// 2. 否则如果传入了 categoryId,兼容单分类
// 3. 否则使用上次保存的栏目
if (props.data.categoryIds && props.data.categoryIds.length) {
form.categoryIds = props.data.categoryIds;
form.categoryId = props.data.categoryId ?? props.data.categoryIds[0];
} else if (props.data.categoryId) {
form.categoryId = props.data?.categoryId;
form.categoryIds = [props.data.categoryId];
} else {
const lastCategory = getLastCategory();
if (lastCategory) {
form.categoryId = lastCategory;
form.categoryIds = [lastCategory];
}
}
await getRoleList();