替代 Shopify/WooCommerce,用 AI 搭建自有电商网站,产品目录、购物车、订单管理一步到位
* Preview is for reference only. Actual results may vary depending on the AI model, variable values, and tools used.
你是一位资深全栈开发者和电商系统架构师。请为我搭建一个完整的自有电商网站,替代 Shopify/WooCommerce,让马来西亚中小企业老板拥有自己的网店。
## 项目基本信息
- 店铺名称:{store_name}
- 店铺类型:{store_type}
- 货币:{currency}
- 税率(SST):{tax_rate}
- 快递公司:{shipping_provider}
- 品牌主色调:{primary_color}
## 技术栈
- 前端 + 后端:Next.js 16(App Router)+ TypeScript
- 样式:Tailwind CSS 4 + shadcn/ui
- 数据库 + 认证 + 存储:Supabase(Postgres + Auth + Storage)
- 支付:Stripe(信用卡/FPX)+ 手动转账(银行转账/Touch n Go)
- 部署:Vercel
## 数据库模型(Supabase Postgres)
请创建以下完整的数据库 schema,包含 RLS 策略和索引:
### 核心表
1. **categories**(产品分类)
- id uuid PK default gen_random_uuid()
- slug text UNIQUE NOT NULL
- name text NOT NULL
- description text
- image_url text
- parent_id uuid FK references categories(id)(支持子分类)
- sort_order int default 0
- is_active boolean default true
- created_at timestamptz default now()
2. **products**(产品)
- id uuid PK default gen_random_uuid()
- slug text UNIQUE NOT NULL
- name text NOT NULL
- description text(富文本,Markdown 格式)
- short_description text(列表页摘要,限100字)
- category_id uuid FK references categories(id)
- base_price decimal(10,2) NOT NULL
- compare_at_price decimal(10,2)(划线价)
- cost_price decimal(10,2)(成本价,仅管理员可见)
- sku text UNIQUE
- barcode text
- weight_kg decimal(5,2) default 0.5
- is_active boolean default true
- is_featured boolean default false
- seo_title text
- seo_description text
- avg_rating decimal(2,1) default 0
- review_count int default 0
- total_sold int default 0
- created_at timestamptz default now()
- updated_at timestamptz default now()
3. **product_variants**(产品变体:颜色、尺码等)
- id uuid PK
- product_id uuid FK references products(id) ON DELETE CASCADE
- name text NOT NULL(如 '红色 / XL')
- sku text UNIQUE
- price_adjustment decimal(10,2) default 0(相对 base_price 的加减)
- stock_quantity int default 0
- low_stock_threshold int default 5
- weight_kg decimal(5,2)
- is_active boolean default true
- sort_order int default 0
- INDEX on product_id
4. **variant_options**(变体选项定义)
- id uuid PK
- product_id uuid FK references products(id) ON DELETE CASCADE
- option_name text NOT NULL(如 '颜色', '尺码')
- option_values text[] NOT NULL(如 ['红色','蓝色','黑色'])
- sort_order int default 0
5. **product_images**(产品图片)
- id uuid PK
- product_id uuid FK references products(id) ON DELETE CASCADE
- url text NOT NULL(Supabase Storage URL)
- alt_text text
- is_primary boolean default false
- sort_order int default 0
- INDEX on product_id
6. **customers**(客户账户,可选注册)
- id uuid PK references auth.users(id)
- email text NOT NULL
- full_name text
- phone text
- default_address jsonb
- created_at timestamptz default now()
7. **orders**(订单)
- id uuid PK
- order_number text UNIQUE NOT NULL(格式:{store_name 缩写}-20260409-0001)
- customer_id uuid FK references customers(id)(NULL = 游客结账)
- guest_email text
- guest_phone text
- status text default 'pending'(pending / confirmed / processing / shipped / delivered / cancelled / refunded)
- payment_status text default 'unpaid'(unpaid / paid / partial / refunded)
- payment_method text(stripe / bank_transfer / tng / cod)
- stripe_payment_intent_id text
- subtotal decimal(10,2) NOT NULL
- shipping_cost decimal(10,2) default 0
- tax_amount decimal(10,2) default 0
- discount_amount decimal(10,2) default 0
- total decimal(10,2) NOT NULL
- promo_code_id uuid FK references promo_codes(id)
- shipping_address jsonb NOT NULL
- billing_address jsonb
- shipping_method text(standard / express)
- tracking_number text
- tracking_url text
- notes text(客户备注)
- admin_notes text(内部备注)
- created_at timestamptz default now()
- updated_at timestamptz default now()
- INDEX on customer_id
- INDEX on status
- INDEX on order_number
8. **order_items**(订单明细)
- id uuid PK
- order_id uuid FK references orders(id) ON DELETE CASCADE
- product_id uuid FK references products(id)
- variant_id uuid FK references product_variants(id)
- product_name text NOT NULL(快照)
- variant_name text(快照)
- quantity int NOT NULL
- unit_price decimal(10,2) NOT NULL
- total_price decimal(10,2) NOT NULL
- INDEX on order_id
9. **order_status_history**(订单状态变更记录)
- id uuid PK
- order_id uuid FK references orders(id) ON DELETE CASCADE
- old_status text
- new_status text NOT NULL
- note text
- changed_by uuid FK references auth.users(id)
- created_at timestamptz default now()
10. **promo_codes**(促销码)
- id uuid PK
- code text UNIQUE NOT NULL(大写,如 RAYA2026)
- description text
- discount_type text NOT NULL(percentage / fixed_amount)
- discount_value decimal(10,2) NOT NULL
- minimum_order decimal(10,2) default 0(最低消费)
- maximum_discount decimal(10,2)(百分比折扣的封顶金额)
- usage_limit int(总使用次数限制)
- used_count int default 0
- per_customer_limit int default 1
- valid_from timestamptz NOT NULL
- valid_until timestamptz NOT NULL
- is_active boolean default true
- applicable_categories uuid[](限定分类,NULL=全场适用)
- created_at timestamptz default now()
11. **product_reviews**(产品评价)
- id uuid PK
- product_id uuid FK references products(id) ON DELETE CASCADE
- customer_id uuid FK references customers(id)
- order_id uuid FK references orders(id)
- rating int NOT NULL CHECK (rating >= 1 AND rating <= 5)
- title text
- comment text
- is_verified boolean default false(已购买验证)
- is_approved boolean default false(管理员审核)
- created_at timestamptz default now()
- INDEX on product_id
- UNIQUE on (product_id, customer_id, order_id)
12. **shipping_zones**(运费区域)
- id uuid PK
- name text NOT NULL(如 '西马', '东马', '新加坡')
- states text[] NOT NULL
- base_rate decimal(10,2) NOT NULL(首重运费)
- per_kg_rate decimal(10,2) NOT NULL(续重运费/公斤)
- free_shipping_threshold decimal(10,2)(满额免运费)
- estimated_days text(如 '2-3 工作日')
- is_active boolean default true
13. **inventory_log**(库存变动记录)
- id uuid PK
- variant_id uuid FK references product_variants(id)
- change_quantity int NOT NULL(正数=入库,负数=出库)
- reason text NOT NULL(sale / restock / adjustment / return)
- reference_id uuid(关联 order_id 或其他)
- created_at timestamptz default now()
- INDEX on variant_id
14. **store_settings**(店铺设置,单行表)
- id uuid PK
- store_name text
- logo_url text
- currency text default 'MYR'
- tax_rate decimal(4,2) default 6.00
- tax_label text default 'SST'
- contact_email text
- contact_phone text
- contact_whatsapp text
- address text
- social_links jsonb
- announcement_bar text(顶部公告栏)
- bank_transfer_details jsonb(手动转账银行信息)
### RLS 策略(关键)
```sql
-- 产品和分类:公开可读
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY 'public_read_products' ON products FOR SELECT USING (is_active = true);
CREATE POLICY 'admin_all_products' ON products FOR ALL USING ((select auth.uid()) IN (SELECT user_id FROM admin_users));
-- 订单:客户只能看自己的
CREATE POLICY 'customer_read_own_orders' ON orders FOR SELECT USING ((select auth.uid()) = customer_id);
-- 评价:公开可读已审核的
CREATE POLICY 'public_read_approved_reviews' ON product_reviews FOR SELECT USING (is_approved = true);
CREATE POLICY 'customer_create_review' ON product_reviews FOR INSERT WITH CHECK ((select auth.uid()) = customer_id);
```
### 数据库函数
```sql
-- 1. 库存自动扣减(订单确认时触发)
CREATE OR REPLACE FUNCTION deduct_inventory(p_order_id uuid)
RETURNS void AS $$
BEGIN
UPDATE product_variants pv
SET stock_quantity = stock_quantity - oi.quantity
FROM order_items oi
WHERE oi.order_id = p_order_id
AND oi.variant_id = pv.id;
-- 记录库存变动
INSERT INTO inventory_log (variant_id, change_quantity, reason, reference_id)
SELECT oi.variant_id, -oi.quantity, 'sale', p_order_id
FROM order_items oi WHERE oi.order_id = p_order_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
-- 2. 运费计算
CREATE OR REPLACE FUNCTION calculate_shipping(p_state text, p_total_weight decimal)
RETURNS TABLE(zone_name text, shipping_cost decimal, estimated_days text) AS $$
BEGIN
RETURN QUERY
SELECT sz.name,
CASE WHEN p_total_weight <= 1 THEN sz.base_rate
ELSE sz.base_rate + (CEIL(p_total_weight - 1) * sz.per_kg_rate)
END,
sz.estimated_days
FROM shipping_zones sz
WHERE p_state = ANY(sz.states) AND sz.is_active = true;
END;
$$ LANGUAGE plpgsql;
-- 3. 促销码验证
CREATE OR REPLACE FUNCTION validate_promo_code(p_code text, p_order_total decimal)
RETURNS jsonb AS $$
DECLARE
v_promo promo_codes%ROWTYPE;
v_discount decimal;
BEGIN
SELECT * INTO v_promo FROM promo_codes
WHERE code = UPPER(p_code) AND is_active = true
AND now() BETWEEN valid_from AND valid_until
AND (usage_limit IS NULL OR used_count < usage_limit);
IF NOT FOUND THEN
RETURN jsonb_build_object('valid', false, 'error', '促销码无效或已过期');
END IF;
IF p_order_total < v_promo.minimum_order THEN
RETURN jsonb_build_object('valid', false, 'error', '最低消费 ' || v_promo.minimum_order || ' 才能使用此促销码');
END IF;
IF v_promo.discount_type = 'percentage' THEN
v_discount := p_order_total * v_promo.discount_value / 100;
IF v_promo.maximum_discount IS NOT NULL AND v_discount > v_promo.maximum_discount THEN
v_discount := v_promo.maximum_discount;
END IF;
ELSE
v_discount := v_promo.discount_value;
END IF;
RETURN jsonb_build_object('valid', true, 'discount', v_discount, 'promo_id', v_promo.id);
END;
$$ LANGUAGE plpgsql;
-- 4. 更新产品平均评分(评价审核后触发)
CREATE OR REPLACE FUNCTION update_product_rating()
RETURNS TRIGGER AS $$
BEGIN
UPDATE products SET
avg_rating = (SELECT ROUND(AVG(rating)::numeric, 1) FROM product_reviews WHERE product_id = NEW.product_id AND is_approved = true),
review_count = (SELECT COUNT(*) FROM product_reviews WHERE product_id = NEW.product_id AND is_approved = true)
WHERE id = NEW.product_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_update_rating
AFTER INSERT OR UPDATE ON product_reviews
FOR EACH ROW EXECUTE FUNCTION update_product_rating();
```
## 页面结构和 UI/UX 规范
### 1. 店铺首页(/)
- 顶部公告栏(可关闭,背景色 {primary_color})
- 导航栏:Logo + 分类下拉 + 搜索框 + 购物车图标(带数量角标)+ 账户
- Hero Banner 轮播(3张,支持后台上传)
- 精选产品网格(4列桌面/2列手机,Card 布局)
- 分类导航(图标+文字卡片,水平滚动)
- 新品上架 / 热卖排行 分区
- 店铺优势条(免运费门槛、退货政策、客服WhatsApp)
- Footer:联系方式、快速链接、社交媒体
### 2. 产品列表页(/products, /category/[slug])
- 左侧筛选栏(桌面)/ 底部 Sheet 筛选(手机)
- 分类筛选
- 价格区间(滑块)
- 评分筛选(4星以上等)
- 排序:最新、价格低到高、价格高到低、最热卖、最高评分
- 产品卡片:图片 + 名称 + 价格(划线价+现价)+ 评分星星 + 已售数量
- 无限滚动或分页(cursor-based)
### 3. 产品详情页(/product/[slug])— SEO 友好
- 面包屑导航
- 产品图片画廊(主图 + 缩略图列表,支持放大)
- 产品信息区:名称、评分、价格、短描述
- 变体选择器(颜色色块 + 尺码按钮)
- 数量选择器 + 加入购物车按钮({primary_color} 背景)
- 库存状态显示(有货 / 仅剩 X 件 / 缺货)
- Tab 切换:详细描述 | 规格参数 | 评价({review_count}条)
- 相关产品推荐(同分类)
- generateMetadata 动态 SEO:title, description, og:image
- JSON-LD 结构化数据(Product schema)
### 4. 购物车(/cart)
- 购物车商品列表(图片、名称、变体、单价、数量调整、小计、删除)
- 促销码输入框 + 应用按钮
- 价格明细:小计、运费、税(SST {tax_rate})、折扣、总计
- 结账按钮
- 购物车数据存储在 localStorage(游客)/ Supabase(已登录)
### 5. 结账页(/checkout)
- 步骤指示器:收货信息 > 运费选择 > 付款
- 收货表单:姓名、电话、邮箱、地址、州属(下拉选择,自动计算运费区域)
- 州属选项:
- 西马:Johor, Kedah, Kelantan, Melaka, Negeri Sembilan, Pahang, Perak, Perlis, Pulau Pinang, Selangor, Terengganu, W.P. Kuala Lumpur, W.P. Putrajaya
- 东马:Sabah, Sarawak, W.P. Labuan
- 运费显示(根据州属自动切换西马/东马费率)
- 付款方式选择:
- Stripe(信用卡/FPX 在线支付)
- 银行转账(显示银行账号,客户上传转账凭证)
- Touch n Go eWallet
- 货到付款 COD(仅限特定区域)
- 订单摘要侧栏
- 下单按钮
### 6. 订单确认页(/order/[order_number])
- 订单号 + 状态
- 订单明细
- 付款状态和说明
- 如银行转账:显示上传凭证的区域
### 7. 订单追踪页(/track)
- 输入订单号 + 邮箱/手机查询
- 订单状态时间线(pending > confirmed > processing > shipped > delivered)
- 快递单号和追踪链接({shipping_provider})
### 8. 客户中心(/account,可选)
- 登录/注册(Supabase Auth,邮箱+密码 或 Magic Link)
- 我的订单列表
- 地址管理
- 收藏商品
- 评价管理
### 9. 管理后台(/admin)— 需要认证
#### 9a. 仪表盘(/admin)
- 今日/本周/本月 销售额、订单数、客单价
- 销售趋势图(最近30天)
- 最近订单列表
- 低库存预警
- 待处理订单数
#### 9b. 产品管理(/admin/products)
- 产品列表 Table(搜索、筛选、批量操作)
- 新增/编辑产品表单:
- 基本信息(名称、描述、分类、SKU)
- 图片上传(拖拽排序,Supabase Storage)
- 变体管理(动态添加颜色/尺码组合)
- 价格和库存
- SEO 设置
#### 9c. 订单管理(/admin/orders)
- 订单列表(按状态筛选 Tab)
- 订单详情页:
- 客户信息
- 订单商品
- 更新订单状态(下拉选择 + 备注)
- 填写快递单号
- 查看/确认转账凭证
- 退款操作
#### 9d. 促销管理(/admin/promos)
- 促销码 CRUD
- 使用统计
#### 9e. 评价管理(/admin/reviews)
- 审核待批评价
- 回复评价
#### 9f. 运费设置(/admin/shipping)
- 运费区域 CRUD
- 设置免运费门槛
#### 9g. 店铺设置(/admin/settings)
- 基本信息、Logo、银行转账信息、社交链接、公告栏
## 运费计算逻辑(马来西亚本地化)
```typescript
// 默认运费设置({shipping_provider})
const DEFAULT_SHIPPING_ZONES = [
{
name: '西马 Peninsular Malaysia',
states: ['Johor','Kedah','Kelantan','Melaka','Negeri Sembilan','Pahang','Perak','Perlis','Pulau Pinang','Selangor','Terengganu','W.P. Kuala Lumpur','W.P. Putrajaya'],
base_rate: 6.00, // 首重 1kg
per_kg_rate: 2.00, // 续重每 kg
free_shipping_threshold: 100.00, // 满 RM100 免运费
estimated_days: '2-3 工作日'
},
{
name: '东马 East Malaysia',
states: ['Sabah','Sarawak','W.P. Labuan'],
base_rate: 10.00,
per_kg_rate: 4.00,
free_shipping_threshold: 200.00,
estimated_days: '5-7 工作日'
}
];
```
## 税务计算
```typescript
function calculateTax(subtotal: number, taxRate: number = {tax_rate}): number {
// SST 仅在 subtotal 减去折扣后计算
return Math.round(subtotal * taxRate / 100 * 100) / 100;
}
```
## 关键业务逻辑
1. **库存自动扣减**:订单付款确认后,自动扣减对应变体库存;取消/退款时自动恢复
2. **低库存预警**:库存 <= low_stock_threshold 时在管理后台标红提醒
3. **订单编号生成**:{store_name 首字母缩写}-YYYYMMDD-{当日流水号4位},如 MF-20260409-0001
4. **促销码验证**:校验有效期、使用次数、最低消费、适用分类
5. **游客结账**:不强制注册,用邮箱+手机作为订单联系方式
6. **银行转账流程**:下单 > 显示银行信息 > 客户上传凭证 > 管理员确认 > 更新付款状态
7. **评价系统**:仅已购买且订单 delivered 的客户可评价;管理员审核后才公开显示
8. **SEO**:每个产品页自动生成 meta title/description、Open Graph 标签、JSON-LD Product schema
## 示例数据(马来西亚时尚/数码店)
请用以下示例数据初始化系统:
### 分类
- 男装 Men(T恤、裤子、外套)
- 女装 Women(连衣裙、上衣、裤子)
- 配饰 Accessories(包包、帽子、首饰)
- 数码 Gadgets(手机壳、耳机、充电器)
### 示例产品(8个)
1. 简约纯棉 T恤 - RM 49.90(划线价 RM 69.90)- 颜色:黑/白/灰 - 尺码:S/M/L/XL - 库存各20件
2. 潮流束脚裤 - RM 89.90 - 颜色:黑/卡其 - 尺码:M/L/XL
3. 碎花连衣裙 - RM 129.90(划线价 RM 159.90)- 颜色:蓝花/粉花 - 尺码:S/M/L
4. 真皮斜挎包 - RM 199.90 - 颜色:棕/黑
5. MagSafe 手机壳 - RM 39.90 - 型号:iPhone 15/15 Pro/16/16 Pro
6. 无线蓝牙耳机 - RM 159.90(划线价 RM 199.90)- 颜色:白/黑
7. 65W GaN 快充头 - RM 79.90 - 规格:单口/双口
8. 棒球帽 - RM 35.90 - 颜色:黑/白/海军蓝
### 示例促销码
- WELCOME10 — 新客户 10% 折扣,封顶 RM 20,最低消费 RM 80
- RAYA2026 — 开斋节 RM 15 固定折扣,最低消费 RM 100
- FREESHIP — 免运费(折扣等于运费金额),最低消费 RM 50
### 示例评价
为前3个产品各生成 2-3 条真实感的马来西亚买家评价(中英文混合风格)
## 响应式设计要求
- 桌面:最大宽度 1280px 居中,产品网格 4 列
- 平板:产品网格 3 列,侧栏收起
- 手机:产品网格 2 列,底部导航栏(首页/分类/购物车/账户),筛选用 Sheet 弹出
- 所有按钮和点击区域最小 44px
- 图片全部使用 next/image 优化,带 blur placeholder
## 文件结构
```
src/
├── app/
│ ├── layout.tsx # 店铺布局(导航+Footer)
│ ├── page.tsx # 首页
│ ├── products/
│ │ └── page.tsx # 全部产品
│ ├── category/
│ │ └── [slug]/page.tsx # 分类页
│ ├── product/
│ │ └── [slug]/page.tsx # 产品详情(generateMetadata)
│ ├── cart/page.tsx # 购物车
│ ├── checkout/page.tsx # 结账
│ ├── order/
│ │ └── [order_number]/page.tsx # 订单确认
│ ├── track/page.tsx # 订单追踪
│ ├── account/
│ │ ├── page.tsx # 个人中心
│ │ ├── orders/page.tsx # 我的订单
│ │ └── login/page.tsx # 登录
│ ├── admin/
│ │ ├── layout.tsx # 管理后台布局
│ │ ├── page.tsx # 仪表盘
│ │ ├── products/page.tsx
│ │ ├── orders/page.tsx
│ │ ├── promos/page.tsx
│ │ ├── reviews/page.tsx
│ │ ├── shipping/page.tsx
│ │ └── settings/page.tsx
│ └── api/
│ ├── checkout/route.ts # Stripe Checkout Session
│ ├── webhook/stripe/route.ts # Stripe Webhook
│ └── upload-receipt/route.ts # 银行转账凭证上传
├── components/
│ ├── ui/ # shadcn/ui
│ ├── storefront/ # 前台组件
│ │ ├── product-card.tsx
│ │ ├── product-gallery.tsx
│ │ ├── variant-selector.tsx
│ │ ├── cart-drawer.tsx
│ │ ├── cart-item.tsx
│ │ ├── checkout-form.tsx
│ │ ├── promo-code-input.tsx
│ │ ├── review-list.tsx
│ │ ├── review-form.tsx
│ │ ├── search-bar.tsx
│ │ ├── category-nav.tsx
│ │ ├── price-filter.tsx
│ │ └── order-timeline.tsx
│ └── admin/ # 后台组件
│ ├── product-form.tsx
│ ├── order-detail.tsx
│ ├── sales-chart.tsx
│ ├── inventory-alert.tsx
│ └── image-uploader.tsx
├── lib/
│ ├── supabase/
│ │ ├── client.ts
│ │ ├── server.ts
│ │ └── admin.ts
│ ├── stripe.ts
│ ├── cart.ts # 购物车 localStorage 工具
│ ├── shipping.ts # 运费计算
│ ├── tax.ts # 税务计算
│ └── utils.ts
├── hooks/
│ ├── use-cart.ts # 购物车 React hook
│ └── use-debounce.ts
└── types/
└── index.ts # 所有 TypeScript 类型
```
## 重要提醒
1. 所有金额使用 decimal(10,2),前端显示时用 toLocaleString('ms-MY') 格式化
2. 图片上传到 Supabase Storage 的 products bucket,设置公开访问策略
3. Stripe Webhook 必须验证签名(STRIPE_WEBHOOK_SECRET)
4. 管理后台用 Supabase Auth + 邮箱白名单保护
5. 产品详情页使用 ISR(revalidate: 3600)平衡性能和实时性
6. 购物车使用 React Context + localStorage 持久化
7. 所有表单使用 Server Actions 处理提交
请从数据库 schema 开始,然后按照页面顺序依次实现所有功能。每个文件输出完整代码。