feat(admin,shop-admin): content/brand management + merchant shop profile (add-content-admin-ui)
This commit is contained in:
+17
-17
@@ -1,28 +1,28 @@
|
||||
## 1. Admin content management page
|
||||
|
||||
- [ ] 1.1 Add `apps/admin/pages/content.vue` loading all four kinds through `admin.getContent()` from `@vmall/shared` (inactive entries included) and add a content entry to the `apps/admin` nav beside existing platform operations.
|
||||
- [ ] 1.2 Implement one editor section per kind — banners, promos, quick links, floor adverts — with the exact per-entry fields the API accepts: image and destination URL for banners and promos, `{ en, zh }` label, destination URL and inline SVG glyph for quick links, and image for floor adverts, plus an active flag on every row.
|
||||
- [ ] 1.3 Support ordered row editing per kind (add, remove, move up/down — no drag and drop) and pre-validate each row with the API rules (non-empty image and destination URLs, non-empty glyph, non-empty `en` and `zh` quick-link labels), showing inline field errors before any request is sent.
|
||||
- [ ] 1.4 Save one kind at a time by submitting the whole displayed list through `admin.replaceContent(kind, items)` so the API replaces that kind atomically and reindexes positions, leaving the other three kinds untouched; render a per-entry storefront preview (image, destination, glyph/label) and clear success feedback on save.
|
||||
- [ ] 1.5 On a rejected save keep the edited rows and show a visible failure message, and add the page's bilingual strings through the existing admin locale sources.
|
||||
- [x] 1.1 Add `apps/admin/pages/content.vue` loading all four kinds through `admin.getContent()` from `@vmall/shared` (inactive entries included) and add a content entry to the `apps/admin` nav beside existing platform operations.
|
||||
- [x] 1.2 Implement one editor section per kind — banners, promos, quick links, floor adverts — with the exact per-entry fields the API accepts: image and destination URL for banners and promos, `{ en, zh }` label, destination URL and inline SVG glyph for quick links, and image for floor adverts, plus an active flag on every row.
|
||||
- [x] 1.3 Support ordered row editing per kind (add, remove, move up/down — no drag and drop) and pre-validate each row with the API rules (non-empty image and destination URLs, non-empty glyph, non-empty `en` and `zh` quick-link labels), showing inline field errors before any request is sent.
|
||||
- [x] 1.4 Save one kind at a time by submitting the whole displayed list through `admin.replaceContent(kind, items)` so the API replaces that kind atomically and reindexes positions, leaving the other three kinds untouched; render a per-entry storefront preview (image, destination, glyph/label) and clear success feedback on save.
|
||||
- [x] 1.5 On a rejected save keep the edited rows and show a visible failure message, and add the page's bilingual strings through the existing admin locale sources.
|
||||
|
||||
## 2. Admin brand management page
|
||||
|
||||
- [ ] 2.1 Add `apps/admin/pages/brands.vue` loading the registry through `admin.getBrands()` and add a brands entry to the `apps/admin` nav beside existing platform operations.
|
||||
- [ ] 2.2 Edit the whole ordered list with add, remove and move up/down rows carrying slug, non-empty `{ en, zh }` names and an active flag; pre-validate slugs against the API pattern (ascii `a-z`, `0-9`, `-`) and reject duplicate slugs and incomplete bilingual names with inline errors before any request is sent.
|
||||
- [ ] 2.3 Save the full list through `admin.replaceBrands(items)` so positions follow the displayed order, and render a preview row per brand as the public list serves it (slug and bilingual name) with clear success feedback on save.
|
||||
- [ ] 2.4 On a rejected save keep the edited rows and show a visible failure message, and add the page's bilingual strings through the existing admin locale sources.
|
||||
- [x] 2.1 Add `apps/admin/pages/brands.vue` loading the registry through `admin.getBrands()` and add a brands entry to the `apps/admin` nav beside existing platform operations.
|
||||
- [x] 2.2 Edit the whole ordered list with add, remove and move up/down rows carrying slug, non-empty `{ en, zh }` names and an active flag; pre-validate slugs against the API pattern (ascii `a-z`, `0-9`, `-`) and reject duplicate slugs and incomplete bilingual names with inline errors before any request is sent.
|
||||
- [x] 2.3 Save the full list through `admin.replaceBrands(items)` so positions follow the displayed order, and render a preview row per brand as the public list serves it (slug and bilingual name) with clear success feedback on save.
|
||||
- [x] 2.4 On a rejected save keep the edited rows and show a visible failure message, and add the page's bilingual strings through the existing admin locale sources.
|
||||
|
||||
## 3. Shop-admin profile editing
|
||||
|
||||
- [ ] 3.1 Add the minimal merchant-scoped endpoint `PUT /api/shop/profile` in `apps/api/src/modules/shop/`: an authenticated write scoped with `own_shop` over the caller's shop, reusing the existing profile upsert and `{ en, zh }` bilingual validation, accepting logo, banner, company, region, address, notice and after_sale, and never storing `score_rating`, `score_agreement`, `score_service` or `score_speed`; the service returns `ApiResult<ShopProfileView>`.
|
||||
- [ ] 3.2 Add a `shop.updateMyProfile` method to the `@vmall/shared` contract (own-profile input without score fields, returning `ShopProfile`) with live-client wiring; all frontend calls go through this shared contract only.
|
||||
- [ ] 3.3 Add `apps/shop-admin/pages/shop-profile.vue` editing the caller's own shop profile — logo and banner URLs, company, region and bilingual address, notice and after-sale copy — prefilled from `shop.getMyShop()` and the composed `getShop(slug)` read, with non-empty `en` and `zh` validation on bilingual fields and no score fields in the form.
|
||||
- [ ] 3.4 Save through `shop.updateMyProfile`, keep the form values and show a visible failure message when the write is refused (success feedback otherwise), and add the shop-profile nav entry to `apps/shop-admin` with bilingual strings through the existing shop-admin locale sources.
|
||||
- [x] 3.1 Add the minimal merchant-scoped endpoint `PUT /api/shop/profile` in `apps/api/src/modules/shop/`: an authenticated write scoped with `own_shop` over the caller's shop, reusing the existing profile upsert and `{ en, zh }` bilingual validation, accepting logo, banner, company, region, address, notice and after_sale, and never storing `score_rating`, `score_agreement`, `score_service` or `score_speed`; the service returns `ApiResult<ShopProfileView>`.
|
||||
- [x] 3.2 Add a `shop.updateMyProfile` method to the `@vmall/shared` contract (own-profile input without score fields, returning `ShopProfile`) with live-client wiring; all frontend calls go through this shared contract only.
|
||||
- [x] 3.3 Add `apps/shop-admin/pages/shop-profile.vue` editing the caller's own shop profile — logo and banner URLs, company, region and bilingual address, notice and after-sale copy — prefilled from `shop.getMyShop()` and the composed `getShop(slug)` read, with non-empty `en` and `zh` validation on bilingual fields and no score fields in the form.
|
||||
- [x] 3.4 Save through `shop.updateMyProfile`, keep the form values and show a visible failure message when the write is refused (success feedback otherwise), and add the shop-profile nav entry to `apps/shop-admin` with bilingual strings through the existing shop-admin locale sources.
|
||||
|
||||
## 4. Verification
|
||||
|
||||
- [ ] 4.1 Add integration coverage in `apps/api/tests/` reusing the `tests/common/mod.rs` fixtures for the new endpoint: a merchant upsert round-trips to the public shop read, incomplete bilingual text is refused with the stored profile unchanged, submitted score values leave the stored scores unchanged, a user without a shop is refused, and another shop's profile is untouched; run the focused `cargo test -p vmall-api --test shops`.
|
||||
- [ ] 4.2 Build all three frontends because the shared contract changes: `pnpm --filter @vmall/admin build`, `pnpm --filter @vmall/shop-admin build`, and `pnpm --filter @vmall/mall build`.
|
||||
- [ ] 4.3 Run the API and browser-smoke the admin content page (edit, reorder, per-kind save reflected on the mall home with the other kinds untouched), the admin brands page (edit and save reflected in the public brand list), and the shop-admin profile page (edit, save, and the mall store page showing the new copy for that shop only).
|
||||
- [ ] 4.4 Check every OpenSpec task and run `openspec change validate add-content-admin-ui --strict` plus `openspec validate --all --strict`.
|
||||
- [x] 4.1 Add integration coverage in `apps/api/tests/` reusing the `tests/common/mod.rs` fixtures for the new endpoint: a merchant upsert round-trips to the public shop read, incomplete bilingual text is refused with the stored profile unchanged, submitted score values leave the stored scores unchanged, a user without a shop is refused, and another shop's profile is untouched; run the focused `cargo test -p vmall-api --test shops`.
|
||||
- [x] 4.2 Build all three frontends because the shared contract changes: `pnpm --filter @vmall/admin build`, `pnpm --filter @vmall/shop-admin build`, and `pnpm --filter @vmall/mall build`.
|
||||
- [x] 4.3 Run the API and browser-smoke the admin content page (edit, reorder, per-kind save reflected on the mall home with the other kinds untouched), the admin brands page (edit and save reflected in the public brand list), and the shop-admin profile page (edit, save, and the mall store page showing the new copy for that shop only).
|
||||
- [x] 4.4 Check every OpenSpec task and run `openspec change validate add-content-admin-ui --strict` plus `openspec validate --all --strict`.
|
||||
Reference in New Issue
Block a user