import { maskContactPhone } from './phone'; import { shanghaiYmd, startOfShanghaiDay } from './shanghai-date'; import { wecomReportPeriod, type WecomReportKind, type WecomReportPeriod } from './wecom-report'; export const WECOM_PLUGIN_PAGE_SIZE_DEFAULT = 5; export const WECOM_PLUGIN_PAGE_SIZE_MAX = 10; export const WECOM_PLUGIN_METRICS_KINDS = ['today', 'daily', 'weekly', 'monthly'] as const; export type WecomPluginMetricsKind = (typeof WECOM_PLUGIN_METRICS_KINDS)[number]; export type WecomPluginMetricsPeriod = Omit & { kind: WecomPluginMetricsKind; }; export function isWecomPluginMetricsKind(v: string): v is WecomPluginMetricsKind { return (WECOM_PLUGIN_METRICS_KINDS as readonly string[]).includes(v); } export function parseWecomPluginMetricsKind(raw?: string | null): WecomPluginMetricsKind | null { const v = String(raw ?? '').trim().toLowerCase(); if (!v) return 'today'; return isWecomPluginMetricsKind(v) ? v : null; } export function clampWecomPluginPageSize(raw?: string | number | null): number { const n = typeof raw === 'number' ? raw : Number(raw); if (!Number.isFinite(n) || n <= 0) return WECOM_PLUGIN_PAGE_SIZE_DEFAULT; return Math.min(WECOM_PLUGIN_PAGE_SIZE_MAX, Math.max(1, Math.floor(n))); } export function clampWecomPluginPage(raw?: string | number | null): number { const n = typeof raw === 'number' ? raw : Number(raw); if (!Number.isFinite(n) || n <= 0) return 1; return Math.min(100, Math.floor(n)); } /** 长度必须相同后再逐字符 XOR,避免短密码走快速失败路径时的明显差异(仍非密码学级) */ export function verifyWecomPluginApiKey(provided: string, expected?: string | null): boolean { const exp = String(expected ?? ''); const got = String(provided ?? ''); if (!exp || !got || exp.length !== got.length) return false; let diff = 0; for (let i = 0; i < exp.length; i++) { diff |= exp.charCodeAt(i) ^ got.charCodeAt(i); } return diff === 0; } export function isWecomPluginEnabled(env: { WECOM_PLUGIN_ENABLED?: string; WECOM_PLUGIN_API_KEY?: string; }): boolean { return env.WECOM_PLUGIN_ENABLED === 'true' && Boolean(String(env.WECOM_PLUGIN_API_KEY ?? '').trim()); } export function wecomPluginMetricsPeriod( kind: WecomPluginMetricsKind, now = new Date(), ): WecomPluginMetricsPeriod { if (kind === 'today') { const start = startOfShanghaiDay(now); const ymd = shanghaiYmd(start); return { kind, start, endExclusive: now, periodKey: ymd, title: `今日(${ymd})`, rangeLabel: ymd, incrementLabel: '今日新增', }; } const period = wecomReportPeriod(kind as WecomReportKind, now); return { ...period, kind }; } export function toWecomPluginUserView(user: { userNo: string; nickname?: string | null; phone?: string | null; }): { userNo: string; nickname: string; phone: string } { return { userNo: user.userNo, nickname: user.nickname?.trim() || '—', phone: maskContactPhone(user.phone), }; }