This commit is contained in:
456
openspec/AGENTS.md
Normal file
456
openspec/AGENTS.md
Normal 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 1–2 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 aren’t 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.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Change: Update agent asset list and detail display
|
||||
|
||||
## Why
|
||||
|
||||
The current agent-side asset experience exposes too much low-value information, hides some high-value state, and requires unnecessary search-type switching. The latest requests also require shop-based filtering, clearer detail presentation, explicit pagination, and a fixed top control area so search and filters remain available while the user browses long lists.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add IoT card device-binding status to the agent asset list
|
||||
- Add cascaded shop filtering for the agent IoT card and device lists
|
||||
- Remove the manual search-type selector and fix search semantics by active tab
|
||||
- Keep the search input and filter controls fixed at the top while the asset list scrolls underneath
|
||||
- Replace bottom-reached auto pagination with an explicit load-more button for both asset tabs
|
||||
- Simplify asset detail basic fields and strengthen bound-card status presentation
|
||||
- Remove `保护状态`
|
||||
- Remove `切卡模式`
|
||||
- Move the bound-card real-name status badge into the slot-title row
|
||||
- Remove low-value device realtime traffic items and move "last online" into the realtime block as `最后上线时间`
|
||||
- Make package effective-period text more prominent in asset detail package lists
|
||||
- Only active packages should show the effective-period line
|
||||
- Adjust the current active package header content
|
||||
- Remove the order number line below the package name
|
||||
- Show the active period there as `生效期:开始时间 - 到期时间`
|
||||
|
||||
## Impact
|
||||
|
||||
- Affected specs:
|
||||
- `agent-asset-list`
|
||||
- `agent-asset-detail`
|
||||
- Affected code:
|
||||
- `src/pages/agent-system/assets/index.vue`
|
||||
- `src/pages/agent-system/asset-search/index.vue`
|
||||
- `src/pages/agent-system/asset-detail/index.vue`
|
||||
- `src/api/assets.ts`
|
||||
@@ -0,0 +1,108 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Agent Asset Detail SHALL Remove Redundant Basic Fields
|
||||
|
||||
The agent asset detail experience SHALL remove fields that are no longer required from the basic information area.
|
||||
|
||||
#### Scenario: Viewing an IoT card detail
|
||||
|
||||
- **WHEN** the current asset is an IoT card
|
||||
- **THEN** the basic information section SHALL NOT show `批次号`
|
||||
|
||||
#### Scenario: Viewing a device detail
|
||||
|
||||
- **WHEN** the current asset is a device
|
||||
- **THEN** the basic information section SHALL NOT show `制造商`
|
||||
- **AND** the basic information section SHALL NOT show `批次号`
|
||||
- **AND** the basic information section SHALL NOT show `保护状态`
|
||||
- **AND** the basic information section SHALL NOT show `切卡模式`
|
||||
|
||||
### Requirement: Agent Asset Detail SHALL Emphasize Bound IoT Card Identity And Status
|
||||
|
||||
The agent device detail view SHALL make bound IoT card identity and real-name status easier to scan.
|
||||
|
||||
#### Scenario: Rendering a bound IoT card item
|
||||
|
||||
- **WHEN** a device detail contains a bound IoT card entry
|
||||
- **THEN** the label `电话` SHALL be renamed to `MSISDN`
|
||||
- **AND** the item SHALL display `carrier_name` as `运营商`
|
||||
- **AND** missing `msisdn` or `carrier_name` values SHALL render as `-`
|
||||
|
||||
#### Scenario: Rendering real-name status
|
||||
|
||||
- **WHEN** a bound IoT card has a `real_name_status`
|
||||
- **THEN** the UI SHALL render that status with stronger visual emphasis than ordinary low-contrast metadata text
|
||||
- **AND** the meaning of existing status values SHALL remain unchanged
|
||||
|
||||
#### Scenario: Rendering the bound-card header row
|
||||
|
||||
- **WHEN** a bound IoT card item is rendered in the device detail page
|
||||
- **THEN** the real-name status badge SHALL be placed in the same row as the slot title
|
||||
- **AND** the badge SHALL appear after the slot title text
|
||||
- **AND** the lower metadata area SHALL NOT render a second standalone real-name field for the same card
|
||||
|
||||
### Requirement: Agent Device Realtime Status SHALL Prioritize High-Value Realtime Information
|
||||
|
||||
The agent device detail realtime block SHALL remove low-value traffic rows and absorb the "last online" field as a realtime-oriented field.
|
||||
|
||||
#### Scenario: Rendering device realtime traffic statistics
|
||||
|
||||
- **WHEN** the device realtime block is shown
|
||||
- **THEN** it SHALL continue to show `今日用量`
|
||||
- **AND** it SHALL continue to show `限速`
|
||||
- **AND** it SHALL NOT show `下载流量`
|
||||
- **AND** it SHALL NOT show `上传流量`
|
||||
|
||||
#### Scenario: Rendering last online time
|
||||
|
||||
- **WHEN** a device detail page has a realtime section
|
||||
- **THEN** the page SHALL show `最后上线时间` inside the realtime section
|
||||
- **AND** it SHALL prefer `realtimeStatus.device_realtime.last_online_time`
|
||||
- **AND** it SHALL fall back to `deviceInfo.last_online_time` when the realtime value is absent
|
||||
|
||||
#### Scenario: Rendering the legacy time-information block
|
||||
|
||||
- **WHEN** the device detail page previously showed `创建时间`, `最后在线`, or `网关同步` in a separate time-information block
|
||||
- **THEN** that block SHALL no longer show `创建时间`
|
||||
- **AND** that block SHALL no longer show `最后在线`
|
||||
- **AND** that block SHALL no longer show `网关同步`
|
||||
|
||||
### Requirement: Agent Asset Detail Package List SHALL Emphasize Effective Period
|
||||
|
||||
The package list in agent asset detail SHALL make the effective period line visually prominent.
|
||||
|
||||
#### Scenario: Package has both start and end time
|
||||
|
||||
- **WHEN** a package list item has both `activated_at` and `expires_at`
|
||||
- **AND** the package is in active status
|
||||
- **THEN** the page SHALL render a dedicated effective-period line with the meaning `生效期:开始时间 至 结束时间`
|
||||
- **AND** that line SHALL have stronger visual prominence than the current weak auxiliary timestamp style
|
||||
|
||||
#### Scenario: Package is missing part of the effective period
|
||||
|
||||
- **WHEN** either `activated_at` or `expires_at` is missing
|
||||
- **AND** the package is in active status
|
||||
- **THEN** the effective-period line SHALL still be rendered
|
||||
- **AND** the missing value SHALL display as `-`
|
||||
|
||||
#### Scenario: Package is not in active status
|
||||
|
||||
- **WHEN** a package list item is not in active status
|
||||
- **THEN** the page SHALL NOT render the dedicated `生效期` line for that package
|
||||
|
||||
### Requirement: Agent Asset Detail Current Package SHALL Prioritize Effective Period Over Order Number
|
||||
|
||||
The current active package card in agent asset detail SHALL remove the order number from the package header area and use that space to surface the package active period.
|
||||
|
||||
#### Scenario: Rendering the current active package card
|
||||
|
||||
- **WHEN** the current active package card is rendered
|
||||
- **THEN** the package name SHALL remain visible
|
||||
- **AND** the order number line below the package name SHALL NOT be shown
|
||||
- **AND** the card SHALL show a labeled `生效期:开始时间 - 到期时间` line in that position instead
|
||||
|
||||
#### Scenario: Current package is missing part of the active period
|
||||
|
||||
- **WHEN** either the current package `activated_at` or `expires_at` is missing
|
||||
- **THEN** the labeled `生效期:开始时间 - 到期时间` line SHALL still be rendered
|
||||
- **AND** the missing value SHALL display as `-`
|
||||
@@ -0,0 +1,123 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Agent IoT Card List SHALL Surface Device Binding Status
|
||||
|
||||
The agent-side IoT card list SHALL derive a device-binding status from the `device_virtual_no` field returned by `GET /api/admin/iot-cards/standalone` and show that status in each IoT card list item.
|
||||
|
||||
#### Scenario: Card is not bound to a device
|
||||
|
||||
- **WHEN** an IoT card item has `device_virtual_no` equal to `null`, `undefined`, an empty string, or a whitespace-only string
|
||||
- **THEN** the list item SHALL show a status tag with `未绑定设备`
|
||||
- **AND** the UI SHALL NOT display a fabricated device identifier
|
||||
- **AND** the UI SHALL NOT prepend an extra `设备绑定` label before the tag
|
||||
|
||||
#### Scenario: Card is bound to a device
|
||||
|
||||
- **WHEN** an IoT card item has a non-empty `device_virtual_no`
|
||||
- **THEN** the list item SHALL show a status tag with `已绑定设备`
|
||||
- **AND** the UI MAY keep the raw `device_virtual_no` hidden
|
||||
|
||||
### Requirement: Agent Asset Lists SHALL Support Cascaded Shop Filtering
|
||||
|
||||
The agent-side asset lists SHALL provide a cascaded shop filter that is backed by `GET /api/admin/shops/cascade` and applies the selected shop ID to the active list request.
|
||||
|
||||
#### Scenario: User chooses a shop node under the IoT card tab
|
||||
|
||||
- **WHEN** the user opens the shop filter under the `IoT卡` tab and confirms a shop node
|
||||
- **THEN** the selected node `id` SHALL be sent as `shop_id` in the subsequent IoT card list request
|
||||
- **AND** the list SHALL refresh using that shop filter
|
||||
|
||||
#### Scenario: User chooses a shop node under the device tab
|
||||
|
||||
- **WHEN** the user opens the shop filter under the `设备` tab and confirms a shop node
|
||||
- **THEN** the selected node `id` SHALL be sent as `shop_id` in the subsequent device list request
|
||||
- **AND** the device list SHALL refresh using that shop filter
|
||||
- **AND** the device list request SHALL keep its existing search semantics and append `shop_id` in addition to them
|
||||
|
||||
#### Scenario: Selected shop has children
|
||||
|
||||
- **WHEN** a shop node returned from `GET /api/admin/shops/cascade` has `has_children = true`
|
||||
- **THEN** the UI SHALL allow the user to continue drilling down to child shops
|
||||
- **AND** the UI SHALL use `parent_id` to load the next level
|
||||
|
||||
#### Scenario: User clears the shop filter
|
||||
|
||||
- **WHEN** the user clears the shop filter
|
||||
- **THEN** subsequent IoT card list requests SHALL omit `shop_id`
|
||||
- **AND** subsequent device list requests SHALL omit `shop_id`
|
||||
|
||||
#### Scenario: Device tab is active
|
||||
|
||||
- **WHEN** the active asset tab is `设备`
|
||||
- **THEN** the shop filter SHALL still be shown
|
||||
- **AND** device list requests SHALL support `shop_id`
|
||||
|
||||
### Requirement: Agent Asset Search Input SHALL Be Fixed By Active Tab
|
||||
|
||||
The agent asset list SHALL remove the manual search-type selector and bind search semantics directly to the active tab.
|
||||
|
||||
#### Scenario: IoT card tab search
|
||||
|
||||
- **WHEN** the active tab is `IoT卡`
|
||||
- **THEN** the search field SHALL target `iccid`
|
||||
- **AND** the search placeholder SHALL be `搜索ICCID`
|
||||
- **AND** the UI SHALL NOT show a search-type switcher
|
||||
|
||||
#### Scenario: Device tab search
|
||||
|
||||
- **WHEN** the active tab is `设备`
|
||||
- **THEN** the search field SHALL target `virtual_no`
|
||||
- **AND** the user-facing search label SHALL be `设备号`
|
||||
- **AND** the search placeholder SHALL be `搜索设备号`
|
||||
- **AND** the UI SHALL NOT show a search-type switcher
|
||||
|
||||
### Requirement: Agent Asset List Controls SHALL Stay Fixed At The Top
|
||||
|
||||
The agent-side asset list page SHALL keep the search input and the filter/tab control area fixed at the top of the page while the list content scrolls independently underneath.
|
||||
|
||||
#### Scenario: User scrolls a long IoT card list
|
||||
|
||||
- **WHEN** the active tab is `IoT卡` and the user scrolls the list
|
||||
- **THEN** the search input SHALL remain visible at the top
|
||||
- **AND** the filter and tab controls directly below it SHALL remain visible at the top
|
||||
- **AND** only the list content area SHALL scroll
|
||||
|
||||
#### Scenario: User scrolls a long device list
|
||||
|
||||
- **WHEN** the active tab is `设备` and the user scrolls the list
|
||||
- **THEN** the search input SHALL remain visible at the top
|
||||
- **AND** the filter and tab controls directly below it SHALL remain visible at the top
|
||||
- **AND** only the list content area SHALL scroll
|
||||
|
||||
#### Scenario: Fixed controls do not cover list content
|
||||
|
||||
- **WHEN** the fixed top control area is rendered
|
||||
- **THEN** the list content SHALL start below that area
|
||||
- **AND** the first list item SHALL remain fully visible and operable
|
||||
|
||||
### Requirement: Agent Asset Lists SHALL Use Explicit Load-More Pagination
|
||||
|
||||
The agent-side IoT card list and device list SHALL stop automatic pagination triggered by scrolling to the bottom and SHALL use an explicit footer button to load the next page.
|
||||
|
||||
#### Scenario: IoT card tab still has more pages
|
||||
|
||||
- **WHEN** the active tab is `IoT卡` and the current IoT card result set has more pages available
|
||||
- **THEN** the footer SHALL show a button labeled `加载更多`
|
||||
- **AND** the next page SHALL NOT be requested until the user clicks that button
|
||||
|
||||
#### Scenario: Device tab still has more pages
|
||||
|
||||
- **WHEN** the active tab is `设备` and the current device result set has more pages available
|
||||
- **THEN** the footer SHALL show a button labeled `加载更多`
|
||||
- **AND** the next page SHALL NOT be requested until the user clicks that button
|
||||
|
||||
#### Scenario: User clicks the load-more button
|
||||
|
||||
- **WHEN** the user clicks the `加载更多` button for the active tab
|
||||
- **THEN** the UI SHALL request the next page for that tab using the existing active filters and search parameters
|
||||
- **AND** the returned items SHALL append to the existing list instead of replacing it
|
||||
|
||||
#### Scenario: No more pages remain
|
||||
|
||||
- **WHEN** the active list has no more pages available
|
||||
- **THEN** the `加载更多` button SHALL NOT be shown
|
||||
@@ -0,0 +1,20 @@
|
||||
## 1. Spec
|
||||
|
||||
- [x] 1.1 Initialize OpenSpec in the repository
|
||||
- [x] 1.2 Capture project context in `openspec/project.md`
|
||||
- [x] 1.3 Create change proposal and delta specs for asset list and asset detail
|
||||
- [x] 1.4 Review and approve the proposal before implementation
|
||||
|
||||
## 2. Implementation
|
||||
|
||||
- [x] 2.1 Extend asset list typing and request parameters for `device_virtual_no` and `shop_id`
|
||||
- [x] 2.2 Update agent asset list UI for binding status, shop filter, and fixed search semantics
|
||||
- [x] 2.3 Update asset detail UI for field removal, bound-card emphasis, and realtime-status changes
|
||||
- [x] 2.4 Update package-list date presentation in detail pages
|
||||
- [ ] 2.5 Verify card and device flows manually after implementation
|
||||
- [x] 2.6 Remove `保护状态` and `切卡模式`, and move bound-card real-name status next to the slot title
|
||||
- [x] 2.7 Restrict package effective-period display to packages in active status only
|
||||
- [x] 2.8 Remove the current-package order number and replace it with a `生效期:开始时间 - 到期时间` line
|
||||
- [x] 2.9 Apply the cascaded shop filter to the device list request and device tab UI
|
||||
- [x] 2.10 Replace bottom-reached auto pagination with an explicit `加载更多` button for the IoT card and device lists
|
||||
- [x] 2.11 Keep the asset-list search input and filter controls fixed at the top while the list scrolls underneath
|
||||
68
openspec/project.md
Normal file
68
openspec/project.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Project Context
|
||||
|
||||
## Purpose
|
||||
|
||||
This project is a Uni-app based agent and enterprise management frontend for IoT assets. It provides asset list, asset search/detail, package display, commission, withdrawal, and related operational pages for two user roles: agent accounts and enterprise accounts.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- TypeScript
|
||||
- Vue 3 with `<script setup>`
|
||||
- Uni-app
|
||||
- Vite
|
||||
- UnoCSS
|
||||
- Pinia
|
||||
- uview-plus
|
||||
|
||||
## Project Conventions
|
||||
|
||||
### Code Style
|
||||
|
||||
- Use Composition API and `<script setup lang="ts">`.
|
||||
- Keep API types close to the request layer in `src/api/*.ts`.
|
||||
- Prefer small, direct page-level logic over premature abstraction.
|
||||
- Existing pages use UnoCSS utility classes heavily; UI changes should preserve the current visual language.
|
||||
- User-facing copy is primarily Chinese.
|
||||
|
||||
### Architecture Patterns
|
||||
|
||||
- Business pages live under `src/pages/agent-system/`.
|
||||
- Backend calls are wrapped in `src/api/*.ts`.
|
||||
- Shared formatting helpers live in `src/utils/format` and nearby page helpers.
|
||||
- Asset pages distinguish between two primary resource types: `card` (IoT card) and `device`.
|
||||
|
||||
### Testing Strategy
|
||||
|
||||
- Run targeted validation with `pnpm type-check`, lint, and manual page checks when implementation begins.
|
||||
- For spec work, validate proposals with `openspec validate --strict`.
|
||||
- User-visible asset changes should be verified on both card and device flows.
|
||||
|
||||
### Git Workflow
|
||||
|
||||
- The repository may contain unrelated user changes; do not revert them.
|
||||
- Use OpenSpec change proposals for user-visible feature changes before implementation.
|
||||
- Keep proposals focused and capability-scoped.
|
||||
|
||||
## Domain Context
|
||||
|
||||
- Assets are mainly IoT cards and devices.
|
||||
- Asset identifiers may be ICCID or VirtualNo depending on the resource and entry point.
|
||||
- Agent-side pages currently include:
|
||||
- asset list: `src/pages/agent-system/assets/index.vue`
|
||||
- asset search/detail: `src/pages/agent-system/asset-search/index.vue`
|
||||
- secondary asset detail page: `src/pages/agent-system/asset-detail/index.vue`
|
||||
- Package display and realtime status are important parts of the asset detail experience.
|
||||
|
||||
## Important Constraints
|
||||
|
||||
- Agent and enterprise views are not identical; requirements in one role should not be assumed to apply globally.
|
||||
- Existing backend contracts are documented partly in `docs/*.md` and partly in the TypeScript API layer.
|
||||
- UI changes should preserve current behavior unless the proposal explicitly changes it.
|
||||
- Search semantics, display labels, and field visibility are product requirements and must be documented precisely.
|
||||
|
||||
## External Dependencies
|
||||
|
||||
- Backend admin APIs under `/api/admin/...`
|
||||
- Shop cascade API for hierarchical shop filtering
|
||||
- Asset resolve, realtime status, current package, and package list APIs
|
||||
- Uni-app runtime and uview-plus components
|
||||
Reference in New Issue
Block a user