B2B网络软件

 找回密码
 立即注册 审核网站号:QQ:896757558
搜索
查看: 3|回复: 0
打印 上一主题 下一主题

整点抢购倒计时倒计时悬浮卡片

[复制链接]

1190

主题

1195

帖子

8037

积分

abc

Rank: 9Rank: 9Rank: 9

积分
8037
跳转到指定楼层
楼主
整点抢购倒计时倒计时悬浮卡片
整点抢购倒计时倒计时悬浮卡片 B2B网络软件

整点抢购倒计时倒计时悬浮卡片 B2B网络软件

整点抢购倒计时倒计时悬浮卡片 B2B网络软件

  1. /**
  2. * ╔══════════════════════════════════════════════════════════╗
  3. * ║   案例 7:整点抢购倒计时倒计时悬浮卡片
  4. * ║   知识点:高精度定时(分段等待 + 提前量)、              ║
  5. * ║          倒计时悬浮卡片、uiPost 线程调度、               ║
  6. * ║          安全点击封装(touch/无障碍降级)、              ║
  7. * ║          命中误差统计、event.onStopBtnEvent              ║
  8. * ╚══════════════════════════════════════════════════════════╝
  9. *
  10. * 目标:全网最经典的"抢购/抢茅台/抢优惠券"套路——
  11. *       1. 屏幕上挂一个倒计时大字卡片
  12. *       2. 粗等 → 细等 → 自旋,三段式逼近目标时间
  13. *       3. 提前 LEAD_MS 毫秒出手(补偿点击本身的耗时)
  14. *       4. 到点连点 3 下,统计实际命中误差
  15. * 难度:★★★☆☆
  16. * 运行:无障碍服务即可;USE_DEMO=true 不用改时间直接看效果
  17. */

  18. // ==================== 第 0 步:配置区(改这里)====================
  19. var USE_DEMO = true;    // true:10 秒后开抢(演示用);false:按下面的整点时间
  20. var DEMO_SECONDS = 10;  // 演示模式:多少秒后开抢
  21. var BUY_HOUR = 10, BUY_MIN = 0, BUY_SEC = 0;  // 真实模式:每天 10:00:00 抢
  22. var LEAD_MS = 80;       // 提前量:点击动作本身约耗时 60~100ms,提前出手才准
  23. var CLICK_TIMES = 3;    // 到点连点几下(抢购页面经常要点多次才进)
  24. var DEMO_KEY_FEEDBACK = true;  // 出手后模拟按一次 HOME 键,让演示肉眼可见(真实用设 false)

  25. // ==================== 顶部:全局变量声明 ====================
  26. var gWin = null;        // 悬浮窗对象
  27. var gTvTitle = null;    // 标题(目标时刻)
  28. var gTvCount = null;    // 倒计时大字
  29. var gTvStatus = null;   // 状态行
  30. var gTvResult = null;   // 结果行(命中误差)
  31. var gTargetTs = 0;      // 目标时间戳(毫秒)
  32. var gStruck = false;    // 是否已出手
  33. var gStopTick = false;  // 倒计时线程退出标志

  34. // ==================== 调色板 ====================
  35. var C_BG = "#CC0B1220";   // 卡片底(深蓝黑)
  36. var C_HEAD = "#F43F5E";   // 标题栏(玫红,抢购氛围)
  37. var C_PANEL = "#0F172A";  // 面板
  38. var C_TEXT = "#E2E8F0";   // 正文
  39. var C_OK = "#4ADE80";     // 成功(绿)
  40. var C_WARN = "#FBBF24";   // 提醒(黄)
  41. var C_ERR = "#F87171";    // 失败(红)
  42. var C_DIM = "#64748B";    // 暗灰

  43. // ==================== 工具函数(先定义,后使用)====================

  44. function doSleep(ms) {
  45.     try { java.lang.Thread.sleep(ms); } catch (e) {}
  46. }

  47. function now() { return new Date().getTime(); }

  48. function pad2(n) { return (n < 10 ? "0" : "") + n; }

  49. // 时间戳 → "10:00:00.000"(毫秒也要,抢购看得清)
  50. function formatMs(ts) {
  51.     var d = new Date(ts);
  52.     return pad2(d.getHours()) + ":" + pad2(d.getMinutes()) + ":" +
  53.            pad2(d.getSeconds()) + "." +
  54.            (d.getMilliseconds() < 100 ? (d.getMilliseconds() < 10 ? "00" : "0") : "") +
  55.            d.getMilliseconds();
  56. }

  57. // 安全点击:touch.tap(无障碍)优先,失败兜底 auto.clickPoint
  58. function safeClick(x, y) {
  59.     try { touch.tap(x, y); }
  60.     catch (e) { auto.clickPoint(x, y); }
  61. }

  62. // ==================== UI 线程调度(案例6 的教训,直接复用)====================
  63. // 从脚本线程 setText 不会触发重新测量,大字倒计时会卡住不刷新,必须 post 到 UI 线程
  64. function uiPost(view, fn) {
  65.     if (view && view.post) {
  66.         try { view.post(fn); return; } catch (e) {}
  67.     }
  68.     try { fn(); } catch (e2) {}
  69. }

  70. function setCountdown(text, color) {
  71.     var c = color;
  72.     uiPost(gTvCount, function () {
  73.         try {
  74.             gTvCount.setText(text);
  75.             gTvCount.setTextColor(android.graphics.Color.parseColor(c));
  76.         } catch (e) {}
  77.     });
  78. }

  79. function setStatus(text, color) {
  80.     var shown = "⏳ " + text, c = color;
  81.     uiPost(gTvStatus, function () {
  82.         try {
  83.             gTvStatus.setText(shown);
  84.             gTvStatus.setTextColor(android.graphics.Color.parseColor(c));
  85.         } catch (e) {}
  86.     });
  87. }

  88. function setResult(text, color) {
  89.     var shown = text, c = color;
  90.     uiPost(gTvResult, function () {
  91.         try {
  92.             gTvResult.setText(shown);
  93.             gTvResult.setTextColor(android.graphics.Color.parseColor(c));
  94.         } catch (e) {}
  95.     });
  96. }

  97. // ==================== 第 1 步:创建倒计时卡片 ====================
  98. function initFloatWindow() {
  99.     var sw = screen.getScreenWidth();
  100.     var sh = screen.getScreenHeight();
  101.     var w = Math.floor(sw * 0.62);   // 宽 62%
  102.     var h = Math.floor(sh * 0.20);   // 高 20%
  103.     var x = Math.floor((sw - w) / 2);        // 水平居中
  104.     var y = Math.floor(sh * 0.30);           // 距顶部 30%

  105.     // 结构:标题栏 → 大字倒计时 → 状态行 → 结果行
  106.     var xml =
  107.         '<LinearLayout orientation="vertical" w="' + w + '" h="' + h +
  108.         '" background="' + C_BG + '" padding="4">' +

  109.         '<LinearLayout orientation="horizontal" w="fill_parent" h="wrap_content" ' +
  110.         'background="' + C_HEAD + '" padding="6">' +
  111.         '  <TextView text="⚡ 整点抢购" textColor="#FFFFFF" textSize="13" textStyle="bold"/>' +
  112.         '  <TextView id="target" text="" textColor="#FFE4E6" textSize="11" ' +
  113.         'w="fill_parent" gravity="right"/>' +
  114.         '</LinearLayout>' +

  115.         '<LinearLayout orientation="vertical" w="fill_parent" h="fill_parent" ' +
  116.         'background="' + C_PANEL + '" padding="8">' +
  117.         '  <TextView id="countdown" text="00:00" textColor="' + C_WARN + '" ' +
  118.         'textSize="34" textStyle="bold" gravity="center" w="fill_parent"/>' +
  119.         '  <TextView id="statusLine" text="⏳ 准备中..." textColor="' + C_DIM + '" ' +
  120.         'textSize="12" gravity="center" w="fill_parent" padding="4"/>' +
  121.         '  <TextView id="resultLine" text="" textColor="' + C_OK + '" ' +
  122.         'textSize="12" gravity="center" w="fill_parent"/>' +
  123.         '</LinearLayout>' +

  124.         '</LinearLayout>';

  125.     try {
  126.         gWin = new floatUI();
  127.         gWin.loadXML(xml);
  128.         gWin.setPosition(x, y);   // loadXML 成功后再调用
  129.         gTvTitle  = gWin.findViewById("target");
  130.         gTvCount  = gWin.findViewById("countdown");
  131.         gTvStatus = gWin.findViewById("statusLine");
  132.         gTvResult = gWin.findViewById("resultLine");
  133.         printl("[卡片] 创建成功 pos=(" + x + "," + y + ") size=" + w + "x" + h);
  134.         return true;
  135.     } catch (e) {
  136.         printl("[卡片] 创建失败: " + e);
  137.         return false;
  138.     }
  139. }

  140. // ==================== 第 2 步:算目标时间 ====================
  141. // 演示模式:现在 + N 秒;真实模式:今天的整点,已过则顺延到明天
  142. function calcTargetTime() {
  143.     if (USE_DEMO) {
  144.         uiPost(gTvTitle, function () { try { gTvTitle.setText("演示模式"); } catch (e) {} });
  145.         return now() + DEMO_SECONDS * 1000;
  146.     }
  147.     var t = new Date();
  148.     t.setHours(BUY_HOUR, BUY_MIN, BUY_SEC, 0);
  149.     if (t.getTime() <= now()) t.setDate(t.getDate() + 1);   // 过点了就等明天
  150.     var label = BUY_HOUR + ":" + pad2(BUY_MIN) + ":" + pad2(BUY_SEC);
  151.     uiPost(gTvTitle, function () {
  152.         try { gTvTitle.setText("目标 " + label); } catch (e) {}
  153.     });
  154.     return t.getTime();
  155. }

  156. // ==================== 第 3 步:倒计时线程 ====================
  157. // 每 100ms 刷一次大字,直到出手为止(gStopTick 控制退出)
  158. function startCountdownThread() {
  159.     new thread().runJsCode(function () {
  160.         while (!gStopTick) {
  161.             if (gStruck) break;
  162.             var remain = gTargetTs - now();
  163.             if (remain <= 0) {
  164.                 setCountdown("抢!", C_ERR);
  165.                 break;
  166.             }
  167.             // 剩 1 秒内显示毫秒,最后阶段更有紧张感
  168.             if (remain < 1000) {
  169.                 setCountdown(remain + "ms", C_ERR);
  170.             } else {
  171.                 var s = Math.ceil(remain / 1000);
  172.                 setCountdown(pad2(Math.floor(s / 60)) + ":" + pad2(s % 60), C_WARN);
  173.             }
  174.             doSleep(100);
  175.         }
  176.     }, "倒计时线程");
  177.     printl("[线程] 倒计时线程已启动");
  178. }

  179. // ==================== 第 4 步:三段式高精度等待 ====================
  180. // 粗等:每次睡 100ms,到目标前 500ms 停(避免睡过头)
  181. // 细等:每次睡 10ms,到目标前 LEAD_MS 停
  182. // 自旋:busy-wait 精确到 1ms,保证出手时刻精准
  183. // 为什么要提前 LEAD_MS:从"判断到点"到"点击落到屏幕"本身要几十毫秒,
  184. //                      提前出手,点击动作才正好压在目标时刻上
  185. function preciseWait(targetTs) {
  186.     // 段 1:粗等
  187.     while (targetTs - now() > 500) {
  188.         doSleep(Math.min(100, targetTs - now() - 500));
  189.     }
  190.     // 段 2:细等
  191.     while (targetTs - now() > LEAD_MS + 20) {
  192.         doSleep(10);
  193.     }
  194.     // 段 3:自旋到出手时刻
  195.     var fireAt = targetTs - LEAD_MS;
  196.     while (now() < fireAt) {
  197.         // busy-wait,不睡,精确咬住毫秒
  198.     }
  199. }

  200. // ==================== 第 5 步:出手(到点连点)====================
  201. function strike() {
  202.     var sw = screen.getScreenWidth();
  203.     var sh = screen.getScreenHeight();
  204.     // 演示:点屏幕中央;真实场景改成抢购按钮的坐标(用识图/找字定位)
  205.     var cx = Math.floor(sw * 0.5);
  206.     var cy = Math.floor(sh * 0.5);

  207.     gStruck = true;
  208.     setStatus("出手!", C_ERR);

  209.     var fireTs = now();
  210.     for (var i = 0; i < CLICK_TIMES; i++) {
  211.         safeClick(cx + rand(-6, 6), cy + rand(-6, 6));   // 随机偏移防检测
  212.         doSleep(40);   // 连点间隔 40ms,太快会被系统吞掉
  213.     }

  214.     // 误差 = 实际出手 - 目标(负数 = 提前,正数 = 迟到)
  215.     var error = fireTs - gTargetTs;
  216.     var line = "✅ 出手于 " + formatMs(fireTs) + " 误差 " +
  217.                (error >= 0 ? "+" : "") + error + "ms(提前量 " + LEAD_MS + "ms)";
  218.     setResult(line, Math.abs(error) <= 30 ? C_OK : C_WARN);
  219.     setStatus("抢购完成,3 秒后自动收起", C_OK);
  220.     printl(line);

  221.     // ---- 演示反馈:出手动作要肉眼可见 ----
  222.     // toast 提示出手时刻和误差(放在点击之后,不能占用出手时机的时间)
  223.     try { toast.show("⚡ 已出手!连点 " + CLICK_TIMES + " 次,误差 " +
  224.                      (error >= 0 ? "+" : "") + error + "ms"); } catch (e) {}
  225.     // 模拟按键反馈:出手后按一次 HOME 键,屏幕会明显回到桌面
  226.     if (DEMO_KEY_FEEDBACK) {
  227.         doSleep(300);
  228.         try {
  229.             auto.home();
  230.             printl("[反馈] 已模拟按 HOME 键");
  231.         } catch (e) { printl("[反馈] 按键模拟失败: " + e); }
  232.     }
  233. }

  234. function rand(a, b) { return a + Math.floor(Math.random() * (b - a + 1)); }

  235. // ==================== 第 6 步:优雅停止 ====================
  236. // 清理动作放前面,runTime.stopAllRuning() 必须放最后
  237. function cleanup() {
  238.     gStopTick = true;
  239.     setStatus("已手动停止", C_DIM);
  240.     doSleep(300);
  241.     try { if (gWin) { gWin.close(); gWin = null; } } catch (e) {}
  242.     printl("[清理] 倒计时卡片已关闭");
  243.     runTime.stopAllRuning();   // 最后才停所有线程
  244.     stop();
  245. }

  246. event.onStopBtnEvent(function () {
  247.     cleanup();
  248. });

  249. // ==================== 第 7 步:主流程 ====================
  250. function runMain() {
  251.     printl("╔══════════════════════════════════════════╗");
  252.     printl("║  案例7:整点抢购倒计时(精准定时)        ║");
  253.     printl("╚══════════════════════════════════════════╝");

  254.     if (!initFloatWindow()) {
  255.         printl("悬浮卡片创建失败,脚本退出");
  256.         return;
  257.     }

  258.     gTargetTs = calcTargetTime();
  259.     printl("[目标] " + formatMs(gTargetTs) + "(" +
  260.            (gTargetTs - now()) + "ms 后)");
  261.     setStatus("等待开抢,提前量 " + LEAD_MS + "ms", C_WARN);
  262.     try {
  263.         toast.show("⚡ 倒计时开始:" + Math.round((gTargetTs - now()) / 1000) +
  264.                    " 秒后出手,注意看悬浮卡片");
  265.     } catch (e) {}

  266.     startCountdownThread();
  267.     doSleep(500);

  268.     // 三段式逼近目标时刻
  269.     preciseWait(gTargetTs);

  270.     // 到点出手
  271.     strike();

  272.     // 让观众看清结果,再收尾
  273.     doSleep(3000);
  274.     cleanup();
  275. }

  276. runMain();
复制代码


回复

使用道具 举报

本版积分规则

关闭

QQ|»营销软件综合讨论|»营销软件有问必答|»营销软件教程专区|»营销软件POST脚本分享|»营销软件普通脚本分享|»营销软件软件资讯|»营销软件精品软件|»营销软件更新公告|营销软件|B2B软件|B2B网络软件 ( 京ICP备09078825号 )本网站开发的营销软件是一款新的网络营销软件,这款营销可以去网站软件,博客软件,B2B软件,分类信息网发贴,可以抢沙发,可以到百度文库上传WORD文档,可以到一些是相册网站自动上传图片,这个自动发帖软件自带云蜘蛛,加快收录,有6种对接打码接口,方便,效率高,速度快,而且对拖动的验证码全网第一家独家支持,全部原创技术,独家研发,正版原创带版权软件。选择万能营销软件,就选择了一种赚钱的效率,从没有被超越过,一直在努力研发新技术。放飞梦想,解放双手,来点创意,成就你的梦想,就在万能营销软件开始

map2

GMT+8, 2026-10-13 07:32 , Processed in 0.082813 second(s), 33 queries .

快速回复 返回顶部 返回列表