feat(admin): redesign GoodsView with dual-tree UX, filter bar, inline CRUD

- Two-line good nodes with country + tag chips, hover tooltip
- Resizable dual-tree with fixed-height panels (no node overlap)
- Filter bar: search, country filter, tag filter (multi-select with rename)
- Mode switch (品类/国家) pushed to right via spacer
- Inline create country/tag in edit & config modals via quick-create buttons
- Right tree node height auto-fix for locate highlight
- Filter dropdown styles in global scope for teleported popper
- Backend: multi-tag (GoodTag junction), goodImage column, origin goods tree API
- Admin response interceptor unwraps {data, success} envelope
- Simplified sidebar to single 商品管理 entry with tabs
- SyncView simplified to product sync only
This commit is contained in:
yeuimu
2026-06-22 01:47:20 +08:00
parent c3472a449b
commit a903dd4903
30 changed files with 1970 additions and 1209 deletions
@@ -13,6 +13,7 @@ export interface GoodRelations {
goodImage: string | null;
goodPrice: unknown;
} | null;
goodTags?: { tag: { id: bigint; tagName: string; tagColor: string | null } }[];
}
export class GoodDto {
@@ -22,6 +23,9 @@ export class GoodDto {
@ApiProperty()
goodName!: string;
@ApiProperty({ nullable: true })
goodImage!: string | null;
@ApiProperty()
goodPriority!: number;
@@ -55,6 +59,9 @@ export class GoodDto {
@ApiProperty({ required: false, nullable: true })
tag?: { id: string; tagName: string; tagColor: string | null } | null;
@ApiProperty({ required: false, type: Array })
tags!: Array<{ id: string; tagName: string; tagColor: string | null }>;
@ApiProperty({ required: false, nullable: true })
position?: { id: string; indexVal: number } | null;
@@ -74,6 +81,7 @@ export class GoodDto {
return {
id: good.id.toString(),
goodName: good.goodName,
goodImage: good.goodImage,
goodPriority: good.goodPriority,
countryId: good.countryId.toString(),
categoryId: good.categoryId.toString(),
@@ -103,6 +111,13 @@ export class GoodDto {
tagColor: rel.tag.tagColor,
}
: null,
tags: rel.goodTags
? rel.goodTags.map((gt) => ({
id: gt.tag.id.toString(),
tagName: gt.tag.tagName,
tagColor: gt.tag.tagColor,
}))
: [],
position: rel.position
? {
id: rel.position.id.toString(),
@@ -131,4 +146,4 @@ export interface PaginatedGoods {
total: number;
page: number;
pageSize: number;
}
}