18 KiB
18 KiB
v2.1.1 快速实施指南
🎯 目标
将开源版本v2.1.1的核心功能集成到你的项目中,优先实现最重要的功能。
📋 推荐实施方案
根据重要性和难度,建议按以下顺序实施:
✅ 第一阶段:性能优化(1天)
目标: 减少控制台日志,提升性能
-
添加logger.js
复制文件:src/utils/logger.js -
修改tokenStore.js
// 替换 import { tokenLogger, wsLogger, gameLogger } from '../utils/logger.js' // 所有的 console.log 改为 wsLogger.debug() // 所有的 console.error 改为 wsLogger.error() -
测试
// 浏览器控制台测试 wsDebug.quiet() // 只显示警告 wsDebug.normal() // 正常模式 wsDebug.verbose() // 详细模式
验收标准:
- ✅ 生产环境不再有大量日志输出
- ✅ 控制台可以动态调整日志级别
- ✅ WebSocket连接正常工作
✅ 第二阶段:月度任务系统(2-3天)
目标: 实现月度任务进度跟踪和自动补齐
Step 1: 准备工作
- 备份GameStatus.vue
cp src/components/GameStatus.vue src/components/GameStatus.vue.backup
Step 2: 修改GameStatus.vue
-
添加月度任务相关变量
<script setup> // 月度任务相关 const FISH_TARGET = 320 const ARENA_TARGET = 240 const monthLoading = ref(false) const fishToppingUp = ref(false) const arenaToppingUp = ref(false) const monthActivity = ref(null) // 时间计算 const now = new Date() const daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate() const dayOfMonth = now.getDate() const remainingDays = computed(() => Math.max(0, daysInMonth - dayOfMonth)) const monthProgress = computed(() => Math.min(1, Math.max(0, dayOfMonth / daysInMonth))) // 进度数据 const myMonthInfo = computed(() => monthActivity.value?.myMonthInfo || {}) const myArenaInfo = computed(() => monthActivity.value?.myArenaInfo || {}) const fishNum = computed(() => Number(myMonthInfo.value?.['2']?.num || 0)) const arenaNum = computed(() => Number(myArenaInfo.value?.num || 0)) const fishPercent = computed(() => Math.min(100, Math.round((fishNum.value / FISH_TARGET) * 100))) const arenaPercent = computed(() => Math.min(100, Math.round((arenaNum.value / ARENA_TARGET) * 100))) // 应该完成的数量 const fishShouldBe = computed(() => remainingDays.value === 0 ? FISH_TARGET : Math.min(FISH_TARGET, Math.ceil(monthProgress.value * FISH_TARGET)) ) const arenaShouldBe = computed(() => remainingDays.value === 0 ? ARENA_TARGET : Math.min(ARENA_TARGET, Math.ceil(monthProgress.value * ARENA_TARGET)) ) const fishNeeded = computed(() => Math.max(0, fishShouldBe.value - fishNum.value)) const arenaNeeded = computed(() => Math.max(0, arenaShouldBe.value - arenaNum.value)) </script> -
添加刷新进度函数
const fetchMonthlyActivity = async () => { if (!tokenStore.selectedToken) { message.warning('请先选择Token') return } const status = tokenStore.getWebSocketStatus(tokenStore.selectedToken.id) if (status !== 'connected') return monthLoading.value = true try { const tokenId = tokenStore.selectedToken.id const result = await tokenStore.sendMessageWithPromise(tokenId, 'activity_get', {}, 10000) const act = result?.activity || result?.body?.activity || result monthActivity.value = act || null if (act) message.success('月度任务进度已更新') } catch (e) { message.error(`获取月度任务失败:${e.message}`) } finally { monthLoading.value = false } } -
添加物品解析函数
const getItemCount = (items, itemId) => { if (!items) return 0 if (Array.isArray(items)) { const found = items.find(it => Number(it.id ?? it.itemId) === itemId) if (!found) return 0 return Number(found.num ?? found.count ?? found.quantity ?? 0) } const node = items[String(itemId)] ?? items[itemId] if (node == null) return 0 if (typeof node === 'number') return Number(node) if (typeof node === 'object') { return Number(node.num ?? node.count ?? node.quantity ?? 0) } return Number(node) || 0 } -
添加钓鱼补齐函数
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) const topUpFish = async (needed) => { fishToppingUp.value = true try { const roleInfo = tokenStore.gameData?.roleInfo?.role const items = roleInfo?.items || {} const normalRod = getItemCount(items, 1011) || 0 const goldRod = getItemCount(items, 1012) || 0 let useFree = Math.min(normalRod, needed) let useGold = Math.min(goldRod, needed - useFree) const total = useFree + useGold if (total === 0) { message.error('没有可用的鱼竿') return } message.info(`开始钓鱼:普通鱼竿${useFree}次,金鱼竿${useGold}次`) // 使用普通鱼竿 for (let i = 0; i < useFree; i++) { await tokenStore.sendMessageWithPromise( tokenStore.selectedToken.id, 'fishing_fish', { fishingType: 1 }, 5000 ) await sleep(500) } // 使用金鱼竿 for (let i = 0; i < useGold; i++) { await tokenStore.sendMessageWithPromise( tokenStore.selectedToken.id, 'fishing_fish', { fishingType: 2 }, 5000 ) await sleep(500) } await sleep(1000) await fetchMonthlyActivity() message.success(`钓鱼补齐完成!共完成${total}次`) } catch (error) { message.error(`钓鱼补齐失败:${error.message}`) } finally { fishToppingUp.value = false } } -
添加竞技场补齐函数
const topUpArena = async (needed) => { arenaToppingUp.value = true try { const roleInfo = tokenStore.gameData?.roleInfo?.role const energy = roleInfo?.energy || 0 const ENERGY_PER_BATTLE = 5 const possibleBattles = Math.floor(energy / ENERGY_PER_BATTLE) if (possibleBattles < needed) { message.warning(`体力不足!当前仅可进行${possibleBattles}次战斗`) needed = possibleBattles } if (needed === 0) { message.error('体力不足') return } message.info(`开始竞技场战斗:共${needed}次`) let successCount = 0 for (let i = 0; i < needed; i++) { try { const matchResult = await tokenStore.sendMessageWithPromise( tokenStore.selectedToken.id, 'arena_matchopponent', {}, 5000 ) await sleep(300) await tokenStore.sendMessageWithPromise( tokenStore.selectedToken.id, 'arena_battle', { targetRoleId: matchResult?.opponent?.roleId, battleType: 1 }, 5000 ) successCount++ await sleep(1000) } catch (error) { console.error(`第${i+1}次战斗失败:`, error) } } await sleep(1000) await fetchMonthlyActivity() message.success(`竞技场补齐完成!成功${successCount}次`) } catch (error) { message.error(`竞技场补齐失败:${error.message}`) } finally { arenaToppingUp.value = false } } -
添加补齐入口函数
const topUpMonthly = (type) => { const isFish = type === 'fish' const needed = isFish ? fishNeeded.value : arenaNeeded.value if (needed === 0) { message.info(`${isFish ? '钓鱼' : '竞技场'}已达标`) return } if (isFish) { topUpFish(needed) } else { topUpArena(needed) } } const fishMoreOptions = [{ label: '一键完成', key: 'complete-fish' }] const arenaMoreOptions = [{ label: '一键完成', key: 'complete-arena' }] const onFishMoreSelect = (key) => { if (key === 'complete-fish') { topUpFish(FISH_TARGET - fishNum.value) } } const onArenaMoreSelect = (key) => { if (key === 'complete-arena') { topUpArena(ARENA_TARGET - arenaNum.value) } } -
添加UI组件
<template> <!-- 在适当位置添加月度任务卡片 --> <div class="status-card monthly-tasks"> <div class="card-header"> <img src="/icons/1736425783912140.png" alt="月度任务" class="status-icon"> <div class="status-info"> <h3>月度任务</h3> <p>进度与一键补齐</p> </div> <div class="status-badge" :class="{ active: monthActivity }"> <div class="status-dot" /> <span v-if="remainingDays > 0">剩余 {{ remainingDays }} 天</span> <span v-else>本月最后一天</span> </div> </div> <div class="card-content"> <div class="monthly-row"> <div class="row-title">钓鱼进度</div> <div class="row-value">{{ fishNum }} / {{ FISH_TARGET }}({{ fishPercent }}%)</div> </div> <div class="monthly-row"> <div class="row-title">竞技场进度</div> <div class="row-value">{{ arenaNum }} / {{ ARENA_TARGET }}({{ arenaPercent }}%)</div> </div> <div class="action-row"> <button class="action-button secondary" :disabled="monthLoading || fishToppingUp || arenaToppingUp" @click="fetchMonthlyActivity" > {{ monthLoading ? '刷新中...' : '刷新进度' }} </button> <n-button-group> <n-button class="action-button" :disabled="monthLoading || fishToppingUp" @click="topUpMonthly('fish')" > {{ fishToppingUp ? '补齐中...' : '钓鱼补齐' }} </n-button> <n-dropdown :options="fishMoreOptions" trigger="click" @select="onFishMoreSelect"> <n-button :disabled="monthLoading || fishToppingUp">▾</n-button> </n-dropdown> </n-button-group> <n-button-group> <n-button class="action-button" :disabled="monthLoading || arenaToppingUp" @click="topUpMonthly('arena')" > {{ arenaToppingUp ? '补齐中...' : '竞技场补齐' }} </n-button> <n-dropdown :options="arenaMoreOptions" trigger="click" @select="onArenaMoreSelect"> <n-button :disabled="monthLoading || arenaToppingUp">▾</n-button> </n-dropdown> </n-button-group> </div> <p class="description muted"> 补齐规则:让"当前天数比例"和"完成比例"一致 </p> </div> </div> </template> -
添加样式
<style scoped lang="scss"> .monthly-tasks { .monthly-row { display: flex; justify-content: space-between; padding: var(--spacing-sm) 0; border-bottom: 1px solid var(--border-light); .row-title { color: var(--text-secondary); } .row-value { font-weight: var(--font-weight-semibold); } } .action-row { display: flex; gap: var(--spacing-sm); margin-top: var(--spacing-md); } .description.muted { margin-top: var(--spacing-sm); font-size: var(--font-size-xs); color: var(--text-tertiary); } } </style>
Step 3: 测试
-
基础测试
- 刷新进度显示正确
- 补齐次数计算正确
- 钓鱼补齐功能正常
- 竞技场补齐功能正常
- 一键完成功能正常
-
边界测试
- 鱼竿不足时的处理
- 体力不足时的处理
- 已达标时的提示
- 本月最后一天的计算
验收标准:
- ✅ 月度任务面板正常显示
- ✅ 进度计算准确
- ✅ 自动补齐功能正常
- ✅ 不影响现有功能
✅ 第三阶段:身份卡系统(2天)
目标: 添加角色身份卡展示
Step 1: 添加组件
-
复制IdentityCard.vue
复制文件:src/components/IdentityCard.vue -
在GameStatus.vue中使用
<script setup> import IdentityCard from './IdentityCard.vue' </script> <template> <!-- 在页面顶部添加 --> <IdentityCard embedded /> </template>
Step 2: 测试
- 身份卡正常显示
- 战力段位显示正确
- 资源信息显示正确
- 头像加载正常
验收标准:
- ✅ 身份卡美观显示
- ✅ 数据获取正常
- ✅ 动画效果正常
✅ 第四阶段:俱乐部功能(2-3天)
目标: 增强俱乐部功能
Step 1: 添加工具函数
- 添加clubBattleUtils.js
复制文件:src/utils/clubBattleUtils.js
Step 2: 添加组件
-
添加ClubInfo.vue
复制文件:src/components/ClubInfo.vue -
添加ClubBattleRecords.vue
复制文件:src/components/ClubBattleRecords.vue -
在GameStatus中使用
<script setup> import ClubInfo from './ClubInfo.vue' </script> <template> <!-- 在俱乐部区域添加 --> <ClubInfo /> </template>
验收标准:
- ✅ 俱乐部信息正常显示
- ✅ 盐场战绩可以查询
- ✅ 导出功能正常
🎨 可选:布局优化
如果你想采用开源版的Tab切换布局:
<template>
<div class="game-status-container">
<!-- 身份卡常驻顶部 -->
<IdentityCard embedded />
<!-- Tab切换 -->
<n-tabs v-model:value="activeSection" type="line" animated size="small">
<n-tab-pane name="daily" tab="日常" />
<n-tab-pane name="club" tab="俱乐部" />
<n-tab-pane name="activity" tab="活动" />
</n-tabs>
<!-- 根据activeSection显示不同内容 -->
<DailyTaskStatus v-show="activeSection === 'daily'" />
<ClubInfo v-show="activeSection === 'club'" />
<div class="monthly-tasks" v-show="activeSection === 'activity'">
<!-- 月度任务 -->
</div>
</div>
</template>
<script setup>
const activeSection = ref('daily')
</script>
⚠️ 注意事项
1. 保留你的特色功能
确保不要覆盖以下文件:
- ❌ BatchTaskPanel.vue
- ❌ SchedulerConfig.vue
- ❌ TaskProgressCard.vue
- ❌ ExecutionHistory.vue
- ❌ UpgradeModule.vue
- ❌ CarManagement.vue
2. 游戏命令兼容性
你的版本的gameCommands.js有额外字段(rtt, code),保持使用你的版本。
3. 数据库方案
开源版有tokenDb.js(IndexedDB),但你的localStorage方案也很好,可以暂时不迁移。
4. 测试要求
每个阶段完成后都要充分测试:
- WebSocket连接
- 批量任务功能
- 定时任务功能
- 现有的所有功能
📊 时间估算
| 阶段 | 工作量 | 说明 |
|---|---|---|
| 第一阶段 | 0.5-1天 | 添加logger系统 |
| 第二阶段 | 2-3天 | 月度任务系统(最复杂) |
| 第三阶段 | 1-2天 | 身份卡系统 |
| 第四阶段 | 2-3天 | 俱乐部功能 |
| 总计 | 6-9天 | 包含测试时间 |
✅ 检查清单
开发前
- 创建功能分支
- 备份关键文件
- 阅读完整对比报告
第一阶段完成
- logger.js已添加
- tokenStore.js已集成logger
- 浏览器控制台测试通过
- 生产环境日志减少
第二阶段完成
- 月度任务面板显示
- 刷新进度功能正常
- 钓鱼补齐测试通过
- 竞技场补齐测试通过
- 一键完成测试通过
第三阶段完成
- IdentityCard组件添加
- 战力段位显示正确
- 资源信息显示正确
第四阶段完成
- ClubInfo组件添加
- ClubBattleRecords组件添加
- 盐场战绩功能正常
上线前
- 所有功能测试通过
- 批量任务不受影响
- 定时任务不受影响
- 性能测试通过
- 用户体验良好
🆘 遇到问题?
常见问题
-
月度任务进度不显示
- 检查WebSocket连接状态
- 检查
activity_get命令响应 - 查看浏览器控制台错误
-
钓鱼补齐失败
- 检查鱼竿数量获取
- 检查
fishing_fish命令 - 查看错误提示
-
样式显示异常
- 检查CSS变量定义
- 检查naive-ui组件引入
- 清理浏览器缓存
获取帮助
如果遇到问题,可以:
- 查看详细文档:
代码对比报告-v2.1.1.md - 查看实现细节:
月度任务系统详细实现.md - 向我提问,提供详细错误信息
🎉 完成后
恭喜完成v2.1.1功能集成!
你的项目现在拥有:
- ✅ 高性能的日志系统
- ✅ 智能的月度任务自动化
- ✅ 精美的角色身份卡
- ✅ 强大的俱乐部管理
- ✅ 你原有的批量任务系统
- ✅ 你原有的定时任务系统
下一步:
- 部署到测试环境
- 用户测试反馈
- 优化和完善
- 部署到生产环境
祝开发顺利! 🚀