{"id":365,"date":"2026-01-22T10:55:01","date_gmt":"2026-01-22T10:55:01","guid":{"rendered":"https:\/\/huicheng.dpdns.org\/?page_id=365"},"modified":"2026-02-25T07:23:09","modified_gmt":"2026-02-25T07:23:09","slug":"global-sim-sms-service","status":"publish","type":"page","link":"https:\/\/huicheng.dpdns.org\/?page_id=365","title":{"rendered":"Global SIM SMS service"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"365\" class=\"elementor elementor-365\">\n\t\t\t\t<div class=\"elementor-element elementor-element-efca3f6 e-flex e-con-boxed e-con e-parent\" data-id=\"efca3f6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-545af74 elementor-widget elementor-widget-html\" data-id=\"545af74\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div style=\"border:1px solid #ddd;padding:16px;border-radius:10px;max-width:1180px;width:100%;box-sizing:border-box;\">\r\n  <h3 style=\"margin-top:0;\">\u83b7\u53d6\u53f7\u7801 (Get Number)<\/h3>\r\n\r\n  <div id=\"hs_login_tip\" style=\"display:none;padding:10px;border:1px solid #f0c;border-radius:8px;background:#fff5fb;margin:8px 0;\">\r\n    \u4f60\u5f53\u524d\u672a\u767b\u5f55\uff0c\u8bf7\u5148\u767b\u5f55\u540e\u5237\u65b0\u9875\u9762\u3002\r\n  <\/div>\r\n\r\n  <div style=\"display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:8px 0;\">\r\n    <b>\u7528\u6237\uff1a<\/b><span id=\"hs_user\">\u52a0\u8f7d\u4e2d...<\/span>\r\n    <b style=\"margin-left:10px;\">\u4f59\u989d\uff1a<\/b><span id=\"hs_balance\">$0.00<\/span>\r\n    <button id=\"hs_refresh_boot\" type=\"button\">\u5237\u65b0\u767b\u5f55\u4fe1\u606f<\/button>\r\n  <\/div>\r\n\r\n  <div style=\"display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:8px 0;\">\r\n    <label>\u670d\u52a1(service)\uff1a<\/label>\r\n    <select id=\"hs_service\" style=\"min-width:360px;flex:1;max-width:520px;\">\r\n      <option value=\"\">\u6b63\u5728\u52a0\u8f7d\u670d\u52a1...<\/option>\r\n    <\/select>\r\n\r\n    <label style=\"margin-left:6px;\">\u81ea\u5b9a\u4e49code\uff1a<\/label>\r\n    <input id=\"hs_service_custom\" placeholder=\"\u53ef\u7559\u7a7a\uff08\u4f18\u5148\u7528\u4e0b\u62c9\uff09\" style=\"width:200px;max-width:240px;\">\r\n\r\n    <label style=\"margin-left:6px;white-space:nowrap;\">\r\n      <input type=\"checkbox\" id=\"hs_show_all\">\r\n      \u663e\u793a\u65e0\u5e93\u5b58\u56fd\u5bb6\uff08\u5168\u91cf\uff09\r\n    <\/label>\r\n\r\n    <button id=\"hs_load_btn\" type=\"button\" style=\"min-width:110px;white-space:nowrap;\">\u52a0\u8f7d\u56fd\u5bb6<\/button>\r\n  <\/div>\r\n\r\n  <div style=\"display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:8px 0;\">\r\n    <label>\u56fd\u5bb6(country)\uff1a<\/label>\r\n    <select id=\"hs_country\" style=\"min-width:520px;flex:1;\">\r\n      <option value=\"\">\u5148\u52a0\u8f7d\u56fd\u5bb6<\/option>\r\n    <\/select>\r\n\r\n    <label style=\"margin-left:6px;white-space:nowrap;\">\u6570\u91cf\uff1a<\/label>\r\n    <input id=\"hs_qty\" type=\"number\" min=\"1\" max=\"20\" value=\"1\" style=\"width:90px;\">\r\n\r\n    <button id=\"hs_order_btn\" type=\"button\" disabled>\u4e0b\u5355\u4e70\u53f7\uff08\u81ea\u52a8\u8f6e\u8be2\uff09<\/button>\r\n  <\/div>\r\n\r\n  <!-- \u2705 \u8fd9\u4e00\u884c\u4fdd\u7559\uff1a\u7528\u4e8e\u201c\u4ec5\u8f6e\u8be2\u6b64ID \/ \u505c\u6b62\u6b64ID \/ \u505c\u6b62\u5168\u90e8\u8f6e\u8be2\u201d -->\r\n  <div style=\"display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:8px 0;\">\r\n    <label>\u6fc0\u6d3bID(id)\uff1a<\/label>\r\n    <input id=\"hs_id\" value=\"\" style=\"width:220px;\" placeholder=\"\u4ece\u8ba2\u5355\u5217\u8868\u9009\u62e9\/\u590d\u5236\">\r\n    <button id=\"hs_poll_one_btn\" type=\"button\" disabled>\u4ec5\u8f6e\u8be2\u6b64ID<\/button>\r\n    <button id=\"hs_stop_one_btn\" type=\"button\" disabled>\u505c\u6b62\u6b64ID<\/button>\r\n    <button id=\"hs_stop_all_btn\" type=\"button\">\u505c\u6b62\u5168\u90e8\u8f6e\u8be2<\/button>\r\n  <\/div>\r\n\r\n  <div id=\"hs_orders_box\" style=\"border:1px dashed #ccc;padding:10px;border-radius:8px;margin:10px 0;background:#fafafa;\">\r\n    <div style=\"display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;\">\r\n      <b>\u5df2\u4e0b\u5355\u53f7\u7801\u5217\u8868\uff08\u652f\u6301\u591a\u4e2a\uff0c\u81ea\u52a8\u83b7\u53d6\u9a8c\u8bc1\u7801\uff09<\/b>\r\n      <div style=\"display:flex;gap:8px;flex-wrap:wrap;\">\r\n        <button id=\"hs_clear_orders\" type=\"button\">\u6e05\u7a7a\u8ba2\u5355<\/button>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div id=\"hs_orders_list\" style=\"margin-top:8px;\"><\/div>\r\n\r\n    <div style=\"font-size:12px;color:#666;margin-top:6px;\">\r\n      \u8bf4\u660e\uff1a\u6bcf\u4e2a\u8ba2\u5355\u90fd\u4f1a\u81ea\u52a8\u8f6e\u8be2\uff1b\u6536\u5230\u9a8c\u8bc1\u7801\u4e0d\u4f1a\u505c\u6b62\uff08\u652f\u630120\u5206\u949f\u5185\u91cd\u590d\u83b7\u53d6\u6700\u65b0\u9a8c\u8bc1\u7801\uff09\u3002\u53d6\u6d88\u8ba2\u5355\u9700\u7b49\u5f85 2 \u5206\u949f\u3002<br>\r\n      \uff0820\u5206\u949f\u672a\u51fa\u7801\uff1a\u7cfb\u7edf\u5c06\u81ea\u52a8\u53d6\u6d88\u5e76\u9000\u6b3e\uff1b\u51fa\u4efb\u610f\u9a8c\u8bc1\u7801\u5373\u6210\u4ea4\u4e0d\u9000\u6b3e\u3002\uff09\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <pre id=\"hs_out\" style=\"white-space:pre-wrap;background:#f7f7f7;padding:10px;border-radius:6px;display:none;\"><\/pre>\r\n<\/div>\r\n\r\n<script>\r\n(function() {\r\n  let API_BASE = (window.location.origin || '') + '\/wp-json\/herosms\/v1';\r\n\r\n  let USER_ID = 0;\r\n  let BALANCE = 0;\r\n  let SYMBOL = '$';\r\n\r\n  let AJAX_URL = (window.location.origin || '') + '\/wp-admin\/admin-ajax.php';\r\n  let AJAX_NONCE = '';\r\n\r\n  const out = document.getElementById('hs_out');\r\n  const tip = document.getElementById('hs_login_tip');\r\n  const userEl = document.getElementById('hs_user');\r\n  const balEl = document.getElementById('hs_balance');\r\n  const bootBtn = document.getElementById('hs_refresh_boot');\r\n\r\n  const serviceEl = document.getElementById('hs_service');\r\n  const serviceCustomEl = document.getElementById('hs_service_custom');\r\n  const showAllEl = document.getElementById('hs_show_all');\r\n\r\n  const countryEl = document.getElementById('hs_country');\r\n  const qtyEl = document.getElementById('hs_qty');\r\n  const idEl = document.getElementById('hs_id');\r\n\r\n  const loadBtn = document.getElementById('hs_load_btn');\r\n  const orderBtn = document.getElementById('hs_order_btn');\r\n\r\n  const pollOneBtn = document.getElementById('hs_poll_one_btn');\r\n  const stopOneBtn = document.getElementById('hs_stop_one_btn');\r\n  const stopAllBtn = document.getElementById('hs_stop_all_btn');\r\n\r\n  const ordersListEl = document.getElementById('hs_orders_list');\r\n  const clearOrdersBtn = document.getElementById('hs_clear_orders');\r\n\r\n  let countryNameMap = {};\r\n  let servicesNameMap = {};\r\n  const pollers = {};\r\n  const LS_KEY = 'herosms_orders_v1';\r\n\r\n  const LS_CLEARED_AT = 'herosms_orders_cleared_at_v1';\r\n  function getClearedAt(){ return parseInt(localStorage.getItem(LS_CLEARED_AT) || '0', 10) || 0; }\r\n  function setClearedAt(){ localStorage.setItem(LS_CLEARED_AT, String(Date.now())); }\r\n\r\n  \/\/ \u2705 \u6bcf\u535520\u5206\u949f\u81ea\u52a8\u53d6\u6d88\uff08\u9875\u9762\u6253\u5f00\u65f6\u751f\u6548\uff1b\u540e\u7aef\u5e94\u6709\u515c\u5e95\uff09\r\n  const AUTO_CANCEL_MS = 20 * 60 * 1000;\r\n  const AUTO_CANCEL_SCAN_MS = 10 * 1000;\r\n\r\n  const FEATURED = [\r\n    {code:'tg', name:'Telegram'},\r\n    {code:'ig', name:'Instagram \/ Threads'},\r\n    {code:'fb', name:'Facebook'},\r\n    {code:'wa', name:'WhatsApp'},\r\n    {code:'tw', name:'Twitter \/ X'},\r\n    {code:'lf', name:'TikTok \/ Douyin'},\r\n    {code:'ds', name:'Discord'},\r\n    {code:'wb', name:'WeChat'},\r\n    {code:'qf', name:'RedBook \/ \u5c0f\u7ea2\u4e66'},\r\n    {code:'am', name:'Amazon'},\r\n    {code:'mm', name:'Microsoft'},\r\n    {code:'wx', name:'Apple'},\r\n    {code:'nf', name:'Netflix'},\r\n    {code:'ts', name:'PayPal'},\r\n    {code:'ot', name:'Any other'},\r\n  ];\r\n\r\n  function show(obj) {\r\n    if (!out) return;\r\n    out.textContent = (typeof obj === 'string') ? obj : JSON.stringify(obj, null, 2);\r\n  }\r\n\r\n  function setLoginUI() {\r\n    if (USER_ID > 0) {\r\n      tip.style.display = 'none';\r\n      userEl.textContent = 'UID=' + USER_ID;\r\n      balEl.textContent = SYMBOL + (Number(BALANCE || 0).toFixed(2));\r\n    } else {\r\n      tip.style.display = 'block';\r\n      userEl.textContent = '\u672a\u767b\u5f55';\r\n      balEl.textContent = SYMBOL + '0.00';\r\n    }\r\n  }\r\n\r\n  function getServiceCode() {\r\n    const c = (serviceCustomEl.value || '').trim();\r\n    return c ? c : (serviceEl.value || '').trim();\r\n  }\r\n\r\n  function apiUrl(endpoint, params) {\r\n    endpoint = String(endpoint || '').replace(\/^\\\/+\/, '');\r\n    params = params || {};\r\n\r\n    if (String(API_BASE).includes('rest_route=')) {\r\n      const u = new URL(API_BASE, window.location.origin);\r\n      const rr = (u.searchParams.get('rest_route') || '').replace(\/\\\/+$\/, '');\r\n      u.searchParams.set('rest_route', rr + '\/' + endpoint);\r\n      Object.keys(params).forEach(k => u.searchParams.set(k, params[k]));\r\n      return u.toString();\r\n    }\r\n\r\n    const base = String(API_BASE).replace(\/\\\/+$\/, '');\r\n    const url = base + '\/' + endpoint;\r\n    const qs = new URLSearchParams(params).toString();\r\n    return qs ? (url + '?' + qs) : url;\r\n  }\r\n\r\n  async function fetchPublicJson(url) {\r\n    const res = await fetch(url, {\r\n      credentials: 'omit',\r\n      cache: 'no-store',\r\n      headers: { 'Accept': 'application\/json' }\r\n    });\r\n    const text = await res.text();\r\n    let json = null;\r\n    try { json = JSON.parse(text); } catch(e) {}\r\n    return { ok: res.ok, status: res.status, text, json };\r\n  }\r\n\r\n  async function fetchAjax(action, dataObj) {\r\n    const body = new URLSearchParams();\r\n    body.set('action', action);\r\n    body.set('nonce', AJAX_NONCE || '');\r\n    Object.keys(dataObj || {}).forEach(k => body.set(k, dataObj[k]));\r\n\r\n    const res = await fetch(AJAX_URL, {\r\n      method: 'POST',\r\n      credentials: 'same-origin',\r\n      cache: 'no-store',\r\n      headers: { 'Content-Type': 'application\/x-www-form-urlencoded; charset=UTF-8' },\r\n      body: body.toString()\r\n    });\r\n\r\n    const text = await res.text();\r\n    let json = null;\r\n    try { json = JSON.parse(text); } catch(e) {}\r\n\r\n    return { ok: res.ok, status: res.status, json, textPreview: String(text || '').slice(0, 2000) };\r\n  }\r\n\r\n  async function bootstrap() {\r\n    const url = (window.location.origin || '') + '\/wp-admin\/admin-ajax.php?action=herosms_bootstrap&_t=' + Date.now();\r\n    const res = await fetch(url, { credentials:'same-origin', cache:'no-store' });\r\n    const text = await res.text();\r\n    let j = null;\r\n    try { j = JSON.parse(text); } catch(e) {}\r\n\r\n    if (!res.ok || !j || !j.ok) {\r\n      USER_ID = 0; BALANCE=0; SYMBOL='$';\r\n      setLoginUI();\r\n      return false;\r\n    }\r\n\r\n    API_BASE = j.rest_base || API_BASE;\r\n    USER_ID = j.user_id || 0;\r\n    BALANCE = j.balance || 0;\r\n    SYMBOL = j.symbol || '$';\r\n    AJAX_URL = j.ajax_url || AJAX_URL;\r\n    AJAX_NONCE = j.ajax_nonce || '';\r\n\r\n    setLoginUI();\r\n    return true;\r\n  }\r\n\r\n  \/\/ \u2705 \u5173\u952e\uff1a\u6e05\u7406\u7a7a\u5305\u8ba2\u5355\uff08Unknown \u6839\u56e0\uff09\r\n  function isValidOrder(o){\r\n    if (!o) return false;\r\n    const id = String(o.activationId || '').trim();\r\n    if (!id || !\/^\\d+$\/.test(id)) return false;\r\n    if (!o.service || !String(o.service).trim()) return false;\r\n    if (o.country === undefined || o.country === null || String(o.country).trim() === '') return false;\r\n\r\n    const clearedAt = getClearedAt();\r\n    if (clearedAt > 0 && o.time && Number(o.time) < clearedAt) return false;\r\n\r\n    return true;\r\n  }\r\n  function sanitizeOrders(arr){ return (Array.isArray(arr) ? arr : []).filter(isValidOrder); }\r\n\r\n  function loadOrders() {\r\n    try {\r\n      const raw = JSON.parse(localStorage.getItem(LS_KEY) || '[]');\r\n      const clean = sanitizeOrders(raw);\r\n      if (Array.isArray(raw) && clean.length !== raw.length) {\r\n        localStorage.setItem(LS_KEY, JSON.stringify(clean));\r\n      }\r\n      return clean;\r\n    } catch(e){ return []; }\r\n  }\r\n  function saveOrders(arr) { localStorage.setItem(LS_KEY, JSON.stringify(arr || [])); }\r\n  function cleanupOrdersStorage(){\r\n    const arr = sanitizeOrders(loadOrders());\r\n    saveOrders(arr);\r\n    return arr;\r\n  }\r\n\r\n  function upsertOrder(order) {\r\n    if (!isValidOrder(order)) return;\r\n    const arr = loadOrders();\r\n    const id = String(order.activationId);\r\n    const idx = arr.findIndex(x => String(x.activationId) === id);\r\n    if (idx >= 0) arr[idx] = Object.assign({}, arr[idx], order);\r\n    else arr.unshift(order);\r\n    saveOrders(arr);\r\n    renderOrders();\r\n  }\r\n  function removeOrder(activationId) {\r\n    const id = String(activationId);\r\n    saveOrders(loadOrders().filter(x => String(x.activationId) !== id));\r\n    renderOrders();\r\n  }\r\n  function clearOrders() { saveOrders([]); renderOrders(); }\r\n\r\n  function formatTime(ts) { try { return new Date(ts).toLocaleString(); } catch(e){ return ''; } }\r\n\r\n  function isPolling(id){ return !!pollers[String(id)]; }\r\n  function stopPolling(id){\r\n    id = String(id);\r\n    if (pollers[id]) { clearInterval(pollers[id]); delete pollers[id]; renderOrders(); }\r\n  }\r\n  function stopAllPolling(){\r\n    Object.keys(pollers).forEach(id => { clearInterval(pollers[id]); delete pollers[id]; });\r\n    renderOrders();\r\n  }\r\n\r\n  async function copyTextQuiet(text) {\r\n    text = String(text || '').trim();\r\n    if (!text) return false;\r\n    try {\r\n      if (navigator.clipboard && window.isSecureContext) {\r\n        await navigator.clipboard.writeText(text);\r\n        return true;\r\n      }\r\n      const ta = document.createElement('textarea');\r\n      ta.value = text;\r\n      ta.style.position = 'fixed';\r\n      ta.style.left = '-9999px';\r\n      ta.style.top = '-9999px';\r\n      document.body.appendChild(ta);\r\n      ta.focus();\r\n      ta.select();\r\n      const ok = document.execCommand('copy');\r\n      document.body.removeChild(ta);\r\n      return !!ok;\r\n    } catch(e) {\r\n      return false;\r\n    }\r\n  }\r\n\r\n  \/\/ \u2705 \u9a8c\u8bc1\u7801\u53ef\u91cd\u590d\u83b7\u53d6\u6700\u65b0\uff1a\u4e0d\u518d stopPolling\r\n  async function checkStatusOnce(id){\r\n    id = String(id);\r\n    const r = await fetchAjax('herosms_status', { id });\r\n\r\n    if (!r.json) {\r\n      const prev = loadOrders().find(x => String(x.activationId) === id) || {};\r\n      upsertOrder({\r\n        activationId:id,\r\n        service: prev.service,\r\n        country: prev.country,\r\n        serviceName: prev.serviceName,\r\n        countryName: prev.countryName,\r\n        phoneNumber: prev.phoneNumber,\r\n        time: prev.time,\r\n        lastState:'error',\r\n        lastMessage:`HTTP ${r.status} (\u975eJSON)`,\r\n        lastCheck:Date.now()\r\n      });\r\n      return;\r\n    }\r\n\r\n    const j = r.json;\r\n    const prev = loadOrders().find(x => String(x.activationId) === id) || {};\r\n    const newCode = String(j.code || '');\r\n\r\n    upsertOrder({\r\n      activationId:id,\r\n      service: prev.service,\r\n      country: prev.country,\r\n      serviceName: prev.serviceName,\r\n      countryName: prev.countryName,\r\n      phoneNumber: prev.phoneNumber,\r\n      time: prev.time,\r\n      lastState: j.state || '',\r\n      lastMessage: j.message || '',\r\n      code: newCode,\r\n      lastCheck: Date.now()\r\n    });\r\n\r\n    \/\/ \u2705 \u5982\u679c\u540e\u7aef\u5df2\u7ecf\u53d6\u6d88\u4e86\uff08\u6216\u4e0a\u6e38\u4e0d\u5b58\u5728\uff09\uff0c\u9875\u9762\u4e5f\u81ea\u52a8\u79fb\u9664\r\n    const st = String(j.state || '').toLowerCase();\r\n    if (st === 'canceled' || st === 'cancelled' || st === 'no_activation') {\r\n      stopPolling(id);\r\n      removeOrder(id);\r\n      bootstrap();\r\n      return;\r\n    }\r\n  }\r\n\r\n  function startPolling(id){\r\n    id = String(id);\r\n    if (!id || isPolling(id)) return;\r\n    checkStatusOnce(id);\r\n    pollers[id] = setInterval(() => checkStatusOnce(id), 2000);\r\n    renderOrders();\r\n  }\r\n\r\n  \/\/ \u2705 20\u5206\u949f\u81ea\u52a8\u53d6\u6d88\uff1a\u4ec5\u672a\u51fa\u7801\u8ba2\u5355\r\n  async function autoCancelOneOrder(it){\r\n    const id = String(it.activationId || '').trim();\r\n    if (!id) return;\r\n    try { await fetchAjax('herosms_cancel', { id }); } catch(e) {}\r\n    stopPolling(id);\r\n    removeOrder(id);\r\n    bootstrap();\r\n  }\r\n\r\n  async function autoCancelExpiredOrders(){\r\n    const arr = loadOrders();\r\n    if (!arr.length) return;\r\n\r\n    const now = Date.now();\r\n    for (const it of arr) {\r\n      const id = String(it.activationId || '').trim();\r\n      const t = Number(it.time || 0);\r\n      if (!id || !t) continue;\r\n\r\n      \/\/ \u5df2\u51fa\u4efb\u610f\u9a8c\u8bc1\u7801\u89c6\u4e3a\u6210\u4ea4\uff0c\u4e0d\u81ea\u52a8\u53d6\u6d88\r\n      if (String(it.code || '').trim()) continue;\r\n\r\n      if ((now - t) >= AUTO_CANCEL_MS) {\r\n        await autoCancelOneOrder(it);\r\n      }\r\n    }\r\n  }\r\n\r\n  setInterval(autoCancelExpiredOrders, AUTO_CANCEL_SCAN_MS);\r\n\r\n  function renderOrders(){\r\n    const arr = loadOrders();\r\n    if (!arr.length) { ordersListEl.innerHTML = '<div style=\"color:#666;\">\u6682\u65e0\u8ba2\u5355<\/div>'; return; }\r\n    ordersListEl.innerHTML = '';\r\n\r\n    const now = Date.now();\r\n\r\n    arr.forEach(item => {\r\n      const row = document.createElement('div');\r\n      row.style.cssText = 'border:1px solid #e5e5e5;border-radius:8px;padding:10px;margin:8px 0;background:#fff;';\r\n      const svcCode = item.service || '';\r\n      const svcName = item.serviceName || servicesNameMap[svcCode] || svcCode || 'Unknown';\r\n      const cName = item.countryName || countryNameMap[String(item.country||'')] || ('ID:' + (item.country||''));\r\n      const id = String(item.activationId);\r\n\r\n      const polling = isPolling(id);\r\n      const pollingMark = polling ? '<span style=\"color:#0a7;\">\uff08\u8f6e\u8be2\u4e2d\uff09<\/span>' : '';\r\n\r\n      let leftTxt = '';\r\n      if (item.code) {\r\n        leftTxt = '<span style=\"color:#0a7;\">\u5df2\u6210\u4ea4<\/span>';\r\n      } else if (item.time) {\r\n        const leftMs = Math.max(0, AUTO_CANCEL_MS - (now - Number(item.time)));\r\n        const leftMin = Math.floor(leftMs \/ 60000);\r\n        const leftSec = Math.floor((leftMs % 60000) \/ 1000);\r\n        leftTxt = `<span style=\"color:#666;\">\u81ea\u52a8\u53d6\u6d88\u5012\u8ba1\u65f6\uff1a${leftMin}\u5206${leftSec}\u79d2<\/span>`;\r\n      }\r\n\r\n      const codeTxt = item.code ? `<span style=\"color:#c00;\">\u9a8c\u8bc1\u7801\uff1a<b>${item.code}<\/b><\/span>` : '';\r\n      const stateTxt = item.lastState ? `\u72b6\u6001\uff1a<code>${item.lastState}<\/code>` : '';\r\n\r\n      \/\/ \u2705 \u53bb\u6389\u300c\u4f7f\u7528\u300d\u300c\u505c\u6b62\u300d\u6309\u94ae\uff1b\u300c\u5f00\u59cb\u8f6e\u8be2\u300d\u53d8\u4e3a\u201c\u5f00\u59cb\/\u6682\u505c\u201d\u5207\u6362\r\n      row.innerHTML = `\r\n        <div style=\"display:flex;gap:10px;flex-wrap:wrap;align-items:center;\">\r\n          <div style=\"flex:1;min-width:280px;\">\r\n            <div><b>${svcName} (${svcCode})<\/b> \uff5c ${cName} ${pollingMark}<\/div>\r\n            <div style=\"font-size:12px;color:#666;\">\r\n              ID: <code>${id}<\/code>\r\n              ${item.phoneNumber ? '\uff5c \u53f7\u7801: <code>'+ item.phoneNumber +'<\/code>' : ''}\r\n              ${item.time ? '\uff5c '+ formatTime(item.time) : ''}\r\n              ${leftTxt ? '\uff5c ' + leftTxt : ''}\r\n            <\/div>\r\n            <div style=\"font-size:12px;margin-top:4px;\">\r\n              ${stateTxt} ${codeTxt}\r\n              ${item.lastMessage ? `\uff5c ${String(item.lastMessage)}` : ''}\r\n              ${item.lastCheck ? `\uff5c \u68c0\u67e5\uff1a${formatTime(item.lastCheck)}` : ''}\r\n            <\/div>\r\n          <\/div>\r\n\r\n          <div style=\"display:flex;gap:8px;flex-wrap:wrap;\">\r\n            <button type=\"button\" data-act=\"toggle_poll\" data-id=\"${id}\">${polling ? '\u6682\u505c\u8f6e\u8be2' : '\u5f00\u59cb\u8f6e\u8be2'}<\/button>\r\n            <button type=\"button\" data-act=\"copy_phone\" data-id=\"${id}\">\u590d\u5236\u53f7\u7801<\/button>\r\n            <button type=\"button\" data-act=\"copy_code\" data-id=\"${id}\">\u590d\u5236\u9a8c\u8bc1\u7801<\/button>\r\n            <button type=\"button\" data-act=\"cancel\" data-id=\"${id}\">\u53d6\u6d88\u8ba2\u5355<\/button>\r\n          <\/div>\r\n        <\/div>\r\n      `;\r\n      ordersListEl.appendChild(row);\r\n    });\r\n\r\n    ordersListEl.querySelectorAll('button[data-act]').forEach(btn => {\r\n      btn.onclick = async () => {\r\n        const act = btn.getAttribute('data-act');\r\n        const id = btn.getAttribute('data-id');\r\n        const it = loadOrders().find(x => String(x.activationId) === String(id));\r\n        if (!it) return;\r\n\r\n        if (act === 'toggle_poll') {\r\n          if (isPolling(it.activationId)) stopPolling(it.activationId);\r\n          else startPolling(it.activationId);\r\n          return;\r\n        }\r\n\r\n        if (act === 'copy_phone') {\r\n          const text = it.phoneNumber || '';\r\n          if (!text) return alert('\u6b64\u8ba2\u5355\u6ca1\u6709\u53f7\u7801\u5b57\u6bb5');\r\n          const ok = await copyTextQuiet(text);\r\n          if (!ok) alert('\u590d\u5236\u5931\u8d25\uff0c\u8bf7\u624b\u52a8\u590d\u5236\uff1a' + text);\r\n          return;\r\n        }\r\n\r\n        if (act === 'copy_code') {\r\n          const code = it.code || '';\r\n          if (!code) return alert('\u6b64\u8ba2\u5355\u6682\u65e0\u9a8c\u8bc1\u7801');\r\n          const ok = await copyTextQuiet(code);\r\n          if (!ok) alert('\u590d\u5236\u5931\u8d25\uff0c\u8bf7\u624b\u52a8\u590d\u5236\uff1a' + code);\r\n          return;\r\n        }\r\n\r\n        if (act === 'cancel') {\r\n          const r = await fetchAjax('herosms_cancel', { id: it.activationId });\r\n\r\n          if (!r.json) {\r\n            alert(`\u53d6\u6d88\u5931\u8d25\uff1aHTTP ${r.status}\uff08\u975eJSON\u8fd4\u56de\uff09`);\r\n            return;\r\n          }\r\n\r\n          const j = r.json;\r\n          if (j.ok) {\r\n            stopPolling(it.activationId);\r\n            removeOrder(it.activationId);\r\n            await bootstrap(); \/\/ \u53d6\u6d88\u540e\u53ef\u80fd\u89e6\u53d1\u9000\u6b3e\uff0c\u5237\u65b0\u4f59\u989d\r\n          } else if (j.blocked) {\r\n            alert(`\u8ba2\u5355 ${it.activationId} \u9700\u7b49\u5f85 ${j.waitSec} \u79d2\u540e\u624d\u80fd\u53d6\u6d88\u3002`);\r\n          } else {\r\n            alert(`\u53d6\u6d88\u5931\u8d25\uff1a${(j.error || j.message) || 'unknown'}`);\r\n          }\r\n          return;\r\n        }\r\n      };\r\n    });\r\n  }\r\n\r\n  function buildServicesDropdown(allServices) {\r\n    const map = {};\r\n    servicesNameMap = {};\r\n\r\n    (allServices || []).forEach(s => {\r\n      if (!s || !s.code) return;\r\n      const code = String(s.code);\r\n      const nm = String(s.name || '');\r\n      map[code] = nm;\r\n      servicesNameMap[code] = nm;\r\n    });\r\n\r\n    serviceEl.innerHTML = '';\r\n\r\n    const g1 = document.createElement('optgroup');\r\n    g1.label = '\u5e38\u7528\u670d\u52a1\uff08\u7f6e\u9876\uff09';\r\n    FEATURED.forEach(f => {\r\n      const opt = document.createElement('option');\r\n      opt.value = f.code;\r\n      opt.textContent = `${f.name} (${f.code})`;\r\n      g1.appendChild(opt);\r\n      if (!servicesNameMap[f.code]) servicesNameMap[f.code] = f.name;\r\n    });\r\n    serviceEl.appendChild(g1);\r\n\r\n    const g2 = document.createElement('optgroup');\r\n    g2.label = '\u5168\u90e8\u670d\u52a1\uff08\u5e73\u53f0\u8fd4\u56de\uff09';\r\n    Object.keys(map).sort().forEach(code => {\r\n      const opt = document.createElement('option');\r\n      opt.value = code;\r\n      opt.textContent = `${map[code] || code} (${code})`;\r\n      g2.appendChild(opt);\r\n    });\r\n    serviceEl.appendChild(g2);\r\n\r\n    serviceEl.value = 'tg';\r\n  }\r\n\r\n  async function loadServices() {\r\n    const r = await fetchPublicJson(apiUrl('services', { lang:'cn' }));\r\n    if (r.ok && r.json && r.json.ok && r.json.parsed) {\r\n      buildServicesDropdown(r.json.services || []);\r\n    }\r\n  }\r\n\r\n  async function loadCountryNames() {\r\n    const r = await fetchPublicJson(apiUrl('countries', { lang:'cn' }));\r\n    if (r.ok && r.json && r.json.ok && r.json.parsed && Array.isArray(r.json.countries)) {\r\n      countryNameMap = {};\r\n      r.json.countries.forEach(x => { countryNameMap[String(x.id)] = x.name || ('Country '+x.id); });\r\n    }\r\n  }\r\n\r\n  async function loadCountries() {\r\n    const svc = getServiceCode();\r\n    if (!svc) return;\r\n\r\n    const includeZero = showAllEl.checked ? '1' : '0';\r\n    const r = await fetchPublicJson(apiUrl('prices', { service: svc, include_zero: includeZero }));\r\n\r\n    if (!r.ok || !r.json) {\r\n      countryEl.innerHTML = '<option value=\"\">\u8bf7\u6c42\u5931\u8d25<\/option>';\r\n      orderBtn.disabled = true;\r\n      return;\r\n    }\r\n\r\n    const j = r.json;\r\n    countryEl.innerHTML = '';\r\n\r\n    if (!j.ok || !j.parsed || !j.countries || !j.countries.length) {\r\n      countryEl.innerHTML = '<option value=\"\">\u8be5\u670d\u52a1\u6682\u65e0\u56fd\u5bb6\/\u5e93\u5b58<\/option>';\r\n      orderBtn.disabled = true;\r\n      return;\r\n    }\r\n\r\n    countryEl.innerHTML = '<option value=\"\">\u8bf7\u9009\u62e9\u56fd\u5bb6<\/option>';\r\n    j.countries.forEach(c => {\r\n      const opt = document.createElement('option');\r\n      opt.value = c.countryCode;\r\n\r\n      const cname = countryNameMap[String(c.countryCode)] || ('\u56fd\u5bb6ID ' + c.countryCode);\r\n      const stockTxt = c.inStock ? `\u5e93\u5b58 ${c.count}` : `\u65e0\u5e93\u5b58`;\r\n      opt.textContent = `${cname} (ID:${c.countryCode}) \uff5c \u4ef7 ${c.cost} \uff5c ${stockTxt}`;\r\n\r\n      if (!c.inStock) opt.disabled = true;\r\n      countryEl.appendChild(opt);\r\n    });\r\n\r\n    orderBtn.disabled = !countryEl.value;\r\n  }\r\n\r\n  async function orderOne() {\r\n    if (USER_ID <= 0 || !AJAX_NONCE) {\r\n      const ok = await bootstrap();\r\n      if (!ok) return { ok:false, error:'bootstrap_failed' };\r\n    }\r\n\r\n    const svc = getServiceCode();\r\n    const cty = countryEl.value;\r\n    if (!svc || !cty) return { ok:false, error:'missing_params' };\r\n\r\n    const r = await fetchAjax('herosms_order', { service: svc, country: cty });\r\n    if (!r.json) return { ok:false, error:'non_json', httpStatus:r.status };\r\n\r\n    await bootstrap(); \/\/ \u4e0b\u5355\u7acb\u523b\u6263\u94b1\uff0c\u5237\u65b0\u4f59\u989d\r\n    return r.json;\r\n  }\r\n\r\n  async function orderNumberBatch() {\r\n    const qty = Math.max(1, Math.min(20, parseInt(qtyEl.value || '1', 10)));\r\n    const svc = getServiceCode();\r\n    const cty = countryEl.value;\r\n    if (!svc || !cty) return;\r\n\r\n    if (USER_ID <= 0) return alert('\u8bf7\u5148\u767b\u5f55\u518d\u4e0b\u5355');\r\n\r\n    orderBtn.disabled = true;\r\n\r\n    for (let i = 1; i <= qty; i++) {\r\n      const j = await orderOne();\r\n\r\n      if (!j || j.ok === false) {\r\n        alert('\u4e0b\u5355\u5931\u8d25\uff1a' + (j.error || j.message || 'unknown'));\r\n        break;\r\n      }\r\n\r\n      if (j.ok && j.parsed && j.activationId) {\r\n        const actId = String(j.activationId);\r\n        const svcName = servicesNameMap[String(svc)] || svc;\r\n        const cName = countryNameMap[String(cty)] || ('ID:' + cty);\r\n\r\n        upsertOrder({\r\n          activationId: actId,\r\n          phoneNumber: j.phoneNumber ? String(j.phoneNumber) : '',\r\n          service: String(svc),\r\n          serviceName: String(svcName).replace(\/\\s*\\(.+\\)\\s*$\/,'').trim(),\r\n          country: String(cty),\r\n          countryName: String(cName),\r\n          time: Date.now(),\r\n          lastState: 'created',\r\n          lastMessage: j.activationCost ? ('cost: ' + j.activationCost) : ''\r\n        });\r\n\r\n        startPolling(actId);\r\n\r\n        \/\/ \u2705 \u4ecd\u4fdd\u7559\u201c\u4ec5\u8f6e\u8be2\u6b64ID\/\u505c\u6b62\u6b64ID\u201d\u7684\u8f93\u5165\u6846\u529f\u80fd\r\n        idEl.value = actId;\r\n        pollOneBtn.disabled = false;\r\n        stopOneBtn.disabled = false;\r\n      } else {\r\n        alert('\u4e0b\u5355\u8fd4\u56de\u7ed3\u6784\u5f02\u5e38');\r\n        break;\r\n      }\r\n    }\r\n\r\n    orderBtn.disabled = !countryEl.value;\r\n  }\r\n\r\n  \/\/ \u7ed1\u5b9a\u4e8b\u4ef6\r\n  bootBtn.onclick = bootstrap;\r\n  loadBtn.onclick = loadCountries;\r\n  countryEl.onchange = () => { orderBtn.disabled = !countryEl.value; };\r\n  orderBtn.onclick = orderNumberBatch;\r\n\r\n  pollOneBtn.onclick = () => {\r\n    const id = (idEl.value || '').trim();\r\n    if (!id) return alert('id \u4e0d\u80fd\u4e3a\u7a7a');\r\n    startPolling(id);\r\n  };\r\n  stopOneBtn.onclick = () => {\r\n    const id = (idEl.value || '').trim();\r\n    if (!id) return alert('id \u4e0d\u80fd\u4e3a\u7a7a');\r\n    stopPolling(id);\r\n  };\r\n\r\n  stopAllBtn.onclick = () => stopAllPolling();\r\n  clearOrdersBtn.onclick = () => {\r\n    if (confirm('\u786e\u5b9a\u6e05\u7a7a\u6240\u6709\u8ba2\u5355\u5417\uff1f')) {\r\n      setClearedAt();\r\n      stopAllPolling();\r\n      setTimeout(() => {\r\n        clearOrders();\r\n        cleanupOrdersStorage();\r\n      }, 300);\r\n    }\r\n  };\r\n\r\n  \/\/ \u521d\u59cb\u5316\r\n  (async function init() {\r\n    await bootstrap();\r\n    await loadCountryNames();\r\n    await loadServices();\r\n    cleanupOrdersStorage();\r\n    renderOrders();\r\n    autoCancelExpiredOrders(); \/\/ \u8fdb\u9875\u9762\u7acb\u523b\u626b\u4e00\u6b21\r\n  })();\r\n})();\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>\u83b7\u53d6\u53f7\u7801 (Get Number) \u4f60\u5f53\u524d\u672a\u767b\u5f55\uff0c\u8bf7\u5148\u767b\u5f55\u540e\u5237\u65b0\u9875\u9762\u3002 \u7528\u6237\uff1a\u52a0\u8f7d\u4e2d&#8230; \u4f59\u989d\uff1a$0.00 \u5237\u65b0\u767b\u5f55\u4fe1\u606f \u670d\u52a1(service)\uff1a \u6b63\u5728\u52a0\u8f7d\u670d\u52a1&#8230; \u81ea\u5b9a\u4e49code\uff1a \u663e\u793a\u65e0\u5e93\u5b58\u56fd\u5bb6\uff08\u5168\u91cf\uff09 \u52a0\u8f7d\u56fd\u5bb6 \u56fd\u5bb6(country)\uff1a \u5148\u52a0\u8f7d\u56fd\u5bb6 \u6570\u91cf\uff1a \u4e0b\u5355\u4e70\u53f7\uff08\u81ea\u52a8\u8f6e\u8be2\uff09 \u6fc0\u6d3bID(id)\uff1a \u4ec5\u8f6e\u8be2\u6b64ID \u505c\u6b62\u6b64ID \u505c\u6b62\u5168\u90e8\u8f6e\u8be2 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-365","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=\/wp\/v2\/pages\/365","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=365"}],"version-history":[{"count":82,"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=\/wp\/v2\/pages\/365\/revisions"}],"predecessor-version":[{"id":461,"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=\/wp\/v2\/pages\/365\/revisions\/461"}],"wp:attachment":[{"href":"https:\/\/huicheng.dpdns.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=365"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}