feat: 更新SproutGate前后端代码

This commit is contained in:
2026-04-01 22:04:01 +08:00
parent 90590c7cb0
commit 650e1c7707
49 changed files with 3609 additions and 768 deletions

View File

@@ -0,0 +1,61 @@
/** 纯数字 @qq.com大小写不敏感→ QQ 号码,用于与后端一致的展示逻辑 */
export function qqUinFromEmail(email) {
if (!email || typeof email !== "string") return "";
const e = email.trim().toLowerCase();
const at = e.lastIndexOf("@");
if (at <= 0 || at >= e.length - 1) return "";
const local = e.slice(0, at);
const domain = e.slice(at + 1);
if (domain !== "qq.com" || !local) return "";
if (!/^\d+$/.test(local)) return "";
return local;
}
export function qqUinFromUser(user) {
if (!user || typeof user !== "object") return "";
const primary = qqUinFromEmail(user.email);
if (primary) return primary;
for (const em of user.secondaryEmails || []) {
const u = qqUinFromEmail(em);
if (u) return u;
}
return "";
}
/** 与后端 ResolvedAvatarURL 一致的三档 QQ CDN依次作为 img onError 回退) */
export function qqAvatarUrlCandidates(uin) {
if (!uin) return [];
return [
`https://q.qlogo.cn/headimg_dl?dst_uin=${encodeURIComponent(uin)}&spec=640&img_type=jpg`,
`https://q1.qlogo.cn/g?b=qq&nk=${encodeURIComponent(uin)}&s=100`,
`https://q2.qlogo.cn/headimg_dl?dst_uin=${encodeURIComponent(uin)}&spec=100`
];
}
export function placeholderAvatarUrl(size) {
return `https://dummyimage.com/${size}x${size}/ddd/fff&text=Avatar`;
}
/** 用于 <img src>:自选链接优先,否则 QQ 邮箱推断的多 CDN否则 API 下发的 avatarUrl最后占位图 */
export function avatarImageCandidates(user, placeholderSize = 120) {
const custom = (user?.customAvatarUrl != null && String(user.customAvatarUrl).trim()) || "";
if (custom) return [custom];
const uin = qqUinFromUser(user);
if (uin) return qqAvatarUrlCandidates(uin);
const resolved = (user?.avatarUrl != null && String(user.avatarUrl).trim()) || "";
if (resolved) return [resolved];
return [placeholderAvatarUrl(placeholderSize)];
}
export function resolveDisplayAvatarUrl(user, placeholderSize = 120) {
const c = avatarImageCandidates(user, placeholderSize);
return c[0] || placeholderAvatarUrl(placeholderSize);
}
export function avatarStatusLabel(user) {
const custom = (user?.customAvatarUrl != null && String(user.customAvatarUrl).trim()) || "";
if (custom) return "已设置";
if (qqUinFromUser(user)) return "QQ 邮箱头像";
return "未填写";
}