feat: 产品列表页排序
- 为ProductType添加sort字段用于排序 - 产品列表页项目按照sort升序排序
This commit is contained in:
@ -19,6 +19,7 @@ export const useProductList = () => {
|
||||
{
|
||||
translations: ['id', 'name'],
|
||||
},
|
||||
'sort',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -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<ProductType>(raw.product_type)
|
||||
? raw.product_type.translations.length === 0
|
||||
? ''
|
||||
: raw.product_type.translations[0].name
|
||||
: '';
|
||||
? toProductTypeView(raw.product_type)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
id: raw.id,
|
||||
|
||||
@ -1,3 +1,13 @@
|
||||
/**
|
||||
* 产品类型视图模型
|
||||
* 用于产品列表页的section渲染与排序
|
||||
*/
|
||||
export interface ProductTypeView {
|
||||
id: number;
|
||||
name: string;
|
||||
sort: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 产品列表视图模型
|
||||
* 用于产品列表(/products)渲染的数据结构
|
||||
@ -13,7 +23,7 @@ export interface ProductListView {
|
||||
summary: string;
|
||||
|
||||
/** 产品类型 **/
|
||||
product_type: string;
|
||||
product_type: ProductTypeView;
|
||||
|
||||
/** 产品封面(图片的id) **/
|
||||
cover: string;
|
||||
|
||||
@ -8,14 +8,14 @@
|
||||
<div class="products-container">
|
||||
<el-collapse v-model="activeNames" class="product-collapse">
|
||||
<el-collapse-item
|
||||
v-for="(group, type) in groupedProducts"
|
||||
:key="type"
|
||||
:title="type || '未分类'"
|
||||
:name="type || 'no-category'"
|
||||
v-for="[key, value] in groupedProducts"
|
||||
:key="key"
|
||||
:title="key || '未分类'"
|
||||
:name="key || 'no-category'"
|
||||
>
|
||||
<div class="group-list">
|
||||
<product-card
|
||||
v-for="product in group"
|
||||
v-for="product in value.data"
|
||||
:key="product.id"
|
||||
:slug="product.id.toString()"
|
||||
:image-url="getImageUrl(product.cover.toString())"
|
||||
@ -51,25 +51,23 @@
|
||||
productsRaw.value.map((item) => toProductListView(item))
|
||||
);
|
||||
|
||||
logger.debug('products: ', products.value);
|
||||
|
||||
// 按类型分组
|
||||
// 兼容 product_type 既可能为对象也可能为字符串
|
||||
const groupedProducts = computed(() => {
|
||||
const groups: Record<string, ProductListView[]> = {};
|
||||
const groups: Record<string, { data: ProductListView[]; sort: number }> =
|
||||
{};
|
||||
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.entries(groups)
|
||||
.sort(([, a], [, b]) => a.sort - b.sort)
|
||||
.map(([key, value]) => [key, value]);
|
||||
return sortedGroups;
|
||||
});
|
||||
|
||||
watch(groupedProducts, () => {
|
||||
|
||||
Reference in New Issue
Block a user