320 lines
20 KiB
Markdown
320 lines
20 KiB
Markdown
## ADDED Requirements
|
||
|
||
### Requirement: Backend-first field semantics
|
||
|
||
The admin frontend SHALL use backend-provided business facts for real-name status, payment methods, estimated expiry, approval status, task status, balances, available amounts, debt amounts, and asset identifiers. The frontend MUST NOT infer or recalculate these values from partial data.
|
||
|
||
#### Scenario: Payment methods are displayed from the API
|
||
|
||
- **WHEN** the asset or recharge API returns `allowed_payment_methods`
|
||
- **THEN** the admin or related integration UI uses that list instead of hard-coded payment rules
|
||
|
||
#### Scenario: Financial amounts are displayed from the API
|
||
|
||
- **WHEN** a fund or credit response returns calculated balances
|
||
- **THEN** the frontend displays the returned values in fen-based data and only converts them for presentation
|
||
|
||
### Requirement: Admin asset and shop integration
|
||
|
||
The admin frontend SHALL support the confirmed July filters and fields for shops, IoT cards, devices, orders, exchanges, and assets, including contact-phone search, salesperson data, client login restriction, real-name filters, separate old/new exchange searches, asset identifiers, and estimated final expiry.
|
||
|
||
#### Scenario: Exchange assets are searched independently
|
||
|
||
- **WHEN** a user enters old and new asset search terms
|
||
- **THEN** the frontend sends `old_asset_keyword` and `new_asset_keyword` independently and preserves AND filtering semantics
|
||
|
||
#### Scenario: A shop login restriction is edited
|
||
|
||
- **WHEN** an authorized user updates a shop
|
||
- **THEN** the request includes the optional `client_login_disabled` value and the list/detail views display the returned value
|
||
|
||
### Requirement: Package allocation and series authorization
|
||
|
||
The admin frontend SHALL use the existing package and series authorization APIs for default expiry settings, override expiry settings, package multi-selection, authorization detail lookup, and package add/update/remove operations.
|
||
|
||
#### Scenario: A series authorization is edited
|
||
|
||
- **WHEN** a user opens an existing authorization
|
||
- **THEN** the frontend queries by authorization record ID, marks authorized package IDs, and keeps company cost price separate from authorization cost price
|
||
|
||
#### Scenario: Authorized packages are updated
|
||
|
||
- **WHEN** a user submits package changes
|
||
- **THEN** the frontend sends a 1–100 item `packages[]` array, uses `remove=true` for removals, and loads additional package pages when the series contains more than 100 packages
|
||
|
||
### Requirement: Credit and system configuration integration
|
||
|
||
The admin frontend SHALL integrate role default credit, shop actual credit, fund summary, and controlled system configuration APIs using fen-based amounts, server-calculated values, optimistic-lock versions, and registered configuration validation metadata.
|
||
|
||
#### Scenario: A shop credit limit update conflicts
|
||
|
||
- **WHEN** the credit update is rejected because the wallet `version` is stale
|
||
- **THEN** the frontend refreshes the latest fund summary and asks the user to retry with the latest version
|
||
|
||
#### Scenario: A configuration is read-only
|
||
|
||
- **WHEN** a configuration item is returned with `readonly=true`
|
||
- **THEN** the frontend disables its editing control and does not submit an update for that item
|
||
|
||
### Requirement: WeCom approval status integration
|
||
|
||
The admin frontend SHALL provide the confirmed WeCom configuration workflow and SHALL display business approval status as read-only for refund and offline recharge records when the approval provider is WeCom or an approval instance exists.
|
||
|
||
#### Scenario: A WeCom business record is awaiting approval
|
||
|
||
- **WHEN** a refund or offline recharge record has `approval_provider=wecom` or an `approval_instance_id`
|
||
- **THEN** the frontend displays the backend approval status and hides legacy manual approval actions
|
||
|
||
#### Scenario: A template mapping is rejected
|
||
|
||
- **WHEN** the backend rejects a scene template mapping
|
||
- **THEN** the frontend preserves the submitted form values and displays the backend validation message
|
||
|
||
### Requirement: Notifications, asynchronous tasks, exports, and Gateway controls
|
||
|
||
The admin frontend SHALL integrate low-balance notifications, expiring asset summaries, batch purchase tasks, export tasks, card speed tiers, and device allocation tasks according to the confirmed task, CSV, datasource, and timeout semantics.
|
||
|
||
#### Scenario: A batch task is restored
|
||
|
||
- **WHEN** a user reloads or re-enters a batch purchase or device allocation page
|
||
- **THEN** the frontend queries the existing task detail using the saved task identifier and does not create a duplicate task
|
||
|
||
#### Scenario: A speed tier is selected
|
||
|
||
- **WHEN** a user operates on an IoT card
|
||
- **THEN** the frontend submits a fixed speed-tier code from `-1` through `8`; a device page does not expose a speed-tier control
|
||
|
||
### Requirement: H5 and C-end work is explicitly external
|
||
|
||
The July integration specification SHALL identify H5/C-end changes as external follow-up work. This change MUST NOT modify H5/C-end pages or their API call implementations.
|
||
|
||
#### Scenario: A requirement depends on C-end behavior
|
||
|
||
- **WHEN** a requirement involves C-end login restriction, real-name flow, payment methods, asset display, order renewal, or C-end notifications
|
||
- **THEN** the item is marked as an external dependency and excluded from this change's implementation tasks
|
||
|
||
### Requirement: Permission and error boundaries
|
||
|
||
The admin frontend SHALL apply confirmed permission codes to new pages, buttons, and row actions, enforce data isolation in the UI, and present stable user-facing errors for authentication, authorization, validation, timeout, conflict, and unknown-result cases.
|
||
|
||
#### Scenario: A user lacks an action permission
|
||
|
||
- **WHEN** the current account does not have the configured permission code
|
||
- **THEN** the corresponding page action is hidden or disabled and the frontend does not invoke the API
|
||
|
||
#### Scenario: An asynchronous operation has an unknown result
|
||
|
||
- **WHEN** a task or Gateway operation times out with an unknown result
|
||
- **THEN** the frontend preserves the current data, shows a safe status message, and provides a refresh or manual verification path instead of blindly retrying
|
||
|
||
### Requirement: Documented API contract alignment
|
||
|
||
The admin frontend SHALL implement the July integration against the documented API paths and request/response contracts. The documented interface files under `docs/所需接口文档/` SHALL be treated as the source of truth for parameter names, enum values, nullable fields, pagination, permissions, and HTTP error semantics.
|
||
|
||
#### Scenario: A page loads a documented resource
|
||
|
||
- **WHEN** a July page queries or mutates a resource
|
||
- **THEN** it uses the corresponding documented `/api/admin` endpoint and sends the documented parameter names without translating them to legacy frontend names
|
||
|
||
#### Scenario: A response contains a nullable or enumerated field
|
||
|
||
- **WHEN** a documented response returns a nullable field, numeric status, string enum, or `*_name` display field
|
||
- **THEN** the frontend preserves the nullable state, uses the documented enum values, and prefers the backend display name instead of inventing a local label
|
||
|
||
#### Scenario: An API rejects a request
|
||
|
||
- **WHEN** a documented endpoint returns `400`, `401`, `403`, or `500`
|
||
- **THEN** the frontend applies the shared authentication, authorization, validation, server-error, and retry-safe handling without exposing raw transport details as the user-facing message
|
||
|
||
### Requirement: File upload and batch task contract
|
||
|
||
The admin frontend SHALL use `POST /api/admin/storage/upload-url` for file-backed July operations, upload to the returned `upload_url` with the requested content type, and pass only the returned `file_key` to the business endpoint. Batch purchase and device allocation CSVs SHALL be UTF-8 single-column files, accept an optional UTF-8 BOM, stay within 10 MB and 1000 data rows, and preserve identifiers as text.
|
||
|
||
#### Scenario: A batch purchase is submitted
|
||
|
||
- **WHEN** the user selects one package and one payment method and uploads a valid CSV
|
||
- **THEN** the frontend calls `POST /api/admin/asset-package-batch-orders` with `file_key`, `package_id`, `payment_method`, and, for offline payment, 1–5 `voucher_keys`
|
||
|
||
#### Scenario: A device allocation is submitted
|
||
|
||
- **WHEN** a platform user selects an allocation target and uploads a valid device CSV
|
||
- **THEN** the frontend calls `POST /api/admin/devices/import/allocations` with `file_key`, `operation_type` set to `assign_shop` or `assign_series`, and the selected `target_id`
|
||
|
||
#### Scenario: A batch task is resumed
|
||
|
||
- **WHEN** the page is reloaded while a task is non-terminal
|
||
- **THEN** the frontend queries the saved task ID, displays the backend `status_name` and progress/result counts, stops polling at the documented terminal state, and never creates a second task
|
||
|
||
### Requirement: WeCom configuration API workflow
|
||
|
||
The admin frontend SHALL implement the documented WeCom configuration sequence: list or save applications through `/api/admin/wecom/applications`, test the application, synchronize and query visible members, set the default creator, bind system accounts through `/api/admin/accounts/{account_id}/wecom-binding`, and save or query the two supported scene mappings.
|
||
|
||
#### Scenario: A WeCom application is configured
|
||
|
||
- **WHEN** a super administrator saves valid application credentials
|
||
- **THEN** the frontend refreshes the application, allows connection testing, and clearly distinguishes `data.success=true` for access-token acquisition from completed member, template, and callback configuration
|
||
|
||
#### Scenario: A default creator is selected
|
||
|
||
- **WHEN** the user sets a default creator
|
||
- **THEN** the frontend only submits a `userid` selected from the latest synchronized visible-member list and preserves the real local submitter in business records
|
||
|
||
#### Scenario: A scene mapping is validated
|
||
|
||
- **WHEN** the user saves `refund_approval` or `offline_recharge_approval`
|
||
- **THEN** the frontend submits `application_id`, `template_id`, `control_mapping`, and `status`, preserves input on validation failure, and displays the returned verification/status fields after success
|
||
|
||
### Requirement: Approval and financial business API contract
|
||
|
||
The admin frontend SHALL use the documented refund and agent-recharge APIs for business creation and read-only approval tracking. Amounts and voucher keys SHALL follow the documented units and cardinality, and a record with `approval_provider=wecom` or `approval_instance_id` SHALL not expose legacy manual approval actions.
|
||
|
||
#### Scenario: An offline agent recharge is created
|
||
|
||
- **WHEN** a platform user submits an offline recharge
|
||
- **THEN** the frontend calls `POST /api/admin/agent-recharges` with the target `shop_id`, amount in fen, `payment_method=offline`, and 1–5 voucher keys
|
||
|
||
#### Scenario: A refund is awaiting WeCom approval
|
||
|
||
- **WHEN** `GET /api/admin/refunds` or `GET /api/admin/refunds/{id}` returns a WeCom approval instance
|
||
- **THEN** the frontend displays `approval_status_name`, `submitter_name`, and documented amount fields as read-only and does not show approve/reject actions
|
||
|
||
#### Scenario: Approval submission has an unknown result
|
||
|
||
- **WHEN** `approval_status=8` or the documented status name indicates an unknown submission result
|
||
- **THEN** the frontend does not recreate the business record and offers refresh or manual verification instead
|
||
|
||
### Requirement: Documented device allocation permissions
|
||
|
||
The admin frontend SHALL enforce the documented permission boundary for device allocation task list and detail APIs. Because those APIs are documented as platform-only, agent and enterprise accounts SHALL not see the allocation task entry or be allowed to invoke the task list/detail endpoints from the UI.
|
||
|
||
#### Scenario: A non-platform user opens device allocation
|
||
|
||
- **WHEN** an agent or enterprise account loads the device allocation area
|
||
- **THEN** the frontend hides the entry and does not call `/api/admin/devices/import/tasks` or `/api/admin/devices/import/tasks/{id}`
|
||
|
||
### Requirement: Agent Wallet Online Recharge Contract
|
||
|
||
The admin frontend SHALL support the documented agent wallet online QR recharge flow through `/api/admin/agent-recharges/payment-methods` and `/api/admin/agent-recharges`. The available payment methods and amount limits SHALL come from the payment-methods response; the online create request SHALL contain only `amount` in integer fen, `payment_method` from the returned methods, and a required `request_id`. Online agent recharge requests MUST NOT send `shop_id`, `payment_voucher_key`, `remark`, merchant credentials, or payment configuration identifiers.
|
||
|
||
#### Scenario: Load available online payment methods
|
||
|
||
- **WHEN** an agent opens the online recharge dialog
|
||
- **THEN** the frontend calls `GET /api/admin/agent-recharges/payment-methods`
|
||
- **AND** it displays only the returned `methods` values (`wechat` and/or `alipay`)
|
||
- **AND** it validates the integer-fen amount against the returned `min_amount` and `max_amount`
|
||
|
||
#### Scenario: No online payment method is available
|
||
|
||
- **WHEN** the payment-methods response returns an empty `methods` array
|
||
- **THEN** the frontend hides or disables the submit action
|
||
- **AND** it displays that no online payment method is currently available
|
||
- **AND** it does not call the online create endpoint
|
||
|
||
#### Scenario: Create an online QR recharge
|
||
|
||
- **WHEN** an authorized agent submits a valid online recharge
|
||
- **THEN** the frontend calls `POST /api/admin/agent-recharges` with `amount`, `payment_method`, and `request_id`
|
||
- **AND** it converts the displayed yuan amount to an integer amount in fen before submission
|
||
- **AND** it uses the returned `recharge_id` and does not derive the target shop or wallet from user-editable form fields
|
||
|
||
#### Scenario: Render the returned QR content
|
||
|
||
- **WHEN** online recharge creation succeeds with a non-empty `qr_content`
|
||
- **THEN** the frontend passes `qr_content` unchanged to the QR-code component
|
||
- **AND** it does not parse, concatenate, replace, upload, persist, or log the QR content
|
||
|
||
### Requirement: Idempotent Online Recharge Submission
|
||
|
||
The frontend SHALL preserve one `request_id` for the lifetime of one active online recharge submission. A timeout or network interruption MAY retry the same submission once with the same `request_id`, but a user-initiated new recharge MUST generate a new request ID. A conflict caused by reusing the same request ID with a different amount or payment method SHALL preserve the existing form state and require an explicit new recharge attempt.
|
||
|
||
#### Scenario: Retry after an uncertain create result
|
||
|
||
- **WHEN** the online create request times out or the network disconnects
|
||
- **THEN** the frontend retries at most once with the original `request_id`
|
||
- **AND** it does not create a new `request_id` or blindly open a second recharge dialog
|
||
|
||
#### Scenario: Start a new recharge after closing the dialog
|
||
|
||
- **WHEN** the user closes the QR dialog and clicks online recharge again
|
||
- **THEN** the frontend creates a new `request_id`
|
||
- **AND** the new amount and payment method are treated as a new active submission
|
||
|
||
#### Scenario: Reused request ID conflicts
|
||
|
||
- **WHEN** the backend rejects a request because the same `request_id` is paired with different recharge parameters
|
||
- **THEN** the frontend displays the backend business message
|
||
- **AND** it does not overwrite the original request or automatically submit another amount
|
||
|
||
### Requirement: Online Payment And Wallet Arrival Polling
|
||
|
||
The online QR recharge dialog SHALL poll only the documented local payment-status endpoint `GET /api/admin/agent-recharges/{id}/payment-status`. While the QR dialog is visible and the recharge is non-terminal, the frontend SHALL poll at approximately three-second intervals. The frontend SHALL stop polling when the dialog is hidden, the page is not visible, or the recharge status is `3` (completed), `4` (closed), `5` (refunded), or `6` (rejected). It MUST treat `status=2` as third-party payment completed but wallet arrival still processing; only `status=3` permits refreshing the wallet balance and recharge list.
|
||
|
||
#### Scenario: Payment is waiting for the user
|
||
|
||
- **WHEN** payment-status returns `status=1` and `payment_status=0`
|
||
- **THEN** the dialog displays that the user is waiting to scan and pay
|
||
- **AND** polling continues while the dialog is visible
|
||
|
||
#### Scenario: Payment is received but wallet arrival is processing
|
||
|
||
- **WHEN** payment-status returns `status=2` and `payment_status=1`
|
||
- **THEN** the dialog displays payment success and wallet arrival processing
|
||
- **AND** the frontend does not increase or refresh the wallet balance as completed
|
||
- **AND** polling continues
|
||
|
||
#### Scenario: Wallet arrival completes
|
||
|
||
- **WHEN** payment-status returns `status=3`
|
||
- **THEN** the frontend displays that the recharge has arrived
|
||
- **AND** it stops polling
|
||
- **AND** it refreshes the current wallet balance and recharge list
|
||
|
||
#### Scenario: Online recharge reaches a terminal failure state
|
||
|
||
- **WHEN** payment-status returns `status=4`, `status=5`, or `status=6`
|
||
- **THEN** the frontend displays the backend status name or an appropriate failure message
|
||
- **AND** it stops polling without automatically creating a replacement recharge
|
||
|
||
### Requirement: Recharge Source And Operation Boundaries
|
||
|
||
The recharge list and detail pages SHALL use `recharge_source` as the only business branch: `agent_online` for agent online self-recharge and `platform_offline` for platform offline代充. They SHALL prefer `recharge_source_name` for display and use the documented list filters `shop_id`, `status`, `recharge_source`, `start_date`, and `end_date`. Online records SHALL show payment information and payment/completion timestamps while hiding offline vouchers and manual approval operations. Offline records SHALL show vouchers, remarks, submitter, and approval status; they SHALL not show QR content or invoke the online payment-status endpoint.
|
||
|
||
#### Scenario: Filter online recharge records
|
||
|
||
- **WHEN** a user selects online recharge source or status filters
|
||
- **THEN** the frontend requests `GET /api/admin/agent-recharges` with the documented filter names and values
|
||
- **AND** it displays the backend recharge source name, amount, payment method, status, submitter, and timestamps
|
||
|
||
#### Scenario: Display a platform offline recharge
|
||
|
||
- **WHEN** a platform user opens a record with `recharge_source=platform_offline`
|
||
- **THEN** the detail view displays the payment voucher, remark, submitter, and approval status
|
||
- **AND** it does not render a QR code or start payment-status polling
|
||
|
||
#### Scenario: Confirm or reject an offline recharge
|
||
|
||
- **WHEN** a pending offline recharge has no WeCom approval provider or approval instance
|
||
- **THEN** an authorized platform user MAY confirm it through `POST /api/admin/agent-recharges/{id}/offline-pay` with `operation_password`
|
||
- **AND** an authorized platform user MAY reject it through `POST /api/admin/agent-recharges/{id}/reject` with a required `rejection_reason` of at most 500 characters
|
||
|
||
#### Scenario: WeCom approval controls the offline record
|
||
|
||
- **WHEN** an offline recharge has `approval_provider=wecom` or an `approval_instance_id`
|
||
- **THEN** the frontend displays approval progress as read-only
|
||
- **AND** it hides confirm and reject operations
|
||
|
||
### Requirement: Agent Recharge Export Permissions
|
||
|
||
The agent recharge list SHALL show its export entry only with `agent_recharge:export`. The export-task page SHALL protect the `agent_recharge` detail and download operations with `export_task:agent_recharge_detail` and `export_task:agent_recharge_download`, respectively. The frontend SHALL hide unauthorized controls and SHALL NOT invoke the corresponding API as a fallback.
|
||
|
||
#### Scenario: An authorized user exports agent recharges
|
||
|
||
- **WHEN** the current account has `agent_recharge:export`
|
||
- **THEN** the agent recharge page displays the export entry and opens the `agent_recharge` export flow
|
||
|
||
#### Scenario: An unauthorized user accesses export actions
|
||
|
||
- **WHEN** the current account lacks an export permission
|
||
- **THEN** the related entry, detail action, or download action is hidden
|
||
- **AND** the frontend does not call the export-task detail or download endpoint
|