feat(mall): classic B2B2C PC storefront with fixed mock API layer
- Mock adapter implementing @vmall/shared ApiClient (localStorage-persisted cart/orders/invoices), runtime switch via mockApi flag (default on) - Fixed bilingual mock catalog: 3-level categories, 24 products w/ SKUs, stores, brands, banners, floors, seckill/collective/integral, comments, coupons, addresses, seeded orders/shipments/invoices - B2B2C mall shell: top bar, logo/search/cart header, dark nav + category mega-menu, value-prop footer, back-to-top; 1200px grid, #ca151e theme - UI primitives replacing element-plus: carousel, pagination, breadcrumb, qty stepper, rating stars, modal, tabs, step bar, product card - Pages: home floors, search (filters/sort/paging), goods detail (SKU picker, store rail, review tabs), cart -> checkout -> pay -> success, auth pages, user center (dashboard/orders/addresses/favorites/coupons/ invoices), stores, seckill, collective, integral - i18n split into per-domain locale modules (en+zh) - OpenSpec change mall-pc-storefront-replica archived; all specs green
This commit is contained in:
+47
-105
@@ -1,111 +1,53 @@
|
||||
// App-local message extensions, deep-merged over @vmall/shared locales.
|
||||
// Add keys here (never edit the shared locale files from an app agent).
|
||||
export const enExtra = {
|
||||
mall: {
|
||||
catalogTitle: "Shop products",
|
||||
searchPlaceholder: "Search products",
|
||||
categoryPlaceholder: "Choose a category",
|
||||
allCategories: "All categories",
|
||||
clear: "Clear",
|
||||
viewDetails: "View details",
|
||||
noImage: "No image",
|
||||
noProducts: "No products found",
|
||||
productDescription: "Description",
|
||||
attributes: "Attributes",
|
||||
sku: "SKU",
|
||||
chooseSku: "Choose an option",
|
||||
quantity: "Quantity",
|
||||
available: "available",
|
||||
unavailable: "Unavailable",
|
||||
addedToCart: "Added to cart",
|
||||
cartItems: "Cart items",
|
||||
lineTotal: "Line total",
|
||||
orderPreview: "Order preview",
|
||||
checkoutTitle: "Checkout",
|
||||
placeOrder: "Place order",
|
||||
orderSuccess: "Your order has been placed",
|
||||
orderNumbers: "Order numbers",
|
||||
viewOrders: "View orders",
|
||||
backToShop: "Continue shopping",
|
||||
noOrders: "No orders found",
|
||||
created: "Created",
|
||||
items: "Items",
|
||||
address: "Address",
|
||||
shipments: "Shipments",
|
||||
invoices: "Invoices",
|
||||
noInvoice: "No invoice requested",
|
||||
invoiceRequested: "Invoice requested",
|
||||
notAvailable: "—",
|
||||
companyTaxRequired: "Tax number is required for company invoices",
|
||||
invalidQuantity: "Enter a valid quantity",
|
||||
loadFailed: "Unable to load data",
|
||||
signInRequired: "Please sign in to continue",
|
||||
filter: "Filter",
|
||||
details: "Details",
|
||||
update: "Update",
|
||||
confirm: "Confirm",
|
||||
totalItems: "Total items",
|
||||
shippingOptional: "Optional",
|
||||
orderDetails: "Order details",
|
||||
payment: "Payment",
|
||||
requestInvoiceForOrder: "Request an invoice for this order",
|
||||
},
|
||||
auth: {
|
||||
wrongRole: "This account is not a customer account",
|
||||
},
|
||||
} as Record<string, unknown>;
|
||||
// Each domain module owns its own namespace; register new domains below.
|
||||
// (Never edit the shared locale files from an app agent.)
|
||||
|
||||
export const zhExtra = {
|
||||
import shell from "./locales/shell";
|
||||
import home from "./locales/home";
|
||||
import search from "./locales/search";
|
||||
import product from "./locales/product";
|
||||
import cart from "./locales/cart";
|
||||
import checkout from "./locales/checkout";
|
||||
import auth from "./locales/auth";
|
||||
import user from "./locales/user";
|
||||
import stores from "./locales/stores";
|
||||
import marketing from "./locales/marketing";
|
||||
|
||||
type Tree = Record<string, unknown>;
|
||||
|
||||
function deepMerge<T extends Tree>(base: T, extra: Tree): T {
|
||||
const out: Tree = { ...base };
|
||||
for (const [k, v] of Object.entries(extra)) {
|
||||
const b = out[k];
|
||||
out[k] = b && v && typeof b === "object" && typeof v === "object"
|
||||
? deepMerge(b as Tree, v as Tree)
|
||||
: v;
|
||||
}
|
||||
return out as T;
|
||||
}
|
||||
|
||||
// Keys referenced by retained shared components (PriceText) and generic handlers.
|
||||
const legacyEn: Tree = {
|
||||
mall: {
|
||||
catalogTitle: "选购商品",
|
||||
searchPlaceholder: "搜索商品",
|
||||
categoryPlaceholder: "选择分类",
|
||||
allCategories: "全部分类",
|
||||
clear: "清除",
|
||||
viewDetails: "查看详情",
|
||||
noImage: "暂无图片",
|
||||
noProducts: "未找到商品",
|
||||
productDescription: "商品描述",
|
||||
attributes: "属性",
|
||||
sku: "SKU",
|
||||
chooseSku: "选择规格",
|
||||
quantity: "数量",
|
||||
available: "件可用",
|
||||
unavailable: "暂不可用",
|
||||
addedToCart: "已加入购物车",
|
||||
cartItems: "购物车商品",
|
||||
lineTotal: "行合计",
|
||||
orderPreview: "订单预览",
|
||||
checkoutTitle: "结算",
|
||||
placeOrder: "提交订单",
|
||||
orderSuccess: "订单提交成功",
|
||||
orderNumbers: "订单号",
|
||||
viewOrders: "查看订单",
|
||||
backToShop: "继续购物",
|
||||
noOrders: "暂无订单",
|
||||
created: "创建时间",
|
||||
items: "商品数",
|
||||
address: "地址",
|
||||
shipments: "发货信息",
|
||||
invoices: "发票",
|
||||
noInvoice: "尚未申请发票",
|
||||
invoiceRequested: "发票已申请",
|
||||
notAvailable: "—",
|
||||
companyTaxRequired: "企业发票必须填写税号",
|
||||
invalidQuantity: "请输入有效数量",
|
||||
loadFailed: "无法加载数据",
|
||||
signInRequired: "请先登录",
|
||||
filter: "筛选",
|
||||
details: "详情",
|
||||
update: "更新",
|
||||
confirm: "确认",
|
||||
totalItems: "商品总数",
|
||||
shippingOptional: "可选",
|
||||
orderDetails: "订单详情",
|
||||
payment: "支付",
|
||||
requestInvoiceForOrder: "申请本订单发票",
|
||||
loadFailed: "Unable to load data",
|
||||
},
|
||||
auth: {
|
||||
wrongRole: "此账号不是买家账号",
|
||||
};
|
||||
|
||||
const legacyZh: Tree = {
|
||||
mall: {
|
||||
notAvailable: "—",
|
||||
loadFailed: "加载失败",
|
||||
},
|
||||
} as Record<string, unknown>;
|
||||
};
|
||||
|
||||
const domains = [shell, home, search, product, cart, checkout, auth, user, stores, marketing];
|
||||
|
||||
export const enExtra: Tree = domains.reduce<Tree>(
|
||||
(acc, m) => deepMerge(acc, m.en as Tree),
|
||||
legacyEn,
|
||||
);
|
||||
export const zhExtra: Tree = domains.reduce<Tree>(
|
||||
(acc, m) => deepMerge(acc, m.zh as Tree),
|
||||
legacyZh,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user