Skip to content

feat(frontend): P2-C 部门/成员管理 + 加额审批 + 用量报表 + 运营者视图(v0.3.3) - #80

Merged
argszero merged 1 commit into
mainfrom
feat/frontend-p2c-admin-ops
Aug 18, 2026
Merged

argszero merged 1 commit into
mainfrom
feat/frontend-p2c-admin-ops

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

P2-C (rant 2026-08-18T14:03:51): backend domains (departments / raise requests / usage reports / operator view) fully implemented, frontend wired to real APIs — admin view has no mock data left (data.js remains for guest/fallback only).

Backend (schema v4, idempotent migration)

  • departments table + users.dept_id column; raise_requests table
  • GET/POST /api/admin/departments, PATCH/DELETE /api/admin/departments/:id (dup name 409, delete non-empty 409)
  • PATCH /api/admin/users/:id {dept_id} — member reassignment/removal
  • POST /api/raise-requests + GET (own vs all by role, ?status= filter); duplicate pending 409
  • POST /api/admin/raise-requests/:id/approve (adds permanent balance + topup tx, counterpart=加额审批) / reject
  • GET /api/ops/runtime, POST /api/ops/credits (counterpart=运营者), GET /api/ops/users — role in (admin, ops), user 403
  • GET /api/admin/usage extended → {users, models, departments} three-group aggregation
  • Seeded operator account ops@aitokenpool.local / ops1234 (role=ops)

Frontend

  • Sidebar role visibility: admin → 管理视图, ops → 运营视图 (per-role instead of both)
  • 组织管理 tab: department CRUD + member dept assignment (real API)
  • 成员管理 tab: dept column + raise-request approve/reject (real API)
  • 用量报表 tab: by-model / by-member / by-department bar lists (real data)
  • Wallet 申请加额 → real POST; 运营视图: runtime stat cards + member topup

Tests

  • 64 → 70: dept CRUD / dup 409 / delete-non-empty 409 / member dept change; raise apply / dup-pending 409 / approve adds points + topup tx / reject; ops 403 / runtime / credits; usage three-group aggregation
  • cargo build + cargo test (70/70) + cargo fmt --check + clippy --all-targets -D warnings all green; live smoke (clean DB) passed for every new endpoint

Rant

Host rant 2026-08-18T14:03:51 (前端对接 P2-C — 部门/成员管理 + 加额审批 + 用量报表 + 运营者视图).

后端(schema v4,幂等迁移):
- departments 表 + users.dept_id;raise_requests 表
- GET/POST /api/admin/departments、PATCH/DELETE /api/admin/departments/:id
- PATCH /api/admin/users/:id {dept_id} 成员改部门/移除
- POST /api/raise-requests + GET(用户自己/admin 全部,role 区分)
- POST /api/admin/raise-requests/:id/approve|reject(批准加永久点数 + topup 交易)
- GET /api/ops/runtime、POST /api/ops/credits(counterpart=运营者)、GET /api/ops/users
- GET /api/admin/usage 扩展为 {users, models, departments} 三组聚合
- seed 运营者账号 ops@aitokenpool.local / ops1234(role=ops)

前端(管理视图全真实,运营视图独立):
- 侧边栏按 role 显隐:admin→管理视图、ops→运营视图(原型两者都显示改为按角色)
- 组织管理 tab 部门 CRUD + 成员改部门(真实 API)
- 成员 tab 部门列/加额申请审批(真实 API)
- 用量报表 tab 模型/成员/部门三组柱状条(真实数据)
- 钱包页「申请加额」真实提交;运营视图:运行概览 stat 卡 + 成员充值

测试 64→70(dept CRUD/重名409/删非空409/成员改部门、加额申请/重复409/批准+交易/驳回、
ops 403/runtime/credits、usage 三组聚合);fmt/clippy 干净;live smoke 全过
@argszero
argszero merged commit 85982e8 into main Aug 18, 2026
1 check passed
@argszero
argszero deleted the feat/frontend-p2c-admin-ops branch August 18, 2026 06:18
argszero added a commit that referenced this pull request Sep 12, 2026
`GET /api/ops/runtime` has returned `total_txs` (a global
`COUNT(*) FROM transactions`) since 85982e8 (PR #80), but the live
operator view never rendered it. The mock branch did:

    stat(T("ops.stats.trades"), T("cnt.trades", { n: txs.length }),
         T("ops.stats.trades.sub"))

and 89963f3 ("zero mock data in logged-in views", v1.22) deleted that
line without re-pointing the live branch at `rt.total_txs`, which the
same response object already carried. So this is a regression being
repaired, not a new feature — and not prototype parity: the prototype
has four ops cards and no trades card at all, while the live view has
nine by design.

The card's two i18n keys were already present in both packs, which is
why the change adds no keys.

The field had no assertion in either direction, which is exactly why it
could sit unused for 23 commits: `grep total_txs src/routes/ops.rs`
found only the compute and the serialize lines. The new route test
pins both that it is returned and that its scope is global and
all-types (rows span two users, so a per-user or consume-only
regression is falsifiable). No production backend change: the field
already ships.

Co-authored-by: argszero <argszero@argszerodeMac-mini.local>
argszero added a commit that referenced this pull request Sep 13, 2026
…ow number (#227)

Three tables rebuild their list with .filter() and then tag every row button with
the index *inside the searched list*, while the handlers resolve that index
against the full cached array:

  #api-keys   copyKey / renameKey / deleteKey   -> Live.apiKeys[i]
  #model-body editModelRow / deleteModel        -> Live.adminModels[i]
  #dept-body  openDeptForm / deleteDept         -> Live.departments[i]

So as soon as the search box hides one earlier row, a button acts on a different
record than the row it sits in: the delete removed the wrong API key / model /
department, copy handed out another key's secret, and the edit form opened with
another record's values.

Both correct idioms already exist in the same file — #emp-body tags rows with
users.indexOf(u) and #ops-body with u.id — these three tables were simply never
updated when their search boxes were added (#79, #80, #97).

- api-keys: carry the cached index through the mapping, add data-key-row and
  resolve the row by that locator instead of nth-child
- model-body / dept-body: derive the locator with indexOf, mirroring #emp-body
- bump the app.js cache-bust
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant