# CRMEB商城系统到uvue项目的重构迁移指南 ## 项目概述 本文档基于CRMEB开源商城系统(PHP版本),指导如何将其核心功能迁移到基于uvue技术栈的项目中。后端使用`@components/supadb`组件库实现,不使用PHP技术栈。 ## 参考项目分析 ### CRMEB核心功能模块 #### 1. 用户系统 (User Module) - **用户注册登录**:手机号验证码、微信授权登录 - **用户资料管理**:个人信息、收货地址、会员等级 - **用户积分系统**:积分获取、积分消费记录 - **分销系统**:用户推广、佣金结算 #### 2. 商品系统 (Product Module) - **商品管理**:商品信息、SKU规格、商品分类 - **商品展示**:商品详情、商品列表、商品搜索 - **库存管理**:商品库存、规格库存管理 #### 3. 订单系统 (Order Module) - **购物车**:添加商品、修改数量、删除商品 - **订单创建**:订单确认、地址选择、支付方式 - **订单管理**:订单状态跟踪、订单取消、退款处理 - **物流跟踪**:快递信息查询、物流状态更新 #### 4. 营销活动 (Activity Module) - **秒杀活动**:限时抢购、库存锁定 - **拼团活动**:团购发起、参团流程 - **砍价活动**:好友助力、砍价进度 - **优惠券系统**:券领取、使用规则 - **积分商城**:积分兑换商品 #### 5. 支付系统 (Payment Module) - **多渠道支付**:微信支付、支付宝、余额支付 - **支付回调**:订单状态更新、支付记录 #### 6. 客服系统 (Service Module) - **在线客服**:实时聊天、消息记录 - **售后服务**:退换货处理、服务评价 #### 7. 内容管理系统 (CMS Module) - **文章系统**:资讯发布、分类管理 - **广告位管理**:首页banner、推荐位 #### 8. 系统配置 (System Module) - **基础配置**:站点信息、支付配置、物流配置 - **权限管理**:管理员权限、操作日志 ## 技术栈对比 ### 原CRMEB技术栈 ``` 后端: ThinkPHP 6 + MySQL + Redis 前端: Vue2 + ElementUI + UniApp 其他: Workerman(长连接)、队列、定时任务 ``` ### 目标技术栈 ``` 后端: Supabase (PostgreSQL + Auth + Storage + Edge Functions) 前端: uvue + @components/supadb 其他: 实时订阅、文件存储、服务器less函数 ``` ## 数据架构设计 ### Supabase数据库表结构设计 #### 核心数据表 ##### 1. 用户表 (users) ```sql -- 继承Supabase auth.users表,扩展字段 CREATE TABLE public.users ( id UUID REFERENCES auth.users(id) PRIMARY KEY, phone TEXT, nickname TEXT, avatar_url TEXT, gender INTEGER DEFAULT 0, birthday DATE, level_id INTEGER DEFAULT 0, integral INTEGER DEFAULT 0, balance DECIMAL(10,2) DEFAULT 0, spread_uid INTEGER, spread_time TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 2. 商品表 (products) ```sql CREATE TABLE public.products ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, description TEXT, images TEXT[], category_id INTEGER, brand_id INTEGER, price DECIMAL(10,2), ot_price DECIMAL(10,2), cost DECIMAL(10,2), stock INTEGER DEFAULT 0, sales INTEGER DEFAULT 0, is_show BOOLEAN DEFAULT true, is_del BOOLEAN DEFAULT false, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 3. 商品规格表 (product_skus) ```sql CREATE TABLE public.product_skus ( id SERIAL PRIMARY KEY, product_id INTEGER REFERENCES products(id), sku TEXT, price DECIMAL(10,2), stock INTEGER DEFAULT 0, image TEXT, attributes JSONB, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 4. 订单表 (orders) ```sql CREATE TABLE public.orders ( id SERIAL PRIMARY KEY, order_sn TEXT UNIQUE, user_id UUID REFERENCES users(id), total_price DECIMAL(10,2), pay_price DECIMAL(10,2), coupon_price DECIMAL(10,2), pay_type INTEGER DEFAULT 1, -- 1微信 2余额 3线下 status INTEGER DEFAULT 0, -- 订单状态 address_info JSONB, mark TEXT, paid BOOLEAN DEFAULT false, pay_time TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 5. 订单商品表 (order_items) ```sql CREATE TABLE public.order_items ( id SERIAL PRIMARY KEY, order_id INTEGER REFERENCES orders(id), product_id INTEGER REFERENCES products(id), sku_id INTEGER REFERENCES product_skus(id), product_title TEXT, product_image TEXT, sku_info JSONB, price DECIMAL(10,2), quantity INTEGER, total_price DECIMAL(10,2), created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 6. 购物车表 (cart) ```sql CREATE TABLE public.cart ( id SERIAL PRIMARY KEY, user_id UUID REFERENCES users(id), product_id INTEGER REFERENCES products(id), sku_id INTEGER REFERENCES product_skus(id), quantity INTEGER, selected BOOLEAN DEFAULT true, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 7. 优惠券表 (coupons) ```sql CREATE TABLE public.coupons ( id SERIAL PRIMARY KEY, title TEXT, type INTEGER, -- 1满减 2折扣 value DECIMAL(10,2), min_price DECIMAL(10,2), use_start_time TIMESTAMP WITH TIME ZONE, use_end_time TIMESTAMP WITH TIME ZONE, stock INTEGER, receive_count INTEGER DEFAULT 0, is_show BOOLEAN DEFAULT true, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ##### 8. 用户优惠券表 (user_coupons) ```sql CREATE TABLE public.user_coupons ( id SERIAL PRIMARY KEY, user_id UUID REFERENCES users(id), coupon_id INTEGER REFERENCES coupons(id), status INTEGER DEFAULT 0, -- 0未使用 1已使用 2已过期 use_time TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); ``` ## API接口设计 ### 使用@components/supadb实现的数据操作 #### 用户相关接口 ##### 用户注册 ```typescript // 使用Supabase Auth实现 const { data, error } = await supa.auth.signUp({ email: 'user@example.com', password: 'password' }) ``` ##### 用户登录 ```typescript const { data, error } = await supa.auth.signInWithPassword({ email: 'user@example.com', password: 'password' }) ``` ##### 获取用户信息 ```typescript // 使用supadb组件 ``` ##### 更新用户信息 ```typescript const result = await supa.from('users').update(userData).eq('id', userId) ``` #### 商品相关接口 ##### 获取商品列表 ```vue ``` ##### 获取商品详情 ```vue ``` ##### 商品搜索 ```vue ``` #### 订单相关接口 ##### 创建订单 ```typescript // 先创建订单记录 const orderData = { order_sn: generateOrderSn(), user_id: userId, total_price: totalPrice, // ...其他字段 } const { data: order } = await supa.from('orders').insert(orderData).select().single() // 然后创建订单商品记录 const orderItems = cartItems.map(item => ({ order_id: order.id, product_id: item.product_id, // ...其他字段 })) await supa.from('order_items').insert(orderItems) ``` ##### 获取订单列表 ```vue ``` #### 营销活动接口 ##### 秒杀活动 ```vue ``` ##### 优惠券领取 ```typescript // 检查用户是否已领取 const { data: existing } = await supa .from('user_coupons') .select('*') .eq('user_id', userId) .eq('coupon_id', couponId) .single() if (!existing) { await supa.from('user_coupons').insert({ user_id: userId, coupon_id: couponId }) } ``` ## uvue前端页面重构方案 ### 页面结构重组 #### 1. 首页 (pages/index/index.uvue) ```vue ``` #### 2. 商品详情页 (pages/goods/detail.uvue) ```vue ``` #### 3. 购物车页面 (pages/cart/index.uvue) ```vue ``` ## 实时功能实现 ### 使用Supabase实时订阅 #### 订单状态更新监听 ```typescript // 监听订单状态变化 const orderSubscription = supa .channel('order-updates') .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'orders', filter: `user_id=eq.${userId}` }, (payload) => { console.log('Order updated:', payload) // 更新订单状态 } ) .subscribe() ``` #### 库存变化监听 ```typescript // 监听商品库存变化 const stockSubscription = supa .channel('stock-updates') .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'products' }, (payload) => { // 更新本地商品库存 updateLocalStock(payload.new) } ) .subscribe() ``` ## 文件存储实现 ### 使用Supabase Storage #### 商品图片上传 ```typescript const uploadProductImage = async (filePath: string, productId: number) => { const fileName = `product_${productId}_${Date.now()}.jpg` const { data, error } = await supa.storage .from('products') .upload(fileName, filePath) if (data) { const { data: urlData } = supa.storage .from('products') .getPublicUrl(fileName) return urlData.publicUrl } } ``` #### 用户头像上传 ```typescript const uploadAvatar = async (filePath: string) => { const fileName = `avatar_${userId}_${Date.now()}.jpg` const { data, error } = await supa.storage .from('avatars') .upload(fileName, filePath) if (data) { const { data: urlData } = supa.storage .from('avatars') .getPublicUrl(fileName) // 更新用户头像 await supa.from('users').update({ avatar_url: urlData.publicUrl }).eq('id', userId) } } ``` ## 服务器端逻辑实现 ### 使用Supabase Edge Functions #### 订单创建函数 ```typescript // supabase/functions/create-order/index.ts import { serve } from "https://deno.land/std@0.168.0/http/server.ts" import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' serve(async (req) => { const { userId, items, address } = await req.json() const supabase = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_ANON_KEY') ?? '' ) // 生成订单号 const orderSn = `ORDER${Date.now()}${Math.random().toString(36).substr(2, 6).toUpperCase()}` // 计算总价 let totalPrice = 0 for (const item of items) { const { data: product } = await supabase .from('products') .select('price') .eq('id', item.productId) .single() totalPrice += product.price * item.quantity } // 创建订单 const { data: order, error } = await supabase .from('orders') .insert({ order_sn: orderSn, user_id: userId, total_price: totalPrice, address_info: address }) .select() .single() if (error) throw error // 创建订单商品记录 const orderItems = items.map(item => ({ order_id: order.id, product_id: item.productId, quantity: item.quantity, price: item.price, total_price: item.price * item.quantity })) const { error: itemsError } = await supabase .from('order_items') .insert(orderItems) if (itemsError) throw itemsError return new Response( JSON.stringify({ order }), { headers: { "Content-Type": "application/json" } } ) }) ``` #### 支付回调函数 ```typescript // supabase/functions/payment-callback/index.ts import { serve } from "https://deno.land/std@0.168.0/http/server.ts" import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' serve(async (req) => { const { orderSn, paymentResult } = await req.json() const supabase = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_ANON_KEY') ?? '' ) // 更新订单支付状态 const { error } = await supabase .from('orders') .update({ paid: true, pay_time: new Date().toISOString(), status: 1 // 已支付 }) .eq('order_sn', orderSn) if (error) throw error return new Response( JSON.stringify({ success: true }), { headers: { "Content-Type": "application/json" } } ) }) ``` ## 组件重构对照表 ### CRMEB组件 → uvue组件映射 | CRMEB组件 | uvue组件 | 功能说明 | |----------|---------|---------| | HomeComb | home-comb.uvue | 首页搜索组合 | | GoodList | product-list.uvue | 商品列表 | | CouponWindow | coupon-popup.uvue | 优惠券弹窗 | | CartList | cart-list.uvue | 购物车列表 | | Payment | payment-selector.uvue | 支付方式选择 | | AddressWindow | address-selector.uvue | 地址选择弹窗 | | UserEvaluation | product-review.uvue | 商品评价 | | ShareRedPackets | share-popup.uvue | 分享红包 | ## 性能优化建议 ### 1. 数据缓存策略 ```typescript // 使用Supabase内置缓存 const { data, error } = await supa .from('products') .select('*') .eq('category_id', categoryId) .order('sales', { ascending: false }) .limit(20) // 启用缓存 .single() ``` ### 2. 图片懒加载 ```vue ``` ### 3. 列表虚拟化 ```vue ``` ## 部署和维护 ### 环境配置 ```javascript // config/app.js export default { supabase: { url: 'https://your-project.supabase.co', anonKey: 'your-anon-key', serviceRoleKey: 'your-service-role-key' // 服务端使用 } } ``` ### 数据库迁移 ```sql -- 数据库初始化脚本 -- 创建表结构 -- 设置RLS策略 -- 创建索引 -- 设置触发器 ``` ### 监控和日志 ```typescript // 错误监控 const handleError = (error) => { console.error('App Error:', error) // 上报到监控系统 } // 性能监控 const reportPerformance = (metrics) => { // 上报性能数据 } ``` ## 总结 通过本重构指南,我们将CRMEB的核心功能成功迁移到基于uvue + Supabase的技术栈: 1. **数据层**:使用Supabase替代MySQL + Redis 2. **API层**:使用@components/supadb替代ThinkPHP 3. **前端**:使用uvue替代uni-app 4. **实时功能**:使用Supabase实时订阅 5. **文件存储**:使用Supabase Storage 6. **服务器逻辑**:使用Edge Functions 这种架构具有以下优势: - **开发效率高**:减少后端开发工作 - **维护成本低**:Serverless架构 - **扩展性好**:支持实时功能和全球化部署 - **安全性高**:Supabase提供完善的安全机制 实际迁移时需要根据具体业务需求进行调整,并充分测试各项功能。