156 lines
4.4 KiB
TypeScript
156 lines
4.4 KiB
TypeScript
export type StoreCategoryLike = {
|
|
id?: string;
|
|
name?: string;
|
|
parentId?: string | null;
|
|
parent?: { name?: string } | null;
|
|
};
|
|
|
|
export type StoreCategoryTreeNode = {
|
|
id: string;
|
|
name: string;
|
|
children?: { id: string; name: string }[];
|
|
};
|
|
|
|
export function storeStarCount(rating?: number | string | null): number {
|
|
const n = Number(rating);
|
|
if (!Number.isFinite(n) || n <= 0) return 5;
|
|
return Math.min(5, Math.max(1, Math.round(n)));
|
|
}
|
|
|
|
export function storeCategoryTags(
|
|
store: {
|
|
tags?: unknown;
|
|
categoryId?: string | null;
|
|
category?: StoreCategoryLike | null;
|
|
categories?: StoreCategoryLike[] | null;
|
|
},
|
|
tree: StoreCategoryTreeNode[] = [],
|
|
): string[] {
|
|
const fromJson = Array.isArray(store.tags)
|
|
? store.tags.map((t) => String(t).trim()).filter(Boolean)
|
|
: [];
|
|
if (fromJson.length) return fromJson;
|
|
|
|
const multi = Array.isArray(store.categories) ? store.categories : [];
|
|
if (multi.length) {
|
|
return groupCategoryTags(multi, tree);
|
|
}
|
|
|
|
if (store.category || store.categoryId) {
|
|
const grouped = groupCategoryTags(
|
|
store.category ? [store.category] : [],
|
|
tree,
|
|
store.categoryId,
|
|
);
|
|
if (grouped.length) return grouped;
|
|
}
|
|
|
|
const storeCatId = String(store.categoryId || '');
|
|
if (storeCatId) {
|
|
for (const root of tree) {
|
|
for (const child of root.children ?? []) {
|
|
if (child.id === storeCatId) {
|
|
return [`${root.name}|${child.name}`];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return [];
|
|
}
|
|
|
|
/** 按大类分组:餐饮|火锅·江浙菜、娱乐|KTV */
|
|
function groupCategoryTags(
|
|
categories: StoreCategoryLike[],
|
|
tree: StoreCategoryTreeNode[] = [],
|
|
fallbackCategoryId?: string | null,
|
|
): string[] {
|
|
if (!categories.length && fallbackCategoryId) {
|
|
return groupCategoryTags([{ id: String(fallbackCategoryId) }], tree);
|
|
}
|
|
|
|
const groups = new Map<string, { parentName: string; children: string[] }>();
|
|
const order: string[] = [];
|
|
|
|
for (const cat of categories) {
|
|
const resolved = resolveCategoryParts(cat, tree);
|
|
if (!resolved) continue;
|
|
const { parentKey, parentName, childName } = resolved;
|
|
if (!groups.has(parentKey)) {
|
|
groups.set(parentKey, { parentName, children: [] });
|
|
order.push(parentKey);
|
|
}
|
|
const group = groups.get(parentKey)!;
|
|
if (childName && childName !== parentName && !group.children.includes(childName)) {
|
|
group.children.push(childName);
|
|
}
|
|
}
|
|
|
|
return order
|
|
.map((key) => {
|
|
const group = groups.get(key)!;
|
|
if (group.parentName && group.children.length) {
|
|
return `${group.parentName}|${group.children.join('·')}`;
|
|
}
|
|
if (group.children.length) return group.children.join('·');
|
|
return group.parentName;
|
|
})
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function resolveCategoryParts(
|
|
cat: StoreCategoryLike,
|
|
tree: StoreCategoryTreeNode[] = [],
|
|
): { parentKey: string; parentName: string; childName: string } | null {
|
|
const childName = String(cat.name || '').trim();
|
|
let parentName = String(cat.parent?.name || '').trim();
|
|
const catId = String(cat.id || '');
|
|
const parentId = String(cat.parentId || '');
|
|
|
|
if (!parentName && (parentId || catId)) {
|
|
for (const root of tree) {
|
|
if (parentId && root.id === parentId) {
|
|
parentName = root.name;
|
|
break;
|
|
}
|
|
for (const child of root.children ?? []) {
|
|
if (catId && child.id === catId) {
|
|
parentName = root.name;
|
|
if (!childName) return { parentKey: root.id, parentName, childName: child.name };
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!childName && !parentName) return null;
|
|
|
|
const parentKey = parentId || parentName || catId;
|
|
if (!parentName && catId) {
|
|
for (const root of tree) {
|
|
for (const child of root.children ?? []) {
|
|
if (child.id === catId) {
|
|
return { parentKey: root.id, parentName: root.name, childName: child.name };
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
parentKey,
|
|
parentName: parentName || childName,
|
|
childName: childName || parentName,
|
|
};
|
|
}
|
|
|
|
export function storeLeafCategoryIds(store: {
|
|
categoryId?: string | null;
|
|
category?: StoreCategoryLike | null;
|
|
categories?: StoreCategoryLike[] | null;
|
|
}): string[] {
|
|
if (Array.isArray(store.categories) && store.categories.length) {
|
|
return store.categories.map((c) => String(c.id || '')).filter(Boolean);
|
|
}
|
|
const id = String(store.categoryId || store.category?.id || '');
|
|
return id ? [id] : [];
|
|
}
|