- All UI copy via `$t()` / `t()`; keys live ONLY in your assigned `apps/mall/locales/<domain>.ts` file (shape: `export default { en: { <domain>: {...} }, zh: { <domain>: {...} } }`). Extend the existing structure; both en and zh always.
- Mock content fields are `LocalizedText` (`{en, zh}`); render with `t as pick` from `@vmall/shared`: `pick(text, locale)` where `const { locale } = useI18n()`.
- Money: integer minor units. Render prices ONLY via `<PriceText :amount-minor="n" currency="USD" />` (auto-imported component). No float math, no hardcoded exponent.
- Styling: scoped CSS per component using the global tokens/utilities in `apps/mall/assets/mall.css` (`--mall-red` etc., `.w1200`, `.mbtn`, `.mpanel`, `.mtable`, `.section-bg`, `.hover-lift`). No Tailwind, no element-plus, no new deps.
- Do NOT run builds/tests/dev servers; the integrator validates.
- Do NOT create/modify files outside your assigned list. If you believe a shared file must change, note it in your final report instead.
## Mock data layer (import from `~/mock/data`; read the file for full signatures)
Follow `design-reference.md` (reference digest): 1200px grid, `#ca151e` red, `#333` dark nav, hairline `#efefef` borders, 12–14px text, card hover lift, red price + struck market price, 4-step bar on transaction pages, right-floating 400px auth panel over `/mock/login-bg.svg`, user center 234px left menu + white `.mpanel` content.
| `/` | `Home/default.vue` | Home landing page: hero/banner, quick links and category product floors. `/home` response supplies `goods` groups; each group has `name`, `goods[]`, and each product has `id`, `goods_master_image`, `goods_name`, `goods_subname`, `goods_price`, `goods_market_price`. |
`views/App.vue` is only `<router-view/>`; `/Admin/login` and `/Seller/login` are separate non-buyer routes (Admin/Seller areas exist but are out of this survey). `router.js` creates a history router, installs `baseRoute`, and has global progress/auth navigation logic.
## 2. Global layout anatomy
The naming is slightly split: `views/Home/index.vue` is the shell, `views/Home/default.vue` is the actual home landing page, and `components/home/base.vue` is the shared outer layout.
1.**`components/home/top.vue` fixed top bar (`.head`, 30px):** 1200px `.head_in`; left links in order: 平台官网, separator, 商城官网, separator, 联系方式, separator, 关于我们, separator, city/location (default 北京市, optionally IP/AMap-resolved). Right side conditionally shows 登录/注册 or `欢迎您,nickname`, 个人中心, 注销账号; then 商家入驻, 手机端, APP下载. Uses `#ca151e` for login/location/merchant links.
2.**`components/home/head.vue` fixed header (`top:30px`, white):** `.center_top center1200` logo (`.shop_logo`, 242x74), then `.shop_top_seach` with 434px text input (`data.keywords`), search icon button and `.index_my_car` “我的商城/我的购物车” with cart count badge `.shop_car_dot`. Below is 40px dark `.shop_top_nav`: 240px red `.shop_top_nav_left` “全部商品” (hover mounts `leftbar`), then links 首页, 店铺街, 秒杀, 拼团, 积分商城, 帮助中心. Header collapses logo/search area after scroll >200; home category menu can collapse after scroll. Search pushes `/s/` + base64 JSON `{keywords}`.
3.**`components/home/leftbar.vue` category mega-menu:** 240px x 450px `.leftbar` (white) or `.leftbar2` (black translucent when over hero). Each top-level `goodsClass` renders `.left_bar_block`: `.class_1` top category name, `.class_2` up to three child names, and hidden hover `.subbar` 960px wide. Mega menu contains optional top tags, right brand tiles from `goodsBrand[]` (`thumb`), optional advert, and `.subbar_subnav` rows: child heading `name`, grandchildren `{id,pid,name}`. Navigation encodes `pid/sid/tid/class_id` into `/s/:params`.
4.**`components/home/base.vue`:** `<div class="home_default"><top/><div class="padding_content"/><slot name="main"/><foot/></div>`. `.padding_content` is 228px to offset fixed top + header. On mount dispatches `init/loadCommon` (common config, classes, brands, cart, etc.). In `Home/index.vue`, the main slot is `<head-view/><router-view/>`; therefore every buyer page receives the top/header/footer shell. Home `default.vue` itself is just the route content under that shell.
5.**`components/home/foot.vue`:** centered 1200px `.shop_foot`; four value propositions in order (“500强企业 品质保证”, “7天退货 15天换货”, “99元起免运费”, “448家维修网点 全国联保”), then copyright/ICP/security text interpolating `common.web_name` and `common.icp`, plus Element `el-backtop`. Replace `el-backtop` with a small fixed scroll-to-top control in Nuxt.
Element Plus pieces to replace in this shell: `el-icon`/icons (search, cart, etc.), `el-image` (native img with lazy loading), `el-carousel`/transition (CSS/Headless carousel), `el-backtop`, and any `el-breadcrumb` used by child pages.
## 3. Homepage sections and mock data
`views/Home/default.vue` is intentionally simpler than the nav labels suggest—there are no dedicated seckill/collective/brand sections in this file. Those are quick links in `banner_adv`; product floors are generic category groups.
1.**Hero carousel (`components/home/banner.vue`, first child):**`<el-carousel height=450>` → each `<el-carousel-item>` → `.shop_banner` background image (`background-position:center; background-size:cover`) → full 1200x450 router link. `banner` shape: `[{image:string, url?:string, name?:string}]`; default landing mock is one `default_banner.jpg` item. Nuxt replacement: regular CSS/JS carousel.
2.**Below-hero promo/quick-link strip (`components/home/banner_adv.vue`):**`.banner_bottom_adv center1200`; left 240px six 78x80 cells in order: 实名认证 (`/user/safe`), 积分商城, 优惠团购, 秒杀活动, 公告 (`/user`), 入驻商家. Each icon is an image; right side has up to three 312x160 linked promo images. `index_adv` shape: `[{image:string, url?:string, name?:string}]`. Uses `el-image` (replace with img).
3.**Floor background:**`.index_bg` gray `#f5f5f5`, top margin 40px and 20px/60px padding. For every `data.goods` category group, render `.goods_class_list w1200`; if `v.goods.length > 0`, first `adv-view` full-width placeholder (`adv:{image,url?}`), then `.title` group name + “查看更多”.
4.**Floor body:** left `.index_adv_goods_left` 234x614 image from `data.classLeftAdv[k].image_url` or fallback `pc_class_btadv.jpg`; right `.index_class_goods_right` 966px with product cards in `<ul>`. Product cards are 220x300 white `.product_act_in` with 140x140 image, title, subtitle, red sale price and struck market price. Floor product shape: `{id, goods_master_image, goods_name, goods_subname, goods_price, goods_market_price}`; floor group shape: `{name, goods:[product...]}`. Note `classLeftAdv` is initialized but not assigned from `/home` in the shown code, so a mock can supply it separately.
Visual card behavior: hover lifts cards by 3px and adds `0 2px 12px rgba(0,0,0,.1)`. A Nuxt mock module should include `home {goods: Floor[], classLeftAdv: Adv[]}`, `banner`, and `index_adv` even though the current banner/floor images are hardcoded assets.
## 4. Goods list (`views/Home/goods/index.vue`)
- Breadcrumb `.w1200 breadcrumb`: 首页, then either `搜索 "..." 结果列表` (decoded `keywords`) or 商品列表.
- **Filter block `.goods_where w1200`:** three `.item` rows: 商品分类, 品牌筛选, 筛选排序. Category has “全部”, top-level `common.classes`, selected second-level and third-level children; each class is `{id,name,children:[...]}`. Brand options are `{id,name}`. The route state/query shape is `{keywords?,pid?,sid?,tid?,class_id?:number[],brand_id?,sort_type?,sort_order?}` encoded in base64 path.
- **Important reference limitation:** despite a request to survey “attrs/brands/price”, this template has no attribute facet row and no price-range controls. It exposes category + brands + sort only. Do not infer an attrs/price UI from this file; if the new app adds them, it is an intentional enhancement rather than parity.
- Sort choices are default, 价格 (`goods_price`), 销量 (`goods_sale`), 评论 (`order_comment_count`), each toggling `sort_order` asc/desc. In the shown template the sort controls are also in `.goods_where`, not a separate bar.
- **Results:** `.s_goods_content`; `.s_goods_list` five cards/row (`.item` 224x364). Each card `<dl>` has 176x176 image, title, red price, footer “立即购买” and `{order_comment_count} 人评论`; links `/goods/{id}`. Product list shape: `{id,goods_master_image,goods_name,goods_price,order_comment_count}` (market/subname are not rendered here).
- **Pagination:** `.fy` Element `el-pagination` total/prev/pager/next; response fields are `data`, `total`, `per_page`, `last_page`, `current_page`; empty state is `el-empty`. Replace with plain button/page-number pagination, empty state, and native img.
- **SKU/quantity:** `attrList[]` each `{name,specs:[{id,name,is_chose?}]}`; `skuList[]` each `{id,spec_id:number[],goods_price,goods_market_price,goods_stock}`. Chosen `sku_id`, `buy_num`, current stock; “立即购买”, “加入购物车” (regular goods) or “立即抢购” (seckill). Group buy adds `collective_id`.
- **Store card / left rail:** `.goods_info_content` left `.left_item` store card with `store_info.store_name`, `store_company_name`, `area_info`, `store_address`, `id`, `user_id`; four scores in `rate_info` (`scoreAll`, `agreeAll`, `serviceAll`, `speedAll`); buttons enter store/customer service. Below, 销售排行 from `goods_info.sale_list[]` product `{id,goods_master_image,goods_name,goods_price}`.
- **Tabs:** right `.right_item` Element tabs: 商品详情 renders sanitized `goods_content`; 用户评价 renders statistics `{all,good,commonly,bad,rate}`, comment filters, paginated `comments[]` where `{avatar,nickname,score,content,image:string[],reply}`; 售后服务 renders `store_info.after_sale_service`. Replace `el-tabs`, `el-rate`, `el-pagination`, `el-image` with native tabs, stars and controls. `Chat` is a separate common component and may be replaced with a simple contact CTA if chat is not in scope.
## 6. Cart and order flow
**Cart (`views/Home/carts/index.vue`):**`.create_order_1 w1200` begins a four-step `.step_bar` (cart active, address, payment, success). If nonempty, `.cart_th` header columns are 商品, 规格, 单价(元), 数量, 小计, 操作. `.cart_table` groups `data.list` by store: store group `{store_id,store_name,checked,css,cart_list[]}`, item `{cart_id,goods_id,goods_image,goods_name,sku_name,goods_price,buy_num,checked}`. Each item has checkbox, 40px thumb/name link, SKU, +/- quantity controls, subtotal and 移除. Bottom select-all summarizes `allCount`, `allPrice` and 结算; empty `el-empty`. Pagination response state exists (`data.params={page,per_page,last_page,total}`) but no pager is rendered. Replace Element checkboxes/empty/icons.
**Order before (`orders/before.vue`):** same step bar with cart/address active. Address selection list entries `{id,receive_name,receive_tel,area_info,address,is_default}`; then order preview grouped by store. Order group includes `store_info:{id,store_logo,store_name}`, `coupon_id`, `coupons[]:{id,money}`, `is_coupon`, `goods_list[]:{goods_master_image,goods_name,sku_name,goods_price,buy_num,total}`. Shows remark textarea (`data.remark`), total, create-order button. Submit payload uses encoded route `params`, `address_id`, comma-joined `coupon_id`, `remark`.
**Order pay (`orders/pay.vue`):** step bar through payment; balance panel `userInfo.money`; payment options are balance/password, WeChat and Alipay. Displays generated `order[]` groups `{order_no,coupon_money,order_goods[]:{goods_image,goods_name,sku_name,goods_price,buy_num,total_price}}`, `total`, `freight_money`; balance password and QR modal state `{pay_password,qr_code}`. Replace `el-dialog`, QR Vue and Element grid with Tailwind modal/grid and a QR library.
**Order success (`orders/success.vue`):** all four steps active, success result (“订单支付成功!”), link to `/user`; replace Element `el-result` with a simple success panel.
## 7. User center
`Home/users/index.vue` is a two-column `.user_default` shell: 234px `.user_left` + 20px gap, 946px `.user_right` with nested `<router-view>`. Profile card has avatar, `nickname`, edit link, account-profile progress (`check`) and safety indicators (`phone`, `check`). Nav menu groups/items, in order:
- **帮助中心:** 网站公告、其他合作、帮助中心、关于我们 at `/user/article/:name`.
`users/default.vue` dashboard data shape: `user_info:{money,integral,frozen_money}`, `count[5]` for pending payment/shipping/receipt/comment/after-sale, `order[]` with `{id,created_at,order_no,order_status,order_status_cn,order_goods[]:{goods_image,goods_name,sku_name,buy_num,total_price}}`, `fav[]` with `{out_id,goods_master_image,goods_name,goods_price}`, and local `history[]` with `{id,image,goods_name,goods_price}`. It renders balance cards, five status links/badges, recent orders, recent favorites and browsing history, all in `.user_main` cards.
- **Orders:** filter `{order_status,order_no,created_at:[start,end],is_type}`; statuses -1/0/1/2/3/4/5/6 = all/cancelled/wait-pay/wait-ship/wait-receive/wait-comment/after-sale/completed. Cards use the same order/item shape above and action buttons; logistics modal expects `order_info.delivery_list[]:{context,time}`.
- **Favorites:** toggle `isGoods`; product table fields `goods_master_image,goods_name,goods_price,created_at`, store table fields `store_logo,store_name,created_at`, records carry `is_type,out_id`.
- **Coupons:** generic table columns `name,money,use_money,end_time,created_at`; no custom card UI. `table-view` is a large Element-based shared component and should be replaced with a plain responsive table in Nuxt.
## 8. Stores, seckill, collective and integral pages
- **Stores list (`stores/list.vue`):** breadcrumb + one sort row (default/distance), then store rows with 80px logo and `{id,store_logo,store_name,store_company_name,area_info,store_address,distance}`; center hardcodes 好评率 100%, right shows distance and 进入店铺; 30/page pagination. Location comes from local `lonlat`. Replace `el-breadcrumb`, icons, image and pagination.
- **Store info (`stores/info.vue`):** 350px banner from `store_info.store_slide[]`, left store profile/rates/company/address/favorite/contact and sales ranking; right store-scoped sort (default/price/sales/comments) plus 220x300 product cards with `{id,goods_master_image,goods_name,goods_subname,goods_price,goods_market_price}` and pagination. Store payload adds `id,user_id,store_verify,store_status,store_logo,sale_list[]`, `rate:{scoreAll,agreeAll,serviceAll,speedAll}`, and `after_sale_service` where relevant.
- **Seckills (`seckills/index.vue`):** breadcrumb, four equal timed session selectors (`timeList` hours, `timeIndex`, `timeFormat` countdown), then a 4-column product grid using `{id,goods_master_image,goods_name,goods_subname,goods_price,goods_market_price}`, paginated by `{page,per_page,last_page,total,start_time}`. Countdown refreshes the page when the hour expires.
- **Collectives (`collectives/index.vue`):** 350px collective banner, then the same 3-row category/brand/sort filter and 5-column standard goods cards as `/s`; API query adds `is_collective:1`. Mock the same class/brand/filter/product/page shapes as goods list.
- **Integral home (`integral/index.vue`):** 350px banner, four info blocks (login/register or avatar + `userInfo.integral`, plus private customization/24H/priority cards), then “热门推荐” and category rails. Data is `{store_slide?,userInfo:{avatar,integral},recommend:[{id,goods_master_image,goods_name,goods_price,goods_market_price}],list:[{name,integral_goods:[same product shape]}]}`.
- **Integral goods/detail/order:** `integral/goods.vue` is a category/sort-only list (`class[]:{id,name}`, product card uses “立即兑换”); `integral/info.vue` is zoom gallery + points price/market price, sale/stock and quantity, “立即兑换”, with `goods_content`; `integral/orders/index.vue` reuses address/remark four-step checkout but has one points product `{goods_master_image,goods_name,sku_name,goods_price,buy_num}`, and submits `{id,buy_num,address_id,remark}` to points pay.
## 9. Auth pages
All three use `.home_login` with `user_login__bgs.png`, a 1200px `.login_block`, and right-floating white `.login_item` 400x450, 40px padding, 50px top margin. Inputs are 320px wide, 35px high; submit is full-width red `#ca151e`; no shared top/header is rendered inside the auth template (they still are routed beneath the Home shell in the current route tree).
- **Login:** title tabs “帐号登录 | 扫码登录”; `username`, `password`; 登录 button; links 注册 and 忘记密码; Element divider and WeChat icon/click. Mock `{username,password,provider:'users'}`.
- **Register:** title “注册账号 | 账号登录”; `username` (phone), `password`, `re_password`, SMS `code`, send-code countdown (`code_text`, `math`); 注册 + forgot-password link. Optional inviter id from query/session. Mock `{username,password,re_password,code,code_text,math}`.
- **Forgot password:** title “忘记密码 | 账号登录”; `username`, new `password`, `re_password`, SMS `code`, send-code state; 确定 + 立即登录. Same `{username,password,re_password,code,code_text,math}`.
Element replacements here: `el-divider` → border/label, `el-message` → toast, and ordinary inputs/buttons can be native/Tailwind.
## 10. Theme and visual language
-`plugins/css/style.css` resets body/common block margins and list styles, sets `html,body,#app` height 100%, base `font-size:14px`, color `#333`, no explicit `font-family` (browser/system font applies). Links default `#333` with no decoration; hover `#000`. `body` margin is zero.
- Fixed desktop container is `.center1200` and `.w1200`, both `width:1200px;margin:0 auto`; floats are `.float_left/.float_right`; `.clear` clears floats. Other recurring utility classes: `.breadcrumb` (30px vertical margin), `.shadow` (`0 2px 12px rgba(0,0,0,.1)`), `.x20` 1px gray divider with 20px margin, `.user_main` white padded card, `.table_lists` min-height 600px, `.block_title` 16px with 3px red left border.
-`base.scss` has `$admin_background:#f4f4f4`; `.home` Element primary CSS vars are `--el-color-primary:#e50e19` and light variants, but storefront source consistently uses `#ca151e` for active links, red prices, buttons, selected filters, nav, and borders. Preserve both: `#ca151e` is the visual brand red; `#e50e19` is Element theme fallback. Status colors are green `#67c23a`, gray `#909399`, yellow `#e6a23c`, red `#f56c6c` (round utility classes).
- Button language: white bordered `.default_btn`, red `.error_btn`, yellow `.warn_btn`, green `.success_btn`, gray `.gray_btn`; all compact 12px, 3px radius, 6px/15px padding. Cards/rows are mostly white with `#efefef` 1px rules, subtle hover lift/shadow, restrained 12–16px text, and red price emphasis. Home/floor backgrounds use `#f5f5f5`; user center uses `#f1f1f1`; header nav is `#333` with a red category block.
- Replication recommendation: keep 1200px desktop grid, 20–30px section rhythm, 20px card gaps, 40px header/nav spacing, 220–224px product cards, gray separators, low-radius 3px controls, red active states and strikethrough market prices. Since the reference relies heavily on Element Plus (`el-carousel`, `el-image`, `el-breadcrumb`, `el-pagination`, `el-empty`, `el-checkbox`, `el-select`, `el-dialog`, `el-form`, `el-tabs`, `el-rate`, `el-result`, `el-badge`, `el-progress`, `el-timeline`, `el-icon`), a fresh Nuxt 3/Tailwind build should provide plain semantic replacements rather than porting Element’s runtime.
The current mall is a bare API-wired storefront (plain grid, minimal chrome). We want a real PC mall experience modeled on a classic open-source B2B2C buyer mall (Vue2 + element-plus, outdated): its layout, components and visual language — but rebuilt in our Nuxt 3 stack. The backend assortment/marketing/user-center endpoints for this experience do not exist yet, so the MVP serves everything from fixed mock data behind a mock API adapter, keeping the `$api` call shape so pages can later switch back to the live API without rewrites.
## What changes
-`apps/mall` is rebuilt as a full PC storefront replicating a classic B2B2C buyer mall: fixed top bar + header (logo/search/cart badge) + dark nav with category mega-menu + footer; 1200px container, `#ca151e` brand red, card/floor visual language (see `design-reference.md`).
- Mock layer: `apps/mall/mock/` provides (a) a `createMockApi()` adapter implementing the existing `@vmall/shared` API client surface with fixed data, selected via `runtimeConfig.public.mockApi` (default `true`), and (b) a mall-local mock content module for surfaces the real API has no counterpart for (banners, home floors, brands, seckill sessions, collectives, stores, comments, coupons, addresses, user dashboard stats).
- Pages (all mock-backed):
- Home `/`: hero carousel, quick-link/promo strip, category product floors.
- Element Plus widgets are NOT ported; plain Nuxt equivalents are built (carousel, pagination, tabs, checkbox, dialog, empty state, back-to-top, rating stars).
- All UI copy stays `$t()`-driven (en/zh via `locales-extra.ts`); mock content fields keep the `{"en","zh"}` JSONB shape; money stays integer minor units through `formatMoney`.
## Non-goals
- No backend changes; no changes to `@vmall/shared` contract, shop-admin, or admin apps.
- No SEO/SSR tuning, no real payment, no chat/customer-service, no distribution/cash/integral-order subsystems beyond display mocks.
- No element-plus or Tailwind introduction; styling is scoped CSS in the mall app.
## Capabilities
-`frontend-mall`: rebuilt PC storefront experience (mock-backed MVP).
### Requirement: B2B2C mall-style PC storefront shell
The mall SHALL render a buyer-facing desktop shell modeled on a classic B2B2C PC mall: a 30px utility bar, logo/search/cart header, dark primary navigation with a hover category mega-menu, a 1200px content grid, and a value-proposition footer. The visual language SHALL use #ca151e for brand/price/active states, #f5f5f5 section backgrounds, gray hairline borders, compact controls, and product-card hover lift/shadow. The implementation SHALL use Nuxt-native semantic components and SHALL NOT depend on Element Plus.
#### Scenario: shopper opens any mall page
- **WHEN** a shopper navigates to a buyer-facing route
- **THEN** the shared desktop shell wraps the route content and its nav/search/cart controls are usable
### Requirement: Mock API adapter
The mall SHALL default to a fixed-data mock adapter that implements the existing `@vmall/shared` API client surface. The adapter SHALL support auth, catalog, currency conversion, cart mutation, checkout, order/payment/shipment state, and invoices without a backend. A runtime configuration switch SHALL select the live API client later without changing page call sites.
#### Scenario: mall runs without backend
- **WHEN** the mall starts with mock mode enabled and the API service is unavailable
- **THEN** browsing, cart, checkout, payment, orders and invoice pages return deterministic mock data and remain functional
### Requirement: Mock PC home page
The mall home page SHALL render a hero carousel, a six-item quick-link strip with promotion tiles, and bilingual product floors with a left advert and product-card grid.
#### Scenario: shopper lands on home
- **WHEN** `/` loads in mock mode
- **THEN** the carousel, quick links, promotions and every non-empty product floor render fixed mock content
### Requirement: Product discovery pages
The mall SHALL provide `/search` with breadcrumb, category, brand and sort controls, a five-column desktop product grid, pagination and an empty state. It SHALL provide `/goods/[id]` with image gallery/zoom, bilingual name/subtitle, integer-minor-unit prices, attribute and SKU selection, stock-aware quantity, coupons/activity summary, store card, sales rail, and detail/comments/after-sale tabs.
#### Scenario: filter and inspect a product
- **WHEN** a shopper filters the search page and opens a product
- **THEN** matching mock cards are shown and selecting an in-stock SKU updates the displayed price, stock and cart target
### Requirement: Mock transaction flow
The mall SHALL provide a store-grouped cart, address-selecting checkout preview, mock payment selection and payment-success result. Cart quantity/removal, selection totals, checkout and mock payment SHALL update the in-memory mock state for the current browser session.
#### Scenario: complete mock purchase
- **WHEN** a shopper adds an in-stock SKU, checks out with a mock address and confirms a mock payment
- **THEN** the cart is cleared, the success page is shown and the new order appears in the user order list
### Requirement: Auth and buyer center
The mall SHALL provide B2B2C mall-style login, register and forgot-password panels backed by deterministic mock auth. `/user` SHALL render a two-column buyer center with dashboard, order list/detail, addresses, favorites, coupons and invoices.
#### Scenario: sign in and inspect buyer data
- **WHEN** a shopper submits the mock login form and opens `/user`
- **THEN** the buyer-center shell and fixed account/order/address/favorite/coupon/invoice data render without backend access
### Requirement: Store and marketing pages
The mall SHALL provide a store directory, store home, timed seckill page, collective-buy list and points-mall home using fixed bilingual mock content. Marketing pages MAY be display-only except navigation to product detail.
- **WHEN** a shopper opens stores, seckill, collective or integral routes
- **THEN** each page renders the appropriate B2B2C mall-style banner/filter/session/card layout and product links resolve to mock product details
## MODIFIED Requirements
### Requirement: Localized storefront
The mall SHALL render every UI string and all catalog/store/marketing mock content in en or zh from one switcher, defaulting to en. Switching locale SHALL update the desktop shell and current page without a full reload.
#### Scenario: switch to Chinese
- **WHEN** a shopper switches locale to zh
- **THEN** navigation, buttons, product/store names and mock marketing content render in Chinese without reload errors
### Requirement: Multi-currency display
The mall SHALL offer a currency switcher sourced from the selected API adapter and SHALL convert product, cart and order prices through integer minor units and each currency's exponent. Mock mode SHALL use deterministic fixed conversion rates; live mode SHALL use the API.
#### Scenario: switch currency
- **WHEN** a shopper switches from USD to JPY on a product priced $10.00
- **THEN** the displayed price reflects the selected adapter's conversion rate with JPY exponent 0 and no floating-point money arithmetic
### Requirement: Shopping flow
A shopper SHALL be able to browse, view detail, add to cart, checkout with a shipping address, pay (mock), track orders/shipments, confirm delivery, and request an invoice through the selected API adapter. The MVP SHALL default to the fixed-data mock adapter and SHALL not require the live API.
#### Scenario: end-to-end purchase
- **WHEN** a shopper completes checkout on a non-empty mock cart
- **THEN** the resulting order appears in the buyer center and the cart is empty
- [x]`apps/mall/mock/data.ts`: fixed bilingual catalog (categories tree, brands, products+SKUs+images, stores, banners, home floors, seckill sessions, collectives, integral goods, comments, coupons, addresses, user profile/orders/invoices), money in minor units
- [x]`apps/mall/mock/api.ts`: `createMockApi()` implementing the `@vmall/shared` client surface (auth, products, categories, currencies+convert, cart with in-memory state, checkout, orders, shipments, invoices) returning fixed/derived data
- [x]`apps/mall/plugins/api.ts`: select mock vs real client via `runtimeConfig.public.mockApi` (default `true`)
- [x]`openspec change validate mall-pc-storefront-replica --strict` green
- [x] Browser smoke: home, search, goods detail (SKU pick), cart → checkout → pay → success, login, user center, stores, seckill — in both locales
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.