fix(data): 清理旧数据并保护服务端写入

This commit is contained in:
Script Generator
2026-07-02 09:30:50 +08:00
parent 28e0c6de19
commit 916bd17a48
38 changed files with 1346 additions and 194 deletions

View File

@@ -1,3 +1,5 @@
import { pinyin } from 'pinyin-pro';
export interface Department {
id: string;
name: string;
@@ -9,6 +11,7 @@ export interface Department {
export interface Member {
id: string;
name: string;
username?: string;
departmentId: string;
roleId: string;
phone: string;
@@ -65,3 +68,62 @@ export function maskPhone(phone: string): string {
if (!phone || phone.length < 7) return phone;
return phone.slice(0, 3) + '****' + phone.slice(7);
}
export function normalizeUsername(username: string | undefined | null): string {
return (username ?? '').trim().replace(/\s+/g, '').toLowerCase();
}
function nameToUsernameBase(name: string): string {
const raw = name.trim();
if (!raw) return 'USER';
const letters = pinyin(raw, { toneType: 'none', type: 'array' })
.join('')
.replace(/[^a-zA-Z0-9]/g, '')
.toLowerCase();
return letters || 'USER';
}
function duplicateSuffix(attempt: number): string {
return attempt === 1 ? '1' : `${'0'.repeat(attempt - 1)}1`;
}
function uniqueUsernameFromBase(base: string, existingUsernames: Iterable<string>): string {
const normalizedBase = normalizeUsername(base) || 'USER';
const used = new Set(Array.from(existingUsernames, normalizeUsername).filter(Boolean));
if (!used.has(normalizedBase)) return normalizedBase;
for (let attempt = 1; attempt < 1000; attempt += 1) {
const candidate = `${normalizedBase}${duplicateSuffix(attempt)}`;
if (!used.has(candidate)) return candidate;
}
return `${normalizedBase}${Date.now()}`;
}
export function generateUsernameFromName(
name: string,
existingUsernames: Iterable<string>,
currentUsername?: string,
): string {
const normalizedCurrent = normalizeUsername(currentUsername);
if (normalizedCurrent) return normalizedCurrent;
return uniqueUsernameFromBase(nameToUsernameBase(name), existingUsernames);
}
export function ensureMemberUsernames(members: Member[]): { members: Member[]; changed: boolean } {
const used = new Set<string>();
let changed = false;
const normalizedMembers = members.map((member) => {
const requested = normalizeUsername(member.username);
const username = requested
? uniqueUsernameFromBase(requested, used)
: generateUsernameFromName(member.name, used);
used.add(username);
if (member.username === username) return member;
changed = true;
return { ...member, username };
});
return { members: normalizedMembers, changed };
}