fix: 优化体验
All checks were successful
构建并部署前端到生产环境 / build-and-deploy (push) Successful in 1m37s

This commit is contained in:
sexygoat
2026-05-09 16:14:06 +08:00
parent c798cdba7f
commit 3f997063f4
27 changed files with 1191 additions and 62 deletions

456
openspec/AGENTS.md Normal file
View File

@@ -0,0 +1,456 @@
# OpenSpec Instructions
Instructions for AI coding assistants using OpenSpec for spec-driven development.
## TL;DR Quick Checklist
- Search existing work: `openspec spec list --long`, `openspec list` (use `rg` only for full-text search)
- Decide scope: new capability vs modify existing capability
- Pick a unique `change-id`: kebab-case, verb-led (`add-`, `update-`, `remove-`, `refactor-`)
- Scaffold: `proposal.md`, `tasks.md`, `design.md` (only if needed), and delta specs per affected capability
- Write deltas: use `## ADDED|MODIFIED|REMOVED|RENAMED Requirements`; include at least one `#### Scenario:` per requirement
- Validate: `openspec validate [change-id] --strict` and fix issues
- Request approval: Do not start implementation until proposal is approved
## Three-Stage Workflow
### Stage 1: Creating Changes
Create proposal when you need to:
- Add features or functionality
- Make breaking changes (API, schema)
- Change architecture or patterns
- Optimize performance (changes behavior)
- Update security patterns
Triggers (examples):
- "Help me create a change proposal"
- "Help me plan a change"
- "Help me create a proposal"
- "I want to create a spec proposal"
- "I want to create a spec"
Loose matching guidance:
- Contains one of: `proposal`, `change`, `spec`
- With one of: `create`, `plan`, `make`, `start`, `help`
Skip proposal for:
- Bug fixes (restore intended behavior)
- Typos, formatting, comments
- Dependency updates (non-breaking)
- Configuration changes
- Tests for existing behavior
**Workflow**
1. Review `openspec/project.md`, `openspec list`, and `openspec list --specs` to understand current context.
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, optional `design.md`, and spec deltas under `openspec/changes/<id>/`.
3. Draft spec deltas using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement.
4. Run `openspec validate <id> --strict` and resolve any issues before sharing the proposal.
### Stage 2: Implementing Changes
Track these steps as TODOs and complete them one by one.
1. **Read proposal.md** - Understand what's being built
2. **Read design.md** (if exists) - Review technical decisions
3. **Read tasks.md** - Get implementation checklist
4. **Implement tasks sequentially** - Complete in order
5. **Confirm completion** - Ensure every item in `tasks.md` is finished before updating statuses
6. **Update checklist** - After all work is done, set every task to `- [x]` so the list reflects reality
7. **Approval gate** - Do not start implementation until the proposal is reviewed and approved
### Stage 3: Archiving Changes
After deployment, create separate PR to:
- Move `changes/[name]/``changes/archive/YYYY-MM-DD-[name]/`
- Update `specs/` if capabilities changed
- Use `openspec archive <change-id> --skip-specs --yes` for tooling-only changes (always pass the change ID explicitly)
- Run `openspec validate --strict` to confirm the archived change passes checks
## Before Any Task
**Context Checklist:**
- [ ] Read relevant specs in `specs/[capability]/spec.md`
- [ ] Check pending changes in `changes/` for conflicts
- [ ] Read `openspec/project.md` for conventions
- [ ] Run `openspec list` to see active changes
- [ ] Run `openspec list --specs` to see existing capabilities
**Before Creating Specs:**
- Always check if capability already exists
- Prefer modifying existing specs over creating duplicates
- Use `openspec show [spec]` to review current state
- If request is ambiguous, ask 12 clarifying questions before scaffolding
### Search Guidance
- Enumerate specs: `openspec spec list --long` (or `--json` for scripts)
- Enumerate changes: `openspec list` (or `openspec change list --json` - deprecated but available)
- Show details:
- Spec: `openspec show <spec-id> --type spec` (use `--json` for filters)
- Change: `openspec show <change-id> --json --deltas-only`
- Full-text search (use ripgrep): `rg -n "Requirement:|Scenario:" openspec/specs`
## Quick Start
### CLI Commands
```bash
# Essential commands
openspec list # List active changes
openspec list --specs # List specifications
openspec show [item] # Display change or spec
openspec validate [item] # Validate changes or specs
openspec archive <change-id> [--yes|-y] # Archive after deployment (add --yes for non-interactive runs)
# Project management
openspec init [path] # Initialize OpenSpec
openspec update [path] # Update instruction files
# Interactive mode
openspec show # Prompts for selection
openspec validate # Bulk validation mode
# Debugging
openspec show [change] --json --deltas-only
openspec validate [change] --strict
```
### Command Flags
- `--json` - Machine-readable output
- `--type change|spec` - Disambiguate items
- `--strict` - Comprehensive validation
- `--no-interactive` - Disable prompts
- `--skip-specs` - Archive without spec updates
- `--yes`/`-y` - Skip confirmation prompts (non-interactive archive)
## Directory Structure
```
openspec/
├── project.md # Project conventions
├── specs/ # Current truth - what IS built
│ └── [capability]/ # Single focused capability
│ ├── spec.md # Requirements and scenarios
│ └── design.md # Technical patterns
├── changes/ # Proposals - what SHOULD change
│ ├── [change-name]/
│ │ ├── proposal.md # Why, what, impact
│ │ ├── tasks.md # Implementation checklist
│ │ ├── design.md # Technical decisions (optional; see criteria)
│ │ └── specs/ # Delta changes
│ │ └── [capability]/
│ │ └── spec.md # ADDED/MODIFIED/REMOVED
│ └── archive/ # Completed changes
```
## Creating Change Proposals
### Decision Tree
```
New request?
├─ Bug fix restoring spec behavior? → Fix directly
├─ Typo/format/comment? → Fix directly
├─ New feature/capability? → Create proposal
├─ Breaking change? → Create proposal
├─ Architecture change? → Create proposal
└─ Unclear? → Create proposal (safer)
```
### Proposal Structure
1. **Create directory:** `changes/[change-id]/` (kebab-case, verb-led, unique)
2. **Write proposal.md:**
```markdown
# Change: [Brief description of change]
## Why
[1-2 sentences on problem/opportunity]
## What Changes
- [Bullet list of changes]
- [Mark breaking changes with **BREAKING**]
## Impact
- Affected specs: [list capabilities]
- Affected code: [key files/systems]
```
3. **Create spec deltas:** `specs/[capability]/spec.md`
```markdown
## ADDED Requirements
### Requirement: New Feature
The system SHALL provide...
#### Scenario: Success case
- **WHEN** user performs action
- **THEN** expected result
## MODIFIED Requirements
### Requirement: Existing Feature
[Complete modified requirement]
## REMOVED Requirements
### Requirement: Old Feature
**Reason**: [Why removing]
**Migration**: [How to handle]
```
If multiple capabilities are affected, create multiple delta files under `changes/[change-id]/specs/<capability>/spec.md`—one per capability.
4. **Create tasks.md:**
```markdown
## 1. Implementation
- [ ] 1.1 Create database schema
- [ ] 1.2 Implement API endpoint
- [ ] 1.3 Add frontend component
- [ ] 1.4 Write tests
```
5. **Create design.md when needed:**
Create `design.md` if any of the following apply; otherwise omit it:
- Cross-cutting change (multiple services/modules) or a new architectural pattern
- New external dependency or significant data model changes
- Security, performance, or migration complexity
- Ambiguity that benefits from technical decisions before coding
Minimal `design.md` skeleton:
```markdown
## Context
[Background, constraints, stakeholders]
## Goals / Non-Goals
- Goals: [...]
- Non-Goals: [...]
## Decisions
- Decision: [What and why]
- Alternatives considered: [Options + rationale]
## Risks / Trade-offs
- [Risk] → Mitigation
## Migration Plan
[Steps, rollback]
## Open Questions
- [...]
```
## Spec File Format
### Critical: Scenario Formatting
**CORRECT** (use #### headers):
```markdown
#### Scenario: User login success
- **WHEN** valid credentials provided
- **THEN** return JWT token
```
**WRONG** (don't use bullets or bold):
```markdown
- **Scenario: User login** ❌
**Scenario**: User login ❌
### Scenario: User login ❌
```
Every requirement MUST have at least one scenario.
### Requirement Wording
- Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)
### Delta Operations
- `## ADDED Requirements` - New capabilities
- `## MODIFIED Requirements` - Changed behavior
- `## REMOVED Requirements` - Deprecated features
- `## RENAMED Requirements` - Name changes
Headers matched with `trim(header)` - whitespace ignored.
#### When to use ADDED vs MODIFIED
- ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
- MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
- RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.
Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you arent explicitly changing the existing requirement, add a new requirement under ADDED instead.
Authoring a MODIFIED requirement correctly:
1) Locate the existing requirement in `openspec/specs/<capability>/spec.md`.
2) Copy the entire requirement block (from `### Requirement: ...` through its scenarios).
3) Paste it under `## MODIFIED Requirements` and edit to reflect the new behavior.
4) Ensure the header text matches exactly (whitespace-insensitive) and keep at least one `#### Scenario:`.
Example for RENAMED:
```markdown
## RENAMED Requirements
- FROM: `### Requirement: Login`
- TO: `### Requirement: User Authentication`
```
## Troubleshooting
### Common Errors
**"Change must have at least one delta"**
- Check `changes/[name]/specs/` exists with .md files
- Verify files have operation prefixes (## ADDED Requirements)
**"Requirement must have at least one scenario"**
- Check scenarios use `#### Scenario:` format (4 hashtags)
- Don't use bullet points or bold for scenario headers
**Silent scenario parsing failures**
- Exact format required: `#### Scenario: Name`
- Debug with: `openspec show [change] --json --deltas-only`
### Validation Tips
```bash
# Always use strict mode for comprehensive checks
openspec validate [change] --strict
# Debug delta parsing
openspec show [change] --json | jq '.deltas'
# Check specific requirement
openspec show [spec] --json -r 1
```
## Happy Path Script
```bash
# 1) Explore current state
openspec spec list --long
openspec list
# Optional full-text search:
# rg -n "Requirement:|Scenario:" openspec/specs
# rg -n "^#|Requirement:" openspec/changes
# 2) Choose change id and scaffold
CHANGE=add-two-factor-auth
mkdir -p openspec/changes/$CHANGE/{specs/auth}
printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md
printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md
# 3) Add deltas (example)
cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'
## ADDED Requirements
### Requirement: Two-Factor Authentication
Users MUST provide a second factor during login.
#### Scenario: OTP required
- **WHEN** valid credentials are provided
- **THEN** an OTP challenge is required
EOF
# 4) Validate
openspec validate $CHANGE --strict
```
## Multi-Capability Example
```
openspec/changes/add-2fa-notify/
├── proposal.md
├── tasks.md
└── specs/
├── auth/
│ └── spec.md # ADDED: Two-Factor Authentication
└── notifications/
└── spec.md # ADDED: OTP email notification
```
auth/spec.md
```markdown
## ADDED Requirements
### Requirement: Two-Factor Authentication
...
```
notifications/spec.md
```markdown
## ADDED Requirements
### Requirement: OTP Email Notification
...
```
## Best Practices
### Simplicity First
- Default to <100 lines of new code
- Single-file implementations until proven insufficient
- Avoid frameworks without clear justification
- Choose boring, proven patterns
### Complexity Triggers
Only add complexity with:
- Performance data showing current solution too slow
- Concrete scale requirements (>1000 users, >100MB data)
- Multiple proven use cases requiring abstraction
### Clear References
- Use `file.ts:42` format for code locations
- Reference specs as `specs/auth/spec.md`
- Link related changes and PRs
### Capability Naming
- Use verb-noun: `user-auth`, `payment-capture`
- Single purpose per capability
- 10-minute understandability rule
- Split if description needs "AND"
### Change ID Naming
- Use kebab-case, short and descriptive: `add-two-factor-auth`
- Prefer verb-led prefixes: `add-`, `update-`, `remove-`, `refactor-`
- Ensure uniqueness; if taken, append `-2`, `-3`, etc.
## Tool Selection Guide
| Task | Tool | Why |
|------|------|-----|
| Find files by pattern | Glob | Fast pattern matching |
| Search code content | Grep | Optimized regex search |
| Read specific files | Read | Direct file access |
| Explore unknown scope | Task | Multi-step investigation |
## Error Recovery
### Change Conflicts
1. Run `openspec list` to see active changes
2. Check for overlapping specs
3. Coordinate with change owners
4. Consider combining proposals
### Validation Failures
1. Run with `--strict` flag
2. Check JSON output for details
3. Verify spec file format
4. Ensure scenarios properly formatted
### Missing Context
1. Read project.md first
2. Check related specs
3. Review recent archives
4. Ask for clarification
## Quick Reference
### Stage Indicators
- `changes/` - Proposed, not yet built
- `specs/` - Built and deployed
- `archive/` - Completed changes
### File Purposes
- `proposal.md` - Why and what
- `tasks.md` - Implementation steps
- `design.md` - Technical decisions
- `spec.md` - Requirements and behavior
### CLI Essentials
```bash
openspec list # What's in progress?
openspec show [item] # View details
openspec validate --strict # Is it correct?
openspec archive <change-id> [--yes|-y] # Mark complete (add --yes for automation)
```
Remember: Specs are truth. Changes are proposals. Keep them in sync.

View File

@@ -0,0 +1,26 @@
## Why
The wallet recharge confirmation, package payment confirmation, order list immediate payment, and wallet recharge order immediate payment flows can be triggered repeatedly when users tap quickly or when the page is slow to respond. This can cause duplicate order creation, duplicate payment preparation, repeated payment invocation, and inconsistent UI state.
## What Changes
- Add a front-end submit guard for the wallet recharge confirmation flow in `pages/my-wallet/my-wallet.vue`
- Add a front-end submit guard for the package payment confirmation flow in `pages/package-order/package-order.vue`
- Add a front-end submit guard for the order list immediate payment flow in `pages/order-list/order-list.vue`
- Add a front-end submit guard for the wallet recharge order immediate payment flow in `pages/my-wallet/my-wallet.vue`
- Standardize button behavior during submission so repeated taps are ignored until the current flow ends
- Require submit state recovery for success, failure, cancel, validation failure, list refresh, and modal re-entry paths
## Capabilities
### New Capabilities
- `payment-submit-guard`: Prevent duplicate submission in recharge and payment entry points across wallet, package order, and order list flows
### Modified Capabilities
## Impact
- Affected code: `pages/my-wallet/my-wallet.vue`, `pages/package-order/package-order.vue`, `pages/order-list/order-list.vue`
- Affected UI flows: wallet recharge modal, wallet recharge order list immediate payment, package payment method modal, order list immediate payment
- No backend API changes
- No payment business rule changes

View File

@@ -0,0 +1,81 @@
## ADDED Requirements
### Requirement: Wallet recharge confirmation SHALL prevent duplicate submission
The system SHALL prevent repeated taps on the wallet recharge confirmation button from starting more than one recharge submission flow at the same time.
#### Scenario: User taps confirm recharge repeatedly during submission
- **WHEN** the user taps the wallet recharge confirmation button multiple times before the current `confirmRecharge` flow completes
- **THEN** the system SHALL execute only the first submission flow
- **AND** the system SHALL ignore subsequent taps until the current flow ends
#### Scenario: Wallet recharge confirmation enters submitting state
- **WHEN** the first valid wallet recharge confirmation tap is accepted
- **THEN** the system SHALL mark the wallet recharge confirmation flow as submitting immediately
- **AND** the system SHALL present the confirmation button as non-repeatable during that state
#### Scenario: Wallet recharge confirmation recovers after terminal outcome
- **WHEN** the wallet recharge flow ends because of success, failure, cancellation, local validation failure, or modal re-entry
- **THEN** the system SHALL clear the submitting state
- **AND** the user SHALL be able to start a new recharge attempt
### Requirement: Package payment confirmation SHALL prevent duplicate submission
The system SHALL prevent repeated taps on the package payment confirmation button from starting more than one package payment submission flow at the same time.
#### Scenario: User taps confirm payment repeatedly during submission
- **WHEN** the user taps the package payment confirmation button multiple times before the current `confirmPay` flow completes
- **THEN** the system SHALL execute only the first submission flow
- **AND** the system SHALL ignore subsequent taps until the current flow ends
#### Scenario: Package payment confirmation enters submitting state
- **WHEN** the first valid package payment confirmation tap is accepted
- **THEN** the system SHALL mark the package payment confirmation flow as submitting immediately
- **AND** the system SHALL present the confirmation button as non-repeatable during that state
#### Scenario: Package payment confirmation recovers after terminal outcome
- **WHEN** the package payment flow ends because of success, failure, cancellation, validation failure, strong recharge prompt completion, or modal re-entry
- **THEN** the system SHALL clear the submitting state
- **AND** the user SHALL be able to start a new payment attempt
### Requirement: Order list immediate payment SHALL prevent duplicate submission
The system SHALL prevent repeated taps on an order list item's immediate payment button from starting more than one payment submission flow for the current order at the same time.
#### Scenario: User taps order list immediate payment repeatedly during submission
- **WHEN** the user taps the immediate payment button multiple times before the current `handleOrderPayment` flow completes
- **THEN** the system SHALL execute only the first submission flow
- **AND** the system SHALL ignore subsequent taps until the current flow ends
#### Scenario: Order list immediate payment enters submitting state
- **WHEN** the first valid order list immediate payment tap is accepted
- **THEN** the system SHALL mark the current order payment flow as submitting immediately
- **AND** the system SHALL present the triggered immediate payment button as non-repeatable during that state
#### Scenario: Order list immediate payment recovers after terminal outcome
- **WHEN** the order list payment flow ends because of success, failure, cancellation, list refresh, or page re-entry
- **THEN** the system SHALL clear the submitting state
- **AND** the user SHALL be able to start a new payment attempt if the order remains payable
### Requirement: Wallet recharge order immediate payment SHALL prevent duplicate submission
The system SHALL prevent repeated taps on a wallet recharge order item's immediate payment button from starting more than one recharge order payment flow for the current recharge order at the same time.
#### Scenario: User taps wallet recharge order immediate payment repeatedly during submission
- **WHEN** the user taps the immediate payment button multiple times before the current `handleRechargePayment` flow completes
- **THEN** the system SHALL execute only the first submission flow
- **AND** the system SHALL ignore subsequent taps until the current flow ends
#### Scenario: Wallet recharge order immediate payment enters submitting state
- **WHEN** the first valid wallet recharge order immediate payment tap is accepted
- **THEN** the system SHALL mark the current recharge order payment flow as submitting immediately
- **AND** the system SHALL present the triggered immediate payment button as non-repeatable during that state
#### Scenario: Wallet recharge order immediate payment recovers after terminal outcome
- **WHEN** the wallet recharge order payment flow ends because of success, failure, cancellation, list refresh, or page re-entry
- **THEN** the system SHALL clear the submitting state
- **AND** the user SHALL be able to start a new payment attempt if the recharge order remains payable
### Requirement: Submit guards SHALL NOT change existing payment business rules
The system SHALL preserve the current recharge validation, recharge order payment, order list payment, order creation, strong recharge decision, wallet payment, WeChat payment, toast, modal, and balance refresh behavior while adding submit guards.
#### Scenario: Existing business validation remains unchanged
- **WHEN** the user submits with an invalid recharge amount or reaches an existing payment business rule branch
- **THEN** the system SHALL keep the current validation and messaging behavior
- **AND** the duplicate submission guard SHALL only affect repeated-trigger protection

View File

@@ -0,0 +1,31 @@
## 1. Wallet Recharge Confirmation Submit Guard
- [x] 1.1 Add a dedicated submitting state for the wallet recharge confirmation flow
- [x] 1.2 Ignore repeated taps while `confirmRecharge` is already running
- [x] 1.3 Bind the confirmation button state to the submitting state and restore it on every exit path
## 2. Package Payment Confirmation Submit Guard
- [x] 2.1 Add a dedicated submitting state for the package payment confirmation flow
- [x] 2.2 Ignore repeated taps while `confirmPay` is already running
- [x] 2.3 Bind the confirmation button state to the submitting state and restore it on every exit path
## 3. Order List Immediate Payment Submit Guard
- [x] 3.1 Add a dedicated submitting state for order list immediate payment
- [x] 3.2 Ignore repeated taps while `handleOrderPayment` is already running for the current payment flow
- [x] 3.3 Bind the order list immediate payment button state to the submitting state and restore it on every exit path
## 4. Wallet Recharge Order Immediate Payment Submit Guard
- [x] 4.1 Add a dedicated submitting state for wallet recharge order immediate payment
- [x] 4.2 Ignore repeated taps while `handleRechargePayment` is already running for the current payment flow
- [x] 4.3 Bind the recharge order immediate payment button state to the submitting state and restore it on every exit path
## 5. Regression Verification
- [x] 5.1 Verify repeated taps only trigger one effective submit in the wallet recharge modal
- [x] 5.2 Verify repeated taps only trigger one effective submit in the package payment modal
- [x] 5.3 Verify repeated taps only trigger one effective submit in the order list immediate payment flow
- [x] 5.4 Verify repeated taps only trigger one effective submit in the wallet recharge order immediate payment flow
- [x] 5.5 Verify users can retry after validation failure, payment cancel, payment failure, list refresh, and modal reopen

View File

@@ -0,0 +1,25 @@
## Why
The current login flow decides whether to send the user to the bind-phone page based on `loginData.need_bind_phone`. This makes the phone-binding gate happen only at login time, which is fragile because the actual requirement belongs to entering the homepage, not only to completing login. As a result, the app can enter an inconsistent state when the user reaches `index` through other paths or when the latest bind requirement should be re-evaluated on homepage entry.
## What Changes
- Move the mandatory phone-binding gate out of `pages/login/login.vue`
- Make login success redirect to `pages/index/index` consistently
- Require `pages/index/index.vue` to check whether the current account still needs phone binding every time the page is entered
- Redirect to `pages/bind/bind` from `index` when binding is required, instead of deciding that only during login
- Keep the bind-phone page as the place where the user completes the required binding flow
## Capabilities
### New Capabilities
- `index-phone-bind-gate`: Define homepage-entry binding rules so phone binding is enforced from `index` instead of only from login
### Modified Capabilities
## Impact
- Affected code: `pages/login/login.vue`, `pages/index/index.vue`, `pages/bind/bind.vue`
- Affected flow: post-login routing, homepage entry, mandatory bind-phone redirect
- No backend API changes
- No login credential or bind-phone API contract changes

View File

@@ -0,0 +1,44 @@
## ADDED Requirements
### Requirement: Login success SHALL NOT own the bind-phone routing decision
The system SHALL stop deciding mandatory bind-phone routing inside the login success handler and SHALL route successful login into the homepage entry flow instead.
#### Scenario: Login succeeds for a user who may need binding
- **WHEN** the user completes login successfully
- **THEN** the system SHALL route the user to `pages/index/index`
- **AND** the system SHALL NOT branch directly from the login page to the bind-phone page based only on login-time routing logic
### Requirement: Index entry SHALL enforce the bind-phone gate
The system SHALL determine whether phone binding is required whenever the homepage is entered and SHALL redirect to the bind-phone page if the current account is not yet bound.
#### Scenario: User enters index and binding is required
- **WHEN** the user enters `pages/index/index`
- **AND** the latest account state indicates the phone is not yet bound
- **THEN** the system SHALL redirect the user from `index` to `pages/bind/bind`
#### Scenario: User enters index and binding is not required
- **WHEN** the user enters `pages/index/index`
- **AND** the latest account state indicates the phone is already bound
- **THEN** the system SHALL keep the user on the homepage
#### Scenario: User re-enters index later without binding
- **WHEN** the user enters `pages/index/index` again through a later navigation path
- **AND** the latest account state still indicates the phone is not yet bound
- **THEN** the system SHALL re-apply the bind-phone redirect
- **AND** the redirect SHALL NOT depend on whether the user just came from the login page
### Requirement: Bind completion SHALL remain compatible with homepage entry
The system SHALL preserve the existing bind-phone completion destination to the homepage while allowing the homepage gate to be the source of truth for whether binding is still required.
#### Scenario: User completes binding and returns to index
- **WHEN** the user completes phone binding successfully
- **THEN** the system SHALL return the user to `pages/index/index`
- **AND** entering `index` afterward SHALL no longer redirect if the account is now bound
### Requirement: Index phone-bind gate SHALL NOT change login or bind API contracts
The system SHALL preserve the existing login API, bind-phone API, token handling, and account retrieval contracts while changing only the routing responsibility.
#### Scenario: Routing responsibility changes without API change
- **WHEN** the new homepage-entry gate is applied
- **THEN** the system SHALL change only where the bind requirement is evaluated for routing
- **AND** the system SHALL NOT require backend API contract changes

View File

@@ -0,0 +1,23 @@
## 1. Login Redirect Responsibility
- [x] 1.1 Remove the bind-phone branching decision from the login success handler
- [x] 1.2 Make login success enter `pages/index/index` consistently
## 2. Index Entry Binding Gate
- [x] 2.1 Add a homepage-entry binding check in `pages/index/index.vue`
- [x] 2.2 Re-evaluate whether binding is required every time `index` is entered, not only after login
- [x] 2.3 Redirect from `index` to the bind-phone page when binding is still required
## 3. Bind Flow Compatibility
- [x] 3.1 Keep the bind-phone completion flow returning to `index`
- [x] 3.2 Ensure users who are already bound are not redirected away from `index`
- [x] 3.3 Ensure users who return to `index` without binding are checked again and redirected again if binding is still required
## 4. Regression Verification
- [x] 4.1 Verify login success always routes into `index`
- [x] 4.2 Verify entering `index` without a bound phone redirects to the bind page
- [x] 4.3 Verify entering `index` with a bound phone stays on the homepage
- [x] 4.4 Verify re-entering `index` through later navigation still rechecks binding state

View File

@@ -0,0 +1,46 @@
## Context
The project moved mandatory phone-binding enforcement to homepage entry, and then added a one-time homepage bypass after bind success to avoid an immediate redirect loop. A later draft proposed automatically re-running `POST /api/c/v1/auth/wechat-login` after bind success. The required direction is now simpler than both of those approaches: after mandatory bind success, route the user back to the login page, explain that they need to log in again, preserve the identifier they already entered, and let them manually restart login.
The login page already has behavior that can trigger login automatically from some restored inputs or URL parameters. The new flow therefore needs to preserve the identifier for convenience without accidentally auto-submitting login on the user's behalf.
## Goals / Non-Goals
- Goals:
- Return mandatory bind-success users to the login page
- Show a clear re-login prompt after bind success
- Preserve the previously entered identifier in the login input
- Require the user to manually tap login again
- Non-Goals:
- Do not add a new backend endpoint
- Do not auto-run `POST /api/c/v1/auth/wechat-login` after bind success
- Do not change the ordinary bind flow that starts from homepage actions
## Decisions
- Decision: Mandatory bind completion SHALL route to `pages/login/login` instead of continuing directly to `pages/index/index`.
- Decision: The system SHALL show a one-time prompt that binding succeeded and the user must log in again.
- Decision: The previously entered identifier SHALL be preserved through the bind-success redirect and restored into the login input.
- Decision: Restoring the identifier SHALL NOT auto-submit login or auto-trigger the OAuth flow; the user must explicitly tap login.
## Alternatives Considered
- Keep the one-time homepage bypass: rejected because the post-bind continuation no longer needs to jump directly into the homepage.
- Automatically re-run `POST /api/c/v1/auth/wechat-login`: rejected because the requested flow is to require an explicit user-driven re-login.
- Pass the identifier through a login-page path that auto-starts login: rejected because the user explicitly wants the identifier preserved without automatic login.
## Risks / Trade-offs
- The client must distinguish between restoring an identifier for display and restoring one for automatic login initiation.
- The re-login prompt must be one-time or clearly scoped so it does not keep reappearing on unrelated later visits to the login page.
## Migration Plan
1. Remove the automatic post-bind wechat-login continuation plan from the active draft.
2. Route mandatory bind success back to `pages/login/login`.
3. Preserve the identifier so the login input remains prefilled.
4. Show the re-login prompt and require a manual login tap.
## Open Questions
- Which client-side storage path is the best fit for preserving the identifier while avoiding accidental auto-login behavior on the login page?

View File

@@ -0,0 +1,30 @@
# Change: Return to login for manual re-login after mandatory phone bind
## Why
The current mandatory bind-success continuation either relies on a homepage bypass workaround or on an automatic follow-up login flow. Both approaches make the post-bind path more fragile than necessary. The desired behavior is simpler: after successful mandatory phone binding, return the user to the login page, tell them they need to log in again, preserve the identifier they already entered, and let the user manually tap login.
## What Changes
- Return the user to `pages/login/login` after successful phone binding when the bind page was entered from the mandatory login gate
- Show a one-time prompt on the login page that phone binding succeeded and re-login is required
- Preserve the identifier the user already entered so the login input stays prefilled after returning
- Require the user to manually tap login again instead of auto-starting the login flow
- Keep the existing non-mandatory bind completion behavior unchanged
- Remove dependence on an automatic post-bind wechat-login recheck for this flow
- Preserve the current login and bind-phone API contracts without adding backend endpoints
## Capabilities
### New Capabilities
- `post-bind-manual-relogin`: Define the mandatory post-bind return-to-login and identifier-preservation flow
### Modified Capabilities
- `index-phone-bind-gate`: Allow mandatory bind completion from the login gate to return to login instead of homepage
## Impact
- Affected code: `pages/bind/bind.vue`, `pages/login/login.vue`, `pages/index/index.vue`
- Affected flow: mandatory phone binding, post-bind routing, login input restoration, manual re-login
- No backend API changes
- No login or bind-phone response schema changes

View File

@@ -0,0 +1,15 @@
## MODIFIED Requirements
### Requirement: Bind completion SHALL remain compatible with homepage entry
The system SHALL keep ordinary bind-phone completion compatible with homepage entry while allowing mandatory bind-phone completion from the login gate to return to the login page for a manual re-login.
#### Scenario: User completes ordinary binding and returns to index
- **WHEN** the user completes phone binding successfully after entering the bind page from a later homepage action
- **THEN** the system SHALL return the user to `pages/index/index`
- **AND** entering `index` afterward SHALL no longer redirect if the account is now bound
#### Scenario: User completes mandatory binding and returns to login
- **WHEN** the user completes phone binding successfully after entering the bind page from the mandatory login gate
- **THEN** the system SHALL return the user to `pages/login/login`
- **AND** the system SHALL preserve the previously entered identifier for the login input
- **AND** the user SHALL manually trigger the next login attempt before the homepage-entry gate is evaluated again

View File

@@ -0,0 +1,37 @@
## ADDED Requirements
### Requirement: Mandatory bind completion SHALL return the user to login for manual re-login
The system SHALL return the user to `pages/login/login` after successful phone binding when the bind page was entered from the mandatory login gate, and SHALL require an explicit user-driven re-login before continuing.
#### Scenario: Mandatory bind succeeds and requires manual re-login
- **WHEN** the user enters `pages/bind/bind` from the mandatory bind-phone gate
- **AND** the user completes phone binding successfully
- **THEN** the system SHALL route the user to `pages/login/login` instead of routing directly to `pages/index/index`
- **AND** the system SHALL show a prompt that binding succeeded and re-login is required
- **AND** the system SHALL wait for the user to explicitly trigger login again
### Requirement: Login input SHALL preserve the prior identifier without auto-submitting
The system SHALL preserve the identifier that the user previously entered before the mandatory bind flow and SHALL restore it into the login input without automatically starting login.
#### Scenario: Login page restores identifier after mandatory bind success
- **WHEN** the user is returned to `pages/login/login` after successful mandatory phone binding
- **THEN** the login input SHALL remain populated with the identifier that was entered before the bind flow
- **AND** the system SHALL NOT auto-submit login or auto-trigger the OAuth flow only because the identifier was restored
- **AND** the user SHALL manually tap the login action to continue
### Requirement: Mandatory post-bind return SHALL avoid automatic recheck dependencies
The system SHALL avoid depending on an automatic post-bind wechat-login recheck for the mandatory bind-success continuation flow.
#### Scenario: Mandatory bind success does not auto-call wechat-login
- **WHEN** the user completes phone binding successfully from the mandatory login gate
- **THEN** the system SHALL NOT automatically call `POST /api/c/v1/auth/wechat-login` as the immediate continuation step
- **AND** the post-bind continuation SHALL depend on the user re-entering the login flow manually
### Requirement: Non-mandatory bind completion SHALL keep existing behavior
The system SHALL keep the existing non-mandatory bind completion behavior when the bind page was entered from a later homepage action rather than from the mandatory login gate.
#### Scenario: Ordinary bind completion remains unchanged
- **WHEN** the user enters `pages/bind/bind` from a later homepage action rather than the mandatory login gate
- **AND** the user completes phone binding successfully
- **THEN** the system SHALL keep the current non-mandatory bind completion behavior
- **AND** the system SHALL NOT force the user back to `pages/login/login` for that ordinary bind flow

View File

@@ -0,0 +1,25 @@
## 1. Post-Bind Manual Re-Login
- [x] 1.1 Route mandatory bind success to `pages/login/login` instead of continuing directly to `pages/index/index`
- [x] 1.2 Show a one-time prompt that the user needs to log in again after successful binding
- [x] 1.3 Preserve the previously entered identifier so the login input stays prefilled after returning
- [x] 1.4 Ensure the restored identifier does not auto-trigger login and the user must manually tap login
## 2. Flow Compatibility
- [x] 2.1 Keep the existing non-mandatory bind completion behavior unchanged
- [x] 2.2 Remove dependence on automatic post-bind wechat-login continuation
- [x] 2.3 Keep the normal homepage bind gate behavior for later homepage entries
- [x] 2.4 Remove dependence on a one-time homepage bypass for mandatory bind success
## 3. API Contract Preservation
- [x] 3.1 Keep using the existing login and bind-phone API contracts
- [x] 3.2 Avoid adding a backend endpoint or changing current response schemas
## 4. Regression Verification
- [x] 4.1 Verify mandatory bind success returns to the login page with the identifier still visible
- [x] 4.2 Verify the login page shows the re-login prompt after bind success
- [x] 4.3 Verify login does not auto-start until the user clicks login
- [x] 4.4 Verify ordinary bind entry from homepage actions still follows the current completion path

View File

@@ -0,0 +1,24 @@
## Why
The homepage wallet entry currently displays the raw wallet balance value returned by the backend, which is cent-based. This causes incorrect user-facing values such as showing `100` instead of `1`. In addition, the wallet recharge order list always renders the auto purchase row, which can show misleading fallback text when the backend does not provide auto purchase data.
## What Changes
- Convert the homepage wallet entry balance from cents to yuan before rendering the value inside `钱包(...)`
- Keep the homepage wallet entry aligned with user-facing currency expectations instead of exposing the raw cent amount
- Render the recharge order `自动购包` field only when the recharge order includes auto purchase status data
- Preserve the current auto purchase status text mapping when the field exists, including existing compatibility values
## Capabilities
### New Capabilities
- `wallet-display-rules`: Define wallet-related UI display rules for homepage balance presentation and recharge order field visibility
### Modified Capabilities
## Impact
- Affected code: `components/FunctionCard.vue`, `pages/index/index.vue`, `pages/my-wallet/my-wallet.vue`
- Affected UI flows: homepage function menu wallet entry, wallet recharge order list
- No backend API changes
- No payment flow changes

View File

@@ -0,0 +1,42 @@
## ADDED Requirements
### Requirement: Homepage wallet entry SHALL display wallet balance in yuan
The system SHALL convert the backend wallet balance value from cents to yuan before rendering the balance inside the homepage wallet entry label.
#### Scenario: Cent-based balance is converted for homepage display
- **WHEN** the homepage wallet entry receives a wallet balance value of `100`
- **THEN** the system SHALL display the wallet entry label as `钱包 (1)` instead of showing the raw cent value
#### Scenario: Non-round cent amount is converted for homepage display
- **WHEN** the homepage wallet entry receives a cent-based wallet balance that is not a whole yuan amount
- **THEN** the system SHALL display the converted yuan value
- **AND** the system SHALL NOT display the raw cent integer
#### Scenario: Zero balance is displayed consistently
- **WHEN** the homepage wallet entry receives a wallet balance value of `0`
- **THEN** the system SHALL display `钱包 (0)`
### Requirement: Recharge order auto purchase row SHALL render only when data exists
The system SHALL render the `自动购包` row in the wallet recharge order list only when the recharge order includes auto purchase status data.
#### Scenario: Auto purchase data exists on a recharge order
- **WHEN** a recharge order includes `auto_purchase_status`
- **THEN** the system SHALL render the `自动购包` row
- **AND** the system SHALL display the status text mapped from that value
#### Scenario: Compatible disabled value still counts as existing data
- **WHEN** a recharge order includes `auto_purchase_status` with a value of `0` or `'0'`
- **THEN** the system SHALL render the `自动购包` row
- **AND** the system SHALL display the compatible disabled status text
#### Scenario: Auto purchase data is absent on a recharge order
- **WHEN** a recharge order does not include `auto_purchase_status`
- **THEN** the system SHALL NOT render the `自动购包` row
### Requirement: Wallet display rules SHALL NOT change API contracts or payment behavior
The system SHALL preserve the existing backend data contract, recharge order retrieval flow, payment actions, and wallet detail page amount handling while applying these display rules.
#### Scenario: Display-only adjustment does not alter business flow
- **WHEN** the homepage wallet balance or recharge order list is rendered with the new display rules
- **THEN** the system SHALL only change user-facing presentation
- **AND** the system SHALL NOT change payment processing or backend request behavior

View File

@@ -0,0 +1,18 @@
## 1. Homepage Wallet Balance Display
- [x] 1.1 Add a display rule for the homepage wallet entry that converts the backend cent amount to yuan before rendering
- [x] 1.2 Ensure converted values do not expose the raw cent amount in the `钱包(...)` label
- [x] 1.3 Preserve correct display for zero and non-integer yuan values
## 2. Recharge Order Auto Purchase Field Visibility
- [x] 2.1 Render the recharge order `自动购包` row only when the recharge order includes auto purchase status data
- [x] 2.2 Preserve the existing status text mapping when auto purchase status data exists, including compatible `0` and `1` values
- [x] 2.3 Hide the row entirely when auto purchase status data is absent
## 3. Regression Verification
- [x] 3.1 Verify a homepage wallet balance of `100` is displayed as `1` in the wallet entry
- [x] 3.2 Verify a non-round cent amount is displayed as its yuan value rather than the raw cent integer
- [x] 3.3 Verify recharge orders with `auto_purchase_status` render the `自动购包` row
- [x] 3.4 Verify recharge orders without `auto_purchase_status` do not render the `自动购包` row

31
openspec/project.md Normal file
View File

@@ -0,0 +1,31 @@
# Project Context
## Purpose
[Describe your project's purpose and goals]
## Tech Stack
- [List your primary technologies]
- [e.g., TypeScript, React, Node.js]
## Project Conventions
### Code Style
[Describe your code style preferences, formatting rules, and naming conventions]
### Architecture Patterns
[Document your architectural decisions and patterns]
### Testing Strategy
[Explain your testing approach and requirements]
### Git Workflow
[Describe your branching strategy and commit conventions]
## Domain Context
[Add domain-specific knowledge that AI assistants need to understand]
## Important Constraints
[List any technical, business, or regulatory constraints]
## External Dependencies
[Document key external services, APIs, or systems]