完善页面布局
This commit is contained in:
807
docs/CRMEB_TO_UVUE_MIGRATION_GUIDE.md
Normal file
807
docs/CRMEB_TO_UVUE_MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,807 @@
|
||||
# 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组件
|
||||
<supadb
|
||||
collection="users"
|
||||
:filter="{ id: userId }"
|
||||
:getone="true"
|
||||
v-slot="{ data: userInfo }"
|
||||
>
|
||||
<!-- 用户信息显示 -->
|
||||
</supadb>
|
||||
```
|
||||
|
||||
##### 更新用户信息
|
||||
```typescript
|
||||
const result = await supa.from('users').update(userData).eq('id', userId)
|
||||
```
|
||||
|
||||
#### 商品相关接口
|
||||
|
||||
##### 获取商品列表
|
||||
```vue
|
||||
<supadb
|
||||
collection="products"
|
||||
:filter="{ is_show: true, is_del: false }"
|
||||
:orderby="'sales.desc'"
|
||||
:pageSize="20"
|
||||
v-slot="{ data: products, loading, hasmore, loadMore }"
|
||||
>
|
||||
<view v-for="product in products" :key="product.id">
|
||||
<!-- 商品卡片 -->
|
||||
</view>
|
||||
<button v-if="hasmore" @click="loadMore">加载更多</button>
|
||||
</supadb>
|
||||
```
|
||||
|
||||
##### 获取商品详情
|
||||
```vue
|
||||
<supadb
|
||||
collection="products"
|
||||
:filter="{ id: productId }"
|
||||
:getone="true"
|
||||
v-slot="{ data: product }"
|
||||
>
|
||||
<!-- 商品详情页 -->
|
||||
</supadb>
|
||||
```
|
||||
|
||||
##### 商品搜索
|
||||
```vue
|
||||
<supadb
|
||||
collection="products"
|
||||
:filter="{ title: { ilike: `%${keyword}%` }, is_show: true }"
|
||||
v-slot="{ data: searchResults }"
|
||||
>
|
||||
<!-- 搜索结果 -->
|
||||
</supadb>
|
||||
```
|
||||
|
||||
#### 订单相关接口
|
||||
|
||||
##### 创建订单
|
||||
```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
|
||||
<supadb
|
||||
collection="orders"
|
||||
:filter="{ user_id: userId }"
|
||||
:orderby="'created_at.desc'"
|
||||
v-slot="{ data: orders }"
|
||||
>
|
||||
<view v-for="order in orders" :key="order.id">
|
||||
<!-- 订单卡片 -->
|
||||
</view>
|
||||
</supadb>
|
||||
```
|
||||
|
||||
#### 营销活动接口
|
||||
|
||||
##### 秒杀活动
|
||||
```vue
|
||||
<supadb
|
||||
collection="seckill_products"
|
||||
:filter="{
|
||||
start_time: { lte: currentTime },
|
||||
end_time: { gte: currentTime },
|
||||
stock: { gt: 0 }
|
||||
}"
|
||||
v-slot="{ data: seckillProducts }"
|
||||
>
|
||||
<!-- 秒杀商品列表 -->
|
||||
</supadb>
|
||||
```
|
||||
|
||||
##### 优惠券领取
|
||||
```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
|
||||
<template>
|
||||
<view class="index-page">
|
||||
<!-- 轮播图 -->
|
||||
<swiper-banner />
|
||||
<!-- 分类导航 -->
|
||||
<category-nav />
|
||||
<!-- 商品推荐 -->
|
||||
<product-recommend />
|
||||
<!-- 营销活动 -->
|
||||
<activity-section />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
|
||||
// 首页数据
|
||||
const bannerList = ref([])
|
||||
const categoryList = ref([])
|
||||
const recommendProducts = ref([])
|
||||
|
||||
// 获取首页数据
|
||||
const loadHomeData = async () => {
|
||||
// 获取轮播图
|
||||
const bannerResult = await supa.from('banners').select('*').eq('position', 'home')
|
||||
bannerList.value = bannerResult.data || []
|
||||
|
||||
// 获取分类
|
||||
const categoryResult = await supa.from('categories').select('*').eq('level', 1)
|
||||
categoryList.value = categoryResult.data || []
|
||||
|
||||
// 获取推荐商品
|
||||
const productResult = await supa.from('products')
|
||||
.select('*')
|
||||
.eq('is_recommend', true)
|
||||
.eq('is_show', true)
|
||||
.limit(10)
|
||||
recommendProducts.value = productResult.data || []
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
#### 2. 商品详情页 (pages/goods/detail.uvue)
|
||||
```vue
|
||||
<template>
|
||||
<view class="product-detail">
|
||||
<supadb
|
||||
collection="products"
|
||||
:filter="{ id: productId }"
|
||||
:getone="true"
|
||||
v-slot="{ data: product, loading }"
|
||||
>
|
||||
<!-- 商品图片轮播 -->
|
||||
<image-swiper :images="product?.images || []" />
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<product-info :product="product" />
|
||||
|
||||
<!-- 商品规格选择 -->
|
||||
<sku-selector
|
||||
:product="product"
|
||||
@sku-change="handleSkuChange"
|
||||
/>
|
||||
|
||||
<!-- 商品详情 -->
|
||||
<product-description :content="product?.description" />
|
||||
</supadb>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
|
||||
const props = defineProps<{
|
||||
productId: number
|
||||
}>()
|
||||
|
||||
const selectedSku = ref(null)
|
||||
|
||||
const handleSkuChange = (sku) => {
|
||||
selectedSku.value = sku
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
#### 3. 购物车页面 (pages/cart/index.uvue)
|
||||
```vue
|
||||
<template>
|
||||
<view class="cart-page">
|
||||
<supadb
|
||||
collection="cart"
|
||||
:filter="{ user_id: userId }"
|
||||
v-slot="{ data: cartItems, loading }"
|
||||
>
|
||||
<!-- 购物车商品列表 -->
|
||||
<cart-item
|
||||
v-for="item in cartItems"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
@quantity-change="updateQuantity"
|
||||
@delete="removeItem"
|
||||
/>
|
||||
|
||||
<!-- 结算栏 -->
|
||||
<cart-footer
|
||||
:items="cartItems"
|
||||
@checkout="goCheckout"
|
||||
/>
|
||||
</supadb>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
|
||||
const userId = ref('') // 从用户信息获取
|
||||
|
||||
const updateQuantity = async (itemId, quantity) => {
|
||||
await supa.from('cart').update({ quantity }).eq('id', itemId)
|
||||
}
|
||||
|
||||
const removeItem = async (itemId) => {
|
||||
await supa.from('cart').delete().eq('id', itemId)
|
||||
}
|
||||
|
||||
const goCheckout = () => {
|
||||
// 跳转到结算页面
|
||||
uni.navigateTo({
|
||||
url: '/pages/order/checkout'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 实时功能实现
|
||||
|
||||
### 使用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
|
||||
<template>
|
||||
<image
|
||||
:src="imageUrl"
|
||||
:lazy-load="true"
|
||||
@load="onImageLoad"
|
||||
@error="onImageError"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 3. 列表虚拟化
|
||||
```vue
|
||||
<template>
|
||||
<scroll-view
|
||||
scroll-y="true"
|
||||
:scroll-top="scrollTop"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<view
|
||||
v-for="(item, index) in visibleItems"
|
||||
:key="item.id"
|
||||
:style="{ transform: `translateY(${item.top}px)` }"
|
||||
>
|
||||
<!-- 商品项 -->
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 部署和维护
|
||||
|
||||
### 环境配置
|
||||
```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提供完善的安全机制
|
||||
|
||||
实际迁移时需要根据具体业务需求进行调整,并充分测试各项功能。
|
||||
Reference in New Issue
Block a user