From b713a71feea83d54f8a41a3aa048af836a600a0d Mon Sep 17 00:00:00 2001 From: qinhan Date: Fri, 10 Apr 2026 15:44:23 +0800 Subject: [PATCH] feat(game): complete bag feature MVP --- .../plans/2026-04-10-bag-feature-plan.md | 548 ++++++++++++++++++ .../specs/2026-04-10-bag-feature-design.md | 52 ++ opencode.json | 4 + 3 files changed, 604 insertions(+) create mode 100644 docs/superpowers/plans/2026-04-10-bag-feature-plan.md create mode 100644 docs/superpowers/specs/2026-04-10-bag-feature-design.md create mode 100644 opencode.json diff --git a/docs/superpowers/plans/2026-04-10-bag-feature-plan.md b/docs/superpowers/plans/2026-04-10-bag-feature-plan.md new file mode 100644 index 0000000..3f6585f --- /dev/null +++ b/docs/superpowers/plans/2026-04-10-bag-feature-plan.md @@ -0,0 +1,548 @@ +# 背包功能 MVP 实现计划 + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 在游戏客户端添加背包展示页面,显示角色背包中的物品,鼠标悬停显示物品名称和基本信息 + +**Architecture:** 使用现有后端API,前端本地分页,每页16个物品(4×4网格) + +**Tech Stack:** Vue 3 + TypeScript + Pinia + Element Plus + +--- + +### Task 1: 添加背包 API 模块 + +**Files:** +- Create: `Build_God_Game/src/api/bag.ts` + +- [ ] **Step 1: 创建 bag.ts API 模块** + +```typescript +import http from './index' + +export interface Bag { + id: number + name: string + rarity: number + capacity: number + description: string | null +} + +export interface CharacterBag { + id: number + characterId: number + bagId: number + bagName: string | null + bagCapacity: number +} + +export interface BagItem { + id: number + characterBagId: number + itemType: number + itemId: number + quantity: number + itemName: string | null + itemRarity: number | null +} + +export const getCharacterBag = (characterId: number): Promise => { + return http.get(`bag/character/${characterId}`) +} + +export const getBagItems = (characterBagId: number): Promise => { + return http.get(`bag/${characterBagId}/items`) +} +``` + +- [ ] **Step 2: 提交代码** + +```bash +git add Build_God_Game/src/api/bag.ts +git commit -m "feat(game): add bag API module" +``` + +--- + +### Task 2: 添加背包 Store + +**Files:** +- Create: `Build_God_Game/src/stores/bag.ts` + +- [ ] **Step 1: 创建 bag.ts Store** + +```typescript +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { getCharacterBag, getBagItems, type CharacterBag, type BagItem } from '@/api/bag' +import { useCharacterStore } from './character' + +const PAGE_SIZE = 16 + +export const useBagStore = defineStore('bag', () => { + const characterStore = useCharacterStore() + + const characterBag = ref(null) + const bagItems = ref([]) + const currentPage = ref(1) + const loading = ref(false) + const error = ref(null) + + const currentCharacterId = computed(() => characterStore.currentCharacter?.id) + + const totalItems = computed(() => bagItems.value.length) + + const totalPages = computed(() => Math.ceil(totalItems.value / PAGE_SIZE)) + + const paginatedItems = computed(() => { + const start = (currentPage.value - 1) * PAGE_SIZE + const end = start + PAGE_SIZE + return bagItems.value.slice(start, end) + }) + + const usedCapacity = computed(() => { + return bagItems.value.reduce((sum, item) => sum + item.quantity, 0) + }) + + const loadBag = async () => { + if (!currentCharacterId.value) { + error.value = '请先选择角色' + return + } + + try { + loading.value = true + error.value = null + + characterBag.value = await getCharacterBag(currentCharacterId.value) + + if (characterBag.value) { + bagItems.value = await getBagItems(characterBag.value.id) + } else { + bagItems.value = [] + } + + currentPage.value = 1 + } catch (e: any) { + error.value = e.message || '加载背包失败' + console.error('Load bag error:', e) + } finally { + loading.value = false + } + } + + const nextPage = () => { + if (currentPage.value < totalPages.value) { + currentPage.value++ + } + } + + const prevPage = () => { + if (currentPage.value > 1) { + currentPage.value-- + } + } + + return { + characterBag, + bagItems, + currentPage, + totalPages, + totalItems, + paginatedItems, + usedCapacity, + loading, + error, + loadBag, + nextPage, + prevPage + } +}) +``` + +- [ ] **Step 2: 提交代码** + +```bash +git add Build_God_Game/src/stores/bag.ts +git commit -m "feat(game): add bag store" +``` + +--- + +### Task 3: 添加背包页面 + +**Files:** +- Create: `Build_God_Game/src/views/BagView.vue` + +- [ ] **Step 1: 创建 BagView.vue** + +```vue + + + + + +``` + +- [ ] **Step 2: 提交代码** + +```bash +git add Build_God_Game/src/views/BagView.vue +git commit -m "feat(game): add bag view page" +``` + +--- + +### Task 4: 添加路由 + +**Files:** +- Modify: `Build_God_Game/src/router/index.ts:45-53` + +- [ ] **Step 1: 添加背包路由** + +在 `routes` 数组中,在 `/scrap` 路由后添加: + +```typescript +{ + path: '/bag', + name: 'bag', + component: () => import('@/views/BagView.vue'), + meta: { requiresAuth: true } +} +``` + +- [ ] **Step 2: 提交代码** + +```bash +git add Build_God_Game/src/router/index.ts +git commit -m "feat(game): add bag route" +``` + +--- + +### Task 5: 更新游戏主页导航菜单 + +**Files:** +- Modify: `Build_God_Game/src/views/GameView.vue:41-46` + +- [ ] **Step 1: 在 menuItems 中添加背包入口** + +找到 `const menuItems = computed(() => [...])`,在数组中添加: + +```typescript +{ label: '背包', icon: '🎒', useImage: false } +``` + +- [ ] **Step 2: 添加 navigateTo 跳转逻辑** + +在 `navigateTo` 函数中添加: + +```typescript +} else if (item.label === '背包') { + router.push('/bag') +} +``` + +- [ ] **Step 3: 提交代码** + +```bash +git add Build_God_Game/src/views/GameView.vue +git commit -m "feat(game): add bag menu entry in game view" +``` + +--- + +### Task 6: 验证构建 + +**Files:** +- Test: `Build_God_Game/` 整个项目 + +- [ ] **Step 1: 运行类型检查** + +```bash +cd Build_God_Game && npm run type-check +``` + +- [ ] **Step 2: 运行构建** + +```bash +cd Build_God_Game && npm run build +``` + +- [ ] **Step 3: 提交最终代码** + +```bash +git add -A && git commit -m "feat(game): complete bag feature MVP" +``` \ No newline at end of file diff --git a/docs/superpowers/specs/2026-04-10-bag-feature-design.md b/docs/superpowers/specs/2026-04-10-bag-feature-design.md new file mode 100644 index 0000000..3c49cce --- /dev/null +++ b/docs/superpowers/specs/2026-04-10-bag-feature-design.md @@ -0,0 +1,52 @@ +# 背包功能 MVP 设计 + +## 需求 + +在游戏客户端添加背包展示页面,显示角色背包中的物品,鼠标悬停显示物品名称和基本信息。 + +## 现有后端 API + +- `GET /api/god/bag/character/{characterId}` - 获取角色背包信息(包含背包名称和容量) +- `GET /api/god/bag/{characterBagId}/items` - 获取背包物品列表 +- 物品类型:装备(1)、丹药(2) + +## 实现方案 + +### 1. 添加游戏客户端 API (`src/api/bag.ts`) + +- `getCharacterBag(characterId)` - 获取角色背包信息 +- `getBagItems(characterBagId)` - 获取背包物品 + +### 2. 添加 Pinia Store (`src/stores/bag.ts`) + +- 管理背包数据、当前页码等状态 +- 提供加载、刷新方法 + +### 3. 添加背包页面 (`src/views/BagView.vue`) + +- 顶部:显示背包名称和容量信息(如 "普通背包 5/20") +- 物品网格:每页显示 **16** 个物品(4列 × 4行) +- 底部:分页控件(上一页/下一页) +- 物品格子:显示物品图标、名称、数量角标(仅数量>1时显示) +- 鼠标悬停:使用 Element Plus 的 `el-tooltip` 显示详细信息 + +### 4. 添加路由 (`src/router/index.ts`) + +- 路径:`/bag` +- 需登录访问 + +### 5. 更新导航菜单 (`GameView.vue`) + +- 在 menuItems 中添加:{ label: '背包', icon: '🎒' } + +## 物品信息展示(hover 提示内容) + +- **装备**:名称、稀有度(普通/稀有/史诗/传说) +- **丹药**:名称、功效描述 + +## 技术细节 + +- 使用前端本地分页(不修改后端) +- 当前角色从 `characterStore` 获取 +- 页面访问需要登录验证 +- 背包容量:普通20格、稀有40格、史诗60格、传说100格 \ No newline at end of file diff --git a/opencode.json b/opencode.json new file mode 100644 index 0000000..02598a1 --- /dev/null +++ b/opencode.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://opencode.ai/config.json", + "plugin": ["superpowers@git+https://github.com/obra/superpowers.git"] +} \ No newline at end of file