# 退单接口使用说明

## 📋 功能概述

退单接口允许代理用户对自己创建的链接进行退单操作。执行退单时，系统会：

1. 调用外部脚本退单接口：`http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断退单&cc2={machineId}`
2. 将链接状态更新为 `REFUNDED`
3. 记录退单时间

## 🔧 接口详情

### 基本信息
- **请求方式**: `POST`
- **请求路径**: `/api/link/{codeNo}/refund`
- **认证方式**: JWT Bearer Token
- **返回类型**: `application/json`

### 请求参数

#### 路径参数
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| codeNo | String | 是 | 链接编号 |

#### 请求头
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| Authorization | String | 是 | JWT认证令牌，格式：`Bearer {token}` |

### 响应格式

#### 成功响应 (HTTP 200)
```json
{
  "data": true,
  "success": true,
  "message": "操作成功"
}
```

#### 错误响应
```json
{
  "success": false,
  "message": "错误详情",
  "code": "错误代码"
}
```

## 📝 使用示例

### 1. 基本退单操作

```bash
curl -X POST 'http://localhost:8080/api/link/ABC12345/refund' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...' \
  -H 'Content-Type: application/json'
```

**成功响应：**
```json
{
  "data": true,
  "success": true,
  "message": "退单操作成功"
}
```

### 2. JavaScript 示例

```javascript
async function refundOrder(codeNo, jwt_token) {
    try {
        const response = await fetch(`http://localhost:8080/api/link/${codeNo}/refund`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${jwt_token}`,
                'Content-Type': 'application/json'
            }
        });
        
        const result = await response.json();
        
        if (result.success) {
            console.log('退单成功');
            return true;
        } else {
            console.error('退单失败:', result.message);
            return false;
        }
    } catch (error) {
        console.error('退单请求失败:', error);
        return false;
    }
}

// 使用示例
refundOrder('ABC12345', 'your_jwt_token');
```

### 3. Python 示例

```python
import requests

def refund_order(code_no, jwt_token):
    """执行退单操作"""
    url = f'http://localhost:8080/api/link/{code_no}/refund'
    headers = {
        'Authorization': f'Bearer {jwt_token}',
        'Content-Type': 'application/json'
    }
    
    try:
        response = requests.post(url, headers=headers)
        response.raise_for_status()
        
        result = response.json()
        
        if result.get('success'):
            print('退单成功')
            return True
        else:
            print(f'退单失败: {result.get("message")}')
            return False
            
    except requests.exceptions.RequestException as e:
        print(f'退单请求失败: {e}')
        return False

# 使用示例
refund_order('ABC12345', 'your_jwt_token')
```

## 🚫 错误处理

### 常见错误类型

| 错误码 | HTTP状态 | 错误信息 | 说明 |
|-------|---------|---------|------|
| AUTH_001 | 401 | 用户未认证 | JWT令牌无效或过期 |
| LINK_001 | 400 | 链接不存在 | 指定的链接编号不存在 |
| LINK_002 | 400 | 权限不足 | 用户无权操作此链接 |
| LINK_003 | 400 | 链接已经退过单 | 不能重复退单 |
| LINK_004 | 400 | 过期链接不允许退单 | 链接已过期 |
| LINK_005 | 400 | 已完成链接不允许退单 | 游戏已完成的链接 |

### 错误处理示例

```javascript
async function handleRefund(codeNo, token) {
    try {
        const response = await fetch(`/api/link/${codeNo}/refund`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${token}`,
                'Content-Type': 'application/json'
            }
        });
        
        const result = await response.json();
        
        if (!result.success) {
            switch (result.code) {
                case 'LINK_003':
                    alert('此链接已经退过单了');
                    break;
                case 'LINK_004':
                    alert('过期链接无法退单');
                    break;
                case 'LINK_005':
                    alert('已完成的游戏无法退单');
                    break;
                default:
                    alert('退单失败: ' + result.message);
            }
            return false;
        }
        
        alert('退单成功');
        return true;
        
    } catch (error) {
        console.error('退单请求失败:', error);
        alert('网络错误，请稍后重试');
        return false;
    }
}
```

## 🔄 状态流转

### 允许退单的状态
- `NEW` (新建)
- `USING` (使用中) 
- `LOGGED_IN` (已登录)

### 不允许退单的状态
- `REFUNDED` (已退款) - 已经退过单
- `EXPIRED` (已过期) - 链接已过期
- `COMPLETED` (已完成) - 游戏已完成

### 状态流转图
```
NEW/USING/LOGGED_IN  →  [退单操作]  →  REFUNDED (最终状态)
```

## 📊 业务逻辑

### 退单流程

1. **身份验证**
   - 验证JWT令牌有效性
   - 确认用户有权限操作该链接

2. **状态检查**
   - 检查链接是否存在
   - 检查链接当前状态是否允许退单

3. **外部接口调用**
   - 如果链接有关联设备，调用脚本端退单接口
   - URL格式：`http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断退单&cc2={真实设备ID}`
   - 即使外部接口调用失败，仍会更新数据库状态

4. **数据库更新**
   - 更新链接状态为 `REFUNDED`
   - 记录退单时间 `refund_at`
   - 更新修改时间 `updated_at`

### 注意事项

1. **权限控制**: 用户只能退单自己创建的链接
2. **状态限制**: 只有特定状态的链接才能退单
3. **重复操作**: 已退单的链接不能再次退单
4. **外部接口**: 即使外部接口调用失败，也会更新本地状态，避免用户重复操作
5. **事务性**: 整个退单操作在事务中执行，确保数据一致性

## 🧪 测试示例

### 完整测试流程

```bash
# 1. 登录获取JWT令牌
curl -X POST 'http://localhost:8080/api/auth/login' \
  -H 'Content-Type: application/json' \
  -d '{"username":"test_user","password":"password"}'

# 2. 生成测试链接
curl -X POST 'http://localhost:8080/api/link/generate' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"times":1,"linkCount":1}'

# 3. 查看链接状态 (退单前)
curl -X GET 'http://localhost:8080/api/link/YOUR_CODE_NO/status'

# 4. 执行退单操作
curl -X POST 'http://localhost:8080/api/link/YOUR_CODE_NO/refund' \
  -H 'Authorization: Bearer YOUR_JWT_TOKEN'

# 5. 查看链接状态 (退单后，应该是REFUNDED状态)
curl -X GET 'http://localhost:8080/api/link/YOUR_CODE_NO/status'
```

## 🔍 日志示例

### 成功退单日志
```
2024-01-15 14:30:00.123 INFO  LinkStatusService - === 开始处理退单操作 ===
2024-01-15 14:30:00.124 INFO  LinkStatusService - 链接编号: ABC12345, 代理ID: 1001
2024-01-15 14:30:00.125 INFO  LinkStatusService - 链接关联设备: f1, 调用脚本端退单接口
2024-01-15 14:30:00.234 INFO  ScriptClient - 调用退单接口: 设备=f1, url=http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断退单&cc2=f1
2024-01-15 14:30:00.567 INFO  ScriptClient - 退单接口调用成功: 设备=f1, 结果=SUCCESS
2024-01-15 14:30:00.580 INFO  LinkStatusService - 退单操作成功: codeNo=ABC12345, 设备=f1, 状态更新为REFUNDED
2024-01-15 14:30:00.581 INFO  LinkStatusService - === 退单操作完成 ===
```

### 失败退单日志
```
2024-01-15 14:30:00.123 INFO  LinkStatusService - === 开始处理退单操作 ===
2024-01-15 14:30:00.124 INFO  LinkStatusService - 链接编号: ABC12345, 代理ID: 1001
2024-01-15 14:30:00.125 WARN  LinkStatusService - 链接已经退过单: codeNo=ABC12345, status=REFUNDED
2024-01-15 14:30:00.126 ERROR LinkStatusService - === 退单操作失败 ===
2024-01-15 14:30:00.127 ERROR LinkStatusService - codeNo=ABC12345, agentId=1001, 错误详情: 链接已经退过单
```

## 🔗 相关接口

- [链接生成接口](./API文档.md#链接生成)
- [链接状态查询接口](./链接状态接口测试.md)
- [链接列表接口](./链接列表接口测试.md)
- [JWT认证说明](./JWT认证使用说明.md)
