From 71233b671504dc349d52f450291899be11a1e10a Mon Sep 17 00:00:00 2001 From: liangxu Date: Wed, 8 Jul 2026 21:48:20 +0800 Subject: [PATCH] feat(brand): add brand sort order and drag-to-reorder Add a sort_order column to brands with a migration, expose a PUT /api/tenant/brands/order reorder endpoint, and wire the admin-web BrandsView with drag-and-drop reordering plus i18n. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/admin-web/src/i18n/messages/en-US.ts | 10 + apps/admin-web/src/i18n/messages/zh-CN.ts | 10 + apps/admin-web/src/lib/api.ts | 4 + apps/admin-web/src/stores/company.ts | 10 +- apps/admin-web/src/views/BrandsView.vue | 376 +++++++++++++++++- packages/shared-types/src/index.ts | 5 + server/internal/tenant/app/brand_service.go | 139 ++++++- server/internal/tenant/domain/brand.go | 1 + .../tenant/repository/generated/brand.sql.go | 27 +- .../tenant/repository/generated/models.go | 1 + .../tenant/repository/queries/brand.sql | 12 +- .../tenant/transport/brand_handler.go | 14 + server/internal/tenant/transport/router.go | 1 + .../internal/tenant/transport/router_test.go | 1 + ...260708110000_add_brand_sort_order.down.sql | 4 + ...20260708110000_add_brand_sort_order.up.sql | 24 ++ 16 files changed, 608 insertions(+), 31 deletions(-) create mode 100644 server/migrations/20260708110000_add_brand_sort_order.down.sql create mode 100644 server/migrations/20260708110000_add_brand_sort_order.up.sql diff --git a/apps/admin-web/src/i18n/messages/en-US.ts b/apps/admin-web/src/i18n/messages/en-US.ts index eaaeb69..616e515 100644 --- a/apps/admin-web/src/i18n/messages/en-US.ts +++ b/apps/admin-web/src/i18n/messages/en-US.ts @@ -1494,10 +1494,20 @@ const enUS = { competitorLines: 'Product lines', competitorLinesHint: 'Separate multiple product lines with commas.', }, + order: { + eyebrow: 'Display Order', + title: 'Company display order', + adjust: 'Adjust order', + done: 'Done', + dragHandle: 'Drag to reorder', + moveUp: 'Move up', + moveDown: 'Move down', + }, messages: { createBrand: 'Brand created.', updateBrand: 'Brand updated.', deleteBrand: 'Brand deleted.', + reorderBrand: 'Company display order updated.', createKeyword: 'Keyword created.', updateKeyword: 'Keyword updated.', deleteKeyword: 'Keyword deleted.', diff --git a/apps/admin-web/src/i18n/messages/zh-CN.ts b/apps/admin-web/src/i18n/messages/zh-CN.ts index 2a48c53..1ef1f7f 100644 --- a/apps/admin-web/src/i18n/messages/zh-CN.ts +++ b/apps/admin-web/src/i18n/messages/zh-CN.ts @@ -1430,10 +1430,20 @@ const zhCN = { competitorLines: '重点产品线', competitorLinesHint: '使用英文逗号分隔多个产品线', }, + order: { + eyebrow: '排序', + title: '公司展示顺序', + adjust: '调整排序', + done: '完成', + dragHandle: '拖动排序', + moveUp: '上移', + moveDown: '下移', + }, messages: { createBrand: '品牌已创建', updateBrand: '品牌已更新', deleteBrand: '品牌已删除', + reorderBrand: '公司展示顺序已更新', createKeyword: '关键词已创建', updateKeyword: '关键词已更新', deleteKeyword: '关键词已删除', diff --git a/apps/admin-web/src/lib/api.ts b/apps/admin-web/src/lib/api.ts index bd13d2b..337e1cf 100644 --- a/apps/admin-web/src/lib/api.ts +++ b/apps/admin-web/src/lib/api.ts @@ -10,6 +10,7 @@ import type { AuthTokens, Brand, BrandLibrarySummary, + BrandReorderRequest, BrandRequest, ChangePasswordRequest, ClassifiedQuestion, @@ -1158,6 +1159,9 @@ export const brandsApi = { remove(id: number) { return apiClient.remove(`/api/tenant/brands/${id}`) }, + reorder(payload: BrandReorderRequest) { + return apiClient.put('/api/tenant/brands/order', payload) + }, listKeywords(brandId: number) { return apiClient.get(`/api/tenant/brands/${brandId}/keywords`) }, diff --git a/apps/admin-web/src/stores/company.ts b/apps/admin-web/src/stores/company.ts index 6114684..f715c76 100644 --- a/apps/admin-web/src/stores/company.ts +++ b/apps/admin-web/src/stores/company.ts @@ -59,8 +59,7 @@ export const useCompanyStore = defineStore('company', () => { loading.value = true try { const nextBrands = normalizeBrandList(await brandsApi.list()) - brands.value = nextBrands - syncCurrentBrand(nextBrands) + setBrands(nextBrands) initialized.value = true return nextBrands } finally { @@ -68,6 +67,12 @@ export const useCompanyStore = defineStore('company', () => { } } + function setBrands(value: Brand[] | null | undefined): void { + const nextBrands = normalizeBrandList(value) + brands.value = nextBrands + syncCurrentBrand(nextBrands) + } + function reset(): void { brands.value = [] currentBrandId.value = null @@ -84,6 +89,7 @@ export const useCompanyStore = defineStore('company', () => { loading, initialized, refreshBrands, + setBrands, setCurrentBrand, reset, } diff --git a/apps/admin-web/src/views/BrandsView.vue b/apps/admin-web/src/views/BrandsView.vue index 0f60930..e551855 100644 --- a/apps/admin-web/src/views/BrandsView.vue +++ b/apps/admin-web/src/views/BrandsView.vue @@ -1,7 +1,12 @@