feat: 添加用户端链接状态查询接口及自动刷新逻辑

主要修改:
1. 在LinkController中新增获取用户链接状态的接口,支持通过linkId或codeNo查询。
2. 在LinkStatusService中实现用户链接状态查询逻辑,包含自动刷新和二维码更新功能。
3. 更新LinkTask实体,添加needRefresh、refreshTime、qrCreatedAt和qrExpireAt字段以支持新功能。
4. 在ScriptClient中新增检查空闲设备、选区、刷新、检查上号状态等操作的实现。
5. 更新SecurityConfig,允许用户端获取链接状态接口公开访问。

技术细节:
- 新增UserLinkStatusResponse DTO以支持用户链接状态的返回格式。
- 通过脚本端接口实现链接状态的自动刷新和二维码信息更新。
This commit is contained in:
zyh
2025-08-26 18:07:44 +08:00
parent e9858bfec1
commit 3847250c2b
13 changed files with 1106 additions and 18 deletions

View File

@@ -0,0 +1,118 @@
明白了!让我重新整理接口设计:
## 后端接口设计文档(最终版)
### 1. 获取链接状态接口
**接口:** `GET /api/link/status?code={code}`
**业务逻辑:**
1. 解密和验证code参数包含linkId、签发时间、过期时间等
2. 检查链接是否过期默认24小时
3. 从数据库查询链接当前状态
4. **如果状态不是NEW后端自动执行刷新逻辑**
- 调用脚本端刷新:`POST http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断刷新&编号=刷新`
- 设置need_refresh=true记录refresh_time
- 等待10秒或配置的刷新等待时间
- 执行完毕后继续下面的逻辑
5. **如果状态为USING重新获取二维码**
- 调用:`http://36.138.184.60:12345/{编号}/二维码.png?t={timestamp}`
- 更新qr_created_at和qr_expire_at
6. 返回链接状态和相关信息
**前端调用方式:**
```javascript
// 前端只需要调用一次,后端会自动处理刷新逻辑
const statusResponse = await fetch('/api/link/status?code=' + code);
const status = await statusResponse.json();
// 根据返回的状态直接渲染对应页面
```
**数据库操作:**
- 如果状态不是NEW设置need_refresh=true记录refresh_time
- 如果状态为USING更新qr_created_at和qr_expire_at
### 2. 刷新接口(保留,供手动刷新使用)
**接口:** `POST /api/link/refresh`
**请求体:** `{ code: string }`
**业务逻辑:**
1. 验证code参数
2. 调用脚本端刷新
3. 设置need_refresh=true记录refresh_time
4. 返回等待时间
**使用时机:**
- 用户在扫码页面手动点击"刷新"按钮时
### 3. 选区接口
**接口:** `POST /api/link/select-region`
**请求体:** `{ code: string, region: "Q" | "V" }`
**业务逻辑:**
1. 验证code和region参数
2. 检查链接状态只有NEW状态才能选区
3. **如果need_refresh=true检查是否已等待10秒否则返回423错误**
4. 调用脚本端分配空闲设备
5. 调用脚本端选区
6. 等待脚本端生成二维码
7. 更新数据库状态为USING
8. 返回二维码信息
### 4. 轮询上号接口
**接口:** `GET /api/link/poll-login?code={code}`
**业务逻辑:**
1. 验证code参数
2. 检查链接状态只有USING状态才能轮询
3. 调用脚本端检查上号状态
4. 如果返回"已上号"更新状态为LOGGED_IN
5. 返回上号结果和资源信息
### 5. 核心改动说明
**获取状态接口的核心逻辑:**
```java
@GetMapping("/status")
public ResponseEntity<LinkStatusResponse> getStatus(@RequestParam String code) {
// 1. 验证code
LinkTask linkTask = validateAndGetLinkTask(code);
// 2. 如果状态不是NEW自动执行刷新
if (!"NEW".equals(linkTask.getStatus())) {
// 调用脚本端刷新
scriptClient.refresh(linkTask.getCodeNo());
// 设置刷新标记和时间
linkTask.setNeedRefresh(true);
linkTask.setRefreshTime(new Date());
linkTaskMapper.updateById(linkTask);
// 等待10秒
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 3. 如果状态为USING重新获取二维码
if ("USING".equals(linkTask.getStatus())) {
long timestamp = System.currentTimeMillis();
String qrUrl = String.format("http://36.138.184.60:12345/%s/二维码.png?t=%d",
linkTask.getCodeNo(), timestamp);
linkTask.setQrCreatedAt(new Date());
linkTask.setQrExpireAt(new Date(System.currentTimeMillis() + 60000));
linkTaskMapper.updateById(linkTask);
}
// 4. 返回状态信息
return ResponseEntity.ok(buildStatusResponse(linkTask));
}
```
这样的设计是否符合你的需求?前端只需要调用一次获取状态接口,后端会自动处理所有刷新逻辑。