56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
/** 报名者项(mock 用 name,DB 用 nickname) */
|
||
export type JoinerItem = {
|
||
name?: string;
|
||
nickname?: string;
|
||
avatar?: string;
|
||
xiaohongshu_url?: string;
|
||
};
|
||
|
||
/** 去重 key:小红书 url 相同视为 1 人,无 url 时用 avatar,再 fallback nickname */
|
||
function dedupeKey(j: JoinerItem, useAvatarForMock: boolean): string {
|
||
const xh = (j.xiaohongshu_url || "").trim();
|
||
if (xh && !useAvatarForMock) return `xh:${xh}`;
|
||
const avatar = (j.avatar || "").trim();
|
||
if (avatar) return `av:${avatar}`;
|
||
return `_${(j.nickname || j.name || "").trim()}`;
|
||
}
|
||
|
||
/**
|
||
* 合并 mock 与数据库报名者:mock 固定 3 个在左,DB 在右
|
||
* 小红书 url 相同视为 1 人,avatar 相同也只显示 1 个
|
||
* 最多显示 8 个,保证 PC/H5 排版合理
|
||
*/
|
||
export function mergeJoiners(
|
||
mock: JoinerItem[],
|
||
db: JoinerItem[] | undefined
|
||
): JoinerItem[] {
|
||
const seen = new Set<string>();
|
||
const result: JoinerItem[] = [];
|
||
mock.forEach((j) => {
|
||
const key = dedupeKey(j, true);
|
||
if (!seen.has(key)) {
|
||
seen.add(key);
|
||
result.push(j);
|
||
}
|
||
});
|
||
(db || []).forEach((j) => {
|
||
const key = dedupeKey(j, false);
|
||
if (!seen.has(key)) {
|
||
seen.add(key);
|
||
result.push(j);
|
||
}
|
||
});
|
||
return result.slice(0, 8);
|
||
}
|
||
|
||
/** 数据库报名者按小红书 url 去重后的数量(用于显示报名人数) */
|
||
export function getUniqueDbCount(db: JoinerItem[] | undefined): number {
|
||
if (!db?.length) return 0;
|
||
const seen = new Set<string>();
|
||
for (const j of db) {
|
||
const key = dedupeKey(j, false);
|
||
seen.add(key);
|
||
}
|
||
return seen.size;
|
||
}
|