428 lines
12 KiB
Markdown
428 lines
12 KiB
Markdown
|
|
# 功能更新-批量任务添加发车功能 v3.9.0
|
|||
|
|
|
|||
|
|
## 📋 功能描述
|
|||
|
|
|
|||
|
|
在批量自动化任务中新增"发车"功能,支持自动查询、刷新、收获和发送俱乐部赛车。
|
|||
|
|
|
|||
|
|
## 🎯 用户需求
|
|||
|
|
|
|||
|
|
> 包含任务中,添加游戏功能模块中的 发车功能(先查询车辆,再批量刷新可选,默认1次,且只针对无刷新票的车辆进行刷新,然后就一键发车,每个token卡片每天四次的发车限制)
|
|||
|
|
|
|||
|
|
## ✨ 新增功能
|
|||
|
|
|
|||
|
|
### 1. **发车任务流程**
|
|||
|
|
|
|||
|
|
发车任务按照以下顺序执行:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. 查询车辆
|
|||
|
|
↓
|
|||
|
|
2. 批量刷新(可选)
|
|||
|
|
- 默认1次刷新
|
|||
|
|
- 只刷新无刷新票的车辆
|
|||
|
|
- 可设置0-10次
|
|||
|
|
↓
|
|||
|
|
3. 批量收获
|
|||
|
|
- 自动收获已到达的车辆
|
|||
|
|
↓
|
|||
|
|
4. 批量发送
|
|||
|
|
- 发送待发车的车辆
|
|||
|
|
- 严格执行每日4次限制
|
|||
|
|
↓
|
|||
|
|
5. 完成
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. **配置项**
|
|||
|
|
|
|||
|
|
#### **发车刷新次数**
|
|||
|
|
- **位置**:批量任务面板 → 发车刷新次数
|
|||
|
|
- **范围**:0-10次
|
|||
|
|
- **默认值**:1次
|
|||
|
|
- **说明**:
|
|||
|
|
- 设置为0:跳过刷新步骤
|
|||
|
|
- 设置为N:每辆车刷新N轮
|
|||
|
|
- 只刷新无刷新票的车辆(itemId: 35002)
|
|||
|
|
|
|||
|
|
#### **每日发车限制**
|
|||
|
|
- **限制**:每个token每天最多发送4辆车
|
|||
|
|
- **实现**:
|
|||
|
|
- 基于 localStorage 按 tokenId 和日期独立计数
|
|||
|
|
- 跨日期自动重置
|
|||
|
|
- 支持多账号独立计数
|
|||
|
|
|
|||
|
|
### 3. **任务模板更新**
|
|||
|
|
|
|||
|
|
已将"发车"任务添加到以下模板:
|
|||
|
|
|
|||
|
|
| 模板名称 | 包含任务 |
|
|||
|
|
|---------|---------|
|
|||
|
|
| 完整套餐 | 一键补差、俱乐部签到、一键答题、领取挂机奖励、加钟、**发车**、爬塔 |
|
|||
|
|
| 快速套餐 | 俱乐部签到、一键答题、领取挂机奖励、加钟、**发车**、爬塔 |
|
|||
|
|
| 仅一键补差 | 一键补差 |
|
|||
|
|
|
|||
|
|
## 🔧 技术实现
|
|||
|
|
|
|||
|
|
### 1. **Store 修改 (batchTaskStore.js)**
|
|||
|
|
|
|||
|
|
#### **新增配置项**
|
|||
|
|
```javascript
|
|||
|
|
// 发车配置
|
|||
|
|
const carRefreshCount = ref(
|
|||
|
|
parseInt(localStorage.getItem('carRefreshCount') || '1')
|
|||
|
|
) // 发车前刷新次数(0-10,0表示跳过刷新)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **新增方法**
|
|||
|
|
```javascript
|
|||
|
|
// 设置发车刷新次数
|
|||
|
|
const setCarRefreshCount = (count) => {
|
|||
|
|
if (count < 0 || count > 10) {
|
|||
|
|
console.warn('⚠️ 发车刷新次数必须在0-10之间')
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
carRefreshCount.value = count
|
|||
|
|
localStorage.setItem('carRefreshCount', count.toString())
|
|||
|
|
console.log(`🚗 发车刷新次数已设置为: ${count}`)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **executeTask 新增 sendCar case**
|
|||
|
|
```javascript
|
|||
|
|
case 'sendCar':
|
|||
|
|
// 发车任务(查询、刷新、发送)
|
|||
|
|
// 1. 查询车辆
|
|||
|
|
// 2. 批量刷新(可选,只刷新无刷新票的车)
|
|||
|
|
// 3. 检查每日发车次数限制
|
|||
|
|
// 4. 批量收获
|
|||
|
|
// 5. 批量发送
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. **UI 组件修改 (BatchTaskPanel.vue)**
|
|||
|
|
|
|||
|
|
#### **新增配置UI**
|
|||
|
|
```vue
|
|||
|
|
<n-grid-item>
|
|||
|
|
<div class="tower-count-selector">
|
|||
|
|
<div class="selector-header">
|
|||
|
|
<label>发车刷新次数:</label>
|
|||
|
|
<n-input-number
|
|||
|
|
v-model:value="batchStore.carRefreshCount"
|
|||
|
|
:min="0"
|
|||
|
|
:max="10"
|
|||
|
|
:step="1"
|
|||
|
|
@update:value="handleCarRefreshCountChange"
|
|||
|
|
>
|
|||
|
|
<template #suffix>
|
|||
|
|
<span style="margin-left: 4px;">次</span>
|
|||
|
|
</template>
|
|||
|
|
</n-input-number>
|
|||
|
|
</div>
|
|||
|
|
<n-slider
|
|||
|
|
v-model:value="batchStore.carRefreshCount"
|
|||
|
|
:min="0"
|
|||
|
|
:max="10"
|
|||
|
|
:step="1"
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</n-grid-item>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **任务定义更新**
|
|||
|
|
```javascript
|
|||
|
|
const taskDefinitions = {
|
|||
|
|
dailyFix: { label: '一键补差', type: 'warning' },
|
|||
|
|
legionSignIn: { label: '俱乐部签到', type: 'info' },
|
|||
|
|
autoStudy: { label: '一键答题', type: 'warning' },
|
|||
|
|
claimHangupReward: { label: '领取挂机奖励', type: 'success' },
|
|||
|
|
addClock: { label: '加钟', type: 'info' },
|
|||
|
|
sendCar: { label: '发车', type: 'info' }, // ← 新增
|
|||
|
|
climbTower: { label: '爬塔', type: 'error' }
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. **发车任务详细逻辑**
|
|||
|
|
|
|||
|
|
#### **第1步:查询车辆**
|
|||
|
|
```javascript
|
|||
|
|
const queryResponse = await client.sendWithPromise('car_getrolecar', {}, 1500)
|
|||
|
|
const carDataMap = queryResponse.roleCar.carDataMap || {}
|
|||
|
|
const carIds = Object.keys(carDataMap).sort() // 按ID排序
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **第2步:批量刷新(可选)**
|
|||
|
|
```javascript
|
|||
|
|
const refreshCount = carRefreshCount.value
|
|||
|
|
if (refreshCount > 0) {
|
|||
|
|
for (let round = 1; round <= refreshCount; round++) {
|
|||
|
|
for (const carId of carIds) {
|
|||
|
|
const carInfo = carDataMap[carId]
|
|||
|
|
|
|||
|
|
// 跳过有刷新票的车辆
|
|||
|
|
if (carHasRefreshTicket(carInfo)) {
|
|||
|
|
console.log(`⏭️ 跳过有刷新票的车辆: ${carId}`)
|
|||
|
|
continue
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 刷新车辆
|
|||
|
|
await client.sendWithPromise('car_refresh', { carId: carId }, 1500)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **第3步:检查每日发车次数**
|
|||
|
|
```javascript
|
|||
|
|
const getTodayKey = (tokenId) => {
|
|||
|
|
const today = new Date().toLocaleDateString('zh-CN', {
|
|||
|
|
year: 'numeric', month: '2-digit', day: '2-digit'
|
|||
|
|
})
|
|||
|
|
return `car_daily_send_count_${today}_${tokenId}`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const dailySendKey = getTodayKey(tokenId)
|
|||
|
|
const dailySendCount = parseInt(localStorage.getItem(dailySendKey) || '0')
|
|||
|
|
|
|||
|
|
if (dailySendCount >= 4) {
|
|||
|
|
return {
|
|||
|
|
task: '发车',
|
|||
|
|
success: true,
|
|||
|
|
message: `今日发车次数已达上限(${dailySendCount}/4)`
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **第4步:批量收获**
|
|||
|
|
```javascript
|
|||
|
|
for (const carId of carIds) {
|
|||
|
|
const carInfo = carDataMap[carId]
|
|||
|
|
const state = getCarState(carInfo) // 计算车辆状态
|
|||
|
|
|
|||
|
|
if (state === 2) { // 已到达
|
|||
|
|
await client.sendWithPromise('car_claim', { carId: carId }, 1500)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **第5步:批量发送**
|
|||
|
|
```javascript
|
|||
|
|
const remainingSendCount = 4 - dailySendCount
|
|||
|
|
const readyToSendCars = carIds.filter(carId => getCarState(carDataMap[carId]) === 0)
|
|||
|
|
const carsToSend = readyToSendCars.slice(0, remainingSendCount)
|
|||
|
|
|
|||
|
|
for (const carId of carsToSend) {
|
|||
|
|
await client.sendWithPromise('car_send', {
|
|||
|
|
carId: carId,
|
|||
|
|
helperId: 0,
|
|||
|
|
text: ""
|
|||
|
|
}, 1500)
|
|||
|
|
|
|||
|
|
// 更新发车次数
|
|||
|
|
const newCount = dailySendCount + sendSuccessCount
|
|||
|
|
localStorage.setItem(dailySendKey, newCount.toString())
|
|||
|
|
|
|||
|
|
if (newCount >= 4) break // 达到上限,停止发送
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. **辅助函数**
|
|||
|
|
|
|||
|
|
#### **检查车辆是否有刷新票**
|
|||
|
|
```javascript
|
|||
|
|
const carHasRefreshTicket = (carInfo) => {
|
|||
|
|
if (!carInfo?.rewards || !Array.isArray(carInfo.rewards)) {
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
// 刷新票的itemId是35002
|
|||
|
|
return carInfo.rewards.some(reward => reward.itemId === 35002)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### **计算车辆状态**
|
|||
|
|
```javascript
|
|||
|
|
const getCarState = (carInfo) => {
|
|||
|
|
if (!carInfo) return 0
|
|||
|
|
|
|||
|
|
const { sendAt = 0, claimAt = 0, color = 1 } = carInfo
|
|||
|
|
|
|||
|
|
// 运输时间(秒)
|
|||
|
|
const transportDuration = (color === 1 || color === 2) ? 9000 : // 普通/稀有: 150分钟
|
|||
|
|
(color === 3) ? 10800 : // 史诗: 180分钟
|
|||
|
|
14400 // 神话/传奇: 240分钟
|
|||
|
|
|
|||
|
|
// 状态判断
|
|||
|
|
if (sendAt === 0) {
|
|||
|
|
return 0 // 待发车
|
|||
|
|
} else if (claimAt === 0) {
|
|||
|
|
const now = Math.floor(Date.now() / 1000)
|
|||
|
|
const elapsed = now - sendAt
|
|||
|
|
if (elapsed >= transportDuration) {
|
|||
|
|
return 2 // 已到达
|
|||
|
|
} else {
|
|||
|
|
return 1 // 运输中
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
return 0 // 待发车(已收获)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📊 执行日志示例
|
|||
|
|
|
|||
|
|
### 成功执行
|
|||
|
|
```
|
|||
|
|
🚗 [token_123] 开始查询俱乐部车辆...
|
|||
|
|
✅ [token_123] 查询到 4 辆车
|
|||
|
|
🔄 [token_123] 开始批量刷新车辆(1次)...
|
|||
|
|
🔄 [token_123] 第1轮刷新...
|
|||
|
|
⏭️ [token_123] 跳过有刷新票的车辆: car_001
|
|||
|
|
✅ [token_123] 刷新车辆成功: car_002
|
|||
|
|
✅ [token_123] 刷新车辆成功: car_003
|
|||
|
|
✅ [token_123] 刷新车辆成功: car_004
|
|||
|
|
🔄 [token_123] 刷新完成:成功3次,跳过1次,失败0次
|
|||
|
|
📊 [token_123] 今日已发车次数: 0/4
|
|||
|
|
🎁 [token_123] 开始批量收获...
|
|||
|
|
✅ [token_123] 收获车辆成功: car_001
|
|||
|
|
🎁 [token_123] 收获完成:成功1次,跳过3次
|
|||
|
|
🚀 [token_123] 开始批量发送...
|
|||
|
|
🚀 [token_123] 待发车: 4辆,剩余额度: 4个,将发送: 4辆
|
|||
|
|
✅ [token_123] 发送车辆成功: car_001
|
|||
|
|
✅ [token_123] 发送车辆成功: car_002
|
|||
|
|
✅ [token_123] 发送车辆成功: car_003
|
|||
|
|
✅ [token_123] 发送车辆成功: car_004
|
|||
|
|
🚀 [token_123] 发送完成:成功4次,跳过0次
|
|||
|
|
✅ 完成发车任务 (收获1,发送4,今日4/4)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 已达上限
|
|||
|
|
```
|
|||
|
|
🚗 [token_456] 开始查询俱乐部车辆...
|
|||
|
|
✅ [token_456] 查询到 4 辆车
|
|||
|
|
⏭️ [token_456] 刷新次数设置为0,跳过刷新
|
|||
|
|
📊 [token_456] 今日已发车次数: 4/4
|
|||
|
|
⚠️ [token_456] 今日发车次数已达上限: 4/4
|
|||
|
|
✅ 今日发车次数已达上限(4/4)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🎨 UI 展示
|
|||
|
|
|
|||
|
|
### 批量任务面板
|
|||
|
|
```
|
|||
|
|
┌─────────────────────────────────────┐
|
|||
|
|
│ ⚡ 批量自动化任务 │
|
|||
|
|
├─────────────────────────────────────┤
|
|||
|
|
│ 选择任务模板: [完整套餐 ▼] │
|
|||
|
|
│ │
|
|||
|
|
│ 并发数量: [5] ━━━━━○━━━━━━━━━━ 次 │
|
|||
|
|
│ │
|
|||
|
|
│ 爬塔次数: [10] ━━━━━○━━━━━━━━ 次 │
|
|||
|
|
│ │
|
|||
|
|
│ 发车刷新次数: [1] ○━━━━━━━━━━ 次 ← 新增 │
|
|||
|
|
│ │
|
|||
|
|
│ 包含任务 (7个): │
|
|||
|
|
│ [一键补差] [俱乐部签到] [一键答题] │
|
|||
|
|
│ [领取挂机奖励] [加钟] [发车] [爬塔] │
|
|||
|
|
│ ↑ 新增 │
|
|||
|
|
│ │
|
|||
|
|
│ [▶ 开始执行 (318个角色)] │
|
|||
|
|
└─────────────────────────────────────┘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🧪 测试场景
|
|||
|
|
|
|||
|
|
### 场景1:首次发车(刷新1次)
|
|||
|
|
1. 设置发车刷新次数为1
|
|||
|
|
2. 启动批量任务
|
|||
|
|
3. **预期结果**:
|
|||
|
|
- 查询4辆车
|
|||
|
|
- 刷新无刷新票的车辆1次
|
|||
|
|
- 收获已到达的车辆
|
|||
|
|
- 发送待发车的车辆(最多4辆)
|
|||
|
|
- 更新今日发车次数
|
|||
|
|
|
|||
|
|
### 场景2:跳过刷新
|
|||
|
|
1. 设置发车刷新次数为0
|
|||
|
|
2. 启动批量任务
|
|||
|
|
3. **预期结果**:
|
|||
|
|
- 查询车辆
|
|||
|
|
- 跳过刷新步骤
|
|||
|
|
- 直接收获和发送
|
|||
|
|
|
|||
|
|
### 场景3:已达每日上限
|
|||
|
|
1. 账号今日已发送4辆车
|
|||
|
|
2. 再次执行发车任务
|
|||
|
|
3. **预期结果**:
|
|||
|
|
- 查询车辆
|
|||
|
|
- 检测到已达上限
|
|||
|
|
- 跳过收获和发送
|
|||
|
|
- 提示:"今日发车次数已达上限(4/4)"
|
|||
|
|
|
|||
|
|
### 场景4:多账号独立计数
|
|||
|
|
1. 账号A发送4辆车(4/4)
|
|||
|
|
2. 切换到账号B
|
|||
|
|
3. 执行发车任务
|
|||
|
|
4. **预期结果**:
|
|||
|
|
- 账号B显示0/4
|
|||
|
|
- 可以正常发送4辆车
|
|||
|
|
|
|||
|
|
## 📝 相关文件
|
|||
|
|
|
|||
|
|
### 修改的文件
|
|||
|
|
1. **`src/stores/batchTaskStore.js`**
|
|||
|
|
- 添加 `carRefreshCount` 配置项
|
|||
|
|
- 添加 `setCarRefreshCount()` 方法
|
|||
|
|
- 添加 `sendCar` case 到 `executeTask()`
|
|||
|
|
- 更新任务模板,添加 'sendCar'
|
|||
|
|
|
|||
|
|
2. **`src/components/BatchTaskPanel.vue`**
|
|||
|
|
- 添加发车刷新次数配置UI
|
|||
|
|
- 添加 `handleCarRefreshCountChange()` 方法
|
|||
|
|
- 更新 `taskDefinitions`,添加 'sendCar'
|
|||
|
|
|
|||
|
|
### 新增文件
|
|||
|
|
- `MD说明/功能更新-批量任务添加发车功能v3.9.0.md`
|
|||
|
|
|
|||
|
|
## 🔄 版本信息
|
|||
|
|
|
|||
|
|
- **版本号**: v3.9.0
|
|||
|
|
- **更新日期**: 2025-01-08
|
|||
|
|
- **更新内容**:
|
|||
|
|
- 批量任务新增"发车"功能
|
|||
|
|
- 支持可配置的批量刷新
|
|||
|
|
- 支持每日4次发车限制
|
|||
|
|
- 支持多账号独立计数
|
|||
|
|
- **依赖版本**: v3.8.1
|
|||
|
|
|
|||
|
|
## 🎯 使用说明
|
|||
|
|
|
|||
|
|
### 基本使用
|
|||
|
|
1. 打开"批量自动化任务"面板
|
|||
|
|
2. 选择包含"发车"任务的模板(如"完整套餐")
|
|||
|
|
3. 设置发车刷新次数(推荐1次)
|
|||
|
|
4. 点击"开始执行"
|
|||
|
|
|
|||
|
|
### 高级配置
|
|||
|
|
- **跳过刷新**:将发车刷新次数设置为0
|
|||
|
|
- **多轮刷新**:将发车刷新次数设置为2-10(适合追求极品奖励)
|
|||
|
|
- **定时执行**:配合定时任务,每天自动发车
|
|||
|
|
|
|||
|
|
### 注意事项
|
|||
|
|
1. **每日限制**:每个token每天最多发送4辆车,超出会自动跳过
|
|||
|
|
2. **刷新逻辑**:只刷新无刷新票的车辆(有刷新票的车辆会被跳过)
|
|||
|
|
3. **执行顺序**:发车任务在"加钟"之后、"爬塔"之前执行
|
|||
|
|
4. **并发执行**:支持多账号并发,每个账号独立计数
|
|||
|
|
|
|||
|
|
## 🐛 已知问题
|
|||
|
|
|
|||
|
|
无
|
|||
|
|
|
|||
|
|
## 🚀 后续计划
|
|||
|
|
|
|||
|
|
- [ ] 添加发车结果详细统计
|
|||
|
|
- [ ] 支持自定义刷新策略(如只刷新特定品质)
|
|||
|
|
- [ ] 添加发车奖励记录
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**✅ 功能已完成!刷新页面(Ctrl + F5)即可使用批量发车功能!**
|
|||
|
|
|