' ============================================================
' A7P网络验证 - 卡密登录示例 易语言源码
' 对应Python示例: 卡密登录示例.py (流程/交互/提示文案一比一对齐)
' API文档: https://docs.a7p.cn/api/
'
' 使用方法:
' 1. 打开易语言(5.9+), 新建"Windows窗口程序"
' 2. 按下方"组件表"创建窗口与组件(组件名必须一致)
' 3. 把"程序集变量"粘贴到 窗口1 程序集; 把各"子程序"粘贴到对应事件
' 4. 工具→支持库配置 勾选: 数据摘要支持库(取数据摘要用)
'
' 依赖说明:
' - MD5: 取数据摘要() 来自"数据摘要支持库"(dp1.fne, 易语言自带)
' - HTTP: MSXML2.XMLHTTP (系统组件, 同步模式, 超时10秒)
' - 下载更新: 调用系统自带 curl (Win10 1803+)
'
' 功能: 启动自动初始化 → 版本检查(强制更新) → 公告加载 → 卡密登录 → 自动心跳(30秒)
' ============================================================

' ==================== 组件表 ====================
' 窗口1 (卡密登录): 标题"卡密登录 v1.1", 宽420 高280, 不可调整
'   标签_卡密:    "卡密:", 位置(25,18)
'   编辑框_卡密:  位置(85,14) 宽250
'   标签_格式提示: "卡密格式: XXXX-XXXX-XXXX-XXXX", 位置(25,46), 字体颜色=取颜色值(128,128,128)
'   按钮_登录:    "登录", 位置(145,74) 宽130 高28
'   标签_状态:    "初始化中...", 位置(25,112), 字体颜色=取颜色值(255,140,0)
'   分组框_公告:  "软件公告", 位置(10,142) 宽400 高128
'     编辑框_公告: 位置(18,160) 宽384 高104, 多行=真 只读=真 内容="正在加载公告...", 背景颜色=取颜色值(255,255,240)
'   时钟1: 时钟周期=0
'   时钟2: 时钟周期=0   (心跳)
'   时钟3: 时钟周期=0   (更新下载)
'
' 窗口2 (已登录): 标题"已登录", 宽400 高240, 不可调整
'   标签_主用户/标签_主到期/标签_主机器码: 值显示, 字体颜色=#蓝色 / #蓝色 / 灰色
'   标签_心跳: "心跳: 运行中", 字体颜色=#绿色
'   标签_心跳倒计时: "  下次: 30秒"
'   按钮_暂停: "暂停"
'
' 窗口3 (软件更新): 标题"软件更新", 宽470 高260, 不可调整
'   标签_新版本: 位置(25,18), 加粗
'   标签_版本名称: 位置(25,48), 灰色
'   标签_进度: "准备下载...", 位置(25,80)
'   进度条_更新: 位置(25,106) 宽380 高20
'   标签_更新状态: "正在连接服务器...", 位置(25,136), 字体颜色=取颜色值(255,140,0)
'   按钮_取消: "取消", 位置(175,175)

' ==================== 窗口1 程序集变量 ====================
' .版本 2
'
' .程序集 窗口程序集_启动窗口
'
' -------- 配置区域 (请在控制台-产品设置获取你的AppId/AppKey) --------
' .程序集 变量 APP_ID, 文本型
' .程序集 变量 APP_KEY, 文本型
' .程序集 变量 BASE_URL, 文本型
' .程序集 变量 HEARTBEAT_INTERVAL, 整数型
' .程序集 变量 APP_VERSION, 文本型
'
' -------- 运行状态 --------
' .程序集 变量 api_password, 文本型
' .程序集 变量 token, 文本型
' .程序集 变量 notice, 文本型
' .程序集 变量 heartbeat_active, 逻辑型
' .程序集 变量 countdown, 整数型
' .程序集 变量 update_version, 文本型
' .程序集 变量 update_name, 文本型
' .程序集 变量 update_url, 文本型
' .程序集 变量 update_data, 文本型

' ==================== 窗口1_创建完毕 ====================
' 子程序 __启动窗口_创建完毕
'   ' -------- 配置区域 --------
'   APP_ID ＝ “你的AppId”
'   APP_KEY ＝ “你的AppKey”
'   BASE_URL ＝ “https://www.a7p.cn/api/verify”
'   HEARTBEAT_INTERVAL ＝ 30
'   APP_VERSION ＝ “1.1”
'   ' -------- 初始化状态 --------
'   api_password ＝ “”
'   token ＝ “”
'   notice ＝ “正在加载公告...”
'   heartbeat_active ＝ 假
'   countdown ＝ 0
'   update_version ＝ “”
'   update_name ＝ “”
'   update_url ＝ “”
'   update_data ＝ “”
'   编辑框_公告.内容 ＝ notice
'   时钟1.时钟周期 ＝ 200   ' 启动约200ms后自动初始化(对齐 root.after(200))

' ==================== RC4加密 ====================
' 子程序 RC4加密, 文本型
'   .参数 key, 文本型
'   .参数 data, 文本型
'   .局部变量 S, 整数型, , "256"
'   .局部变量 i, 整数型
'   .局部变量 j, 整数型
'   .局部变量 a, 整数型
'   .局部变量 t, 整数型
'   .局部变量 v, 整数型
'   .局部变量 kLen, 整数型
'   .局部变量 dLen, 整数型
'   .局部变量 hexStr, 文本型
'   .局部变量 kb, 字节集
'   .局部变量 db, 字节集
'
'   kb ＝ 到字节集 (key)
'   db ＝ 到字节集 (data)
'   kLen ＝ 取字节集长度 (kb)
'   dLen ＝ 取字节集长度 (db)
'   .如果真 (kLen ＝ 0 或 dLen ＝ 0)
'     返回 (“”)
'   .如果真结束
'   .计次循环首 (256, i)
'     S[i] ＝ i － 1
'   .计次循环尾 ()
'   j ＝ 0
'   .计次循环首 (256, i)
'     j ＝ (j ＋ S[i] ＋ 取字节集数据 (kb, #字节型, (i － 1) ％ kLen ＋ 1)) ％ 256
'     t ＝ S[i]
'     S[i] ＝ S[j]
'     S[j] ＝ t
'   .计次循环尾 ()
'   a ＝ 0
'   j ＝ 0
'   hexStr ＝ “”
'   .计次循环首 (dLen, i)
'     a ＝ (a ＋ 1) ％ 256
'     j ＝ (j ＋ S[a]) ％ 256
'     t ＝ S[a]
'     S[a] ＝ S[j]
'     S[j] ＝ t
'     v ＝ 位异或 (取字节集数据 (db, #字节型, i), S[(S[a] ＋ S[j]) ％ 256 ＋ 1])
'     ' 转2位大写十六进制并拼接
'     hexStr ＝ hexStr ＋ 补文本 (取十六进制文本 (位与 (v, 255)), 2, “0”, 真)
'   .计次循环尾 ()
'   返回 (到大写 (hexStr))

' ==================== MD5哈希 ====================
' 子程序 MD5哈希, 文本型
'   .参数 data, 文本型
'   返回 (到小写 (取数据摘要 (到字节集 (data))))   ' 数据摘要支持库

' ==================== 获取机器码 ====================
' 子程序 获取机器码, 文本型
'   .局部变量 tmp, 文本型
'   .局部变量 out, 文本型
'   .局部变量 result, 文本型
'   .局部变量 pos, 整数型
'   tmp ＝ 取临时目录 () ＋ “a7p_mac.txt”
'   运行 (“cmd /c getmac /fo csv /nh > ” ＋ #引号 ＋ tmp ＋ #引号, 真, #隐藏窗口)
'   out ＝ 到文本 (读入文件 (tmp))
'   删除文件 (tmp)
'   .如果真 (取文本长度 (out) ＜ 2)
'     返回 (“00:00:00:00:00:00”)
'   .如果真结束
'   pos ＝ 寻找文本 (out, “,”, , 假)
'   .如果真 (pos ＝ 0)
'     返回 (“00:00:00:00:00:00”)
'   .如果真结束
'   result ＝ 取文本左边 (out, pos － 1)
'   result ＝ 替换文本 (result, #引号, “”, , , 假)
'   result ＝ 替换文本 (result, “-”, “:”, , , 假)
'   返回 (到大写 (result))

' ==================== HTTP POST ====================
' 子程序 HttpPost, 文本型
'   .参数 url, 文本型
'   .参数 body, 文本型
'   .局部变量 http, 对象
'   .局部变量 result, 文本型
'   result ＝ “”
'   .如果真 (取文本长度 (url) ＝ 0 或 取文本长度 (body) ＝ 0)
'     返回 (“”)
'   .如果真结束
'   http ＝ 创建对象 (“MSXML2.XMLHTTP”)
'   http.写属性 (“timeout”, 10000)   ' 超时10秒
'   http.方法 (“open”, “POST”, url, 假)   ' 同步模式
'   http.方法 (“setRequestHeader”, “Content-Type”, “application/x-www-form-urlencoded”)
'   http.方法 (“send”, body)
'   .如果真 (http.读属性 (“status”) ＝ 200)
'     result ＝ http.读属性 (“responseText”)
'   .如果真结束
'   http.释放 ()
'   返回 (result)

' ==================== JSON取值 ====================
' 子程序 JsonGetValue, 文本型
'   .参数 json, 文本型
'   .参数 key, 文本型
'   .局部变量 search, 文本型
'   .局部变量 pos, 整数型
'   .局部变量 start, 整数型
'   .局部变量 i, 整数型
'   .局部变量 ch, 文本型
'   .局部变量 value, 文本型
'   search ＝ #引号 ＋ key ＋ #引号 ＋ “:”
'   pos ＝ 寻找文本 (json, search, , 假)
'   .如果真 (pos ＝ 0)
'     返回 (“”)
'   .如果真结束
'   pos ＝ pos ＋ 取文本长度 (search)
'   ' 跳过空白
'   .判断循环首 (pos ≤ 取文本长度 (json) 且 (取文本中间 (json, pos, 1) ＝ “ ” 或 取文本中间 (json, pos, 1) ＝ #制表符))
'     pos ＝ pos ＋ 1
'   .判断循环尾 ()
'   ch ＝ 取文本中间 (json, pos, 1)
'   .如果 (ch ＝ #引号)
'     ' 字符串值: 跳过转义找到结束引号
'     pos ＝ pos ＋ 1
'     start ＝ pos
'     i ＝ pos
'     .判断循环首 (i ≤ 取文本长度 (json))
'       ch ＝ 取文本中间 (json, i, 1)
'       .如果真 (ch ＝ “\”)
'         i ＝ i ＋ 2
'         到循环尾 ()
'       .如果真结束
'       .如果真 (ch ＝ #引号)
'         跳出循环
'       .如果真结束
'       i ＝ i ＋ 1
'     .判断循环尾 ()
'     .如果 (i ＞ start)
'       value ＝ 取文本中间 (json, start, i － start)
'     .如果结束
'     返回 (解码JSON文本 (value))
'   .否则
'     ' 数字或其他
'     start ＝ pos
'     i ＝ pos
'     .判断循环首 (i ≤ 取文本长度 (json))
'       ch ＝ 取文本中间 (json, i, 1)
'       .如果真 (ch ＝ “,” 或 ch ＝ “}” 或 ch ＝ “]” 或 ch ＝ “ ”)
'         跳出循环
'       .如果真结束
'       i ＝ i ＋ 1
'     .判断循环尾 ()
'     返回 (取文本中间 (json, start, i － start))
'   .如果结束

' ==================== JSON解码 (\uXXXX → 字符) ====================
' 子程序 解码JSON文本, 文本型
'   .参数 s, 文本型
'   .局部变量 i, 整数型
'   .局部变量 ch, 文本型
'   .局部变量 out, 文本型
'   i ＝ 1
'   out ＝ “”
'   .判断循环首 (i ≤ 取文本长度 (s))
'     ch ＝ 取文本中间 (s, i, 1)
'     .如果 (ch ＝ “\” 且 取文本中间 (s, i ＋ 1, 1) ＝ “u”)
'       out ＝ out ＋ 字符 (到整数 (“&H” ＋ 取文本中间 (s, i ＋ 2, 4)))
'       i ＝ i ＋ 6
'     .否则
'       out ＝ out ＋ ch
'       i ＝ i ＋ 1
'     .如果结束
'   .判断循环尾 ()
'   返回 (out)

' ==================== JSON取状态码 ====================
' 子程序 JsonGetCode, 整数型
'   .参数 json, 文本型
'   .局部变量 s, 文本型
'   s ＝ JsonGetValue (json, “code”)
'   返回 (到整数 (s))

' ==================== 取时间戳(秒) ====================
' 子程序 取时间戳, 长整数型
'   返回 (取日期时间差 (日期 (1970, 1, 1), 取现行时间 (), #秒))

' ==================== 构建API请求体 ====================
' 子程序 BuildApiBody, 文本型
'   .参数 apiPwd, 文本型
'   .参数 plain, 文本型
'   .局部变量 ts, 长整数型
'   .局部变量 enc, 文本型
'   .局部变量 sign, 文本型
'   ts ＝ 取时间戳 ()
'   enc ＝ RC4加密 (apiPwd, plain)
'   sign ＝ MD5哈希 (apiPwd ＋ 到文本 (ts) ＋ enc)
'   返回 (“TimeStamp=” ＋ 到文本 (ts) ＋ “&Sign=” ＋ sign ＋ “&Data=” ＋ enc)

' ==================== 业务请求 ====================
' 子程序 ApiCall, 文本型
'   .参数 apiPwd, 文本型
'   .参数 plain, 文本型
'   返回 (HttpPost (BASE_URL ＋ “/” ＋ apiPwd, BuildApiBody (apiPwd, plain)))

' ==================== 初始化握手 ====================
' 子程序 ApiInit, 文本型
'   .局部变量 ts, 长整数型
'   .局部变量 sign, 文本型
'   .局部变量 body, 文本型
'   ts ＝ 取时间戳 ()
'   sign ＝ MD5哈希 (APP_ID ＋ APP_KEY ＋ 到文本 (ts) ＋ APP_KEY)
'   body ＝ “AppId=” ＋ APP_ID ＋ “&AppKey=” ＋ APP_KEY ＋ “&TimeStamp=” ＋ 到文本 (ts) ＋ “&Sign=” ＋ sign
'   返回 (HttpPost (BASE_URL, body))

' ==================== 版本比较(分段数字逐段比较) ====================
' 子程序 版本比较, 整数型
'   .参数 a, 文本型
'   .参数 b, 文本型
'   .局部变量 la, 文本型, , "0"
'   .局部变量 lb, 文本型, , "0"
'   .局部变量 i, 整数型
'   .局部变量 na, 整数型
'   .局部变量 nb, 整数型
'   .局部变量 max, 整数型
'   分割文本 (a, “.”, la)
'   分割文本 (b, “.”, lb)
'   max ＝ 取数组成员数 (la)
'   .如果真 (取数组成员数 (lb) ＞ max)
'     max ＝ 取数组成员数 (lb)
'   .如果真结束
'   .计次循环首 (max, i)
'     na ＝ 0
'     nb ＝ 0
'     .如果真 (i ≤ 取数组成员数 (la))
'       na ＝ 到整数 (la[i])
'     .如果真结束
'     .如果真 (i ≤ 取数组成员数 (lb))
'       nb ＝ 到整数 (lb[i])
'     .如果真结束
'     .如果 (na ＞ nb)
'       返回 (1)
'     .否则
'       .如果真 (na ＜ nb)
'         返回 (-1)
'       .如果真结束
'     .如果结束
'   .计次循环尾 ()
'   返回 (0)

' ==================== 写日志(带时间戳) ====================
' 子程序 写日志
'   .参数 msg, 文本型
'   .局部变量 f, 整数型
'   f ＝ 打开文件 (取运行目录 () ＋ “a7p-card-login.log”, 2, )
'   .如果真 (f ≠ 0)
'     移入文件尾 (f)
'     写出文本 (f, “[” ＋ 到文本 (取现行时间 ()) ＋ “] ” ＋ msg ＋ #换行符)
'     关闭文件 (f)
'   .如果真结束

' ==================== 时钟1_周期事件 (初始化) ====================
' 子程序 时钟1_周期事件
'   时钟1.时钟周期 ＝ 0
'   初始化 ()

' ==================== 初始化 ====================
' 子程序 初始化
'   .局部变量 result, 文本型
'   .局部变量 msg, 文本型
'   写日志 (“初始化: 开始 (AppId=” ＋ APP_ID ＋ “)”)
'   result ＝ ApiInit ()
'   .如果 (JsonGetCode (result) ＝ 200)
'     api_password ＝ JsonGetValue (result, “api_password”)
'     写日志 (“初始化: 成功”)
'     标签_状态.标题 ＝ “就绪”
'     标签_状态.字体颜色 ＝ #绿色
'     ' -------- 版本检查(发现新版强制更新) --------
'     .局部变量 ver, 文本型
'     ver ＝ ApiCall (api_password, “action=GetLatestVersion”)
'     .如果 (JsonGetCode (ver) ＝ 200)
'       .局部变量 rv, 文本型
'       rv ＝ JsonGetValue (ver, “version”)
'       .如果真 (取文本长度 (rv) ＞ 0)
'         写日志 (“版本检查: 远程 v” ＋ rv ＋ “, 本地 v” ＋ APP_VERSION)
'         .如果真 (版本比较 (rv, APP_VERSION) ＞ 0)
'           update_version ＝ rv
'           update_name ＝ JsonGetValue (ver, “version_name”)
'           update_url ＝ JsonGetValue (ver, “download_url”)
'           update_data ＝ JsonGetValue (ver, “version_data”)
'           提示更新 ()
'           返回 ()
'         .如果真结束
'       .如果真结束
'     .如果结束
'     ' -------- 公告加载 --------
'     .局部变量 bull, 文本型
'     bull ＝ ApiCall (api_password, “action=GetBulletin”)
'     .如果 (JsonGetCode (bull) ＝ 200)
'       .局部变量 content, 文本型
'       content ＝ JsonGetValue (bull, “content”)
'       .如果真 (取文本长度 (content) ＞ 0)
'         notice ＝ content
'         编辑框_公告.内容 ＝ notice
'       .如果真结束
'     .如果结束
'   .否则
'     msg ＝ JsonGetValue (result, “message”)
'     .如果真 (msg ＝ “”)
'       msg ＝ “未知错误”
'     .如果真结束
'     标签_状态.标题 ＝ “初始化失败: ” ＋ msg
'     标签_状态.字体颜色 ＝ #红色
'     写日志 (“初始化: 失败 - ” ＋ msg)
'   .如果结束

' ==================== 强制更新 ====================
' 子程序 提示更新
'   .局部变量 msg, 文本型
'   msg ＝ “发现新版本 v” ＋ update_version
'   .如果真 (取文本长度 (update_name) ＞ 0)
'     msg ＝ msg ＋ #换行符 ＋ “版本名称: ” ＋ update_name
'   .如果真结束
'   msg ＝ msg ＋ #换行符 ＋ “当前版本: v” ＋ APP_VERSION ＋ #换行符 ＋ #换行符 ＋ “此版本为强制更新,必须更新后才能使用!”
'   信息框 (msg, #警告图标, “版本更新”)
'   窗口1.可视 ＝ 假
'   窗口3.标题 ＝ “软件更新”
'   标签_新版本.标题 ＝ “新版本: v” ＋ update_version
'   .如果真 (取文本长度 (update_name) ＞ 0)
'     标签_版本名称.标题 ＝ “版本名称: ” ＋ update_name
'   .如果真结束
'   标签_进度.标题 ＝ “准备下载...”
'   标签_更新状态.标题 ＝ “正在连接服务器...”
'   标签_更新状态.字体颜色 ＝ 取颜色值 (255, 140, 0)
'   进度条_更新.位置 ＝ 0
'   按钮_取消.标题 ＝ “取消”
'   窗口3.可视 ＝ 真
'   时钟3.时钟周期 ＝ 500   ' 对齐 after(500)

' ==================== 时钟3_周期事件 (开始下载) ====================
' 子程序 时钟3_周期事件
'   时钟3.时钟周期 ＝ 0
'   开始下载 ()

' ==================== 开始下载 ====================
' 子程序 开始下载
'   .局部变量 url, 文本型
'   .局部变量 verData, 文本型
'   .局部变量 tmp, 文本型
'   url ＝ update_url
'   verData ＝ update_data
'   .如果 (取文本左边 (url, 7) ＝ “http://” 或 取文本左边 (url, 8) ＝ “https://”)
'     ' 有下载地址: 下载到临时目录, 提示手动运行新版本, 然后退出 (不做自覆盖)
'     tmp ＝ 取临时目录 () ＋ “a7p_update.tmp”
'     标签_进度.标题 ＝ “下载中...”
'     标签_更新状态.标题 ＝ “正在下载...”
'     运行 (“cmd /c curl -sL -o ” ＋ #引号 ＋ tmp ＋ #引号 ＋ “ ” ＋ #引号 ＋ url ＋ #引号, 真, #隐藏窗口)
'     进度条_更新.位置 ＝ 100
'     标签_进度.标题 ＝ “下载完成! 新版本已保存到临时目录”
'     标签_更新状态.标题 ＝ “更新完成! 请重新启动程序”
'     标签_更新状态.字体颜色 ＝ #绿色
'     信息框 (“软件已更新到最新版本!” ＋ #换行符 ＋ “新版本已保存到: ” ＋ tmp ＋ #换行符 ＋ “请手动运行新版本, 程序即将退出。”, #信息图标, “更新完成”)
'     写日志 (“更新: 下载完成, 程序退出”)
'     结束 ()
'   .否则
'     .如果 (取文本长度 (verData) ＞ 0)
'       ' 无下载地址: 展示更新说明
'       进度条_更新.位置 ＝ 100
'       标签_进度.标题 ＝ “更新内容:”
'       标签_更新状态.标题 ＝ verData
'       标签_更新状态.字体颜色 ＝ #蓝色
'       按钮_取消.标题 ＝ “关闭”
'     .否则
'       标签_更新状态.标题 ＝ “未获取到更新信息,请联系管理员获取更新包”
'       标签_更新状态.字体颜色 ＝ #红色
'     .如果结束
'   .如果结束

' ==================== 按钮_取消_被单击 / 窗口3_将被销毁 ====================
' 子程序 按钮_取消_被单击
'   窗口3.销毁 ()
'
' 子程序 窗口3_将被销毁
'   结束 ()   ' 强制更新: 关闭即退出程序, 不可跳过

' ==================== 卡密登录 ====================
' 子程序 按钮_登录_被单击
'   .局部变量 card, 文本型
'   .局部变量 mac, 文本型
'   .局部变量 result, 文本型
'   .如果真 (api_password ＝ “”)
'     信息框 (“初始化未完成,请稍候”, #警告图标, “提示”)
'     返回 ()
'   .如果真结束
'   card ＝ 删除首尾空白 (编辑框_卡密.内容)
'   .如果真 (card ＝ “”)
'     信息框 (“请输入卡密”, #警告图标, “提示”)
'     编辑框_卡密.获取焦点 ()
'     返回 ()
'   .如果真结束
'   按钮_登录.禁止 ＝ 真   ' 请求期间禁用按钮防重复提交
'   mac ＝ 获取机器码 ()
'   result ＝ ApiCall (api_password, “action=SingleLogin&Card=” ＋ card ＋ “&Mac=” ＋ mac ＋ “&DeviceName=PC-” ＋ mac)
'   .如果 (JsonGetCode (result) ＝ 200)
'     token ＝ JsonGetValue (result, “token”)
'     写日志 (“卡密登录: 成功 (用户: ” ＋ JsonGetValue (result, “username”) ＋ “)”)
'     信息框 (“用户: ” ＋ JsonGetValue (result, “username”) ＋ #换行符 ＋ “到期: ” ＋ JsonGetValue (result, “expire_at”), #信息图标, “登录成功”)
'     ' -------- 打开主窗口 --------
'     窗口1.可视 ＝ 假
'     标签_主用户.标题 ＝ JsonGetValue (result, “username”)
'     标签_主到期.标题 ＝ JsonGetValue (result, “expire_at”)
'     标签_主机器码.标题 ＝ mac
'     heartbeat_active ＝ 真
'     countdown ＝ HEARTBEAT_INTERVAL
'     标签_心跳.标题 ＝ “心跳: 运行中”
'     标签_心跳.字体颜色 ＝ #绿色
'     标签_心跳倒计时.标题 ＝ “  下次: ” ＋ 到文本 (countdown) ＋ “秒”
'     按钮_暂停.标题 ＝ “暂停”
'     窗口2.可视 ＝ 真
'     时钟2.时钟周期 ＝ 1000
'   .否则
'     写日志 (“卡密登录: 失败 - ” ＋ JsonGetValue (result, “message”))
'     信息框 (JsonGetValue (result, “message”), #错误图标, “登录失败”)
'   .如果结束
'   按钮_登录.禁止 ＝ 假

' ==================== 回车登录 ====================
' 子程序 编辑框_卡密_按下某键
'   .参数 键代码, 整数型
'   .参数 功能键状态, 整数型
'   .如果真 (键代码 ＝ #回车键)
'     按钮_登录_被单击 ()
'   .如果真结束

' ==================== 时钟2_周期事件 (心跳) ====================
' 子程序 时钟2_周期事件
'   .如果真 (heartbeat_active ＝ 假)
'     返回 ()
'   .如果真结束
'   .如果 (countdown ＞ 0)
'     标签_心跳倒计时.标题 ＝ “  下次: ” ＋ 到文本 (countdown) ＋ “秒”
'     countdown ＝ countdown － 1
'   .否则
'     countdown ＝ HEARTBEAT_INTERVAL
'     发送心跳 ()
'   .如果结束

' ==================== 发送心跳 ====================
' 子程序 发送心跳
'   .局部变量 result, 文本型
'   .局部变量 msg, 文本型
'   result ＝ ApiCall (api_password, “action=UserHeartbeat&Token=” ＋ token ＋ “&Type=user”)
'   .如果 (JsonGetCode (result) ＝ 200)
'     写日志 (“心跳: 正常”)
'     msg ＝ JsonGetValue (result, “msg”)
'     .如果真 (取文本长度 (msg) ＞ 0)
'       信息框 (msg, #信息图标, “后台消息”)
'     .如果真结束
'   .否则
'     写日志 (“心跳: 失败 - ” ＋ JsonGetValue (result, “message”))
'     信息框 (JsonGetValue (result, “message”), #警告图标, “心跳失败”)
'   .如果结束

' ==================== 暂停/继续 ====================
' 子程序 按钮_暂停_被单击
'   .如果 (heartbeat_active ＝ 真)
'     heartbeat_active ＝ 假
'     标签_心跳.标题 ＝ “心跳: 已暂停”
'     标签_心跳.字体颜色 ＝ 取颜色值 (255, 140, 0)
'     标签_心跳倒计时.标题 ＝ “  下次: 暂停”
'     按钮_暂停.标题 ＝ “继续”
'   .否则
'     heartbeat_active ＝ 真
'     标签_心跳.标题 ＝ “心跳: 运行中”
'     标签_心跳.字体颜色 ＝ #绿色
'     按钮_暂停.标题 ＝ “暂停”
'   .如果结束

' ==================== 窗口2_将被销毁 (返回登录窗口) ====================
' 子程序 窗口2_将被销毁
'   时钟2.时钟周期 ＝ 0
'   heartbeat_active ＝ 假
'   窗口1.可视 ＝ 真

' ==================== 窗口1_将被销毁 ====================
' 子程序 __启动窗口_将被销毁
'   结束 ()
