(client: TelegramClient, userId: number)
| 870 | const dividend = divisor * quotient; |
| 871 | return { question: `${dividend} ÷ ${divisor}`, answer: String(quotient) }; |
| 872 | } |
| 873 | if (type === 4) { |
| 874 | const a = rand(2, 9), b = rand(2, 9), c = rand(1, 20); |
| 875 | return { question: `${a} × ${b} + ${c}`, answer: String(a * b + c) }; |
| 876 | } |
| 877 | const a = rand(2, 12); |
| 878 | return { question: `${a}²`, answer: String(a * a) }; |
| 879 | } |
| 880 | |
| 881 | const TEXT_QA: { question: string; answer: string }[] = [ |
| 882 | { question: "天空是什么颜色?(中文)", answer: "蓝色" }, |
| 883 | { question: "一周有几天?(数字)", answer: "7" }, |
| 884 | { question: "一年有几个月?(数字)", answer: "12" }, |
| 885 | { question: "猫叫声是?(中文拟声词)", answer: "喵" }, |
| 886 | { question: "水的化学式是?", answer: "h2o" }, |
| 887 | { question: "太阳从哪边升起?(东/西/南/北)", answer: "东" }, |
| 888 | { question: "地球上最大的洋是?(中文)", answer: "太平洋" }, |
| 889 | { question: "1 + 1 等于几?(数字)", answer: "2" }, |
| 890 | { question: "中国的首都是哪个城市?(中文)", answer: "北京" }, |
| 891 | { question: "一天有多少小时?(数字)", answer: "24" }, |
| 892 | { question: "人有几根手指?(数字)", answer: "10" }, |
| 893 | { question: "苹果是什么颜色的?(中文,常见色)", answer: "红色" }, |
| 894 | { question: "冰是什么状态的水?(固/液/气)", answer: "固" }, |
| 895 | { question: "地球围绕什么转?(中文)", answer: "太阳" }, |
| 896 | { question: "键盘上字母共有几个?(数字)", answer: "26" }, |
| 897 | ]; |
| 898 | |
| 899 | function textQuestion(): { question: string; answer: string } { |
| 900 | return TEXT_QA[Math.floor(Math.random() * TEXT_QA.length)]; |
| 901 | } |
| 902 | |
| 903 | async function sendCaptcha(client: TelegramClient, userId: number): Promise<void> { |
| 904 | const lifecycle = getActiveLifecycle(); |
| 905 | if (!lifecycle) return; |
| 906 | |
| 907 | const existing = removeCaptchaState(userId); |
| 908 | if (existing) { |
| 909 | await cleanupCaptchaMessages(client, userId, existing); |
| 910 | } |
| 911 | |
| 912 | const mode = cfg.mode(); |
| 913 | const timeout = cfg.timeout(); |
| 914 | const tries = cfg.maxTries(); |
| 915 | const actions = cfg.failActions(); |
| 916 | const custom = cfg.prompt(); |
| 917 | |
| 918 | const actionDesc = actions.length |
| 919 | ? actions.map(a => FAIL_ACTION_LABEL[a] ?? a).join("、") |
| 920 | : "仅归档并静音"; |
| 921 | |
| 922 | function buildFooter(): string { |
| 923 | const lines: string[] = []; |
| 924 | if (timeout > 0) lines.push(`⏱ 验证时间:<b>${htmlEscape(timeout)}</b> 秒`); |
| 925 | if (tries > 0) lines.push(`🔢 剩余次数:<b>${htmlEscape(tries)}</b> 次`); |
| 926 | lines.push(`⚠️ 验证失败将会:${htmlEscape(actionDesc)}`); |
| 927 | return lines.length ? "\n\n" + lines.join("\n") : ""; |
| 928 | } |
| 929 |
no test coverage detected