# 上号系统需求文档（PRD/SRS）v0.9

> 基于《安装步骤.docx》与用户确认的补充说明整理。本文作为首版“可评审草案”，确认后进入详细设计与开发。

---

## 0. 版本信息

* 文档版本：v0.9（草案）
* 更新时间：2025-08-23
* 负责人：待定
* 评审人：待定
* 目标里程碑：首版上线（TBD）

---

## 1. 项目概述

### 1.1 背景

提供“上号任务”的一站式系统，生成带签名与加密的用户链接，用户进入后进行选区、扫码上号、实时进度与二界面跳转；面向商家（管理员、代理商）提供链接批量生成与额度（点数）管理、退单与公告等功能。

### 1.2 目标

* 终端用户侧：通过单个加密链接完成选区 → 扫码上号 → 进入二界面。
* 商家侧：

  * 管理员：创建代理商账号、为代理商添加点数（余额）、批量生成链接、退单、公告管理、数据导出。
  * 代理商：查看自身额度、批量生成链接、退单、数据导出、查看公告。

### 1.3 不在范围（本期）

* 对账、统计、风控（均不做）。
* 富文本公告、多语言、公告定时上线下线。
* 数据导入（仅导出）。

---

## 2. 角色与权限

* **终端用户**：仅访问加密链接完成流程。
* **管理员**：代理商管理（创建/启停/加点）、批量生成链接、退单、公告发布、导出。
* **代理商**：批量生成链接（前提是额度充足）、退单、导出、查看公告。

### 2.1 权限矩阵（简表）

| 功能         | 终端用户 | 代理商     | 管理员    |
| ---------- | ---- | ------- | ------ |
| 访问加密链接进行上号 | ✔️   | —       | —      |
| 批量生成链接     | —    | ✔️      | ✔️     |
| 查看/导出链接    | —    | ✔️（仅自己） | ✔️（全量） |
| 退单         | —    | ✔️（仅自己） | ✔️（全量） |
| 公告查看       | —    | ✔️      | ✔️     |
| 公告发布       | —    | —       | ✔️     |
| 代理商账号管理/加点 | —    | —       | ✔️     |

---

## 3. 术语与规则

* **链接（Link）**：一次任务的入口地址，带签名与加密；默认有效期 **24 小时**（可配）。
* **编号（CodeNo）**：由后端自动生成，**全局唯一**、可追踪；用于日志与二界面模板替换。
* **数量（Quantity）**：一次执行产生的奖励数，例如 50。
* **次数（Times）**：重复执行次数，例如 20。
* **总点数（TotalPoints）**：`Times × Quantity`，例如 20×50=1000。
* **批量生成**：同一组设置一次生成 N 个链接（默认 10 个，可配）。
* **二界面**：外部提供的页面或资源，系统在上号成功后 **用编号动态替换**后跳转。
* **脚本端**：运行在手机上的脚本与相关资源（例如二维码图片、进度截图、上号判断等），由系统通过适配器服务进行对接。

---

## 4. 业务流程

### 4.1 链接生命周期（简述）

1. 商家侧生成链接：校验额度 → 扣减点数（`Times×Quantity`）→ 生成编号 → 生成**加密+签名**链接 → 设置过期时间（24h）。
2. 终端用户访问链接：若未过期，进入“选区→扫码上号”流程；成功则跳转二界面；若退单或过期则提示不可用。
3. 退单：释放机器（不回滚额度），记录日志。

### 4.2 终端用户流程（含二次识别/刷新约束）

* **首次进入**：

  1. 选区（安卓QQ/安卓WX）。
  2. 触发脚本端生成二维码；前端按返回的 `qrCreatedAt/qrExpireAt` 本地计算倒计时并轮询上号状态。
  3. 上号成功 → 跳转二界面（按模板替换编号）。
* **未进入二界面即退出/刷新/返回**：

  * 规则：**必须先调用“刷新”接口** → 等待 **Y 秒（默认 10s，可配）** → 才允许再次选区与扫码。

### 4.3 退单流程

* 商家提交编号 → 系统释放关联机器（若有）→ 标记退单 → 记录日志；额度**不回滚**。

### 4.4 扣费时机与计算

* **生成链接时即扣费**：`扣减点数 = Times × Quantity × 批量个数`。
* 额度不足：拒绝生成。

### 4.5 公告

* 简单文本公告（可配置是否展示、展示位置），无定时/富文本/多语言。

### 4.6 用户端（扫码登录）规范（单链接模式 · 定稿）

> 本节**仅**描述用户访问与后端处理逻辑；不涉及商家功能。**一切界面都在同一 URL**：`https://yourdomain.com/play?code={codeNo}`。前端通过该 URL 内的 `code` 调用后端查询状态并渲染对应页面（首界面/扫码界面/二界面）。

#### 4.6.1 URL 与安全

* 入口：`GET https://yourdomain.com/play?code={opaque}`，`code` 为**加密+签名**的**不透明**令牌（包含 linkId/iat/exp 等），不可被推断。
* 后端在**每次**接口调用时校验：解密→签名→有效期（默认 24h）→状态；失败返回 401/403/410（过期）。

#### 4.6.2 状态模型（后端对前端暴露）

* `NEW`：未进入扫码流程（未选区）。
* `USING`：已进入扫码流程（已选区，二维码有效期内）。
* `LOGGED_IN`：已上号（展示二界面）。
* `REFUNDED`：已退单（不可用）。
* `EXPIRED`：已过期（24h）。
* `needRefresh: boolean`：是否必须先刷新→等待 10 秒→再允许选区与扫码（只要进入过扫码但未到二界面时生效）。

#### 4.6.3 用户端 API（仅用户用）

> 路径示例以 `/api/link/*` 说明；实际以最终路由为准。

1. **获取状态**
   `GET /api/link/status?code={code}` →

```json
{
  "status": "NEW | USING | LOGGED_IN | REFUNDED | EXPIRED",
  "needRefresh": false,
  "region": "Q | V | null",
  "qr": { "url": "http://ip:12345/{编号}/二维码.png", "createdAt": 1730000000000, "expireAt": 1730000060000 },
  "view": "FIRST | SCAN | SECOND",          
  "assets": {                                
    "base": "http://ip:12345/{编号}/",       
    "firstHome": "首次主页.png",             
    "firstBonus": "首次赏金.png",            
    "midBonus": "中途赏金.png",              
    "endBonus": "结束赏金.png"               
  }
}
```

* 说明：

  * `qr` 仅在 `status=USING` 时返回；若脚本端无 TTL，后端以默认 **60s** 回填。
  * `view` 是前端渲染建议：`FIRST(选区) / SCAN(扫码) / SECOND(二界面)`；实际以 `status/needRefresh` 为准。
  * `assets` 为二界面所需的静态资源信息（路径中需要自动替换编号）。

2. **选区**
   `POST /api/link/select-region`
   Body: `{ code: string, region: "Q" | "V" }` → 返回：

```json
{
  "status": "USING",
  "needRefresh": false,
  "qr": { "url": "http://ip:12345/{编号}/二维码.png", "createdAt": 1730000000000, "expireAt": 1730000060000 }
}
```

* 后端行为：按需分配机器、下发任务参数、请求脚本端生成二维码；将状态置为 `USING`。

3. **刷新**
   `POST /api/link/refresh`
   Body: `{ code: string }` → 返回：

```json
{ "needRefresh": true, "waitSeconds": 10 }
```

* 规则：**未到二界面前**，再次尝试必须先刷新并在前端**等待 10 秒**后才允许重新选区与扫码。

4. **轮询上号**
   `GET /api/link/poll-login?code={code}` →

* 未上号：`{ "success": false, "status": "USING" }`
* 已上号：

```json
{ "success": true, "status": "LOGGED_IN", "view": "SECOND", "assets": { "base": "http://ip:12345/{编号}/", "endBonus": "结束赏金.png" } }
```

* 前端据返回改为渲染**二界面**（同一个 URL，不跳转）。

> 可选：`GET /api/link/qr.png?code={code}` 由后端代理二维码，确保整链路 HTTPS，避免浏览器混合内容拦截。

#### 4.6.4 前端渲染流程（同一路由）

1. **首访**：调用 `/api/link/status` 渲染：

   * `NEW` → 显示选区页（两个按钮 Q/V）。
   * `USING` → 显示扫码页（二维码+倒计时），并开始轮询 `/poll-login`（每 1s）。
   * `LOGGED_IN` → 显示二界面（依 `assets` 取图/信息）。
   * `REFUNDED/EXPIRED` → 显示不可用页。
2. **选区**：`POST /select-region` 成功后进入扫码页，开始轮询。
3. **二维码过期**：倒计时到 0 或轮询返回需刷新 → 显示“请刷新”按钮；调用 `/refresh` 并禁用按钮 **10s**，倒计时结束后恢复“选区”按钮。
4. **上号成功**：轮询返回 `LOGGED_IN` → 在**同一 URL** 切换到二界面视图；前端可停止所有轮询与倒计时。

#### 4.6.5 后端内部处理要点

* **校验**：对所有接口按 `code` 做鉴权（签名/解密/过期/撤销/退单）。
* **状态流转**：

  * `NEW → USING`：选区成功并生成二维码。
  * `USING → LOGGED_IN`：脚本端返回“已上号”。
  * `NEW/USING → REFUNDED | EXPIRED`：退单或超时达 24h。
* **刷新约束**：对进入过扫码但未上号的会话，标记 `needRefresh=true`；`/refresh` 后写入“刷新时间”，后续 **10s** 内拒绝 `select-region`。
* **脚本端适配**：分配/释放机器、生成二维码、查询“是否上号”、可选的分数读取；超时重试与错误兜底（不把脚本端错误直接暴露给前端）。
* **幂等**：`select-region`/`refresh`/`poll-login` 按 `code` 幂等处理，避免重复侧效应。
* **日志**：记录编号、选区、二维码下发/失效、上号结果、刷新与错误（保留 90 天）。

#### 4.6.6 错误与前端文案（示例）

* 401/403：链接无效或已篡改 → “链接无效，请联系商家”。
* 410：链接已过期 → “链接已过期，请联系商家重新获取”。
* 423：需刷新等待 → “请先刷新并等待 10 秒后再试”。
* 504：脚本端超时 → “当前排队人数较多，请稍后重试”。

> 以上约束确保“同一链接承载首界面/扫码/二界面”的产品体验，前端仅根据后端状态渲染视图，无需路由跳转。



次数链接
http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=总次数&编号=次数

后台操作流程: 后台管理员在后台输入框里面填写了一个次数5, 然后点击了生成, 平台会自动生成一个链接,格式如同:域名/加密

批量生成可以搞成下载文件或者复制粘贴都可以

后台功能:
1.后台可以直接单生成链接或者批量生成链接给用户使用如图
2.代理系统, 代理也可单独生成链接或批量生成, 后台可帮他设置金额, 代理使用多少，自动扣除多少
3.退单: 后台只需填写正确的编号运行退单链接，即可直接退单
4.用户选区之后等待几秒 出现二维码到期时间 刷新时间 用户使用有效期 设置
5.次数等于数量 设置
6.可以设置公告弹窗, 代理也可以自己生成自己的, 不会互通!  只有确定和取消按钮，点确定会跳转某网页

退单链接() 
http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断退单&编号=T

第一步；用户界面 1和2
2
判断空的设备链接 
http://36.138.184.60:1234/yijianwan_netfile/readAllMsg?文件名=判断分数

选区链接
http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断系统&编号=Q或V

刷新链接
http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断刷新&编号=刷新

二维码的http://36.138.184.60:12345/编号/二维码.png

判断是否上号
http://36.138.184.60:1234/yijianwan_netfile/readMsg?文件名=判断上号&对象名=编号  状态: 未上号 已上号 【已上号跳转第二个界面】

讲解:后台生成了一个链接，填写了次数, 用户拿到链接之后，在浏览器运行, 后台会自动获取一个空的编号, 然后用户可以自己选QQ区或微信区, 如果用户选择QQ区，那么直接执行选区链接执行QQ的, 微信也一样, 根据后台设置的等待，几秒后获取二维码链接 如同第三张图, 点击之后你可以观看第三张图，有一个倒数时间，也可在后台设置时间, 如果用户在我设置的60秒内没扫码，自动会跳出扫码超时,如第二张图, 用户可以继续选区, 后台会首先执行刷新链接, 然后根据后台设置的刷新时间，等待多少秒后再执行选择QQ区或微信区的链接, 根据用户选择, 作者可以写一个日志或者其他把把这个些链接的使用流程记录下来，方便第二次识别, 

假如:用户他第一次已经选过了区，但是他直接第二次刷新了浏览器, 导致没办法确认我后台对接的脚本是否在首页,  所以作者必须写个记录, 来判断这个链接是否被使用过一次，如果被使用过一次, 那么用户不管是刷新浏览器，还是等待超时扫码, 都判定为第二次! 所以必须先执行刷新根据后台设计的时间等待 再选区!

用户只要选区了，出现了二维码，那么后台只需要一直识别判断它是否上号那条链接，如果出现已上号，那么直接跳转第二个界面，未上号就一直在第一个界面!



用户扫码后跳转的:第二个界面



②http://36.138.184.60:12345/编号/首次主页.png 
③http://36.138.184.60:12345/编号/首次赏金.png 
④http://36.138.184.60:12345/编号/中途赏金.png 
⑤http://36.138.184.60:12345/编号/结束赏金.png

讲解:
1.选择大厅这个就是用户自己选的区域显示
2.状态=已打完 空闲, 只要显示这两个状态，余地都是已打完，其他都是代练中
3.目标点数0/1000如图1000就是后台设置的次数x次数等于数量=1000 [假如后台设置的次数等于总量为50,那么必须设置20次才等于1000

使用过的所有链接总有效期为24小时 可设置

目标点数
 http://36.138.184.60:1234/yijianwan_netfile/readMsg?文件名=判断分数&对象名=编号



