Browse Source

feat: 任务系统改版 - 收集与狩猎任务

- 后端:MissionType 改为 Collection/Hunting,DailyMissionDto 添加任务类型、难度、进度字段
- 后端:添加任务进度更新 API (POST /mission/progress/update)
- 后端:MissionProgressService 添加自动匹配目标类型更新进度逻辑
- 前端:DailyMissionView 改为卡片布局展示
- 前端:收集任务绿色边框,狩猎任务红色系边框(按难度区分)
- 前端:炼狱难度使用 ElectricBorder 特殊效果
master
hanqin 4 weeks ago
parent
commit
4bad021be5
  1. 82
      .claude/skills/gitnexus/gitnexus-cli/SKILL.md
  2. 89
      .claude/skills/gitnexus/gitnexus-debugging/SKILL.md
  3. 78
      .claude/skills/gitnexus/gitnexus-exploring/SKILL.md
  4. 64
      .claude/skills/gitnexus/gitnexus-guide/SKILL.md
  5. 97
      .claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md
  6. 121
      .claude/skills/gitnexus/gitnexus-refactoring/SKILL.md
  7. 1
      .gitignore
  8. 102
      AGENTS.md
  9. 2
      Build_God_Admin_Frontend/Frontend/.env.development
  10. 31
      Build_God_Api/Build_God_Api/Controllers/MissionController.cs
  11. 10
      Build_God_Api/Build_God_Api/DB/Mission.cs
  12. 14
      Build_God_Api/Build_God_Api/Dto/MissionDtos.cs
  13. 39
      Build_God_Api/Build_God_Api/Services/DailyMissionService.cs
  14. 83
      Build_God_Api/Build_God_Api/Services/MissionProgressService.cs
  15. 2
      Build_God_Game/.env.development
  16. 38
      Build_God_Game/src/api/dailyMission.ts
  17. 536
      Build_God_Game/src/views/DailyMissionView.vue
  18. 101
      CLAUDE.md
  19. 134
      docs/superpowers/specs/2026-04-15-mission-system-redesign.md

82
.claude/skills/gitnexus/gitnexus-cli/SKILL.md

@ -0,0 +1,82 @@
---
name: gitnexus-cli
description: "Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: \"Index this repo\", \"Reanalyze the codebase\", \"Generate a wiki\""
---
# GitNexus CLI Commands
All commands work via `npx` — no global install required.
## Commands
### analyze — Build or refresh the index
```bash
npx gitnexus analyze
```
Run from the project root. This parses all source files, builds the knowledge graph, writes it to `.gitnexus/`, and generates CLAUDE.md / AGENTS.md context files.
| Flag | Effect |
| -------------- | ---------------------------------------------------------------- |
| `--force` | Force full re-index even if up to date |
| `--embeddings` | Enable embedding generation for semantic search (off by default) |
**When to run:** First time in a project, after major code changes, or when `gitnexus://repo/{name}/context` reports the index is stale. In Claude Code, a PostToolUse hook runs `analyze` automatically after `git commit` and `git merge`, preserving embeddings if previously generated.
### status — Check index freshness
```bash
npx gitnexus status
```
Shows whether the current repo has a GitNexus index, when it was last updated, and symbol/relationship counts. Use this to check if re-indexing is needed.
### clean — Delete the index
```bash
npx gitnexus clean
```
Deletes the `.gitnexus/` directory and unregisters the repo from the global registry. Use before re-indexing if the index is corrupt or after removing GitNexus from a project.
| Flag | Effect |
| --------- | ------------------------------------------------- |
| `--force` | Skip confirmation prompt |
| `--all` | Clean all indexed repos, not just the current one |
### wiki — Generate documentation from the graph
```bash
npx gitnexus wiki
```
Generates repository documentation from the knowledge graph using an LLM. Requires an API key (saved to `~/.gitnexus/config.json` on first use).
| Flag | Effect |
| ------------------- | ----------------------------------------- |
| `--force` | Force full regeneration |
| `--model <model>` | LLM model (default: minimax/minimax-m2.5) |
| `--base-url <url>` | LLM API base URL |
| `--api-key <key>` | LLM API key |
| `--concurrency <n>` | Parallel LLM calls (default: 3) |
| `--gist` | Publish wiki as a public GitHub Gist |
### list — Show all indexed repos
```bash
npx gitnexus list
```
Lists all repositories registered in `~/.gitnexus/registry.json`. The MCP `list_repos` tool provides the same information.
## After Indexing
1. **Read `gitnexus://repo/{name}/context`** to verify the index loaded
2. Use the other GitNexus skills (`exploring`, `debugging`, `impact-analysis`, `refactoring`) for your task
## Troubleshooting
- **"Not inside a git repository"**: Run from a directory inside a git repo
- **Index is stale after re-analyzing**: Restart Claude Code to reload the MCP server
- **Embeddings slow**: Omit `--embeddings` (it's off by default) or set `OPENAI_API_KEY` for faster API-based embedding

89
.claude/skills/gitnexus/gitnexus-debugging/SKILL.md

@ -0,0 +1,89 @@
---
name: gitnexus-debugging
description: "Use when the user is debugging a bug, tracing an error, or asking why something fails. Examples: \"Why is X failing?\", \"Where does this error come from?\", \"Trace this bug\""
---
# Debugging with GitNexus
## When to Use
- "Why is this function failing?"
- "Trace where this error comes from"
- "Who calls this method?"
- "This endpoint returns 500"
- Investigating bugs, errors, or unexpected behavior
## Workflow
```
1. gitnexus_query({query: "<error or symptom>"}) → Find related execution flows
2. gitnexus_context({name: "<suspect>"}) → See callers/callees/processes
3. READ gitnexus://repo/{name}/process/{name} → Trace execution flow
4. gitnexus_cypher({query: "MATCH path..."}) → Custom traces if needed
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] Understand the symptom (error message, unexpected behavior)
- [ ] gitnexus_query for error text or related code
- [ ] Identify the suspect function from returned processes
- [ ] gitnexus_context to see callers and callees
- [ ] Trace execution flow via process resource if applicable
- [ ] gitnexus_cypher for custom call chain traces if needed
- [ ] Read source files to confirm root cause
```
## Debugging Patterns
| Symptom | GitNexus Approach |
| -------------------- | ---------------------------------------------------------- |
| Error message | `gitnexus_query` for error text → `context` on throw sites |
| Wrong return value | `context` on the function → trace callees for data flow |
| Intermittent failure | `context` → look for external calls, async deps |
| Performance issue | `context` → find symbols with many callers (hot paths) |
| Recent regression | `detect_changes` to see what your changes affect |
## Tools
**gitnexus_query** — find code related to error:
```
gitnexus_query({query: "payment validation error"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError, PaymentException
```
**gitnexus_context** — full context for a suspect:
```
gitnexus_context({name: "validatePayment"})
→ Incoming calls: processCheckout, webhookHandler
→ Outgoing calls: verifyCard, fetchRates (external API!)
→ Processes: CheckoutFlow (step 3/7)
```
**gitnexus_cypher** — custom call chain traces:
```cypher
MATCH path = (a)-[:CodeRelation {type: 'CALLS'}*1..2]->(b:Function {name: "validatePayment"})
RETURN [n IN nodes(path) | n.name] AS chain
```
## Example: "Payment endpoint returns 500 intermittently"
```
1. gitnexus_query({query: "payment error handling"})
→ Processes: CheckoutFlow, ErrorHandling
→ Symbols: validatePayment, handlePaymentError
2. gitnexus_context({name: "validatePayment"})
→ Outgoing calls: verifyCard, fetchRates (external API!)
3. READ gitnexus://repo/my-app/process/CheckoutFlow
→ Step 3: validatePayment → calls fetchRates (external)
4. Root cause: fetchRates calls external API without proper timeout
```

78
.claude/skills/gitnexus/gitnexus-exploring/SKILL.md

@ -0,0 +1,78 @@
---
name: gitnexus-exploring
description: "Use when the user asks how code works, wants to understand architecture, trace execution flows, or explore unfamiliar parts of the codebase. Examples: \"How does X work?\", \"What calls this function?\", \"Show me the auth flow\""
---
# Exploring Codebases with GitNexus
## When to Use
- "How does authentication work?"
- "What's the project structure?"
- "Show me the main components"
- "Where is the database logic?"
- Understanding code you haven't seen before
## Workflow
```
1. READ gitnexus://repos → Discover indexed repos
2. READ gitnexus://repo/{name}/context → Codebase overview, check staleness
3. gitnexus_query({query: "<what you want to understand>"}) → Find related execution flows
4. gitnexus_context({name: "<symbol>"}) → Deep dive on specific symbol
5. READ gitnexus://repo/{name}/process/{name} → Trace full execution flow
```
> If step 2 says "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] READ gitnexus://repo/{name}/context
- [ ] gitnexus_query for the concept you want to understand
- [ ] Review returned processes (execution flows)
- [ ] gitnexus_context on key symbols for callers/callees
- [ ] READ process resource for full execution traces
- [ ] Read source files for implementation details
```
## Resources
| Resource | What you get |
| --------------------------------------- | ------------------------------------------------------- |
| `gitnexus://repo/{name}/context` | Stats, staleness warning (~150 tokens) |
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores (~300 tokens) |
| `gitnexus://repo/{name}/cluster/{name}` | Area members with file paths (~500 tokens) |
| `gitnexus://repo/{name}/process/{name}` | Step-by-step execution trace (~200 tokens) |
## Tools
**gitnexus_query** — find execution flows related to a concept:
```
gitnexus_query({query: "payment processing"})
→ Processes: CheckoutFlow, RefundFlow, WebhookHandler
→ Symbols grouped by flow with file locations
```
**gitnexus_context** — 360-degree view of a symbol:
```
gitnexus_context({name: "validateUser"})
→ Incoming calls: loginHandler, apiMiddleware
→ Outgoing calls: checkToken, getUserById
→ Processes: LoginFlow (step 2/5), TokenRefresh (step 1/3)
```
## Example: "How does payment processing work?"
```
1. READ gitnexus://repo/my-app/context → 918 symbols, 45 processes
2. gitnexus_query({query: "payment processing"})
→ CheckoutFlow: processPayment → validateCard → chargeStripe
→ RefundFlow: initiateRefund → calculateRefund → processRefund
3. gitnexus_context({name: "processPayment"})
→ Incoming: checkoutHandler, webhookHandler
→ Outgoing: validateCard, chargeStripe, saveTransaction
4. Read src/payments/processor.ts for implementation details
```

64
.claude/skills/gitnexus/gitnexus-guide/SKILL.md

@ -0,0 +1,64 @@
---
name: gitnexus-guide
description: "Use when the user asks about GitNexus itself — available tools, how to query the knowledge graph, MCP resources, graph schema, or workflow reference. Examples: \"What GitNexus tools are available?\", \"How do I use GitNexus?\""
---
# GitNexus Guide
Quick reference for all GitNexus MCP tools, resources, and the knowledge graph schema.
## Always Start Here
For any task involving code understanding, debugging, impact analysis, or refactoring:
1. **Read `gitnexus://repo/{name}/context`** — codebase overview + check index freshness
2. **Match your task to a skill below** and **read that skill file**
3. **Follow the skill's workflow and checklist**
> If step 1 warns the index is stale, run `npx gitnexus analyze` in the terminal first.
## Skills
| Task | Skill to read |
| -------------------------------------------- | ------------------- |
| Understand architecture / "How does X work?" | `gitnexus-exploring` |
| Blast radius / "What breaks if I change X?" | `gitnexus-impact-analysis` |
| Trace bugs / "Why is X failing?" | `gitnexus-debugging` |
| Rename / extract / split / refactor | `gitnexus-refactoring` |
| Tools, resources, schema reference | `gitnexus-guide` (this file) |
| Index, status, clean, wiki CLI commands | `gitnexus-cli` |
## Tools Reference
| Tool | What it gives you |
| ---------------- | ------------------------------------------------------------------------ |
| `query` | Process-grouped code intelligence — execution flows related to a concept |
| `context` | 360-degree symbol view — categorized refs, processes it participates in |
| `impact` | Symbol blast radius — what breaks at depth 1/2/3 with confidence |
| `detect_changes` | Git-diff impact — what do your current changes affect |
| `rename` | Multi-file coordinated rename with confidence-tagged edits |
| `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) |
| `list_repos` | Discover indexed repos |
## Resources Reference
Lightweight reads (~100-500 tokens) for navigation:
| Resource | Content |
| ---------------------------------------------- | ----------------------------------------- |
| `gitnexus://repo/{name}/context` | Stats, staleness check |
| `gitnexus://repo/{name}/clusters` | All functional areas with cohesion scores |
| `gitnexus://repo/{name}/cluster/{clusterName}` | Area members |
| `gitnexus://repo/{name}/processes` | All execution flows |
| `gitnexus://repo/{name}/process/{processName}` | Step-by-step trace |
| `gitnexus://repo/{name}/schema` | Graph schema for Cypher |
## Graph Schema
**Nodes:** File, Function, Class, Interface, Method, Community, Process
**Edges (via CodeRelation.type):** CALLS, IMPORTS, EXTENDS, IMPLEMENTS, DEFINES, MEMBER_OF, STEP_IN_PROCESS
```cypher
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "myFunc"})
RETURN caller.name, caller.filePath
```

97
.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md

@ -0,0 +1,97 @@
---
name: gitnexus-impact-analysis
description: "Use when the user wants to know what will break if they change something, or needs safety analysis before editing code. Examples: \"Is it safe to change X?\", \"What depends on this?\", \"What will break?\""
---
# Impact Analysis with GitNexus
## When to Use
- "Is it safe to change this function?"
- "What will break if I modify X?"
- "Show me the blast radius"
- "Who uses this code?"
- Before making non-trivial code changes
- Before committing — to understand what your changes affect
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → What depends on this
2. READ gitnexus://repo/{name}/processes → Check affected execution flows
3. gitnexus_detect_changes() → Map current git changes to affected flows
4. Assess risk and report to user
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklist
```
- [ ] gitnexus_impact({target, direction: "upstream"}) to find dependents
- [ ] Review d=1 items first (these WILL BREAK)
- [ ] Check high-confidence (>0.8) dependencies
- [ ] READ processes to check affected execution flows
- [ ] gitnexus_detect_changes() for pre-commit check
- [ ] Assess risk level and report to user
```
## Understanding Output
| Depth | Risk Level | Meaning |
| ----- | ---------------- | ------------------------ |
| d=1 | **WILL BREAK** | Direct callers/importers |
| d=2 | LIKELY AFFECTED | Indirect dependencies |
| d=3 | MAY NEED TESTING | Transitive effects |
## Risk Assessment
| Affected | Risk |
| ------------------------------ | -------- |
| <5 symbols, few processes | LOW |
| 5-15 symbols, 2-5 processes | MEDIUM |
| >15 symbols or many processes | HIGH |
| Critical path (auth, payments) | CRITICAL |
## Tools
**gitnexus_impact** — the primary tool for symbol blast radius:
```
gitnexus_impact({
target: "validateUser",
direction: "upstream",
minConfidence: 0.8,
maxDepth: 3
})
→ d=1 (WILL BREAK):
- loginHandler (src/auth/login.ts:42) [CALLS, 100%]
- apiMiddleware (src/api/middleware.ts:15) [CALLS, 100%]
→ d=2 (LIKELY AFFECTED):
- authRouter (src/routes/auth.ts:22) [CALLS, 95%]
```
**gitnexus_detect_changes** — git-diff based impact analysis:
```
gitnexus_detect_changes({scope: "staged"})
→ Changed: 5 symbols in 3 files
→ Affected: LoginFlow, TokenRefresh, APIMiddlewarePipeline
→ Risk: MEDIUM
```
## Example: "What breaks if I change validateUser?"
```
1. gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware (WILL BREAK)
→ d=2: authRouter, sessionManager (LIKELY AFFECTED)
2. READ gitnexus://repo/my-app/processes
→ LoginFlow and TokenRefresh touch validateUser
3. Risk: 2 direct callers, 2 processes = MEDIUM
```

121
.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md

@ -0,0 +1,121 @@
---
name: gitnexus-refactoring
description: "Use when the user wants to rename, extract, split, move, or restructure code safely. Examples: \"Rename this function\", \"Extract this into a module\", \"Refactor this class\", \"Move this to a separate file\""
---
# Refactoring with GitNexus
## When to Use
- "Rename this function safely"
- "Extract this into a module"
- "Split this service"
- "Move this to a new file"
- Any task involving renaming, extracting, splitting, or restructuring code
## Workflow
```
1. gitnexus_impact({target: "X", direction: "upstream"}) → Map all dependents
2. gitnexus_query({query: "X"}) → Find execution flows involving X
3. gitnexus_context({name: "X"}) → See all incoming/outgoing refs
4. Plan update order: interfaces → implementations → callers → tests
```
> If "Index is stale" → run `npx gitnexus analyze` in terminal.
## Checklists
### Rename Symbol
```
- [ ] gitnexus_rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview all edits
- [ ] Review graph edits (high confidence) and ast_search edits (review carefully)
- [ ] If satisfied: gitnexus_rename({..., dry_run: false}) — apply edits
- [ ] gitnexus_detect_changes() — verify only expected files changed
- [ ] Run tests for affected processes
```
### Extract Module
```
- [ ] gitnexus_context({name: target}) — see all incoming/outgoing refs
- [ ] gitnexus_impact({target, direction: "upstream"}) — find all external callers
- [ ] Define new module interface
- [ ] Extract code, update imports
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
### Split Function/Service
```
- [ ] gitnexus_context({name: target}) — understand all callees
- [ ] Group callees by responsibility
- [ ] gitnexus_impact({target, direction: "upstream"}) — map callers to update
- [ ] Create new functions/services
- [ ] Update callers
- [ ] gitnexus_detect_changes() — verify affected scope
- [ ] Run tests for affected processes
```
## Tools
**gitnexus_rename** — automated multi-file rename:
```
gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits across 8 files
→ 10 graph edits (high confidence), 2 ast_search edits (review)
→ Changes: [{file_path, edits: [{line, old_text, new_text, confidence}]}]
```
**gitnexus_impact** — map all dependents first:
```
gitnexus_impact({target: "validateUser", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware, testUtils
→ Affected Processes: LoginFlow, TokenRefresh
```
**gitnexus_detect_changes** — verify your changes after refactoring:
```
gitnexus_detect_changes({scope: "all"})
→ Changed: 8 files, 12 symbols
→ Affected processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM
```
**gitnexus_cypher** — custom reference queries:
```cypher
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"})
RETURN caller.name, caller.filePath ORDER BY caller.filePath
```
## Risk Rules
| Risk Factor | Mitigation |
| ------------------- | ----------------------------------------- |
| Many callers (>5) | Use gitnexus_rename for automated updates |
| Cross-area refs | Use detect_changes after to verify scope |
| String/dynamic refs | gitnexus_query to find them |
| External/public API | Version and deprecate properly |
## Example: Rename `validateUser` to `authenticateUser`
```
1. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: true})
→ 12 edits: 10 graph (safe), 2 ast_search (review)
→ Files: validator.ts, login.ts, middleware.ts, config.json...
2. Review ast_search edits (config.json: dynamic reference!)
3. gitnexus_rename({symbol_name: "validateUser", new_name: "authenticateUser", dry_run: false})
→ Applied 12 edits across 8 files
4. gitnexus_detect_changes({scope: "all"})
→ Affected: LoginFlow, TokenRefresh
→ Risk: MEDIUM — run tests for these flows
```

1
.gitignore

@ -0,0 +1 @@
.gitnexus

102
AGENTS.md

@ -191,3 +191,105 @@ export const useAuthStore = defineStore('auth', () => {
- **Test account**: `Tom` / `123456` (email: 976802198@qq.com)
- Backend: ports 59447 (HTTPS), 59448 (HTTP)
- Always use `await` with async operations
<!-- gitnexus:start -->
# GitNexus — Code Intelligence
This project is indexed by GitNexus as **Build_God** (660 symbols, 954 relationships, 0 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
## Always Do
- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user.
- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows.
- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`.
## When Debugging
1. `gitnexus_query({query: "<error or symptom>"})` — find execution flows related to the issue
2. `gitnexus_context({name: "<suspect function>"})` — see all callers, callees, and process participation
3. `READ gitnexus://repo/Build_God/process/{processName}` — trace the full execution flow step by step
4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed
## When Refactoring
- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`.
- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code.
- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed.
## Never Do
- NEVER edit a function, class, or method without first running `gitnexus_impact` on it.
- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope.
## Tools Quick Reference
| Tool | When to use | Command |
|------|-------------|---------|
| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` |
| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` |
| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` |
| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` |
| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` |
| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` |
## Impact Risk Levels
| Depth | Meaning | Action |
|-------|---------|--------|
| d=1 | WILL BREAK — direct callers/importers | MUST update these |
| d=2 | LIKELY AFFECTED — indirect deps | Should test |
| d=3 | MAY NEED TESTING — transitive | Test if critical path |
## Resources
| Resource | Use for |
|----------|---------|
| `gitnexus://repo/Build_God/context` | Codebase overview, check index freshness |
| `gitnexus://repo/Build_God/clusters` | All functional areas |
| `gitnexus://repo/Build_God/processes` | All execution flows |
| `gitnexus://repo/Build_God/process/{name}` | Step-by-step execution trace |
## Self-Check Before Finishing
Before completing any code modification task, verify:
1. `gitnexus_impact` was run for all modified symbols
2. No HIGH/CRITICAL risk warnings were ignored
3. `gitnexus_detect_changes()` confirms changes match expected scope
4. All d=1 (WILL BREAK) dependents were updated
## Keeping the Index Fresh
After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it:
```bash
npx gitnexus analyze
```
If the index previously included embeddings, preserve them by adding `--embeddings`:
```bash
npx gitnexus analyze --embeddings
```
To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.**
> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`.
## CLI
| Task | Read this skill file |
|------|---------------------|
| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` |
| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` |
| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` |
| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` |
| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` |
| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` |
<!-- gitnexus:end -->

2
Build_God_Admin_Frontend/Frontend/.env.development

@ -1,2 +1,2 @@
# 开发环境配置
VITE_API_URL=https://localhost:59447/api/god/
VITE_API_URL=http://localhost:5091/api/god/

31
Build_God_Api/Build_God_Api/Controllers/MissionController.cs

@ -11,11 +11,15 @@ namespace Build_God_Api.Controllers
[Route("api/god/[controller]")]
public class MissionController(
IMissionService service,
IMissionProgressService progressService
IMissionProgressService progressService,
ICharacterService characterService,
ICurrentUserService currentUserService
) : ControllerBase
{
private readonly IMissionService service = service;
private readonly IMissionProgressService progressService = progressService;
private readonly ICharacterService characterService = characterService;
private readonly ICurrentUserService currentUserService = currentUserService;
// ============ Mission ============
@ -93,6 +97,31 @@ namespace Build_God_Api.Controllers
return await progressService.Delete(id);
}
[HttpPost("progress/update")]
[Authorize]
public async Task<ActionResult<UpdateProgressResultDto>> UpdateProgress([FromBody] UpdateProgressCmd cmd)
{
try
{
var character = await characterService.GetCharacterByAccountId(currentUserService.UserId);
if (character == null)
return BadRequest("角色不存在");
var (success, missionCompleted) = await progressService.UpdateProgressByTargetType(
character.Id, cmd.ProgressType, cmd.ItemId, cmd.ItemName, cmd.Count);
return Ok(new UpdateProgressResultDto
{
Success = success,
MissionCompleted = missionCompleted
});
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
// ============ Enums ============
[HttpGet("types")]

10
Build_God_Api/Build_God_Api/DB/Mission.cs

@ -20,7 +20,7 @@ namespace Build_God_Api.DB
/// 任务类型
/// </summary>
[SugarColumn(IsNullable = false)]
public MissionType Type { get; set; } = MissionType.MainStory;
public MissionType Type { get; set; } = MissionType.Collection;
/// <summary>
/// 任务标题(展示用,与Name不同)
@ -91,11 +91,11 @@ namespace Build_God_Api.DB
/// </summary>
public enum MissionType
{
[Description("悬赏任务")]
MainStory = 1,
[Description("收集任务")]
Collection = 1,
[Description("日常任务")]
DailyTask = 2
[Description("狩猎任务")]
Hunting = 2
}
/// <summary>

14
Build_God_Api/Build_God_Api/Dto/MissionDtos.cs

@ -8,4 +8,18 @@ namespace Build_God_Api.Dto
public int PageSize { get; set; } = 0;
public int? MissionType { get; set; }
}
public class UpdateProgressCmd
{
public ProgressTargetType ProgressType { get; set; }
public int? ItemId { get; set; }
public string? ItemName { get; set; }
public int Count { get; set; } = 1;
}
public class UpdateProgressResultDto
{
public bool Success { get; set; }
public bool MissionCompleted { get; set; }
}
}

39
Build_God_Api/Build_God_Api/Services/DailyMissionService.cs

@ -50,6 +50,9 @@ namespace Build_God_Api.Services
public int TodayClaimedCount { get; set; }
public int TodayTotalCount { get; set; }
public List<MissionRewardDto> Rewards { get; set; } = new();
public MissionType MissionType { get; set; }
public MissionDifficulty Difficulty { get; set; }
public List<MissionProgressDto> Progresses { get; set; } = new();
}
public class MissionRewardDto
@ -61,6 +64,16 @@ namespace Build_God_Api.Services
public int Count { get; set; }
}
public class MissionProgressDto
{
public int MissionProgressId { get; set; }
public ProgressTargetType TargetType { get; set; }
public int? TargetItemId { get; set; }
public string? TargetItemName { get; set; }
public int TargetCount { get; set; }
public int CurrentCount { get; set; }
}
public class DailyMissionService(
ISqlSugarClient db,
IBagService bagService,
@ -125,6 +138,7 @@ namespace Build_God_Api.Services
{
var mission = await _db.Queryable<Mission>()
.Includes(x => x.Rewards)
.Includes(x => x.Progresses)
.FirstAsync(x => x.Id == dm.MissionId);
if (mission == null) continue;
@ -145,7 +159,9 @@ namespace Build_God_Api.Services
AssignedDate = dm.AssignedDate,
ExpReward = CalculateExpReward(mission.Difficulty, character.LevelId),
TodayClaimedCount = todayClaimedCount,
TodayTotalCount = todayTotalCount
TodayTotalCount = todayTotalCount,
MissionType = mission.Type,
Difficulty = mission.Difficulty
};
if (mission.Rewards != null)
@ -163,6 +179,25 @@ namespace Build_God_Api.Services
}
}
if (mission.Progresses != null)
{
foreach (var progress in mission.Progresses)
{
var characterProgress = await _db.Queryable<CharacterMissionProgress>()
.FirstAsync(x => x.CharacterId == characterId && x.MissionId == dm.MissionId && x.MissionProgressId == progress.Id);
dto.Progresses.Add(new MissionProgressDto
{
MissionProgressId = progress.Id,
TargetType = progress.TargetType,
TargetItemId = progress.TargetItemId,
TargetItemName = progress.TargetItemName,
TargetCount = progress.TargetCount,
CurrentCount = characterProgress?.CurrentCount ?? 0
});
}
}
result.Add(dto);
}
@ -312,7 +347,7 @@ namespace Build_God_Api.Services
}
var availableMissions = await _db.Queryable<Mission>()
.Where(x => x.Type == MissionType.DailyTask)
.Where(x => x.Type == MissionType.Collection || x.Type == MissionType.Hunting)
.Where(x => x.IsAvailable == true)
.Where(x => x.RequiredLevelId <= character.LevelId)
.ToListAsync();

83
Build_God_Api/Build_God_Api/Services/MissionProgressService.cs

@ -1,4 +1,5 @@
using Build_God_Api.DB;
using Build_God_Api.Dto;
using SqlSugar;
namespace Build_God_Api.Services
@ -16,6 +17,9 @@ namespace Build_God_Api.Services
Task<List<CharacterMissionProgress>> GetCharacterProgress(int characterId, int missionId);
Task<bool> UpdateCharacterProgress(int characterId, int missionProgressId, int count);
Task<bool> InitCharacterProgress(int characterId, int missionId);
// 更新角色任务进度(根据目标类型自动匹配)
Task<(bool success, bool missionCompleted)> UpdateProgressByTargetType(int characterId, ProgressTargetType targetType, int? itemId, string? itemName, int count);
}
public class MissionProgressService(ISqlSugarClient db) : IMissionProgressService
@ -125,5 +129,84 @@ namespace Build_God_Api.Services
return true;
}
public async Task<(bool success, bool missionCompleted)> UpdateProgressByTargetType(int characterId, ProgressTargetType targetType, int? itemId, string? itemName, int count)
{
// 查找该角色所有进行中的每日任务
var dailyMissions = await db.Queryable<CharacterDailyMission>()
.Where(x => x.CharacterId == characterId && x.Status == DailyMissionStatus.InProgress)
.ToListAsync();
if (!dailyMissions.Any())
return (false, false);
bool anyCompleted = false;
foreach (var dailyMission in dailyMissions)
{
// 获取任务配置
var mission = await db.Queryable<Mission>()
.Includes(x => x.Progresses)
.FirstAsync(x => x.Id == dailyMission.MissionId);
if (mission?.Progresses == null || !mission.Progresses.Any())
continue;
// 查找匹配的目标进度
var matchingProgress = mission.Progresses.FirstOrDefault(p =>
p.TargetType == targetType &&
(targetType != ProgressTargetType.CollectItem || p.TargetItemId == itemId));
if (matchingProgress == null)
continue;
// 获取角色进度
var characterProgress = await db.Queryable<CharacterMissionProgress>()
.FirstAsync(x =>
x.CharacterId == characterId &&
x.MissionId == dailyMission.MissionId &&
x.MissionProgressId == matchingProgress.Id);
if (characterProgress == null)
{
characterProgress = new CharacterMissionProgress
{
CharacterId = characterId,
MissionId = dailyMission.MissionId,
MissionProgressId = matchingProgress.Id,
CurrentCount = 0,
IsCompleted = false,
UpdatedOn = DateTime.UtcNow
};
await db.Insertable(characterProgress).ExecuteCommandAsync();
}
if (characterProgress.IsCompleted)
continue;
// 更新进度
characterProgress.CurrentCount = Math.Min(characterProgress.CurrentCount + count, matchingProgress.TargetCount);
characterProgress.IsCompleted = characterProgress.CurrentCount >= matchingProgress.TargetCount;
characterProgress.UpdatedOn = DateTime.UtcNow;
await db.Updateable(characterProgress).ExecuteCommandAsync();
// 检查任务是否全部完成
var allProgresses = await db.Queryable<CharacterMissionProgress>()
.Where(x => x.CharacterId == characterId && x.MissionId == dailyMission.MissionId)
.ToListAsync();
bool allCompleted = allProgresses.All(p => p.IsCompleted);
if (allCompleted)
{
dailyMission.Status = DailyMissionStatus.Completed;
await db.Updateable(dailyMission).ExecuteCommandAsync();
anyCompleted = true;
}
}
return (true, anyCompleted);
}
}
}

2
Build_God_Game/.env.development

@ -1,2 +1,2 @@
# 开发环境配置
VITE_API_URL=https://localhost:59447/api/god/
VITE_API_URL=http://localhost:5091/api/god/

38
Build_God_Game/src/api/dailyMission.ts

@ -12,6 +12,25 @@ export const RewardType = {
Money: 3
} as const
export type RewardType = typeof RewardType[keyof typeof RewardType]
export const MissionType = {
Collection: 1,
Hunting: 2
} as const
export type MissionType = typeof MissionType[keyof typeof MissionType]
export const MissionDifficulty = {
Normal: 1,
Hard: 2,
Purgatory: 3
} as const
export type MissionDifficulty = typeof MissionDifficulty[keyof typeof MissionDifficulty]
export const ProgressTargetType = {
CollectItem: 1,
Fish: 2,
KillMonster: 3,
ConsumeItem: 4,
Custom: 5
} as const
export type ProgressTargetType = typeof ProgressTargetType[keyof typeof ProgressTargetType]
export interface MissionReward {
rewardType: RewardType
rewardTypeName: string
@ -19,6 +38,14 @@ export interface MissionReward {
itemName: string
count: number
}
export interface MissionProgressDto {
missionProgressId: number
targetType: ProgressTargetType
targetItemId: number | null
targetItemName: string | null
targetCount: number
currentCount: number
}
export interface DailyMission {
id: number
characterId: number
@ -36,6 +63,9 @@ export interface DailyMission {
todayClaimedCount: number
todayTotalCount: number
rewards: MissionReward[]
missionType: MissionType
difficulty: MissionDifficulty
progresses: MissionProgressDto[]
}
export const dailyMissionApi = {
getList: (): Promise<DailyMission[]> => {
@ -46,5 +76,13 @@ export const dailyMissionApi = {
},
claim: (dailyMissionId: number): Promise<boolean> => {
return http.post(`/dailyMission/${dailyMissionId}/claim`)
},
updateProgress: (progressType: ProgressTargetType, itemId: number | null, itemName: string | null, count: number): Promise<{ success: boolean; missionCompleted: boolean }> => {
return http.post('/mission/progress/update', {
progressType,
itemId,
itemName,
count
})
}
}

536
Build_God_Game/src/views/DailyMissionView.vue

@ -1,30 +1,12 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { ref, computed, onMounted, defineComponent, type PropType, h } from 'vue'
import { useRouter } from 'vue-router'
import { dailyMissionApi, type DailyMission, DailyMissionStatus, RewardType } from '@/api/dailyMission'
import { dailyMissionApi, type DailyMission, DailyMissionStatus, RewardType, MissionType, MissionDifficulty, ProgressTargetType } from '@/api/dailyMission'
import Particles from '@/components/Particles/Particles.vue'
import MissionCarousel from '@/components/MissionCarousel/MissionCarousel.vue'
import Carousel from '@/components/Carousel/Carousel.vue'
import type { CarouselItem } from '@/components/Carousel/Carousel.vue'
import ElectricBorder from '@/components/ElectricBorder/ElectricBorder.vue'
const router = useRouter()
const carouselItems: CarouselItem[] = [
{
title: "Custom Item",
description: "A custom carousel item.",
id: 1,
icon: "circle",
},
{
title: "Another Item",
description: "Another carousel item.",
id: 2,
icon: "layers",
},
// Add more items as needed
];
const missions = ref<DailyMission[]>([])
const todayStats = ref({ claimed: 0, total: 0 })
const loading = ref(false)
@ -39,71 +21,6 @@ const showMsg = (text: string, type: 'success' | 'error' = 'success') => {
}, 2000)
}
const getStatusText = (status: DailyMissionStatus) => {
switch (status) {
case DailyMissionStatus.Pending:
return '待接取'
case DailyMissionStatus.InProgress:
return '进行中'
case DailyMissionStatus.Completed:
return '待领取'
case DailyMissionStatus.Claimed:
return '已领取'
default:
return '未知'
}
}
const getStatusClass = (status: DailyMissionStatus) => {
switch (status) {
case DailyMissionStatus.Pending:
return 'status-pending'
case DailyMissionStatus.InProgress:
return 'status-progress'
case DailyMissionStatus.Completed:
return 'status-completed'
case DailyMissionStatus.Claimed:
return 'status-claimed'
default:
return ''
}
}
const getRewardIcon = (type: RewardType) => {
switch (type) {
case RewardType.Money:
return '💰'
case RewardType.Pill:
return '💊'
case RewardType.Equipment:
return '⚔️'
default:
return '🎁'
}
}
const formatRemainingTime = (endTime?: string) => {
if (!endTime) return ''
const end = new Date(endTime)
const now = new Date()
const diff = end.getTime() - now.getTime()
if (diff <= 0) return '已完成'
const minutes = Math.floor(diff / 60000)
const seconds = Math.floor((diff % 60000) / 1000)
return `${minutes}${seconds}`
}
const remainingTimes = ref<Record<number, string>>({})
let timer: number | null = null
const updateRemainingTimes = () => {
missions.value.forEach(mission => {
if (mission.status === DailyMissionStatus.InProgress) {
remainingTimes.value[mission.id] = formatRemainingTime(mission.endTime)
}
})
}
const canAccept = (mission: DailyMission) => mission.status === DailyMissionStatus.Pending
const canClaim = (mission: DailyMission) => mission.status === DailyMissionStatus.Completed
@ -118,7 +35,6 @@ const loadMissions = async () => {
total: data[0].todayTotalCount
}
}
updateRemainingTimes()
} catch (error: any) {
showMsg(error?.message || '加载任务失败', 'error')
} finally {
@ -152,30 +68,139 @@ const handleGoBack = () => {
router.push('/game')
}
const handleMissionSelect = (mission: DailyMission) => {
selectedMission.value = mission
}
onMounted(() => {
loadMissions()
timer = window.setInterval(updateRemainingTimes, 1000)
})
const selectedMission = ref<DailyMission | null>(null)
const activeMissions = computed(() => missions.value.filter(m => !m.isFromYesterday))
const hasAnyMissions = computed(() => activeMissions.value.length > 0)
const getMissionTypeClass = (type: MissionType, difficulty: MissionDifficulty) => {
if (type === MissionType.Collection) {
return 'mission-collection'
}
if (difficulty === MissionDifficulty.Purgatory) {
return 'mission-hunting-purgatory'
}
if (difficulty === MissionDifficulty.Hard) {
return 'mission-hunting-hard'
}
return 'mission-hunting-normal'
}
const getStatusText = (status: DailyMissionStatus) => {
switch (status) {
case DailyMissionStatus.Pending: return '待接取'
case DailyMissionStatus.InProgress: return '进行中'
case DailyMissionStatus.Completed: return '待领取'
case DailyMissionStatus.Claimed: return '已领取'
default: return '未知'
}
}
const getStatusClass = (status: DailyMissionStatus) => {
switch (status) {
case DailyMissionStatus.Pending: return 'status-pending'
case DailyMissionStatus.InProgress: return 'status-progress'
case DailyMissionStatus.Completed: return 'status-completed'
case DailyMissionStatus.Claimed: return 'status-claimed'
default: return ''
}
}
const getDifficultyLabel = (difficulty: MissionDifficulty) => {
switch (difficulty) {
case MissionDifficulty.Normal: return '普通'
case MissionDifficulty.Hard: return '困难'
case MissionDifficulty.Purgatory: return '炼狱'
default: return ''
}
}
const yesterdayMissions = computed(() => missions.value.filter(m => m.isFromYesterday && m.status === DailyMissionStatus.Completed))
const todayMissions = computed(() => missions.value.filter(m => !m.isFromYesterday))
const getDifficultyClass = (difficulty: MissionDifficulty) => {
switch (difficulty) {
case MissionDifficulty.Normal: return 'difficulty-normal'
case MissionDifficulty.Hard: return 'difficulty-hard'
case MissionDifficulty.Purgatory: return 'difficulty-purgatory'
default: return ''
}
}
const hasAnyMissions = computed(() => yesterdayMissions.value.length > 0 || todayMissions.value.length > 0)
const getRewardIcon = (type: RewardType) => {
switch (type) {
case RewardType.Money: return '💰'
case RewardType.Pill: return '💊'
case RewardType.Equipment: return '⚔️'
default: return '🎁'
}
}
const getProgressText = (mission: DailyMission) => {
if (!mission.progresses || mission.progresses.length === 0) return ''
const progress = mission.progresses[0]
const targetType = progress.targetType === ProgressTargetType.CollectItem ? '收集' : '狩猎'
const targetName = progress.targetItemName || (progress.targetType === ProgressTargetType.KillMonster ? '怪物' : '物品')
return `${targetType} ${progress.currentCount}/${progress.targetCount} ${targetName}`
}
const MissionCardContent = defineComponent({
name: 'MissionCardContent',
props: {
mission: {
type: Object as PropType<DailyMission>,
required: true
}
},
emits: ['accept', 'claim'],
setup(props, { emit }) {
return () => h('div', { class: 'mission-card-content' }, [
h('div', { class: 'card-header' }, [
h('div', { class: 'card-title-row' }, [
h('span', { class: 'card-icon' }, '📦'),
h('span', { class: 'card-title' }, props.mission.missionTitle),
]),
h('span', { class: ['card-status', getStatusClass(props.mission.status)] }, getStatusText(props.mission.status)),
]),
h('div', { class: 'card-desc' }, props.mission.missionDescription),
h('div', { class: 'card-difficulty' }, [
h('span', { class: ['difficulty-badge', getDifficultyClass(props.mission.difficulty)] }, getDifficultyLabel(props.mission.difficulty)),
]),
props.mission.progresses && props.mission.progresses.length > 0 && props.mission.status !== DailyMissionStatus.Pending
? h('div', { class: 'card-progress' }, [
h('span', { class: 'progress-label' }, '进度:'),
h('span', { class: 'progress-value' }, getProgressText(props.mission)),
])
: null,
h('div', { class: 'card-rewards' }, [
h('span', { class: 'reward-item exp-reward' }, `${props.mission.expReward}`),
...props.mission.rewards.slice(0, 2).map((reward: any) =>
h('span', { class: 'reward-item' }, `${getRewardIcon(reward.rewardType)}${reward.count}`)
),
props.mission.rewards.length > 2
? h('span', { class: 'reward-more' }, `+${props.mission.rewards.length - 2}`)
: null,
]),
h('div', { class: 'card-actions' }, [
canAccept(props.mission)
? h('button', { class: 'card-btn accept-btn', onClick: () => emit('accept') }, '接取')
: canClaim(props.mission)
? h('button', { class: 'card-btn claim-btn', onClick: () => emit('claim') }, '领取')
: props.mission.status === DailyMissionStatus.InProgress
? h('button', { class: 'card-btn disabled-btn', disabled: true }, '进行中')
: props.mission.status === DailyMissionStatus.Claimed
? h('button', { class: 'card-btn disabled-btn', disabled: true }, '已完成')
: null,
]),
])
}
})
</script>
<template>
<div class="daily-mission-page">
<Particles :particle-count="50" :particle-colors="['#ffffff', '#aaaaaa']" class="particles-bg" />
<div class="page-container">
<div class="page-header">
<span class="back-btn" @click="handleGoBack"> 返回</span>
<span class="title">每日任务</span>
@ -191,109 +216,44 @@ const hasAnyMissions = computed(() => yesterdayMissions.value.length > 0 || toda
</div>
<div v-else class="missions-content">
<div v-if="activeMissions.length > 0" class="stats-bar">
<span class="stats-text">今日进度: {{ todayStats.claimed }}/{{ todayStats.total }}</span>
</div>
<!-- <div v-if="yesterdayMissions.length > 0" class="mission-section yesterday-section">
<div class="section-header">
<span class="section-title">昨日任务</span>
<span class="section-badge highlight">待领取</span>
</div>
<div class="carousel-wrapper">
<MissionCarousel :items="yesterdayMissions" :base-width="340" :card-height="220"
@select="handleMissionSelect">
<template #default="{ item }">
<div class="mission-card-content">
<div class="card-header">
<span class="card-title">{{ item.missionTitle }}</span>
<span class="card-status" :class="getStatusClass(item.status)">
{{ getStatusText(item.status) }}
</span>
</div>
<div class="card-desc">{{ item.missionDescription }}</div>
<div class="card-time">
<span v-if="item.status === DailyMissionStatus.InProgress">
剩余: {{ remainingTimes[item.id] || formatRemainingTime(item.endTime) }}
</span>
<span v-else>
{{ item.spendTimeMinutes }}分钟
</span>
</div>
<div class="card-rewards">
<span class="reward-item exp-reward">{{ item.expReward }}</span>
<span v-for="(reward, idx) in item.rewards.slice(0, 2)" :key="idx" class="reward-item">
{{ getRewardIcon(reward.rewardType) }}{{ reward.count }}
</span>
<span v-if="item.rewards.length > 2" class="reward-more">+{{ item.rewards.length - 2 }}</span>
</div>
<div class="card-actions">
<button v-if="canAccept(item)" class="card-btn accept-btn" @click.stop="handleAccept(item)">
接取
</button>
<button v-if="canClaim(item)" class="card-btn claim-btn" @click.stop="handleClaim(item)">
领取
</button>
<button v-if="item.status === DailyMissionStatus.InProgress" class="card-btn disabled-btn" disabled>
挂机中
</button>
<button v-if="item.status === DailyMissionStatus.Claimed" class="card-btn disabled-btn" disabled>
已完成
</button>
</div>
</div>
</template>
</MissionCarousel>
</div>
</div> -->
<div v-if="todayMissions.length > 0" class="mission-section">
<div class="section-header">
<span class="section-title">今日任务</span>
<span class="section-badge">{{ todayStats.claimed }}/{{ todayStats.total }}</span>
</div>
<div class="carousel-wrapper">
<MissionCarousel :items="todayMissions" :base-width="340" :card-height="180" @select="handleMissionSelect"
:round="true" :loop="true">
<template #default="{ item }">
<div class="mission-card-content">
<div class="card-header">
<span class="card-title">{{ item.missionTitle }}</span>
<span class="card-status" :class="getStatusClass(item.status)">
{{ getStatusText(item.status) }}
</span>
</div>
<div class="card-desc">{{ item.missionDescription }}</div>
<div class="card-time">
<span v-if="item.status === DailyMissionStatus.InProgress">
剩余: {{ remainingTimes[item.id] || formatRemainingTime(item.endTime) }}
</span>
<span v-else>
{{ item.spendTimeMinutes }}分钟
</span>
</div>
<div class="card-rewards">
<span class="reward-item exp-reward">{{ item.expReward }}</span>
<span v-for="(reward, idx) in item.rewards.slice(0, 2)" :key="idx" class="reward-item">
{{ getRewardIcon(reward.rewardType) }}{{ reward.count }}
</span>
<span v-if="item.rewards.length > 2" class="reward-more">+{{ item.rewards.length - 2 }}</span>
</div>
<div class="card-actions">
<button v-if="canAccept(item)" class="card-btn accept-btn" @click.stop="handleAccept(item)">
接取
</button>
<button v-if="canClaim(item)" class="card-btn claim-btn" @click.stop="handleClaim(item)">
领取
</button>
<button v-if="item.status === DailyMissionStatus.InProgress" class="card-btn disabled-btn" disabled>
挂机中
</button>
<button v-if="item.status === DailyMissionStatus.Claimed" class="card-btn disabled-btn" disabled>
已完成
</button>
</div>
</div>
</template>
</MissionCarousel>
</div>
<div v-if="hasAnyMissions" class="mission-list">
<template v-for="mission in activeMissions" :key="mission.id">
<ElectricBorder
v-if="mission.difficulty === MissionDifficulty.Purgatory"
color="#dc2626"
:speed="1.2"
:chaos="1.5"
:thickness="2"
class="mission-card purgatory-card"
>
<div class="card-inner">
<component
:is="MissionCardContent"
:mission="mission"
@accept="handleAccept(mission)"
@claim="handleClaim(mission)"
/>
</div>
</ElectricBorder>
<div
v-else
class="mission-card"
:class="getMissionTypeClass(mission.missionType, mission.difficulty)"
>
<div class="card-inner">
<component
:is="MissionCardContent"
:mission="mission"
@accept="handleAccept(mission)"
@claim="handleClaim(mission)"
/>
</div>
</div>
</template>
</div>
<div v-if="!hasAnyMissions" class="empty-state">
@ -377,7 +337,6 @@ const hasAnyMissions = computed(() => yesterdayMissions.value.length > 0 || toda
opacity: 0;
transform: translateX(-50%) translateY(-10px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
@ -393,124 +352,176 @@ const hasAnyMissions = computed(() => yesterdayMissions.value.length > 0 || toda
.missions-content {
display: flex;
flex-direction: column;
gap: 24px;
gap: 16px;
}
.stats-bar {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
padding: 12px 16px;
text-align: center;
}
.stats-text {
color: #888888;
font-size: 0.9rem;
}
.mission-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.mission-section {
.mission-card {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.08);
border: 1px solid;
border-radius: 12px;
padding: 16px;
overflow: hidden;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.yesterday-section {
background: rgba(255, 68, 68, 0.05);
border-color: rgba(255, 68, 68, 0.2);
.mission-card:hover {
transform: translateY(-2px);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
.purgatory-card {
border: none;
}
.section-title {
color: #ffffff;
font-size: 1rem;
font-weight: 500;
.card-inner {
padding: 16px;
}
.section-badge {
background: rgba(255, 255, 255, 0.1);
color: #888888;
padding: 4px 12px;
border-radius: 12px;
font-size: 0.8rem;
.mission-collection {
border-color: rgba(34, 197, 94, 0.3);
}
.section-badge.highlight {
background: rgba(255, 68, 68, 0.2);
color: #ff4444;
.mission-hunting-normal {
border-color: rgba(239, 68, 68, 0.3);
}
.carousel-wrapper {
display: flex;
justify-content: center;
.mission-hunting-hard {
border-color: rgba(249, 115, 22, 0.4);
}
.mission-hunting-purgatory {
border-color: rgba(220, 38, 38, 0.5);
}
.mission-card-content {
width: 100%;
height: 100%;
padding: 12px;
display: flex;
flex-direction: column;
box-sizing: border-box;
gap: 10px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 6px;
padding-bottom: 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.card-title-row {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
min-width: 0;
}
.card-icon {
font-size: 1.2rem;
}
.card-title {
color: #ffffff;
font-size: 0.9rem;
font-size: 1rem;
font-weight: 600;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 8px;
}
.card-status {
padding: 2px 8px;
border-radius: 8px;
font-size: 0.65rem;
font-size: 0.7rem;
font-weight: 500;
white-space: nowrap;
}
.card-desc {
color: #888888;
font-size: 0.7rem;
line-height: 1.3;
margin-bottom: 6px;
flex: 1;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
font-size: 0.8rem;
line-height: 1.4;
}
.card-time {
color: #ff8844;
.card-difficulty {
display: flex;
align-items: center;
}
.difficulty-badge {
padding: 2px 8px;
border-radius: 4px;
font-size: 0.7rem;
margin-bottom: 8px;
font-weight: 500;
}
.difficulty-normal {
background: rgba(100, 100, 100, 0.3);
color: #888888;
}
.difficulty-hard {
background: rgba(249, 115, 22, 0.2);
color: #f97316;
}
.difficulty-purgatory {
background: rgba(220, 38, 38, 0.3);
color: #fca5a5;
}
.card-progress {
display: flex;
align-items: center;
gap: 6px;
background: rgba(255, 255, 255, 0.03);
padding: 8px 10px;
border-radius: 6px;
}
.progress-label {
color: #666666;
font-size: 0.75rem;
}
.progress-value {
color: #22c55e;
font-size: 0.8rem;
font-weight: 500;
}
.card-rewards {
display: flex;
flex-wrap: wrap;
gap: 3px;
margin-bottom: 8px;
gap: 4px;
}
.card-rewards .reward-item {
.reward-item {
background: rgba(255, 136, 68, 0.1);
border: 1px solid rgba(255, 136, 68, 0.2);
color: #ff8844;
padding: 1px 5px;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.65rem;
font-size: 0.7rem;
}
.card-rewards .exp-reward {
.exp-reward {
background: rgba(255, 215, 0, 0.1);
border-color: rgba(255, 215, 0, 0.3);
color: #ffd700;
@ -519,21 +530,22 @@ const hasAnyMissions = computed(() => yesterdayMissions.value.length > 0 || toda
.reward-more {
background: rgba(255, 255, 255, 0.1);
color: #888888;
padding: 1px 5px;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.65rem;
font-size: 0.7rem;
}
.card-actions {
display: flex;
gap: 6px;
gap: 8px;
margin-top: 4px;
}
.card-btn {
flex: 1;
padding: 6px 10px;
padding: 8px 12px;
border-radius: 6px;
font-size: 0.75rem;
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;

101
CLAUDE.md

@ -0,0 +1,101 @@
<!-- gitnexus:start -->
# GitNexus — Code Intelligence
This project is indexed by GitNexus as **Build_God** (660 symbols, 954 relationships, 0 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
## Always Do
- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user.
- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows.
- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`.
## When Debugging
1. `gitnexus_query({query: "<error or symptom>"})` — find execution flows related to the issue
2. `gitnexus_context({name: "<suspect function>"})` — see all callers, callees, and process participation
3. `READ gitnexus://repo/Build_God/process/{processName}` — trace the full execution flow step by step
4. For regressions: `gitnexus_detect_changes({scope: "compare", base_ref: "main"})` — see what your branch changed
## When Refactoring
- **Renaming**: MUST use `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` first. Review the preview — graph edits are safe, text_search edits need manual review. Then run with `dry_run: false`.
- **Extracting/Splitting**: MUST run `gitnexus_context({name: "target"})` to see all incoming/outgoing refs, then `gitnexus_impact({target: "target", direction: "upstream"})` to find all external callers before moving code.
- After any refactor: run `gitnexus_detect_changes({scope: "all"})` to verify only expected files changed.
## Never Do
- NEVER edit a function, class, or method without first running `gitnexus_impact` on it.
- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope.
## Tools Quick Reference
| Tool | When to use | Command |
|------|-------------|---------|
| `query` | Find code by concept | `gitnexus_query({query: "auth validation"})` |
| `context` | 360-degree view of one symbol | `gitnexus_context({name: "validateUser"})` |
| `impact` | Blast radius before editing | `gitnexus_impact({target: "X", direction: "upstream"})` |
| `detect_changes` | Pre-commit scope check | `gitnexus_detect_changes({scope: "staged"})` |
| `rename` | Safe multi-file rename | `gitnexus_rename({symbol_name: "old", new_name: "new", dry_run: true})` |
| `cypher` | Custom graph queries | `gitnexus_cypher({query: "MATCH ..."})` |
## Impact Risk Levels
| Depth | Meaning | Action |
|-------|---------|--------|
| d=1 | WILL BREAK — direct callers/importers | MUST update these |
| d=2 | LIKELY AFFECTED — indirect deps | Should test |
| d=3 | MAY NEED TESTING — transitive | Test if critical path |
## Resources
| Resource | Use for |
|----------|---------|
| `gitnexus://repo/Build_God/context` | Codebase overview, check index freshness |
| `gitnexus://repo/Build_God/clusters` | All functional areas |
| `gitnexus://repo/Build_God/processes` | All execution flows |
| `gitnexus://repo/Build_God/process/{name}` | Step-by-step execution trace |
## Self-Check Before Finishing
Before completing any code modification task, verify:
1. `gitnexus_impact` was run for all modified symbols
2. No HIGH/CRITICAL risk warnings were ignored
3. `gitnexus_detect_changes()` confirms changes match expected scope
4. All d=1 (WILL BREAK) dependents were updated
## Keeping the Index Fresh
After committing code changes, the GitNexus index becomes stale. Re-run analyze to update it:
```bash
npx gitnexus analyze
```
If the index previously included embeddings, preserve them by adding `--embeddings`:
```bash
npx gitnexus analyze --embeddings
```
To check whether embeddings exist, inspect `.gitnexus/meta.json` — the `stats.embeddings` field shows the count (0 means no embeddings). **Running analyze without `--embeddings` will delete any previously generated embeddings.**
> Claude Code users: A PostToolUse hook handles this automatically after `git commit` and `git merge`.
## CLI
| Task | Read this skill file |
|------|---------------------|
| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` |
| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` |
| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` |
| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` |
| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` |
| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` |
<!-- gitnexus:end -->

134
docs/superpowers/specs/2026-04-15-mission-system-redesign.md

@ -0,0 +1,134 @@
# 任务系统改版设计 - 收集与狩猎任务
**日期**: 2026-04-15
**状态**: 已批准
## 概述
将每日任务从"挂机等待完成"改为"主动收集/狩猎完成"模式,收集任务收集指定数量物品完成,狩猎任务狩猎指定数量怪物完成。
## 后端改动
### 1. DailyMissionDto 新增字段
```csharp
public class DailyMissionDto
{
// 现有字段...
public MissionType MissionType { get; set; } // 任务类型:收集/狩猎
public MissionDifficulty Difficulty { get; set; } // 难度
public List<MissionProgressDto> Progresses { get; set; } // 任务目标列表
public int CurrentProgress { get; set; } // 当前完成进度
public int TargetProgress { get; set; } // 目标进度
}
public class MissionProgressDto
{
public int MissionProgressId { get; set; }
public ProgressTargetType TargetType { get; set; }
public int? TargetItemId { get; set; }
public string? TargetItemName { get; set; }
public int TargetCount { get; set; }
public int CurrentCount { get; set; }
}
```
### 2. 任务进度更新API
**API**: `POST /api/god/mission/{missionId}/progress`
**请求体**:
```json
{
"progressType": "CollectItem" | "KillMonster",
"itemId": 1, // 可选,收集物品时需要
"monsterId": 1, // 可选,狩猎怪物时需要
"count": 1
}
```
**逻辑**:
- 检查角色是否有进行中的任务需要该类型进度
- 更新 CharacterMissionProgress 表
- 如果目标达成,自动标记进度完成
- 如果所有进度完成,标记任务完成(状态变为待领取)
### 3. 每日任务生成逻辑调整
现有逻辑已包含难度分配(Normal/Hard/Purgatory),只需确保:
- 生成任务时同时生成 MissionProgress 记录
- 收集任务的 TargetType = CollectItem
- 狩猎任务的 TargetType = KillMonster
---
## 前端改动
### 1. 页面结构
移除轮播图组件,改为卡片网格布局:
- 单列卡片列表,最大宽度 480px
- 卡片高度自适应
### 2. 卡片样式
**普通/困难难度**:
- 背景: `rgba(255,255,255,0.02)`
- 边框: 1px solid,颜色根据任务类型
- 圆角: 12px
**炼狱难度**:
- 使用 ElectricBorder 组件
- 边框颜色: #dc2626
- 带发光效果
### 3. 颜色方案
| 任务类型 | 难度 | 边框颜色 |
|---------|------|---------|
| 收集任务 | 普通 | #22c55e (绿色) |
| 收集任务 | 困难 | #16a34a (深绿) |
| 收集任务 | 炼狱 | ElectricBorder #15803d |
| 狩猎任务 | 普通 | #ef4444 (红色) |
| 狩猎任务 | 困难 | #f97316 (橙色) |
| 狩猎任务 | 炼狱 | ElectricBorder #dc2626 |
### 4. 卡片内容
```
┌─────────────────────────────────────┐
│ [图标] 任务名称 [难度标签] │
│ 任务描述... │
│ ────────────────────────────────── │
│ 目标: 收集 5/10 灵草 │
│ ────────────────────────────────── │
│ 奖励: 💰100 ✨50 │
│ ────────────────────────────────── │
│ [接取] / [进行中] / [领取] │
└─────────────────────────────────────┘
```
### 5. 图标
- 收集任务: 用户提供的 SVG 图标
- 狩猎任务: 按难度区分
- 普通: 绿色怪物图标
- 困难: 橙色怪物图标
- 炼狱: 红色怪物图标(带发光)
### 6. 状态按钮
- 待接取: "接取" 按钮
- 进行中: "进行中" 按钮(禁用状态)
- 待领取: "领取" 按钮
- 已领取: "已完成" 按钮(禁用状态)
---
## 实施顺序
1. 后端: 修改 DailyMissionDto,添加新字段
2. 后端: 添加任务进度更新 API
3. 后端: 调整每日任务生成逻辑,关联 MissionProgress
4. 前端: 更新 API 类型定义
5. 前端: 重写 DailyMissionView,移除轮播图,使用卡片布局
6. 前端: 添加 ElectricBorder 应用于炼狱难度卡片
Loading…
Cancel
Save