48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
const escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
|
const parseOptionalPositiveInt = (value: unknown, fieldName: string) => {
|
|
const raw = String(value ?? '').trim();
|
|
if (!raw) return { value: undefined as number | undefined };
|
|
|
|
if (!/^\d+$/.test(raw)) {
|
|
return { error: `${fieldName}必须是正整数` };
|
|
}
|
|
|
|
const parsed = Number(raw);
|
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
return { error: `${fieldName}必须大于0` };
|
|
}
|
|
|
|
return { value: parsed };
|
|
};
|
|
|
|
export const buildVocabularySummaryFilters = (query: Record<string, any>) => {
|
|
const studentNo = String(query.studentNo || '').trim();
|
|
const rawMinCorrectWords = query.minCorrectWords ?? query.minWords;
|
|
const wordCountResult = parseOptionalPositiveInt(rawMinCorrectWords, '正确单词数量');
|
|
if ('error' in wordCountResult) return { error: wordCountResult.error };
|
|
|
|
const minCorrectWords = wordCountResult.value;
|
|
const userMatchStages = studentNo
|
|
? [{
|
|
$match: {
|
|
'user.username': {
|
|
$regex: escapeRegex(studentNo),
|
|
$options: 'i'
|
|
}
|
|
}
|
|
}]
|
|
: [];
|
|
|
|
const baseMatch: Record<string, any> = {};
|
|
if (typeof minCorrectWords === 'number') {
|
|
baseMatch['stats.correctWords'] = { $gte: minCorrectWords };
|
|
}
|
|
|
|
return {
|
|
minCorrectWords,
|
|
userMatchStages,
|
|
baseMatch
|
|
};
|
|
};
|