604 lines
15 KiB
Markdown
604 lines
15 KiB
Markdown
# 批量自动化任务功能实现总结
|
||
|
||
## 📋 项目概述
|
||
|
||
本文档记录了批量自动化任务功能的完整技术实现,包括架构设计、核心逻辑、数据流转等。
|
||
|
||
---
|
||
|
||
## 🏗️ 架构设计
|
||
|
||
### 整体架构
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ TokenImport.vue │
|
||
│ (Token管理主页,集成批量任务面板和进度显示) │
|
||
└─────────────────┬───────────────────────────────────────┘
|
||
│
|
||
┌───────────┴───────────┐
|
||
│ │
|
||
┌─────▼──────────┐ ┌───────▼──────────┐
|
||
│BatchTaskPanel │ │TaskProgressCard │
|
||
│(控制面板) │ │(进度卡片) │
|
||
└─────┬──────────┘ └───────┬──────────┘
|
||
│ │
|
||
└──────────┬───────────┘
|
||
│
|
||
┌────────▼────────┐
|
||
│ batchTaskStore │
|
||
│ (核心状态管理) │
|
||
└────────┬────────┘
|
||
│
|
||
┌────────────┼────────────┐
|
||
│ │ │
|
||
┌───▼────┐ ┌───▼────┐ ┌───▼────┐
|
||
│tokenS- │ │task │ │WebSo- │
|
||
│tore │ │Schedu- │ │cket │
|
||
│ │ │ler │ │Client │
|
||
└────────┘ └────────┘ └────────┘
|
||
```
|
||
|
||
### 核心模块
|
||
|
||
1. **UI层**
|
||
- `BatchTaskPanel.vue` - 批量任务控制面板
|
||
- `TaskProgressCard.vue` - 单Token进度卡片
|
||
- `TemplateEditor.vue` - 任务模板编辑器
|
||
- `SchedulerConfig.vue` - 定时任务配置
|
||
- `ExecutionHistory.vue` - 执行历史记录
|
||
|
||
2. **状态管理层**
|
||
- `batchTaskStore.js` - 批量任务状态管理(Pinia)
|
||
- `tokenStore.js` - Token和WebSocket管理
|
||
|
||
3. **工具层**
|
||
- `taskScheduler.js` - 任务调度器
|
||
- `xyzwWebSocket.js` - WebSocket客户端
|
||
- `gameCommands.js` - 游戏指令封装
|
||
|
||
---
|
||
|
||
## 🔧 核心功能实现
|
||
|
||
### 1. 批量任务执行流程
|
||
|
||
#### 1.1 启动流程
|
||
```javascript
|
||
// batchTaskStore.js
|
||
const startBatchExecution = async (tokenIds, tasks) => {
|
||
// 1. 验证参数
|
||
// 2. 初始化状态
|
||
// 3. 创建任务队列
|
||
// 4. 执行并发控制
|
||
// 5. 完成后清理
|
||
}
|
||
```
|
||
|
||
#### 1.2 并发控制
|
||
```javascript
|
||
const executeBatchWithConcurrency = async (tokenIds, tasks) => {
|
||
const queue = [...tokenIds]
|
||
const executing = []
|
||
|
||
while (queue.length > 0 || executing.length > 0) {
|
||
// 填充执行队列(最多maxConcurrency个)
|
||
while (executing.length < maxConcurrency.value && queue.length > 0) {
|
||
const tokenId = queue.shift()
|
||
const promise = executeTokenTasks(tokenId, tasks)
|
||
executing.push(promise)
|
||
}
|
||
|
||
// 等待至少一个任务完成
|
||
if (executing.length > 0) {
|
||
await Promise.race(executing)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 1.3 单Token任务执行
|
||
```javascript
|
||
const executeTokenTasks = async (tokenId, tasks) => {
|
||
try {
|
||
// 1. 确保WebSocket连接(自动从bin文件获取新token)
|
||
const wsClient = await ensureConnection(tokenId)
|
||
|
||
// 2. 依次执行任务
|
||
for (const taskName of tasks) {
|
||
const result = await executeTask(tokenId, taskName)
|
||
// 保存结果
|
||
taskProgress.value[tokenId].result[taskName] = {
|
||
success: true,
|
||
data: result
|
||
}
|
||
}
|
||
|
||
// 3. 标记完成
|
||
updateTaskProgress(tokenId, { status: 'completed' })
|
||
} catch (error) {
|
||
updateTaskProgress(tokenId, { status: 'failed', error })
|
||
} finally {
|
||
// 4. 自动断开WebSocket连接
|
||
tokenStore.closeWebSocketConnection(tokenId)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 任务实现详解
|
||
|
||
#### 2.1 一键补差任务(dailyFix)
|
||
```javascript
|
||
case 'dailyFix':
|
||
// 包含16大类任务
|
||
const fixResults = []
|
||
|
||
// 1. 分享游戏
|
||
fixResults.push(await client.sendWithPromise('system_mysharecallback', {
|
||
isSkipShareCard: true,
|
||
type: 2
|
||
}))
|
||
|
||
// 2. 赠送好友金币
|
||
fixResults.push(await client.sendWithPromise('friend_batch', {}))
|
||
|
||
// 3. 免费招募
|
||
fixResults.push(await client.sendWithPromise('hero_recruit', {
|
||
recruitType: 3,
|
||
recruitNumber: 1
|
||
}))
|
||
|
||
// 4. 免费点金(3次)
|
||
for (let i = 0; i < 3; i++) {
|
||
fixResults.push(await client.sendWithPromise('system_buygold', { buyNum: 1 }))
|
||
}
|
||
|
||
// 5. 福利签到
|
||
fixResults.push(await client.sendWithPromise('system_signinreward', {}))
|
||
|
||
// 6. 领取每日礼包
|
||
fixResults.push(await client.sendWithPromise('discount_claimreward', {}))
|
||
|
||
// 7. 领取免费礼包
|
||
fixResults.push(await client.sendWithPromise('card_claimreward', {}))
|
||
|
||
// 8. 领取永久卡礼包
|
||
fixResults.push(await client.sendWithPromise('card_claimreward', { cardId: 4003 }))
|
||
|
||
// 9. 领取邮件奖励
|
||
fixResults.push(await client.sendWithPromise('mail_claimallattachment', { category: 0 }))
|
||
|
||
// 10. 免费钓鱼(3次)
|
||
for (let i = 0; i < 3; i++) {
|
||
fixResults.push(await client.sendWithPromise('artifact_lottery', {
|
||
lotteryNumber: 1,
|
||
newFree: true,
|
||
type: 1
|
||
}))
|
||
}
|
||
|
||
// 11. 灯神免费扫荡(4个国家)
|
||
for (let gid = 1; gid <= 4; gid++) {
|
||
fixResults.push(await client.sendWithPromise('genie_sweep', { genieId: gid }))
|
||
}
|
||
|
||
// 12. 领取免费扫荡卷(3次)
|
||
for (let i = 0; i < 3; i++) {
|
||
fixResults.push(await client.sendWithPromise('genie_buysweep', {}))
|
||
}
|
||
|
||
// 13. 领取任务奖励(1-10)
|
||
for (let taskId = 1; taskId <= 10; taskId++) {
|
||
fixResults.push(await client.sendWithPromise('task_claimdailypoint', { taskId }))
|
||
}
|
||
|
||
// 14. 领取日常任务奖励
|
||
fixResults.push(await client.sendWithPromise('task_claimdailyreward', {}))
|
||
|
||
// 15. 领取周常任务奖励
|
||
fixResults.push(await client.sendWithPromise('task_claimweekreward', {}))
|
||
|
||
// 16. 重启盐罐机器人服务
|
||
// 16.1 停止机器人
|
||
try {
|
||
fixResults.push(await client.sendWithPromise('bottlehelper_stop', { bottleType: -1 }))
|
||
} catch (error) {
|
||
// 机器人可能未启动,跳过
|
||
}
|
||
|
||
// 16.2 启动机器人
|
||
fixResults.push(await client.sendWithPromise('bottlehelper_start', { bottleType: -1 }))
|
||
|
||
// 16.3 领取奖励
|
||
try {
|
||
fixResults.push(await client.sendWithPromise('bottlehelper_claim', {}))
|
||
} catch (error) {
|
||
// 暂无奖励可领取
|
||
}
|
||
|
||
return fixResults
|
||
```
|
||
|
||
**一键补差包含的所有子任务:**
|
||
1. 分享一次游戏
|
||
2. 赠送好友金币
|
||
3. 免费招募
|
||
4. 免费点金(3次)
|
||
5. 福利签到
|
||
6. 领取每日礼包
|
||
7. 领取免费礼包
|
||
8. 领取永久卡礼包
|
||
9. 领取邮件奖励
|
||
10. 免费钓鱼(3次)
|
||
11. 魏国灯神免费扫荡
|
||
12. 蜀国灯神免费扫荡
|
||
13. 吴国灯神免费扫荡
|
||
14. 群雄灯神免费扫荡
|
||
15. 领取免费扫荡卷(3次)
|
||
16. 领取任务奖励1-10(10个)
|
||
17. 领取日常任务奖励
|
||
18. 领取周常任务奖励
|
||
19. 停止盐罐机器人
|
||
20. 启动盐罐机器人
|
||
21. 领取盐罐奖励
|
||
|
||
**总计:约45+个子操作**
|
||
|
||
#### 2.2 俱乐部签到(legionSignIn)
|
||
```javascript
|
||
case 'legionSignIn':
|
||
return await client.sendWithPromise('legion_signin', {}, 2000)
|
||
```
|
||
|
||
#### 2.3 一键答题(autoStudy)
|
||
```javascript
|
||
case 'autoStudy':
|
||
return await client.sendWithPromise('study_startgame', {}, 2000)
|
||
```
|
||
|
||
#### 2.4 领取奖励-挂机(claimHangupReward)
|
||
```javascript
|
||
case 'claimHangupReward':
|
||
return await client.sendWithPromise('system_claimhangupreward', {}, 2000)
|
||
```
|
||
|
||
#### 2.5 加钟(addClock)
|
||
```javascript
|
||
case 'addClock':
|
||
// 必须在领取挂机奖励之后执行
|
||
return await client.sendWithPromise('system_mysharecallback', {
|
||
type: 3,
|
||
isSkipShareCard: true
|
||
}, 2000)
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 支持的任务列表
|
||
|
||
| 任务ID | 任务名称 | 实现方式 | 说明 |
|
||
|--------|---------|---------|------|
|
||
| `dailyFix` | 一键补差 | 16大类40+子任务 | 完整版每日任务,包含所有日常活动 |
|
||
| `legionSignIn` | 俱乐部签到 | `legion_signin` | 军团/俱乐部每日签到 |
|
||
| `autoStudy` | 一键答题 | `study_startgame` | 触发自动答题流程 |
|
||
| `claimHangupReward` | 领取奖励(挂机) | `system_claimhangupreward` | 领取离线挂机收益 |
|
||
| `addClock` | 加钟 | `system_mysharecallback` (type=3) | 延长挂机时间 |
|
||
|
||
---
|
||
|
||
## 🔄 数据流转
|
||
|
||
### 执行状态流转
|
||
```
|
||
pending → executing → completed/failed
|
||
↓
|
||
paused ⟷ executing
|
||
```
|
||
|
||
### 进度数据结构
|
||
```javascript
|
||
taskProgress = {
|
||
[tokenId]: {
|
||
status: 'pending' | 'executing' | 'completed' | 'failed' | 'skipped',
|
||
progress: 0-100,
|
||
currentTask: 'dailyFix' | 'legionSignIn' | ...,
|
||
tasksCompleted: 3,
|
||
tasksTotal: 5,
|
||
error: null | string,
|
||
result: {
|
||
dailyFix: { success: true, data: [...] },
|
||
legionSignIn: { success: true, data: {...} },
|
||
...
|
||
},
|
||
startTime: timestamp,
|
||
endTime: timestamp
|
||
}
|
||
}
|
||
```
|
||
|
||
### 统计数据结构
|
||
```javascript
|
||
executionStats = {
|
||
total: 10, // 总Token数
|
||
success: 8, // 成功数
|
||
failed: 1, // 失败数
|
||
skipped: 1, // 跳过数
|
||
startTime: timestamp,
|
||
endTime: timestamp
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔐 WebSocket连接管理
|
||
|
||
### 连接策略
|
||
```javascript
|
||
const ensureConnection = async (tokenId) => {
|
||
const connection = tokenStore.wsConnections[tokenId]
|
||
|
||
// 已连接,直接返回
|
||
if (connection && connection.status === 'connected') {
|
||
return connection.client
|
||
}
|
||
|
||
// 重新连接(会自动从bin文件获取新token)
|
||
const wsClient = await tokenStore.reconnectWebSocket(tokenId)
|
||
return wsClient
|
||
}
|
||
```
|
||
|
||
### 自动断开机制
|
||
```javascript
|
||
// executeTokenTasks的finally块
|
||
finally {
|
||
// 任务完成后自动断开WebSocket连接
|
||
if (tokenStore.wsConnections[tokenId]) {
|
||
tokenStore.closeWebSocketConnection(tokenId)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 连接健康检查
|
||
- 每次执行前从bin文件重新获取roleToken
|
||
- 自动处理token失效问题
|
||
- 连接失败自动跳过,不影响其他Token
|
||
|
||
---
|
||
|
||
## ⚙️ 配置管理
|
||
|
||
### 并发数配置
|
||
```javascript
|
||
const maxConcurrency = ref(
|
||
parseInt(localStorage.getItem('maxConcurrency') || '5')
|
||
)
|
||
|
||
const setMaxConcurrency = (count) => {
|
||
if (count < 1 || count > 6) return
|
||
maxConcurrency.value = count
|
||
localStorage.setItem('maxConcurrency', count.toString())
|
||
}
|
||
```
|
||
|
||
### 任务模板配置
|
||
```javascript
|
||
const taskTemplates = {
|
||
'完整套餐': {
|
||
name: '完整套餐',
|
||
tasks: ['dailyFix', 'legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock'],
|
||
enabled: true
|
||
},
|
||
'快速套餐': {
|
||
name: '快速套餐',
|
||
tasks: ['legionSignIn', 'autoStudy', 'claimHangupReward', 'addClock'],
|
||
enabled: true
|
||
},
|
||
'仅一键补差': {
|
||
name: '仅一键补差',
|
||
tasks: ['dailyFix'],
|
||
enabled: true
|
||
}
|
||
}
|
||
```
|
||
|
||
### 调度器配置
|
||
```javascript
|
||
const schedulerConfig = {
|
||
enabled: false,
|
||
type: 'interval' | 'daily',
|
||
interval: 4, // 小时
|
||
dailyTimes: ['08:00', '12:00', '18:00', '22:00'],
|
||
lastExecutionTime: null
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 💾 数据存储结构
|
||
|
||
### localStorage键值
|
||
```javascript
|
||
{
|
||
"taskTemplates": {
|
||
"完整套餐": { ... },
|
||
"快速套餐": { ... },
|
||
...
|
||
},
|
||
"batchTaskHistory": [
|
||
{
|
||
id: "batch_1234567890",
|
||
template: "完整套餐",
|
||
stats: { total: 10, success: 9, ... },
|
||
timestamp: 1234567890,
|
||
duration: 120000
|
||
}
|
||
],
|
||
"schedulerConfig": { ... },
|
||
"maxConcurrency": "5"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 扩展性设计
|
||
|
||
### 添加新任务
|
||
只需要在 `batchTaskStore.js` 的 `executeTask` 方法中添加新case:
|
||
|
||
```javascript
|
||
case 'newTask':
|
||
// 新任务的WebSocket指令
|
||
return await client.sendWithPromise('command_name', { params }, 2000)
|
||
```
|
||
|
||
然后在以下位置添加任务定义:
|
||
1. `BatchTaskPanel.vue` - taskDefinitions
|
||
2. `TemplateEditor.vue` - availableTasks
|
||
3. `TaskProgressCard.vue` - taskLabels
|
||
4. 默认模板(可选)
|
||
|
||
### 修改并发数
|
||
```javascript
|
||
const maxConcurrency = ref(5) // 改为你想要的数字
|
||
```
|
||
|
||
### 自定义任务间隔
|
||
```javascript
|
||
await new Promise(resolve => setTimeout(resolve, 500)) // 修改延迟时间
|
||
```
|
||
|
||
---
|
||
|
||
## 🐛 错误处理机制
|
||
|
||
### 单任务失败处理
|
||
```javascript
|
||
try {
|
||
const result = await executeTask(tokenId, taskName)
|
||
taskProgress.value[tokenId].result[taskName] = { success: true, data: result }
|
||
} catch (error) {
|
||
// 单个任务失败不影响其他任务
|
||
taskProgress.value[tokenId].result[taskName] = { success: false, error: error.message }
|
||
// 继续执行下一个任务
|
||
}
|
||
```
|
||
|
||
### Token执行失败处理
|
||
- 自动标记为失败状态
|
||
- 记录详细错误信息
|
||
- 不影响其他Token的执行
|
||
- 更新统计数据
|
||
|
||
### 连接失败处理
|
||
- 自动跳过该Token
|
||
- 记录为"skipped"状态
|
||
- 继续处理下一个Token
|
||
|
||
---
|
||
|
||
## 📈 性能优化
|
||
|
||
### 1. 并发控制
|
||
- 使用Promise.race实现高效并发控制
|
||
- 动态调整并发数(1-6可配置)
|
||
- 避免同时创建过多WebSocket连接
|
||
|
||
### 2. 资源管理
|
||
- 任务完成后自动断开WebSocket连接
|
||
- 限制历史记录数量(最多10条)
|
||
- 使用localStorage持久化配置
|
||
|
||
### 3. 任务间隔
|
||
- 每个任务间隔200-500ms
|
||
- 避免请求过快触发限流
|
||
- 保证服务器稳定性
|
||
|
||
---
|
||
|
||
## 🔒 安全性考虑
|
||
|
||
### 1. Token安全
|
||
- 每次从bin文件重新获取roleToken
|
||
- 不在内存中长期保存敏感信息
|
||
- 连接失败自动处理,不泄露错误
|
||
|
||
### 2. 数据验证
|
||
- 参数验证(并发数、任务列表等)
|
||
- 状态检查(是否正在执行、是否有Token等)
|
||
- 错误边界处理
|
||
|
||
### 3. 用户控制
|
||
- 提供暂停/继续/停止功能
|
||
- 手动控制进度显示
|
||
- 可查看详细执行结果
|
||
|
||
---
|
||
|
||
## 📝 开发日志
|
||
|
||
### v2.0.0 (2024-10-07)
|
||
- ✨ **重大更新**:重构任务结构
|
||
- 整合完整一键补差(16大类40+子任务)
|
||
- 新增俱乐部签到任务
|
||
- 新增领取奖励(挂机)任务
|
||
- 新增加钟任务
|
||
- 优化任务模板,提供更合理的预设
|
||
- 改进任务顺序,确保执行逻辑正确
|
||
|
||
### v1.2.0
|
||
- ✨ 新增可配置并发数(1-6)
|
||
- ✨ 新增进度显示控制(手动关闭)
|
||
- ✨ 新增任务详情弹窗
|
||
- ✨ 优化WebSocket连接管理
|
||
- 🐛 修复连接未断开的问题
|
||
|
||
### v1.1.0
|
||
- ✨ 新增"加钟"任务
|
||
- ✨ 新增"重启盐罐机器人"任务
|
||
- 🔧 改进任务间隔时间
|
||
|
||
### v1.0.0
|
||
- 🎉 初始版本发布
|
||
- ✅ 基础批量任务功能
|
||
- ✅ 任务模板系统
|
||
- ✅ 定时调度功能
|
||
- ✅ 执行历史记录
|
||
|
||
---
|
||
|
||
## 🎯 后续优化方向
|
||
|
||
1. **性能优化**
|
||
- 实现任务结果缓存
|
||
- 优化大量Token的渲染性能
|
||
- 支持虚拟滚动
|
||
|
||
2. **功能增强**
|
||
- 支持任务条件执行(如:仅未完成的任务)
|
||
- 添加更多游戏任务
|
||
- 支持自定义任务参数
|
||
|
||
3. **用户体验**
|
||
- 提供任务执行预览
|
||
- 添加声音提示
|
||
- 支持深色主题
|
||
|
||
4. **数据分析**
|
||
- 任务成功率统计
|
||
- 执行时间趋势分析
|
||
- Token性能对比
|
||
|
||
---
|
||
|
||
## 📚 参考文档
|
||
|
||
- [Vue 3 官方文档](https://vuejs.org/)
|
||
- [Pinia 状态管理](https://pinia.vuejs.org/)
|
||
- [Naive UI 组件库](https://www.naiveui.com/)
|
||
- [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
|
||
|
||
---
|
||
|
||
**技术实现完成!** 🎉
|