提交 ce372724 authored 作者: 王鹏飞's avatar 王鹏飞

test(admin): freeze route and page migration contracts

上级 09037ada
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"preview": "vite preview", "preview": "vite preview",
"lint": "oxlint --fix .", "lint": "oxlint --fix .",
"format": "oxfmt src/", "format": "oxfmt src/",
"test": "node --test src/store/storage-import.test.mjs src/utils/*.test.js src/layout/components/*.test.js" "test": "node --test src/app/route-manifest.test.mjs src/store/storage-import.test.mjs src/utils/*.test.js src/layout/components/*.test.js"
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^5.4.0", "@ant-design/icons": "^5.4.0",
......
import assert from "node:assert/strict";
import { fileURLToPath } from "node:url";
import test from "node:test";
import { createServer } from "vite";
const appRoot = fileURLToPath(new URL("../..", import.meta.url));
test("admin public route manifest preserves the 38 unique absolute URLs", async () => {
const vite = await createServer({
appType: "custom",
configFile: false,
logLevel: "error",
optimizeDeps: { noDiscovery: true },
root: appRoot,
server: { hmr: false, middlewareMode: true, ws: false },
});
try {
const { adminPublicRoutes } = await vite.ssrLoadModule("/src/app/route-manifest.ts");
assert.equal(adminPublicRoutes.length, 38);
assert.equal(new Set(adminPublicRoutes).size, adminPublicRoutes.length);
assert.ok(adminPublicRoutes.every((route) => route.startsWith("/")));
} finally {
await vite.close();
}
});
export const adminPublicRoutes = [
"/books/management",
"/books/management/add-edit",
"/books/management/chapter",
"/books/audit",
"/books/audit/detail",
"/books/classify",
"/books/label",
"/books/sale",
"/books/sale/detail",
"/books/sale/discussP",
"/books/sale/discuss-detail",
"/books/question-bank",
"/books/discussion",
"/books/order-management",
"/books/order-management/sale-statistics",
"/books/design",
"/member/list",
"/member/list/query",
"/member/list/detail",
"/member/userlevel",
"/advertisement/advert",
"/advertisement/adsense",
"/setting/help",
"/setting/help/addedit",
"/setting/applied",
"/setting/personalized-setting",
"/setting/point-management",
"/setting/app-version",
"/setting/coupon",
"/setting/sensitive",
"/setting/feedback",
"/jurisdiction/admin",
"/jurisdiction/role",
"/teacher/list",
"/userinfo",
"/editor",
"/login",
"/student/book",
] as const;
# Admin page migration inventory
Source of truth: the legacy page files and `apps/admin/src/app/routes.tsx` as
inspected on 2026-07-20. `—` means the current page has no explicit item in
that category; it is not permission to add or remove behaviour during a move.
"Legacy request" names the file that owns the existing wire protocol and must
be moved unchanged before any later extraction.
| Old path | Target module | Legacy API file | Table type | Permission points observed | Dialog / drawer | Upload / preview | Mutations / important actions | Route state |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `/books/management` | `books/management` | `management/request.js`, `management/api.js` | legacy paginated list | `getAllList`, `getInfoById`, `export`, `del`, `release`, `import`, `add` | delete, export, import modals; edit drawer | import `Upload` | delete, release/status, import, export; navigates add/edit and chapter | outgoing `{ id }` to add/edit; chapter navigation retains legacy payload |
| `/books/management/add-edit` | `books/management` | `management/api.js` | form | — | — | `UploadImage` | `addBook` / `updateBook` | reads `location.state.id` |
| `/books/management/chapter` | `books/management` | `section/request.js`, `section/api.js` | chapter/tree editor | — | modal | editor/knowledge-graph preview components | chapter/section/question mutations | reads legacy location state; returns to `/books/management/list` |
| `/books/audit` | `books/audit` | `audit/request.js`, `section/request.js` | Ant Design `Table` | `getInfoByChapterId`, `add` | modal | audit `preview.jsx` | submit audit/examine; opens detail | outgoing audit detail state from selected row |
| `/books/audit/detail` | `books/audit` | `audit/request.js` | detail | `getExamineList` | modal | — | audit history actions | reads location state; `navigate(-1)` |
| `/books/classify` | `books/classify` | `classify/request.js` | legacy paginated list | `getInfoById`, `del`, `add`, `edit` | edit drawer, delete modal | — | add, edit, delete | — |
| `/books/label` | `books/label` | `label/request.js` | legacy paginated list | `getInfoById`, `del`, `add` | edit drawer, delete modal | — | add, edit, delete | — |
| `/books/sale` | `books/sale` | `sale/request.js` | legacy paginated list | `getCommentList`, `getInfoById`, `changeStatus` | edit drawer, status modal | — | status change; opens sale/detail and discussions | outgoing `{ id }` and `{ id, name }` |
| `/books/sale/detail` | `books/sale` | `sale/request.js`, `classify/request.js` | edit form | — | drawer | — | sale edit/save | reads `location.state.id`; `navigate(-1)` |
| `/books/sale/discussP` | `books/sale` | `sale/request.js` | Ant Design `Table` | — | — | — | opens discussion detail | reads `{ id, name }`; sends `{ id, name, book_id }` |
| `/books/sale/discuss-detail` | `books/sale` | `sale/request.js` | discussion detail | — | two modals | — | discussion reply/delete actions | reads `{ id, name, book_id }` |
| `/books/question-bank` | `books/question-bank` | `question-bank/request.js` | legacy paginated list | `getInfoById`, `del`, `add`, `import` | form drawer, delete/import modals | `Upload` import; question editor | add/edit/delete/import question and types | — |
| `/books/discussion` | `books/discussion` | `discussion/requset.js`, `management/request.js` | legacy paginated list | `getSystem`, `delComment` | edit/detail drawers, delete modal | — | delete comment; system filter | — |
| `/books/order-management` | `books/orders` | `order-management/tab/request.js` | order list | `getOrderList`, `getOrderList1`, `salesStatistics`, `refund` | refund drawer | — | refund; tab selection | layout observes pathname; retains `/dataset` alias |
| `/books/order-management/sale-statistics` | `books/orders` | `order-management/tab/request.js` | statistics/chart view | `salesStatistics` | — | — | query statistics | pathname selects statistics tab |
| `/books/design` | `books/design` | — (component signs and opens design page) | design/editor view | — | — | — | external design-page open/close | — |
| `/member/list` | `members/list` | `member/list/request.js` | legacy paginated list | `getInfoById`, `del`, `detail`, `add` | edit drawer, delete modal | — | add/edit/delete; opens detail | outgoing member detail state |
| `/member/list/query` | `members/list` | `member/list/request.js` | same member list leaf | same as `/member/list` | same as `/member/list` | — | same as `/member/list` | same as `/member/list` |
| `/member/list/detail` | `members/list` | `member/list/request.js` | member detail with record tables | — | — | — | displays order, integral and coupon records | reads selected member location state |
| `/member/userlevel` | `members/level` | `member/userlevel/request.js` | legacy paginated list | `getSystem`, `getInfoById`, `del`, `add`, `systemEdit` | edit drawer, delete modal | — | add/edit/delete, system switch | — |
| `/advertisement/advert` | `advertisements/advert` | `advertisement/advert/request.js`, `adsense/request.js` | legacy paginated list | `changeStatus`, `getInfoById`, `del`, `add` | edit drawer, delete modal | `Upload` | add/edit/delete/status | — |
| `/advertisement/adsense` | `advertisements/adsense` | `advertisement/adsense/request.js` | legacy paginated list | `changeStatus` | status modal | — | status change | — |
| `/setting/help` | `settings/help` | `setting/help/requet.js` | legacy paginated list | `getInfoById`, `del`, `add` | delete modal | editor preview is owned by add/edit | delete; opens add/edit | outgoing `{ id }` for edit |
| `/setting/help/addedit` | `settings/help` | `setting/help/addedit/requet.js`, `setting/help/requet.js` | rich-text form | — | — | editor custom upload and preview | add/edit/preview help | reads `location.state.id`; `navigate(-1)` |
| `/setting/applied` | `settings/applied` | `setting/applied/request/index.js` | Ant Design `Table` | `changeStatus`, `getInfoById`, `del`, `add` | edit drawer, delete modal | — | add/edit/delete/status | — |
| `/setting/personalized-setting` | `settings/personalized` | `setting/point-management/request.js` | setting form | — | — | — | saves personalized value | — |
| `/setting/point-management` | `settings/point-management` | `setting/point-management/request.js` | form (not AppList) | `integralSet`, `add`, `integralEdit` | recharge drawer | — | points switch/configure/add/edit | — |
| `/setting/app-version` | `settings/app-version` | `setting/app-version/request.js` | legacy paginated list | current code checks `/setting/applied/getInfoById`, `del`, `add` | edit drawer, delete modal | APK `Upload`, STS token | add/edit/delete version | — |
| `/setting/coupon` | `settings/coupon` | `setting/coupon/request.js`, `setting/coupon/api.js` | legacy list/pagination | `getInfoById`, `del`, `getCoupon`, `add`, `give` | form drawer, send-coupon drawer | — | delete, add/edit, send coupon, switch | — |
| `/setting/sensitive` | `settings/sensitive` | `setting/sensitive/request.js` | legacy paginated list | no explicit `operationPermissionsList` check | edit drawer, delete modal | `Upload` | import and sensitive-word mutations | — |
| `/setting/feedback` | `settings/feedback` | `setting/feedback/api.js` | feedback list | — | — | — | reads/updates feedback workflow | — |
| `/jurisdiction/admin` | `access/admin` | `jurisdiction/admin/request.js`, `role/request.js` | legacy paginated list | `changeStatus`, `getInfoById`, `editPass`, `del`, `/jurisdiction/role/add` | edit/password drawers, delete modal | — | add/edit/delete/status/password | — |
| `/jurisdiction/role` | `access/role` | `jurisdiction/role/request.js` | role list/tree permissions | `changeStatus`, `getInfoById`, `getPowerByRoleId`, `del`, `add` | edit drawer, delete modal | — | add/edit/delete/status/permission tree | — |
| `/teacher/list` | `teachers/list` | `teacher/query/request.js`, `jurisdiction/role/request.js` | legacy paginated list | `getSystem`, `getInfoById`, `del`, `editPass`, `add`, `systemEdit` | edit/password drawers, delete modal | — | add/edit/delete/password/system switch | — |
| `/userinfo` | `account` | `user-module/userInfo/requet.js`, user request API | profile form | — | edit drawer | `UploadImage` | change profile information | — |
| `/editor` | `editor` | — | rich editor | — | — | editor-managed media | editor actions | — |
| `/login` | `auth` | `user-module/login/request/index.js`, `api.js` | login form | — | — | captcha utility | login and redirect | redirects to `/` |
| `/student/book` | `student-book` | `student/book/request.js` | student book detail | — | — | — | book action flow | reads location state; returns to `/books/management/list` |
## Baseline commands (Task 1)
Executed from `apps/admin` after adding the route contract test.
| Command | Exit | Result |
| --- | --- | --- |
| `pnpm test` | 0 | 7 Node tests passed, including the new 38-route contract test. |
| `pnpm build` | 0 | Vite built 6,802 modules in 7.08s. Existing warnings: non-module formula-editor script cannot be bundled; chunks larger than 500 kB. |
| `pnpm exec tsc --noEmit` | 2 | Historical failures in `src/App.tsx`: missing declaration for `./App.less`; `baseRouter` is not assignable to `RouteObject[]` because a lazy component requires `value` and `onChange` props. |
| `pnpm exec oxlint src --deny-warnings` | 1 | Historical lint baseline: 1,123 reported diagnostic lines (output truncated by runner); first errors are `prefer-const` in `src/routes/lazyLoadAndDelay.jsx:26` and `src/pages/books/design/index.jsx`. No lint changes were made. |
The TypeScript and oxlint failures are recorded only; this task does not modify
their legacy sources.
# Admin public route contract
This contract freezes the 38 public URLs declared by `src/app/routes.tsx` before
the modular-route migration. The current component column identifies the leaf
component that renders the URL today; wrapper layouts and index redirects are
not additional public URLs.
| URL | Current leaf component | Current source | Target module |
| --- | --- | --- | --- |
| `/books/management` | Management list | `pages/books/management/list/index` | `modules/books/management` |
| `/books/management/add-edit` | Book add/edit | `pages/books/management/addedit/index` | `modules/books/management` |
| `/books/management/chapter` | Chapter management | `pages/books/section/index` | `modules/books/management` |
| `/books/audit` | Audit table | `pages/books/audit/table` | `modules/books/audit` |
| `/books/audit/detail` | Audit detail | `pages/books/audit/detail` | `modules/books/audit` |
| `/books/classify` | Classify | `pages/books/classify/index` | `modules/books/classify` |
| `/books/label` | Label | `pages/books/label/index` | `modules/books/label` |
| `/books/sale` | Sale table | `pages/books/sale/table` | `modules/books/sale` |
| `/books/sale/detail` | Sale edit | `pages/books/sale/edit` | `modules/books/sale` |
| `/books/sale/discussP` | Sale discussion list | `pages/books/sale/discussList/index` | `modules/books/sale` |
| `/books/sale/discuss-detail` | Sale discussion detail | `pages/books/sale/discussDetail/index` | `modules/books/sale` |
| `/books/question-bank` | Question bank | `pages/books/question-bank/index` | `modules/books/question-bank` |
| `/books/discussion` | Discussion management | `pages/books/discussion/index` | `modules/books/discussion` |
| `/books/order-management` | Order table | `pages/books/order-management/tab/table` | `modules/books/orders` |
| `/books/order-management/sale-statistics` | Sales statistics | `pages/books/order-management/tab/salesStatistics` | `modules/books/orders` |
| `/books/design` | Book design | `pages/books/design/index` | `modules/books/design` |
| `/member/list` | Member list | `pages/member/list/list` | `modules/members/list` |
| `/member/list/query` | Member list | `pages/member/list/list` | `modules/members/list` |
| `/member/list/detail` | Member detail | `pages/member/detail/index` | `modules/members/list` |
| `/member/userlevel` | Member level | `pages/member/userlevel/index` | `modules/members/level` |
| `/advertisement/advert` | Advertisement list | `pages/advertisement/advert/index` | `modules/advertisements/advert` |
| `/advertisement/adsense` | AdSense list | `pages/advertisement/adsense/index` | `modules/advertisements/adsense` |
| `/setting/help` | Help table | `pages/setting/help/table` | `modules/settings/help` |
| `/setting/help/addedit` | Help add/edit | `pages/setting/help/addedit/index` | `modules/settings/help` |
| `/setting/applied` | Application list | `pages/setting/applied/index` | `modules/settings/applied` |
| `/setting/personalized-setting` | Personalized setting | `pages/setting/personalized-setting/index` | `modules/settings/personalized` |
| `/setting/point-management` | Point management | `pages/setting/point-management/index` | `modules/settings/point-management` |
| `/setting/app-version` | App version list | `pages/setting/app-version/index` | `modules/settings/app-version` |
| `/setting/coupon` | Coupon list | `pages/setting/coupon/index` | `modules/settings/coupon` |
| `/setting/sensitive` | Sensitive-word management | `pages/setting/sensitive/index` | `modules/settings/sensitive` |
| `/setting/feedback` | Feedback list | `pages/setting/feedback/index` | `modules/settings/feedback` |
| `/jurisdiction/admin` | Administrator list | `pages/jurisdiction/admin/index` | `modules/access/admin` |
| `/jurisdiction/role` | Role list | `pages/jurisdiction/role/index` | `modules/access/role` |
| `/teacher/list` | Teacher list | `pages/teacher/query/index` | `modules/teachers/list` |
| `/userinfo` | User information | `pages/user-module/userInfo` | `modules/account` |
| `/editor` | Editor | `pages/editor/index` | `modules/editor` |
| `/login` | Login | `pages/user-module/login` | `modules/auth` |
| `/student/book` | Student book | `pages/student/book/index` | `modules/student-book` |
Current non-contract aliases remain an implementation detail to preserve while
moving their owning route: `/books/management/list`, `/books/audit/dataset`,
`/books/sale/dataset`, `/books/order-management/dataset`, and
`/setting/help/list`.
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论