新增系统配置表及默认配置,更新链接生成请求DTO以支持链接数量参数,重构链接生成服务逻辑,添加链接状态查询和有效性检查接口,优化日志记录。
This commit is contained in:
@@ -39,7 +39,7 @@ Content-Type: application/json
|
||||
|
||||
{
|
||||
"times": 10,
|
||||
"perTimeQuantity": 5
|
||||
"linkCount": 5
|
||||
}
|
||||
```
|
||||
|
||||
@@ -56,7 +56,7 @@ Content-Type: application/json
|
||||
```json
|
||||
{
|
||||
"times": 10, // 本次打脚本的次数
|
||||
"perTimeQuantity": 5 // 每次打的数量
|
||||
"linkCount": 5 // 生成多少个链接
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -144,4 +144,33 @@ CREATE TABLE `user_account` (
|
||||
CONSTRAINT `chk_points_nonneg` CHECK (`points_balance` >= 0)
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for system_config
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `system_config`;
|
||||
CREATE TABLE `system_config` (
|
||||
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`config_key` varchar(100) NOT NULL COMMENT '配置键',
|
||||
`config_value` text NOT NULL COMMENT '配置值',
|
||||
`config_type` varchar(50) NOT NULL DEFAULT 'STRING' COMMENT '配置类型:STRING, INTEGER, BOOLEAN, JSON',
|
||||
`description` varchar(500) NULL DEFAULT NULL COMMENT '配置描述',
|
||||
`is_system` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否系统配置(1是,0否)',
|
||||
`created_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `uk_config_key`(`config_key` ASC) USING BTREE,
|
||||
INDEX `idx_config_type`(`config_type` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||
|
||||
-- 插入默认配置
|
||||
INSERT INTO `system_config` (`config_key`, `config_value`, `config_type`, `description`, `is_system`) VALUES
|
||||
('link.default_quantity', '50', 'INTEGER', '链接生成默认奖励点数', 1),
|
||||
('link.refresh_interval', '300', 'INTEGER', '链接刷新间隔(秒)', 1),
|
||||
('link.qr_expire_time', '600', 'INTEGER', '二维码过期时间(秒)', 1),
|
||||
('link.max_times_per_batch', '100', 'INTEGER', '每批次最大刷奖励次数', 1),
|
||||
('link.min_quantity', '10', 'INTEGER', '最小奖励点数', 1),
|
||||
('link.max_quantity', '1000', 'INTEGER', '最大奖励点数', 1),
|
||||
('script.server_url', 'http://36.138.184.60:12345', 'STRING', '脚本服务器地址', 1),
|
||||
('script.qr_path_template', '/{machineId}/二维码.png', 'STRING', '二维码图片路径模板', 1);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
403
docs/前端链接访问示例.md
Normal file
403
docs/前端链接访问示例.md
Normal file
@@ -0,0 +1,403 @@
|
||||
# 前端链接访问示例
|
||||
|
||||
## 概述
|
||||
当用户访问链接页面时(如 `https://你的域名/ABC12345`),前端需要自动请求后端获取链接的详细信息,并根据状态显示相应的内容。
|
||||
|
||||
## 接口说明
|
||||
|
||||
### 1. 获取链接状态(主要接口)
|
||||
```
|
||||
GET /api/link/{codeNo}/status
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
```json
|
||||
{
|
||||
"codeNo": "ABC12345",
|
||||
"batchId": 123,
|
||||
"status": "NEW",
|
||||
"statusDesc": "新建",
|
||||
"expireAt": "2024-01-15T16:30:00",
|
||||
"isExpired": false,
|
||||
"remainingSeconds": 3600,
|
||||
"quantity": 50,
|
||||
"times": 10,
|
||||
"totalPoints": 500,
|
||||
"region": null,
|
||||
"machineId": null,
|
||||
"loginAt": null,
|
||||
"createdAt": "2024-01-15T12:00:00",
|
||||
"updatedAt": "2024-01-15T12:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 检查链接是否存在
|
||||
```
|
||||
GET /api/link/{codeNo}/exists
|
||||
```
|
||||
|
||||
**响应:** `true` 或 `false`
|
||||
|
||||
### 3. 检查链接是否有效
|
||||
```
|
||||
GET /api/link/{codeNo}/valid
|
||||
```
|
||||
|
||||
**响应:** `true` 或 `false`
|
||||
|
||||
## 前端实现示例
|
||||
|
||||
### React 组件示例
|
||||
|
||||
```jsx
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
const LinkPage = () => {
|
||||
const { codeNo } = useParams();
|
||||
const [linkStatus, setLinkStatus] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetchLinkStatus();
|
||||
}, [codeNo]);
|
||||
|
||||
const fetchLinkStatus = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await fetch(`/api/link/${codeNo}/status`);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
setError('链接不存在');
|
||||
} else {
|
||||
setError('获取链接信息失败');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
setLinkStatus(data);
|
||||
} catch (err) {
|
||||
setError('网络错误');
|
||||
console.error('获取链接状态失败:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const formatTime = (seconds) => {
|
||||
if (seconds <= 0) return '已过期';
|
||||
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
const secs = seconds % 60;
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}小时${minutes}分钟`;
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}分钟${secs}秒`;
|
||||
} else {
|
||||
return `${secs}秒`;
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="loading">加载中...</div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="error">
|
||||
<h2>链接错误</h2>
|
||||
<p>{error}</p>
|
||||
<p>链接编号: {codeNo}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!linkStatus) {
|
||||
return <div>未找到链接信息</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="link-page">
|
||||
<div className="link-header">
|
||||
<h1>游戏任务链接</h1>
|
||||
<div className="link-code">链接编号: {linkStatus.codeNo}</div>
|
||||
</div>
|
||||
|
||||
<div className="link-status">
|
||||
<div className="status-item">
|
||||
<span className="label">状态:</span>
|
||||
<span className={`value status-${linkStatus.status.toLowerCase()}`}>
|
||||
{linkStatus.statusDesc}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="status-item">
|
||||
<span className="label">任务信息:</span>
|
||||
<span className="value">
|
||||
打{linkStatus.times}次副本,每次{linkStatus.quantity}点
|
||||
(总计{linkStatus.totalPoints}点)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="status-item">
|
||||
<span className="label">过期时间:</span>
|
||||
<span className="value">
|
||||
{linkStatus.expireAt}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="status-item">
|
||||
<span className="label">剩余时间:</span>
|
||||
<span className={`value ${linkStatus.isExpired ? 'expired' : ''}`}>
|
||||
{formatTime(linkStatus.remainingSeconds)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{linkStatus.isExpired && (
|
||||
<div className="expired-notice">
|
||||
<p>⚠️ 此链接已过期,无法使用</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!linkStatus.isExpired && linkStatus.status === 'NEW' && (
|
||||
<div className="action-section">
|
||||
<h3>开始任务</h3>
|
||||
<p>点击下方按钮开始执行任务</p>
|
||||
<button className="start-btn" onClick={() => startTask()}>
|
||||
开始任务
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{linkStatus.status === 'USING' && (
|
||||
<div className="task-progress">
|
||||
<h3>任务进行中</h3>
|
||||
<p>请按照提示完成游戏任务</p>
|
||||
<div className="progress-bar">
|
||||
<div className="progress-fill" style={{width: '50%'}}></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{linkStatus.status === 'LOGGED_IN' && (
|
||||
<div className="task-complete">
|
||||
<h3>任务完成</h3>
|
||||
<p>恭喜!任务已完成,奖励点数已发放</p>
|
||||
<div className="reward-info">
|
||||
获得奖励: {linkStatus.totalPoints} 点
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="qr-section">
|
||||
<h3>扫码访问</h3>
|
||||
<img
|
||||
src={`/api/link/${codeNo}/qr.png`}
|
||||
alt="二维码"
|
||||
className="qr-code"
|
||||
/>
|
||||
<p>使用手机扫描二维码访问</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const startTask = () => {
|
||||
// 实现开始任务的逻辑
|
||||
console.log('开始任务');
|
||||
};
|
||||
|
||||
export default LinkPage;
|
||||
```
|
||||
|
||||
### Vue 组件示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="link-page">
|
||||
<div v-if="loading" class="loading">加载中...</div>
|
||||
|
||||
<div v-else-if="error" class="error">
|
||||
<h2>链接错误</h2>
|
||||
<p>{{ error }}</p>
|
||||
<p>链接编号: {{ codeNo }}</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="linkStatus" class="link-content">
|
||||
<div class="link-header">
|
||||
<h1>游戏任务链接</h1>
|
||||
<div class="link-code">链接编号: {{ linkStatus.codeNo }}</div>
|
||||
</div>
|
||||
|
||||
<div class="link-status">
|
||||
<div class="status-item">
|
||||
<span class="label">状态:</span>
|
||||
<span :class="['value', `status-${linkStatus.status.toLowerCase()}`]">
|
||||
{{ linkStatus.statusDesc }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="status-item">
|
||||
<span class="label">任务信息:</span>
|
||||
<span class="value">
|
||||
打{{ linkStatus.times }}次副本,每次{{ linkStatus.quantity }}点
|
||||
(总计{{ linkStatus.totalPoints }}点)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="status-item">
|
||||
<span class="label">剩余时间:</span>
|
||||
<span :class="['value', { 'expired': linkStatus.isExpired }]">
|
||||
{{ formatTime(linkStatus.remainingSeconds) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="linkStatus.isExpired" class="expired-notice">
|
||||
<p>⚠️ 此链接已过期,无法使用</p>
|
||||
</div>
|
||||
|
||||
<div v-if="!linkStatus.isExpired && linkStatus.status === 'NEW'" class="action-section">
|
||||
<h3>开始任务</h3>
|
||||
<button class="start-btn" @click="startTask">开始任务</button>
|
||||
</div>
|
||||
|
||||
<div class="qr-section">
|
||||
<h3>扫码访问</h3>
|
||||
<img
|
||||
:src="`/api/link/${codeNo}/qr.png`"
|
||||
alt="二维码"
|
||||
class="qr-code"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LinkPage',
|
||||
data() {
|
||||
return {
|
||||
codeNo: '',
|
||||
linkStatus: null,
|
||||
loading: true,
|
||||
error: null
|
||||
};
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
this.codeNo = this.$route.params.codeNo;
|
||||
await this.fetchLinkStatus();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async fetchLinkStatus() {
|
||||
try {
|
||||
this.loading = true;
|
||||
const response = await fetch(`/api/link/${this.codeNo}/status`);
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 404) {
|
||||
this.error = '链接不存在';
|
||||
} else {
|
||||
this.error = '获取链接信息失败';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.linkStatus = await response.json();
|
||||
} catch (err) {
|
||||
this.error = '网络错误';
|
||||
console.error('获取链接状态失败:', err);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
formatTime(seconds) {
|
||||
if (seconds <= 0) return '已过期';
|
||||
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
const secs = seconds % 60;
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}小时${minutes}分钟`;
|
||||
} else if (minutes > 0) {
|
||||
return `${minutes}分钟${secs}秒`;
|
||||
} else {
|
||||
return `${secs}秒`;
|
||||
}
|
||||
},
|
||||
|
||||
startTask() {
|
||||
// 实现开始任务的逻辑
|
||||
console.log('开始任务');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
## 路由配置
|
||||
|
||||
### React Router
|
||||
```jsx
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import LinkPage from './components/LinkPage';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/:codeNo" element={<LinkPage />} />
|
||||
{/* 其他路由 */}
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Vue Router
|
||||
```javascript
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import LinkPage from '@/components/LinkPage.vue';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/:codeNo',
|
||||
name: 'LinkPage',
|
||||
component: LinkPage
|
||||
}
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes
|
||||
});
|
||||
|
||||
export default router;
|
||||
```
|
||||
|
||||
## 使用流程
|
||||
|
||||
1. **用户访问链接**:`https://你的域名/ABC12345`
|
||||
2. **前端自动请求**:调用 `/api/link/ABC12345/status` 获取链接信息
|
||||
3. **显示相应内容**:根据链接状态显示不同的界面
|
||||
4. **实时更新**:可以定时刷新状态,显示剩余时间等
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **错误处理**:处理链接不存在、已过期等情况
|
||||
2. **加载状态**:显示加载中的状态,提升用户体验
|
||||
3. **响应式设计**:确保在不同设备上都能正常显示
|
||||
4. **缓存策略**:可以适当缓存链接状态,减少请求次数
|
||||
5. **实时更新**:对于进行中的任务,可以定时刷新状态
|
||||
|
||||
150
docs/数据库修改总结.md
Normal file
150
docs/数据库修改总结.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# 数据库修改总结
|
||||
|
||||
## 修改概述
|
||||
根据需求文档和用户要求,对游戏平台系统进行了以下主要修改:
|
||||
|
||||
## 1. LinkBatch表结构调整
|
||||
|
||||
### 修改前
|
||||
- `quantity`: 代表批次大小
|
||||
- `times`: 代表生成次数
|
||||
- `batchSize`: 每次的奖励点数
|
||||
- `deductPoints`: 扣除的点数
|
||||
|
||||
### 修改后
|
||||
- `quantity`: 每次副本的奖励点数(从配置表获取,默认50)
|
||||
- `times`: 打副本的次数
|
||||
- 移除了 `batchSize` 和 `deductPoints` 字段
|
||||
|
||||
### 字段含义
|
||||
- `quantity`: 每次副本完成后获得的点数,从配置表 `link.default_quantity` 获取
|
||||
- `times`: 一个批次中打副本的总次数
|
||||
- `agent_id`: 代理商ID
|
||||
- `operator_id`: 操作者ID
|
||||
- `created_at`: 创建时间
|
||||
|
||||
### 参数说明
|
||||
- **`times`**: 打多少次副本,决定总的目标值
|
||||
- **`linkCount`**: 生成多少个链接,决定链接任务的数量(默认值:1)
|
||||
- **总目标值计算**: `times` × 配置表中的默认奖励点数
|
||||
|
||||
## 2. 新增系统配置表
|
||||
|
||||
### 表名:system_config
|
||||
用于存储系统各种配置参数,支持动态配置和运行时修改。
|
||||
|
||||
#### 主要配置项
|
||||
**链接生成相关:**
|
||||
- `link.default_quantity`: 默认奖励点数(50)
|
||||
- `link.refresh_interval`: 链接刷新间隔(300秒)
|
||||
- `link.qr_expire_time`: 二维码过期时间(600秒)
|
||||
- `link.max_times_per_batch`: 每批次最大刷奖励次数(100)
|
||||
- `link.min_quantity`: 最小奖励点数(10)
|
||||
- `link.max_quantity`: 最大奖励点数(1000)
|
||||
|
||||
**脚本服务器相关:**
|
||||
- `script.server_url`: 脚本服务器地址
|
||||
- `script.qr_path_template`: 二维码图片路径模板
|
||||
|
||||
## 3. 代码结构更新
|
||||
|
||||
### 新增文件
|
||||
1. **实体类**
|
||||
- `SystemConfig.java` - 系统配置实体
|
||||
|
||||
2. **Mapper接口**
|
||||
- `SystemConfigMapper.java` - 系统配置数据访问接口
|
||||
|
||||
3. **XML映射文件**
|
||||
- `SystemConfigMapper.xml` - MyBatis映射配置
|
||||
|
||||
4. **服务类**
|
||||
- `SystemConfigService.java` - 系统配置业务逻辑服务
|
||||
|
||||
5. **控制器**
|
||||
- `SystemConfigController.java` - 系统配置REST API接口
|
||||
|
||||
6. **DTO类**
|
||||
- `SystemConfigRequest.java` - 配置创建/更新请求
|
||||
- `SystemConfigResponse.java` - 配置查询响应
|
||||
- `SystemConfigConverter.java` - 配置对象转换工具
|
||||
|
||||
### 修改文件
|
||||
1. **LinkBatch.java** - 移除不需要的字段
|
||||
2. **LinkBatchMapper.xml** - 更新SQL映射
|
||||
3. **LinkGenerationService.java** - 使用配置服务,修复字段设置
|
||||
|
||||
## 4. API接口
|
||||
|
||||
### 系统配置管理接口
|
||||
- `GET /api/admin/config/list` - 获取配置列表
|
||||
- `GET /api/admin/config/key/{configKey}` - 根据键获取配置
|
||||
- `GET /api/admin/config/type/{configType}` - 根据类型获取配置
|
||||
- `POST /api/admin/config` - 创建配置
|
||||
- `PUT /api/admin/config/{id}` - 更新配置
|
||||
- `DELETE /api/admin/config/{id}` - 删除配置
|
||||
- `GET /api/admin/config/link/defaults` - 获取链接默认配置
|
||||
- `GET /api/admin/config/script/config` - 获取脚本配置
|
||||
|
||||
## 5. 配置使用方式
|
||||
|
||||
### 在服务中使用
|
||||
```java
|
||||
@Autowired
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
// 获取默认奖励点数
|
||||
Integer defaultQuantity = systemConfigService.getDefaultQuantity();
|
||||
|
||||
// 获取刷新间隔
|
||||
Integer refreshInterval = systemConfigService.getRefreshInterval();
|
||||
```
|
||||
|
||||
### 动态修改配置
|
||||
```java
|
||||
// 更新配置
|
||||
SystemConfig config = systemConfigService.getConfigByKey("link.default_quantity");
|
||||
config.setConfigValue("100");
|
||||
systemConfigService.updateConfig(config);
|
||||
```
|
||||
|
||||
## 6. 数据库脚本
|
||||
|
||||
### 执行顺序
|
||||
1. 执行 `docs/game.sql` 中的新表创建语句
|
||||
2. 系统会自动插入默认配置数据
|
||||
|
||||
### 注意事项
|
||||
- 新表使用 `utf8mb4` 字符集
|
||||
- 配置键具有唯一性约束
|
||||
- 系统配置标记为 `is_system=1`,不建议删除
|
||||
|
||||
## 7. 业务逻辑调整
|
||||
|
||||
### LinkGenerationService
|
||||
- 使用配置服务获取过期时间等参数
|
||||
- 修复了字段设置问题
|
||||
- `quantity` 现在代表每次的奖励点数
|
||||
- `times` 代表总次数
|
||||
|
||||
### 配置管理
|
||||
- 支持运行时动态修改配置
|
||||
- 提供完整的CRUD操作
|
||||
- 支持配置类型验证
|
||||
- 提供便捷的配置获取方法
|
||||
|
||||
## 8. 后续扩展建议
|
||||
|
||||
1. **缓存机制**: 对频繁访问的配置添加缓存
|
||||
2. **配置验证**: 在更新配置时添加值格式验证
|
||||
3. **配置变更日志**: 记录配置变更历史
|
||||
4. **配置导入导出**: 支持配置文件导入导出
|
||||
5. **权限控制**: 对敏感配置的修改权限控制
|
||||
|
||||
## 9. 测试建议
|
||||
|
||||
1. 测试配置的增删改查功能
|
||||
2. 验证LinkBatch表的字段映射
|
||||
3. 测试配置的动态修改是否生效
|
||||
4. 验证默认配置值的正确性
|
||||
5. 测试配置服务的异常处理
|
||||
151
docs/系统配置说明.md
Normal file
151
docs/系统配置说明.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# 系统配置说明
|
||||
|
||||
## 概述
|
||||
系统配置表用于存储游戏平台的各种配置参数,支持动态配置和运行时修改。
|
||||
|
||||
## 配置表结构
|
||||
表名:`system_config`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| id | bigint | 主键ID |
|
||||
| config_key | varchar(100) | 配置键(唯一) |
|
||||
| config_value | text | 配置值 |
|
||||
| config_type | varchar(50) | 配置类型:STRING, INTEGER, BOOLEAN, JSON |
|
||||
| description | varchar(500) | 配置描述 |
|
||||
| is_system | tinyint(1) | 是否系统配置(1是,0否) |
|
||||
| created_at | datetime(3) | 创建时间 |
|
||||
| updated_at | datetime(3) | 更新时间 |
|
||||
|
||||
## 默认配置项
|
||||
|
||||
### 链接生成相关配置
|
||||
- `link.default_quantity`: 每次副本的奖励点数(默认值:50)
|
||||
- `link.refresh_interval`: 链接刷新间隔,单位:秒(默认值:300)
|
||||
- `link.qr_expire_time`: 二维码过期时间,单位:秒(默认值:600)
|
||||
- `link.max_times_per_batch`: 每批次最大打副本次数(默认值:100)
|
||||
- `link.min_quantity`: 最小奖励点数(默认值:10)
|
||||
- `link.max_quantity`: 最大奖励点数(默认值:1000)
|
||||
|
||||
### 脚本服务器相关配置
|
||||
- `script.server_url`: 脚本服务器地址(默认值:http://36.138.184.60:12345)
|
||||
- `script.qr_path_template`: 二维码图片路径模板(默认值:/{machineId}/二维码.png)
|
||||
|
||||
## 参数说明
|
||||
|
||||
### 链接生成接口参数
|
||||
- **`times`**: 打多少次副本,决定总的目标值
|
||||
- **`linkCount`**: 生成多少个链接,决定链接任务的数量(默认值:1)
|
||||
|
||||
### 业务逻辑
|
||||
1. 每次副本的奖励点数从配置表 `link.default_quantity` 获取
|
||||
2. 总目标值 = `times` × 配置表中的默认奖励点数
|
||||
3. 生成 `linkCount` 个链接任务供用户使用
|
||||
4. 用户完成链接后,根据 `times` 和配置的奖励点数计算总奖励
|
||||
|
||||
## API接口
|
||||
|
||||
### 获取配置列表
|
||||
```
|
||||
GET /api/admin/config/list?page=1&size=20
|
||||
```
|
||||
|
||||
### 根据键获取配置
|
||||
```
|
||||
GET /api/admin/config/key/{configKey}
|
||||
```
|
||||
|
||||
### 根据类型获取配置
|
||||
```
|
||||
GET /api/admin/config/type/{configType}
|
||||
```
|
||||
|
||||
### 创建配置
|
||||
```
|
||||
POST /api/admin/config
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"configKey": "custom.setting",
|
||||
"configValue": "value",
|
||||
"configType": "STRING",
|
||||
"description": "自定义设置",
|
||||
"isSystem": false
|
||||
}
|
||||
```
|
||||
|
||||
### 更新配置
|
||||
```
|
||||
PUT /api/admin/config/{id}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"configKey": "custom.setting",
|
||||
"configValue": "new_value",
|
||||
"configType": "STRING",
|
||||
"description": "自定义设置",
|
||||
"isSystem": false
|
||||
}
|
||||
```
|
||||
|
||||
### 删除配置
|
||||
```
|
||||
DELETE /api/admin/config/{id}
|
||||
DELETE /api/admin/config/key/{configKey}
|
||||
```
|
||||
|
||||
### 获取链接默认配置
|
||||
```
|
||||
GET /api/admin/config/link/defaults
|
||||
```
|
||||
|
||||
### 获取脚本配置
|
||||
```
|
||||
GET /api/admin/config/script/config
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 在服务中使用配置
|
||||
```java
|
||||
@Autowired
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
// 获取默认奖励点数
|
||||
Integer defaultQuantity = systemConfigService.getDefaultQuantity();
|
||||
|
||||
// 获取刷新间隔
|
||||
Integer refreshInterval = systemConfigService.getRefreshInterval();
|
||||
|
||||
// 获取脚本服务器地址
|
||||
String serverUrl = systemConfigService.getScriptServerUrl();
|
||||
```
|
||||
|
||||
### 动态修改配置
|
||||
```java
|
||||
// 更新配置
|
||||
SystemConfig config = systemConfigService.getConfigByKey("link.default_quantity");
|
||||
config.setConfigValue("100");
|
||||
systemConfigService.updateConfig(config);
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **系统配置**:标记为系统配置的项(is_system=1)通常不建议删除,这些是平台运行必需的基础配置。
|
||||
|
||||
2. **配置类型**:根据实际需要选择合适的配置类型,数值类型建议使用INTEGER,布尔值使用BOOLEAN。
|
||||
|
||||
3. **配置键命名**:建议使用点号分隔的层次结构,如:`module.submodule.setting`。
|
||||
|
||||
4. **配置值验证**:在更新配置时,建议对配置值进行格式验证,确保符合预期类型。
|
||||
|
||||
5. **缓存策略**:对于频繁访问的配置,建议在服务层添加缓存机制,提高性能。
|
||||
|
||||
## 扩展配置
|
||||
|
||||
可以根据业务需要添加更多配置项,例如:
|
||||
- 用户权限相关配置
|
||||
- 游戏规则配置
|
||||
- 第三方服务配置
|
||||
- 日志级别配置
|
||||
- 性能调优参数
|
||||
275
docs/链接状态接口测试.md
Normal file
275
docs/链接状态接口测试.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# 链接状态接口测试文档
|
||||
|
||||
## 接口概览
|
||||
|
||||
新增了三个接口用于前端获取链接状态信息:
|
||||
|
||||
1. **获取链接状态** - `GET /api/link/{codeNo}/status`
|
||||
2. **检查链接是否存在** - `GET /api/link/{codeNo}/exists`
|
||||
3. **检查链接是否有效** - `GET /api/link/{codeNo}/valid`
|
||||
|
||||
## 测试步骤
|
||||
|
||||
### 1. 准备工作
|
||||
|
||||
首先需要生成一个链接用于测试:
|
||||
|
||||
```bash
|
||||
# 1. 登录获取JWT令牌
|
||||
curl -X POST http://localhost:18080/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "your_username",
|
||||
"password": "your_password"
|
||||
}'
|
||||
```
|
||||
|
||||
从响应中获取JWT令牌,后续请求都需要在Header中带上:
|
||||
```bash
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
|
||||
```
|
||||
|
||||
### 2. 生成测试链接
|
||||
|
||||
```bash
|
||||
# 2. 生成链接
|
||||
curl -X POST http://localhost:18080/api/link/generate \
|
||||
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"times": 5,
|
||||
"linkCount": 2
|
||||
}'
|
||||
```
|
||||
|
||||
响应示例:
|
||||
```json
|
||||
{
|
||||
"batchId": 123,
|
||||
"deductPoints": 250,
|
||||
"expireAt": "2024-01-15T16:30:00",
|
||||
"codeNos": ["ABC12345", "DEF67890"]
|
||||
}
|
||||
```
|
||||
|
||||
记录其中一个 `codeNo`,比如 `ABC12345`,用于后续测试。
|
||||
|
||||
### 3. 测试获取链接状态接口
|
||||
|
||||
```bash
|
||||
# 3. 获取链接状态
|
||||
curl -X GET http://localhost:18080/api/link/ABC12345/status \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
**预期响应:**
|
||||
```json
|
||||
{
|
||||
"codeNo": "ABC12345",
|
||||
"batchId": 123,
|
||||
"status": "NEW",
|
||||
"statusDesc": "新建",
|
||||
"expireAt": "2024-01-15T16:30:00",
|
||||
"isExpired": false,
|
||||
"remainingSeconds": 7200,
|
||||
"quantity": 50,
|
||||
"times": 5,
|
||||
"totalPoints": 250,
|
||||
"region": null,
|
||||
"machineId": null,
|
||||
"loginAt": null,
|
||||
"createdAt": "2024-01-15T12:00:00",
|
||||
"updatedAt": "2024-01-15T12:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 测试检查链接是否存在接口
|
||||
|
||||
```bash
|
||||
# 4. 检查链接是否存在
|
||||
curl -X GET http://localhost:18080/api/link/ABC12345/exists \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
**预期响应:** `true`
|
||||
|
||||
### 5. 测试检查链接是否有效接口
|
||||
|
||||
```bash
|
||||
# 5. 检查链接是否有效
|
||||
curl -X GET http://localhost:18080/api/link/ABC12345/valid \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
**预期响应:** `true`
|
||||
|
||||
### 6. 测试错误情况
|
||||
|
||||
#### 6.1 测试不存在的链接
|
||||
|
||||
```bash
|
||||
# 测试不存在的链接
|
||||
curl -X GET http://localhost:18080/api/link/INVALID123/status \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
**预期响应:**
|
||||
```json
|
||||
{
|
||||
"timestamp": "2024-01-15T12:00:00.000+00:00",
|
||||
"status": 400,
|
||||
"error": "Bad Request",
|
||||
"message": "链接不存在: INVALID123",
|
||||
"path": "/api/link/INVALID123/status"
|
||||
}
|
||||
```
|
||||
|
||||
#### 6.2 测试空链接编号
|
||||
|
||||
```bash
|
||||
# 测试空链接编号
|
||||
curl -X GET http://localhost:18080/api/link//status \
|
||||
-H "Accept: application/json"
|
||||
```
|
||||
|
||||
**预期响应:** 404 Not Found
|
||||
|
||||
## 状态值说明
|
||||
|
||||
### 链接状态 (status)
|
||||
- `NEW` - 新建,未开始使用
|
||||
- `USING` - 使用中,正在执行任务
|
||||
- `LOGGED_IN` - 已登录,任务完成
|
||||
- `REFUNDED` - 已退款
|
||||
- `EXPIRED` - 已过期
|
||||
|
||||
### 区域 (region)
|
||||
- `Q` - Q区
|
||||
- `V` - V区
|
||||
- `null` - 未分配区域
|
||||
|
||||
## 测试数据验证
|
||||
|
||||
### 1. 数值计算验证
|
||||
- `totalPoints` = `quantity` × `times`
|
||||
- `remainingSeconds` 应该大于0(如果未过期)
|
||||
- `isExpired` 应该与当前时间和 `expireAt` 一致
|
||||
|
||||
### 2. 状态一致性验证
|
||||
- 如果 `status` 是 `EXPIRED`,那么 `isExpired` 应该是 `true`
|
||||
- 如果 `status` 是 `LOGGED_IN`,那么 `loginAt` 不应该为 `null`
|
||||
|
||||
### 3. 时间验证
|
||||
- `createdAt` ≤ `updatedAt`
|
||||
- `expireAt` > `createdAt`
|
||||
- 如果 `loginAt` 不为空,那么 `loginAt` ≥ `createdAt`
|
||||
|
||||
## 性能测试
|
||||
|
||||
### 1. 响应时间测试
|
||||
```bash
|
||||
# 使用time命令测试响应时间
|
||||
time curl -X GET http://localhost:18080/api/link/ABC12345/status
|
||||
```
|
||||
|
||||
### 2. 并发测试
|
||||
```bash
|
||||
# 使用ab工具进行并发测试
|
||||
ab -n 100 -c 10 http://localhost:18080/api/link/ABC12345/status
|
||||
```
|
||||
|
||||
## 错误处理测试
|
||||
|
||||
### 1. 数据库连接异常
|
||||
模拟数据库连接失败的情况,验证错误处理。
|
||||
|
||||
### 2. 网络超时
|
||||
模拟网络延迟,验证超时处理。
|
||||
|
||||
### 3. 内存不足
|
||||
模拟内存不足情况,验证系统稳定性。
|
||||
|
||||
## 安全测试
|
||||
|
||||
### 1. 权限验证
|
||||
```bash
|
||||
# 不带JWT令牌访问(应该被拦截)
|
||||
curl -X GET http://localhost:18080/api/link/ABC12345/status
|
||||
```
|
||||
|
||||
### 2. SQL注入防护
|
||||
```bash
|
||||
# 测试SQL注入
|
||||
curl -X GET "http://localhost:18080/api/link/ABC12345'; DROP TABLE link_task; --/status"
|
||||
```
|
||||
|
||||
### 3. XSS防护
|
||||
```bash
|
||||
# 测试XSS攻击
|
||||
curl -X GET "http://localhost:18080/api/link/<script>alert('xss')</script>/status"
|
||||
```
|
||||
|
||||
## 测试报告模板
|
||||
|
||||
### 测试结果记录
|
||||
|
||||
| 测试项目 | 测试结果 | 响应时间 | 备注 |
|
||||
|---------|---------|---------|------|
|
||||
| 获取链接状态 | ✅ 通过 | 45ms | 正常 |
|
||||
| 检查链接存在 | ✅ 通过 | 23ms | 正常 |
|
||||
| 检查链接有效 | ✅ 通过 | 28ms | 正常 |
|
||||
| 错误处理 | ✅ 通过 | 15ms | 正常 |
|
||||
| 性能测试 | ✅ 通过 | 平均35ms | 满足要求 |
|
||||
|
||||
### 问题记录
|
||||
|
||||
| 问题描述 | 严重程度 | 状态 | 备注 |
|
||||
|---------|---------|------|------|
|
||||
| 无 | - | - | - |
|
||||
|
||||
### 建议改进
|
||||
|
||||
1. 可以考虑添加缓存机制,减少数据库查询
|
||||
2. 可以添加链接访问统计功能
|
||||
3. 可以考虑添加链接状态变更通知功能
|
||||
|
||||
## 自动化测试
|
||||
|
||||
### 使用Postman Collection
|
||||
|
||||
可以创建Postman Collection来自动化测试这些接口:
|
||||
|
||||
1. 创建环境变量存储JWT令牌和链接编号
|
||||
2. 设置测试脚本验证响应数据
|
||||
3. 使用Postman Runner批量执行测试
|
||||
|
||||
### 使用JUnit测试
|
||||
|
||||
```java
|
||||
@SpringBootTest
|
||||
@AutoConfigureTestDatabase
|
||||
class LinkStatusControllerTest {
|
||||
|
||||
@Test
|
||||
void testGetLinkStatus() {
|
||||
// 测试获取链接状态
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLinkNotExists() {
|
||||
// 测试链接不存在的情况
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
这些接口为前端提供了完整的链接状态查询功能,支持:
|
||||
|
||||
1. **完整的状态信息** - 包括任务详情、过期时间、奖励点数等
|
||||
2. **实时状态计算** - 自动计算是否过期、剩余时间等
|
||||
3. **友好的错误处理** - 提供清晰的错误信息和状态码
|
||||
4. **高性能查询** - 使用响应式编程,支持高并发访问
|
||||
|
||||
前端可以根据这些接口实现丰富的用户界面,提供良好的用户体验。
|
||||
|
||||
Reference in New Issue
Block a user