diff --git a/app/composables/directus/useProductList.ts b/app/composables/directus/useProductList.ts index 273b5d6..989c88d 100644 --- a/app/composables/directus/useProductList.ts +++ b/app/composables/directus/useProductList.ts @@ -19,6 +19,7 @@ export const useProductList = () => { { translations: ['id', 'name'], }, + 'sort', ], }, ], diff --git a/app/composables/directus/useSolutionList.ts b/app/composables/directus/useSolutionList.ts index 030e272..8fe659f 100644 --- a/app/composables/directus/useSolutionList.ts +++ b/app/composables/directus/useSolutionList.ts @@ -12,7 +12,7 @@ export const useSolutionList = () => { 'id', 'cover', { - type: ['id', { translations: ['id', 'name'] }], + type: ['id', { translations: ['id', 'name'] }, 'sort'], }, { translations: ['id', 'title', 'summary'], diff --git a/app/models/mappers/productMapper.test.ts b/app/models/mappers/productMapper.test.ts index 177641a..1e996f0 100644 --- a/app/models/mappers/productMapper.test.ts +++ b/app/models/mappers/productMapper.test.ts @@ -14,6 +14,7 @@ describe('toProductListView', () => { product_type: { id: 1, translations: [{ id: 20, name: 'Type Name' }], + sort: 1, }, }; @@ -22,7 +23,11 @@ describe('toProductListView', () => { name: 'Product Name', summary: 'Product Summary', cover: 'cover-file-uuid-1234', - product_type: 'Type Name', + product_type: { + id: 1, + name: 'Type Name', + sort: 1, + }, }); }); @@ -34,6 +39,7 @@ describe('toProductListView', () => { product_type: { id: 20, translations: [], + sort: 1, }, }; @@ -42,7 +48,11 @@ describe('toProductListView', () => { name: '', summary: '', cover: 'cover-file-uuid-1234', - product_type: '', + product_type: { + id: 20, + name: '', + sort: 1, + }, }); }); }); diff --git a/app/models/mappers/productMapper.ts b/app/models/mappers/productMapper.ts index 9597c49..724faff 100644 --- a/app/models/mappers/productMapper.ts +++ b/app/models/mappers/productMapper.ts @@ -1,3 +1,22 @@ +/** + * 将Directus返回的ProductType数据转换为ProductTypeView视图模型 + * + * @param raw: 原始的ProductType数据 + * @returns 转换后的ProductTypeView对象 + * + * @example + * const view = toProductTypeView(rawProductType); + */ +export function toProductTypeView(raw: ProductType): ProductTypeView { + const trans = raw.translations?.[0] ?? { name: '' }; + + return { + id: raw.id, + name: trans.name, + sort: raw?.sort ?? 999, + }; +} + /** * 将 Directus返回的 Product 数据转换为 ProductListView 视图模型 * @@ -11,10 +30,8 @@ export function toProductListView(raw: Product): ProductListView { const trans = raw.translations?.[0] ?? { name: '', summary: '' }; const type = isObject(raw.product_type) - ? raw.product_type.translations.length === 0 - ? '' - : raw.product_type.translations[0].name - : ''; + ? toProductTypeView(raw.product_type) + : undefined; return { id: raw.id, diff --git a/app/models/mappers/solutionMapper.test.ts b/app/models/mappers/solutionMapper.test.ts index 1850d47..743414f 100644 --- a/app/models/mappers/solutionMapper.test.ts +++ b/app/models/mappers/solutionMapper.test.ts @@ -13,6 +13,7 @@ describe('toSolutionListView', () => { type: { id: 1, translations: [{ id: 1, name: 'Type Name' }], + sort: 1, }, }; @@ -20,7 +21,11 @@ describe('toSolutionListView', () => { id: 1, title: 'Solution Title', summary: 'Solution Summary', - solution_type: 'Type Name', + solution_type: { + id: 1, + name: 'Type Name', + sort: 1, + }, }); }); @@ -31,6 +36,7 @@ describe('toSolutionListView', () => { type: { id: 1, translations: [], + sort: null, }, }; @@ -38,7 +44,11 @@ describe('toSolutionListView', () => { id: 1, title: '', summary: '', - solution_type: '', + solution_type: { + id: 1, + name: '', + sort: 999, + }, }); }); }); diff --git a/app/models/mappers/solutionMapper.ts b/app/models/mappers/solutionMapper.ts index baf1694..d869024 100644 --- a/app/models/mappers/solutionMapper.ts +++ b/app/models/mappers/solutionMapper.ts @@ -1,3 +1,24 @@ +/** + * 将 Directus 返回的 SolutionType 数据转换为 SolutionTypeView 视图模型 + * + * @param raw: 原始的 SolutionType 数据 + * @returns 转换后的 SolutionTypeView 对象 + * + * --- + * + * @example + * const view = toSolutionTypeView(rawSolutionType); + */ +export function toSolutionTypeView(raw: SolutionType): SolutionTypeView { + const trans = raw.translations?.[0] ?? { name: '' }; + + return { + id: raw.id, + name: trans.name, + sort: raw?.sort ?? 999, + }; +} + /** * 将 Directus 返回的 Solution 数据转换为 SolutionListView 视图模型 * @@ -16,10 +37,8 @@ export function toSolutionListView(raw: Solution): SolutionListView { }; const type = isObject(raw.type) - ? raw.type.translations.length === 0 - ? '' - : raw.type.translations[0].name - : ''; + ? toSolutionTypeView(raw.type) + : undefined; return { id: raw.id, diff --git a/app/models/views/ProductListView.ts b/app/models/views/ProductListView.ts index 14912fe..b8511da 100644 --- a/app/models/views/ProductListView.ts +++ b/app/models/views/ProductListView.ts @@ -1,3 +1,18 @@ +/** + * 产品类型视图模型 + * 用于产品列表页的section渲染与排序 + */ +export interface ProductTypeView { + /** 唯一标识符 **/ + id: number; + + /** 类型名 **/ + name: string; + + /** 排序字段 **/ + sort: number; +} + /** * 产品列表视图模型 * 用于产品列表(/products)渲染的数据结构 @@ -13,7 +28,7 @@ export interface ProductListView { summary: string; /** 产品类型 **/ - product_type: string; + product_type: ProductTypeView; /** 产品封面(图片的id) **/ cover: string; diff --git a/app/models/views/SolutionListView.ts b/app/models/views/SolutionListView.ts index fa41cfe..b688271 100644 --- a/app/models/views/SolutionListView.ts +++ b/app/models/views/SolutionListView.ts @@ -1,3 +1,18 @@ +/** + * 解决方案类型视图模型 + * 用于解决方案列表页标签栏的渲染与排序 + */ +export interface SolutionTypeView { + /** 唯一标识符 **/ + id: number; + + /** 类型名 **/ + name: string; + + /** 排序字段 **/ + sort: number; +} + /** * 解决方案列表模型 * 用于解决方案列表(/solutions)渲染的数据结构 @@ -13,7 +28,7 @@ export interface SolutionListView { summary: string; /** 解决方案类型 **/ - solution_type: string; + solution_type: SolutionTypeView; /** 解决方案封面(图片id) **/ cover: string; diff --git a/app/pages/products/index.vue b/app/pages/products/index.vue index 28babe7..57cfa31 100644 --- a/app/pages/products/index.vue +++ b/app/pages/products/index.vue @@ -8,14 +8,14 @@
toProductListView(item)) ); + logger.debug('products: ', products.value); + // 按类型分组 - // 兼容 product_type 既可能为对象也可能为字符串 const groupedProducts = computed(() => { - const groups: Record = {}; + const groups: Record = + {}; for (const prod of products.value) { - let typeKey = ''; - if (typeof prod.product_type === 'string') { - typeKey = prod.product_type; - } else if ( - prod.product_type && - typeof prod.product_type === 'object' && - 'name' in prod.product_type - ) { - typeKey = prod.product_type || ''; + const typeKey = prod.product_type?.name ?? ''; + if (!groups[typeKey]) { + groups[typeKey] = { data: [], sort: prod.product_type?.sort ?? 999 }; } - if (!groups[typeKey]) groups[typeKey] = []; - groups[typeKey]?.push(prod); + groups[typeKey]?.data.push(prod); } - return groups; + const sortedGroups = Object.fromEntries( + Object.entries(groups).sort(([, a], [, b]) => a.sort - b.sort) + ); + return sortedGroups; }); watch(groupedProducts, () => { diff --git a/app/pages/solutions/index.vue b/app/pages/solutions/index.vue index 24f293d..33bf637 100644 --- a/app/pages/solutions/index.vue +++ b/app/pages/solutions/index.vue @@ -19,14 +19,14 @@
{ - const gourps: Record = {}; + const groups: Record = + {}; for (const sol of solutions.value) { - let typeKey = ''; - if (typeof sol.solution_type === 'string') { - typeKey = sol.solution_type; - } else if ( - sol.solution_type && - typeof sol.solution_type === 'object' && - 'type' in sol.solution_type - ) { - typeKey = sol.solution_type || ''; + const typeKey = sol.solution_type?.name ?? ''; + if (!groups[typeKey]) { + groups[typeKey] = { data: [], sort: sol.solution_type?.sort ?? 999 }; } - if (!gourps[typeKey]) gourps[typeKey] = []; - gourps[typeKey]?.push(sol); + groups[typeKey]?.data.push(sol); } - return gourps; + const sortedGroups = Object.fromEntries( + Object.entries(groups).sort(([, a], [, b]) => a.sort - b.sort) + ); + return sortedGroups; }); watch(error, (value) => { diff --git a/shared/types/directus/my-schema.ts b/shared/types/directus/my-schema.ts index e7c279d..0d4c1b0 100644 --- a/shared/types/directus/my-schema.ts +++ b/shared/types/directus/my-schema.ts @@ -142,6 +142,7 @@ export interface ProductType { id: number; /** @description 当前产品条目的状态 */ status?: 'published' | 'draft' | 'archived'; + sort?: number | null; /** @description i18n文本 */ translations?: ProductTypesTranslation[] | null; } @@ -231,6 +232,7 @@ export interface SolutionType { /** @primaryKey */ id: number; status?: 'published' | 'draft' | 'archived'; + sort?: number | null; /** @description i18n字段 */ translations?: SolutionTypesTranslation[] | null; }