consumer模块完成90%,前端完成supabase对接

This commit is contained in:
2026-02-03 17:11:50 +08:00
parent b6200cda28
commit 8a535e3f38
69 changed files with 5020 additions and 33273 deletions

View File

@@ -20,24 +20,42 @@
</view>
</view>
<!-- 商品列表 -->
<!-- 商品列表 (按店铺分组) -->
<view class="products-section">
<!-- 调试信息 -->
<!-- 调试信息 -->
<view v-if="checkoutItems.length > 0" class="debug-info">
<text class="debug-text">调试:共{{ checkoutItems.length }}件商品,总价计算:{{ totalAmount }}</text>
<text class="debug-text">共 {{ checkoutItems.length }} 件商品</text>
</view>
<view v-if="checkoutItems.length > 0">
<view v-for="item in checkoutItems" :key="item.id" class="product-item">
<image class="product-image" :src="item.product_image" />
<view class="product-info">
<text class="product-name">{{ item.product_name }}</text>
<text v-if="item.sku_specifications" class="product-spec">{{ getSpecText(item.sku_specifications) }}</text>
<view class="product-bottom">
<text class="product-price">¥{{ item.price }}</text>
<text class="product-quantity">×{{ item.quantity }}</text>
</view>
</view>
</view>
<view v-if="shopGroups.length > 0">
<view v-for="group in shopGroups" :key="group.shopId" class="shop-group">
<view class="shop-header">
<text class="shop-icon">🏪</text>
<text class="shop-name">{{ group.shopName }}</text>
</view>
<view v-for="item in group.items" :key="item.id" class="product-item">
<image class="product-image" :src="item.product_image" mode="aspectFill" />
<view class="product-info">
<text class="product-name">{{ item.product_name }}</text>
<text v-if="item.sku_specifications" class="product-spec">{{ getSpecText(item.sku_specifications) }}</text>
<view class="product-bottom">
<text class="product-price">¥{{ item.price }}</text>
<text class="product-quantity">×{{ item.quantity }}</text>
</view>
</view>
</view>
<!-- 店铺小计 -->
<view class="shop-subtotal">
<text class="subtotal-label">配送方式</text>
<text class="subtotal-value">快递 免邮</text>
</view>
<view class="shop-subtotal">
<text class="subtotal-text">小计: </text>
<text class="subtotal-price">¥{{ getGroupTotal(group) }}</text>
</view>
</view>
</view>
<view v-else class="no-products">
<text class="no-products-text">暂无商品信息</text>
@@ -286,6 +304,8 @@ type CheckoutItemType = {
sku_specifications: any
price: number
quantity: number
shop_id?: string
shop_name?: string
}
type DeliveryOptionType = {
@@ -329,6 +349,32 @@ const showSaveConfirm = ref<boolean>(false)
const smartAddressInput = ref<string>('')
// 计算属性 - 修复价格同步问题
// 按店铺分组商品
const shopGroups = computed(() => {
const groups = new Map<string, any>()
checkoutItems.value.forEach(item => {
// 使用类型断言访问可能的额外属性
const rawItem = item as any
const shopId = rawItem.shop_id || 'unknown'
if (!groups.has(shopId)) {
groups.set(shopId, {
shopId: shopId,
shopName: rawItem.shop_name || '商城优选',
merchant_id: rawItem.merchant_id || rawItem.shop_id,
items: [] as any[]
})
}
groups.get(shopId).items.push(item)
})
return Array.from(groups.values())
})
const getGroupTotal = (group: any) => {
return group.items.reduce((sum: number, item: any) => {
return sum + (Number(item.price) * Number(item.quantity))
}, 0).toFixed(2)
}
const totalAmount = computed(() => {
console.log('计算商品总价checkoutItems:', checkoutItems.value)
if (!checkoutItems.value || checkoutItems.value.length === 0) {
@@ -405,34 +451,38 @@ watch(checkoutItems, (newItems) => {
// 页面加载时监听eventChannel
onLoad(() => {
// 优先检查Storage中是否有"立即购买"的数据
let dataLoaded = false
// 优先检查Storage中是否有结算数据 (支持 buy_now 和 cart 两种模式)
const checkoutType = uni.getStorageSync('checkout_type')
if (checkoutType === 'buy_now') {
console.log('检测到立即购买模式从Storage加载数据')
if (checkoutType === 'buy_now' || checkoutType === 'cart') {
console.log(`检测到结算模式(${checkoutType})从Storage加载数据`)
const itemsStr = uni.getStorageSync('checkout_items')
if (itemsStr) {
try {
const items = JSON.parse(itemsStr as string)
console.log('从Storage加载的商品数据:', items)
processCheckoutItems(items)
// 清除Storage避免污染下次进入刷新页面时可能需要保留暂时不清除或者在离开页面时清除
// uni.removeStorageSync('checkout_type')
// uni.removeStorageSync('checkout_items')
loadDefaultAddress()
return // 成功加载,直接返回
if (items && Array.isArray(items) && items.length > 0) {
processCheckoutItems(items)
dataLoaded = true
}
} catch (e) {
console.error('解析立即购买数据失败', e)
console.error('解析结算数据失败', e)
}
}
}
// 如果没有从checkout_items加载到数据则尝试从通用购物车Storage加载 (回退方案)
if (!dataLoaded) {
console.log('未找到预结算数据,尝试从购物车本地存储加载')
loadFromLocalStorage()
} else {
// 如果已经加载了数据还需要单独加载地址因为loadFromLocalStorage通常会附带加载地址
loadDefaultAddress()
}
// 从上一页获取数据
const eventChannel = uni.getEventChannel ? uni.getEventChannel() : null
// 默认先尝试从本地存储加载(确保有数据)
loadFromLocalStorage()
if (eventChannel) {
eventChannel.on('acceptData', (data: any) => {
console.log('接收到商品数据:', data)
@@ -539,9 +589,6 @@ const loadFromLocalStorage = () => {
if (selectedCartItems.length > 0) {
// 转换为CheckoutItemType格式
const convertedItems: CheckoutItemType[] = selectedCartItems.map(item => {
// 确保价格和数量是数字
let price = typeof item.price === 'string' ? parseFloat(item.price) : Number(item.price)
if (isNaN(price)) price = 0
let quantity = typeof item.quantity === 'string' ? parseInt(item.quantity) : Number(item.quantity)
if (isNaN(quantity) || quantity < 1) quantity = 1
@@ -553,7 +600,7 @@ const loadFromLocalStorage = () => {
product_name: item.name || '',
product_image: item.image || '',
sku_specifications: item.spec ? { spec: item.spec } : {},
price: price,
price: Number(item.price) || 0,
quantity: quantity
}
})
@@ -1247,8 +1294,7 @@ const submitOrder = async () => {
uni.showLoading({ title: '提交中...' })
try {
const userId = getCurrentUserId()
// 确保使用当前登录用户ID (如果本地存储为空,可能需要处理)
const userId = supabaseService.getCurrentUserId()
if (!userId) {
uni.hideLoading()
uni.showToast({
@@ -1258,59 +1304,77 @@ const submitOrder = async () => {
return
}
// 准备订单项数据
// 注意:需根据 checkoutItems 的实际结构转换为 createOrder 需要的 CartItem 结构
// 假设 checkoutItems 已经包含了 product_id, quantity, price, name, image 等字段
const orderItems = checkoutItems.value.map((item: any): any => ({
id: item.id || '', // 这是一个临时ID或者购物车IDcreateOrder 中会使用 product_id
product_id: item.product_id || item.id, // 确保有 product_id
quantity: item.quantity,
price: item.price,
product_name: item.name,
product_image: item.image,
spec: item.spec,
checked: true
}))
// 准备按店铺分组数据
const groups = shopGroups.value.map((group: any): any => {
return {
merchant_id: group.merchant_id || group.shopId,
shopName: group.shopName,
items: group.items.map((item: any): any => ({
id: item.id, // 用于清理购物车
product_id: item.product_id,
sku_id: item.sku_id,
quantity: item.quantity,
price: item.price,
product_name: item.product_name,
product_image: item.product_image,
specifications: item.sku_specifications // 保持原始对象createOrder 会处理序列化
}))
}
})
// 调用 Supabase 服务创建订单
const result = await supabaseService.createOrder(
userId,
selectedAddress.value!.id, // 地址ID
actualAmount.value, // 实付金额
orderItems
)
// 调用 Supabase 服务创建多店铺订单
const result = await supabaseService.createOrdersByShop({
shipping_address: selectedAddress.value,
shopGroups: groups,
deliveryFee: deliveryFee.value,
discountAmount: discountAmount.value
})
uni.hideLoading()
if (result.success) {
// 清除购买的商品 (如果来自购物车,应该在 createOrder 成功后清除,或者这里手动清除本地存储)
// 这里我们假设购物车清理逻辑可能在 createOrder 后端处理,或者需要在这里清除本地
// 清除结算商品
try {
uni.removeStorageSync('checkout_items')
uni.removeStorageSync('checkout_type')
} catch(e) {
console.error('清除结算商品失败', e)
}
const activeOrderId = result.data as string
const orderIds = result.orderIds
// 跳转支付页面
uni.navigateTo({
url: `/pages/mall/consumer/payment?orderId=${activeOrderId}&amount=${actualAmount.value}&productAmount=${totalAmount.value}&deliveryFee=${deliveryFee.value}&discountAmount=${discountAmount.value}`
})
if (orderIds.length === 1) {
// 单个订单跳转支付
uni.navigateTo({
url: `/pages/mall/consumer/payment?orderId=${orderIds[0]}&amount=${actualAmount.value}`
})
} else {
// 多个订单跳转到订单列表
uni.showToast({
title: `成功创建${orderIds.length}个订单`,
icon: 'success'
})
setTimeout(() => {
uni.redirectTo({
url: '/pages/mall/consumer/orders'
})
}, 1500)
}
} else {
throw new Error(result.error)
throw new Error(result.error || '创建订单失败')
}
} catch (err: any) {
uni.hideLoading()
console.error('创建订单失败:', err)
console.error('提交订单错误:', err)
uni.showToast({
title: err.message || '订单创建失败',
title: err.message || '提交订单失败',
icon: 'none'
})
}
}
// 生成订单号
const generateOrderNo = (): string => {
const date = new Date()
@@ -1463,6 +1527,62 @@ const goBack = () => {
text-align: center;
}
.shop-group {
background-color: #fff;
margin: 10px 0;
border-radius: 12px;
padding: 10px;
}
.shop-header {
display: flex;
flex-direction: row;
align-items: center;
padding-bottom: 10px;
border-bottom: 1px solid #f0f0f0;
}
.shop-icon {
font-size: 18px;
margin-right: 8px;
}
.shop-name {
font-size: 16px;
font-weight: bold;
color: #333;
}
.shop-subtotal {
display: flex;
justify-content: flex-end; /* 右对齐 */
align-items: center;
padding-top: 10px;
margin-top: 5px;
border-top: 1px dashed #f0f0f0;
font-size: 14px;
}
.subtotal-label {
color: #666;
margin-right: 10px;
}
.subtotal-value {
color: #333;
}
.subtotal-text {
color: #333;
margin-right: 5px;
}
.subtotal-price {
color: #ff4757;
font-weight: bold;
font-size: 16px;
}
.product-item {
display: flex;
padding: 15px 0;