diff --git a/.workbuddy/memory/2026-08-14.md b/.workbuddy/memory/2026-08-14.md index 7937f03..43886d5 100644 --- a/.workbuddy/memory/2026-08-14.md +++ b/.workbuddy/memory/2026-08-14.md @@ -17,3 +17,10 @@ - 在「分类标识」form-item 之后新增「链接地址」项,绑定 `form.path`(form 已有该字段,无需改 model/后端)。 - 重置逻辑 Object.assign 补上 `path: undefined`,保证新增时清空。 - 注意:仅前端 UI 改动,后端表 `shop_goods_category.path` 字段已存在,无需迁移。 + +## 商品分类列表树形连线高度调紧凑 + +- 问题:后台 `/shop/shopGoodsCategory` 列表中,树形层级连线 SVG 高度 40px,导致行显得太高、不紧凑。 +- 改动:`src/views/shop/shopGoodsCategory/index.vue` + - `renderTreePrefix` 中 SVG 高度 `H` 从 `40` 改为 `28`,`mid` 自动为 `14`。 +- 效果:二级/三级分类前的树形引导线高度降低,整行更紧凑。 diff --git a/src/api/shop/shopGoods/model/index.ts b/src/api/shop/shopGoods/model/index.ts index 76f16d9..24a265d 100644 --- a/src/api/shop/shopGoods/model/index.ts +++ b/src/api/shop/shopGoods/model/index.ts @@ -31,8 +31,10 @@ export interface ShopGoods { canExpress?: number; // 商品分类 category?: string; - // 商品分类ID + // 商品分类ID(主分类,向后兼容) categoryId?: number; + // 商品分类ID列表(方案B:可归属多个分类) + categoryIds?: number[]; parentName?: string; categoryName?: string; // 一级分类 @@ -174,6 +176,8 @@ export interface ShopGoodsCollectParam { export interface ShopGoodsParam extends PageParam { parentId?: number; categoryId?: number; + // 方案B:按多个分类查询,与单值 categoryId 二选一,多值时优先 + categoryIds?: number[]; goodsId?: number; status?: number; goodsName?: string; diff --git a/src/api/system/user/index.ts b/src/api/system/user/index.ts index 0f47d4c..64c66b6 100644 --- a/src/api/system/user/index.ts +++ b/src/api/system/user/index.ts @@ -170,7 +170,7 @@ export async function updateUserStatus(userId?: number, status?: number) { /** * 修改推荐状态 */ -export async function updateUserRecommend(form) { +export async function updateUserRecommend(form: { userId: number; recommend: number }) { const res = await request.put>( SERVER_API_URL + '/system/user/recommend', form diff --git a/src/views/shop/shopGoods/components/search.vue b/src/views/shop/shopGoods/components/search.vue index 8a01dc9..262398e 100644 --- a/src/views/shop/shopGoods/components/search.vue +++ b/src/views/shop/shopGoods/components/search.vue @@ -52,15 +52,17 @@ { - where.categoryId = id; + // 按分类查询(方案B:支持多选,主分类取首个) + const onCategoryIds = (ids: number[]) => { + where.categoryIds = ids || []; + where.categoryId = ids && ids.length ? ids[0] : undefined; emit('search', where); }; diff --git a/src/views/shop/shopGoods/components/shopGoodsEdit.vue b/src/views/shop/shopGoods/components/shopGoodsEdit.vue index 7da6f25..fdefebe 100644 --- a/src/views/shop/shopGoods/components/shopGoodsEdit.vue +++ b/src/views/shop/shopGoods/components/shopGoodsEdit.vue @@ -32,18 +32,20 @@ v-model:value="form.name" /> - + @@ -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({ 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(); diff --git a/src/views/shop/shopGoods/index.vue b/src/views/shop/shopGoods/index.vue index 315d298..497b34b 100644 --- a/src/views/shop/shopGoods/index.vue +++ b/src/views/shop/shopGoods/index.vue @@ -269,6 +269,15 @@ key: 'name', width: 300 }, + { + title: '分类', + dataIndex: 'categoryName', + key: 'categoryName', + align: 'center', + width: 160, + ellipsis: true, + customRender: ({ text }) => text || '--' + }, { title: '价格', key: 'priceGroup', diff --git a/src/views/shop/shopGoodsCategory/index.vue b/src/views/shop/shopGoodsCategory/index.vue index ee300fe..e4ab06e 100644 --- a/src/views/shop/shopGoodsCategory/index.vue +++ b/src/views/shop/shopGoodsCategory/index.vue @@ -38,7 +38,7 @@ - @@ -176,7 +176,7 @@ const depth = depthMap.value.get(record.categoryId || 0) || 0; if (depth === 0) return ''; const W = 20; - const H = 40; + const H = 20; const mid = H / 2; // 回溯祖先链:chain[0]=顶级 ... chain[depth]=当前节点 const chain: number[] = [];