consumer模块完成90%,前端完成supabase对接
This commit is contained in:
@@ -52,7 +52,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 规格选择 -->
|
||||
<view class="spec-section" @click="showSpecModal">
|
||||
<view class="spec-section" @click="showSpecModal" v-if="productSkus.length > 0">
|
||||
<text class="spec-title">规格</text>
|
||||
<text class="spec-selected">{{ selectedSpec || '请选择规格' }}</text>
|
||||
<text class="spec-arrow">></text>
|
||||
@@ -276,6 +276,13 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
saveFootprint(productId: string) {
|
||||
// 调用后端API记录足迹
|
||||
supabaseService.addFootprint(productId).then(success => {
|
||||
if (success) {
|
||||
console.log('足迹已同步到服务器')
|
||||
}
|
||||
})
|
||||
|
||||
const footprintData = uni.getStorageSync('footprints')
|
||||
let footprints: any[] = []
|
||||
|
||||
@@ -311,330 +318,158 @@ export default {
|
||||
},
|
||||
|
||||
async loadProductDetail(productId: string, options: any = {}) {
|
||||
// 尝试从数据库加载
|
||||
let dbProductRaw = null
|
||||
uni.showLoading({ title: '加载中...' })
|
||||
try {
|
||||
console.log('正在尝试从数据库加载商品详情:', productId)
|
||||
dbProductRaw = await supabaseService.getProductById(productId)
|
||||
console.log('数据库返回的商品详情 (原始数据):', dbProductRaw)
|
||||
|
||||
// 调试:打印数据库返回的所有字段
|
||||
if (dbProductRaw) {
|
||||
console.log('数据库返回字段详情:')
|
||||
if (Array.isArray(dbProductRaw)) {
|
||||
console.log('返回数据是数组,长度:', dbProductRaw.length)
|
||||
if (dbProductRaw.length > 0) {
|
||||
const firstItem = dbProductRaw[0]
|
||||
console.log('数组第一个元素:', firstItem)
|
||||
for (const key in firstItem) {
|
||||
console.log(` ${key}:`, firstItem[key], typeof firstItem[key])
|
||||
}
|
||||
const dbProductResponse = await supabaseService.getProductById(productId)
|
||||
let dbProduct: any = null
|
||||
if (Array.isArray(dbProductResponse) && dbProductResponse.length > 0) {
|
||||
dbProduct = dbProductResponse[0]
|
||||
} else if (dbProductResponse && !Array.isArray(dbProductResponse)) {
|
||||
dbProduct = dbProductResponse
|
||||
}
|
||||
|
||||
if (dbProduct) {
|
||||
// Map DB product to local product
|
||||
this.product = {
|
||||
id: dbProduct.id,
|
||||
merchant_id: dbProduct.merchant_id || dbProduct.shop_id || '',
|
||||
category_id: dbProduct.category_id || '',
|
||||
name: dbProduct.name,
|
||||
description: dbProduct.description || '',
|
||||
images: [] as string[],
|
||||
price: dbProduct.base_price || dbProduct.price || 0,
|
||||
original_price: dbProduct.market_price || dbProduct.original_price || 0,
|
||||
stock: dbProduct.available_stock || dbProduct.total_stock || dbProduct.stock || 0,
|
||||
sales: dbProduct.sale_count || dbProduct.sales || 0,
|
||||
status: dbProduct.status !== undefined ? dbProduct.status : 1,
|
||||
created_at: dbProduct.created_at || new Date().toISOString(),
|
||||
// Attributes
|
||||
specification: dbProduct.specification || null,
|
||||
usage: dbProduct.usage || null,
|
||||
side_effects: dbProduct.side_effects || null,
|
||||
precautions: dbProduct.precautions || null,
|
||||
expiry_date: dbProduct.expiry_date || null,
|
||||
storage_conditions: dbProduct.storage_conditions || null,
|
||||
approval_number: dbProduct.approval_number || null,
|
||||
tags: [] as string[]
|
||||
} as ProductType
|
||||
|
||||
// Handle Images
|
||||
if (dbProduct.image_urls) {
|
||||
try {
|
||||
const parsed = typeof dbProduct.image_urls === 'string' ? JSON.parse(dbProduct.image_urls) : dbProduct.image_urls
|
||||
if (Array.isArray(parsed)) {
|
||||
this.product.images = parsed.map((i: any) => String(i))
|
||||
}
|
||||
} catch (e) { console.error('Error parsing image_urls', e) }
|
||||
}
|
||||
} else {
|
||||
console.log('返回数据是对象')
|
||||
for (const key in dbProductRaw) {
|
||||
console.log(` ${key}:`, dbProductRaw[key], typeof dbProductRaw[key])
|
||||
// Fallback to main_image_url if no images found
|
||||
if (this.product.images.length === 0 && dbProduct.main_image_url) {
|
||||
this.product.images.push(dbProduct.main_image_url)
|
||||
}
|
||||
}
|
||||
// Fallback to 'image' field (legacy)
|
||||
if (this.product.images.length === 0 && dbProduct.image) {
|
||||
this.product.images.push(dbProduct.image)
|
||||
}
|
||||
// Final fallback
|
||||
if (this.product.images.length === 0) {
|
||||
this.product.images.push('/static/default-product.png')
|
||||
}
|
||||
|
||||
// Handle Tags
|
||||
if (dbProduct.tags) {
|
||||
try {
|
||||
const parsedTags = typeof dbProduct.tags === 'string' ? JSON.parse(dbProduct.tags) : dbProduct.tags
|
||||
if (Array.isArray(parsedTags)) {
|
||||
this.product.tags = parsedTags.map((t: any) => String(t))
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Handle JSON attributes if present
|
||||
if (dbProduct.attributes && typeof dbProduct.attributes === 'string') {
|
||||
try {
|
||||
const attrs = JSON.parse(dbProduct.attributes)
|
||||
if (attrs) {
|
||||
// Merge attributes into product if they match keys
|
||||
if (attrs.specification) this.product.specification = attrs.specification
|
||||
if (attrs.usage) this.product.usage = attrs.usage
|
||||
// ... augment as needed
|
||||
}
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
// Load SKUs
|
||||
// this.loadProductSkus(productId) // If SKU logic exists
|
||||
} else {
|
||||
throw new Error('No product found')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load product from DB', e)
|
||||
}
|
||||
|
||||
// 处理数据库返回数据:可能是数组或对象
|
||||
let dbProduct = null
|
||||
if (dbProductRaw) {
|
||||
if (Array.isArray(dbProductRaw)) {
|
||||
if (dbProductRaw.length > 0) {
|
||||
dbProduct = dbProductRaw[0] // 取数组第一个元素
|
||||
} else {
|
||||
console.warn('数据库返回空数组')
|
||||
}
|
||||
} else {
|
||||
dbProduct = dbProductRaw // 已经是对象
|
||||
}
|
||||
}
|
||||
|
||||
if (dbProduct) {
|
||||
console.log('使用数据库数据渲染页面')
|
||||
|
||||
// 调试:打印dbProduct的详细结构和类型
|
||||
console.log('dbProduct类型:', typeof dbProduct)
|
||||
console.log('dbProduct原型:', Object.getPrototypeOf(dbProduct))
|
||||
console.log('dbProduct的键:')
|
||||
for (let key in dbProduct) {
|
||||
console.log(' ', key, ':', dbProduct[key], '类型:', typeof dbProduct[key])
|
||||
}
|
||||
|
||||
// 验证必要字段,如果关键字段缺失则使用模拟数据
|
||||
// 注意:数据库返回的字段可能与本地ProductType不完全匹配
|
||||
console.log('验证必要字段,dbProduct:', dbProduct)
|
||||
|
||||
// 尝试多种方式访问属性
|
||||
const idValue = dbProduct.id !== undefined ? dbProduct.id : (dbProduct['id'] !== undefined ? dbProduct['id'] : undefined)
|
||||
const nameValue = dbProduct.name !== undefined ? dbProduct.name : (dbProduct['name'] !== undefined ? dbProduct['name'] : undefined)
|
||||
|
||||
// 价格字段兼容性处理:优先查找 price,其次查找 base_price
|
||||
let priceValue = dbProduct.price
|
||||
if (priceValue === undefined || priceValue === null) {
|
||||
priceValue = dbProduct.base_price
|
||||
}
|
||||
if (priceValue === undefined || priceValue === null) {
|
||||
priceValue = dbProduct['price']
|
||||
}
|
||||
if (priceValue === undefined || priceValue === null) {
|
||||
priceValue = dbProduct['base_price']
|
||||
}
|
||||
|
||||
const hasId = idValue !== undefined && idValue !== null
|
||||
const hasName = nameValue !== undefined && nameValue !== null
|
||||
const hasPrice = priceValue !== undefined && priceValue !== null
|
||||
|
||||
const hasRequiredFields = dbProduct && hasId && hasName && hasPrice
|
||||
console.log('字段检查 - id:', idValue, 'hasId:', hasId, 'name:', nameValue, 'hasName:', hasName, 'price:', priceValue, 'hasPrice:', hasPrice)
|
||||
console.log('hasRequiredFields:', hasRequiredFields)
|
||||
|
||||
if (!hasRequiredFields) {
|
||||
console.warn('数据库返回数据缺少必要字段,使用模拟数据')
|
||||
// 继续执行,会进入下面的else分支
|
||||
dbProduct = null
|
||||
} else {
|
||||
// 更新dbProduct的字段为实际值,确保后续使用正确的属性访问
|
||||
if (dbProduct.id === undefined && idValue !== undefined) dbProduct.id = idValue
|
||||
if (dbProduct.name === undefined && nameValue !== undefined) dbProduct.name = nameValue
|
||||
if (dbProduct.price === undefined && priceValue !== undefined) dbProduct.price = priceValue
|
||||
// 使用数据库数据 - 处理字段映射
|
||||
// 数据库Product接口和本地ProductType接口字段可能不同
|
||||
const images = [] as Array<string>
|
||||
|
||||
// 处理图片字段:优先使用image_urls字段,其次使用main_image_url
|
||||
console.log('处理数据库图片字段')
|
||||
|
||||
// 尝试从数据库的image_urls字段获取图片(JSON字符串或对象)
|
||||
if (dbProduct.image_urls) {
|
||||
let imagesArray: any[] = []
|
||||
if (typeof dbProduct.image_urls === 'string') {
|
||||
try {
|
||||
imagesArray = JSON.parse(dbProduct.image_urls)
|
||||
} catch (e) {
|
||||
console.error('解析image_urls字段失败:', e, dbProduct.image_urls)
|
||||
// 尝试逗号分割
|
||||
if (dbProduct.image_urls.includes(',')) {
|
||||
imagesArray = dbProduct.image_urls.split(',').map((img: string) => img.trim())
|
||||
}
|
||||
}
|
||||
} else if (Array.isArray(dbProduct.image_urls)) {
|
||||
imagesArray = dbProduct.image_urls
|
||||
}
|
||||
|
||||
if (imagesArray.length > 0) {
|
||||
for (const img of imagesArray) {
|
||||
if (typeof img === 'string' && img) {
|
||||
images.push(img)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有获取到相册图,但有主图,放入相册
|
||||
if (dbProduct.main_image_url) {
|
||||
// 如果相册里没有这张图,把它加到第一位
|
||||
if (!images.includes(dbProduct.main_image_url)) {
|
||||
images.unshift(dbProduct.main_image_url)
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容旧字段 image
|
||||
if (images.length === 0 && dbProduct.image) {
|
||||
images.push(dbProduct.image)
|
||||
}
|
||||
|
||||
// 如果仍然没有图片,使用传入的图片或默认图片
|
||||
if (images.length === 0) {
|
||||
if (options.image) {
|
||||
images.push(decodeURIComponent(options.image as string))
|
||||
} else {
|
||||
images.push('/static/product1.jpg')
|
||||
}
|
||||
}
|
||||
|
||||
// 补充模拟图片(如果图片数量不足3张)
|
||||
const needSupplementCount = 3 - images.length
|
||||
if (needSupplementCount > 0) {
|
||||
const supplementalImages = ['/static/product2.jpg', '/static/product3.jpg']
|
||||
for (let i = 0; i < needSupplementCount && i < supplementalImages.length; i++) {
|
||||
images.push(supplementalImages[i])
|
||||
}
|
||||
}
|
||||
|
||||
console.log('最终图片数组:', images)
|
||||
|
||||
// 映射字段:数据库shop_id对应本地merchant_id
|
||||
const merchantId = dbProduct.shop_id || dbProduct.merchant_id || 'merchant_001'
|
||||
|
||||
// 确保数值字段有效
|
||||
// 优先使用 price,不存在则使用 base_price
|
||||
let productPrice = 0
|
||||
if (typeof dbProduct.price === 'number') {
|
||||
productPrice = dbProduct.price
|
||||
} else if (typeof dbProduct.base_price === 'number') {
|
||||
productPrice = dbProduct.base_price
|
||||
} else if (priceValue !== undefined) {
|
||||
// 使用上面校验时获取到的 priceValue
|
||||
productPrice = Number(priceValue)
|
||||
}
|
||||
|
||||
const stock = (dbProduct.stock != null && !isNaN(Number(dbProduct.stock))) ? Math.floor(Number(dbProduct.stock)) : ((dbProduct.total_stock != null && !isNaN(Number(dbProduct.total_stock))) ? Math.floor(Number(dbProduct.total_stock)) : 100)
|
||||
const sales = (dbProduct.sales != null && !isNaN(Number(dbProduct.sales))) ? Math.floor(Number(dbProduct.sales)) : ((dbProduct.sale_count != null && !isNaN(Number(dbProduct.sale_count))) ? Math.floor(Number(dbProduct.sale_count)) : 50)
|
||||
|
||||
// 解析 attributes
|
||||
let attributes: any = {}
|
||||
if (dbProduct.attributes) {
|
||||
try {
|
||||
if (typeof dbProduct.attributes === 'string') {
|
||||
attributes = JSON.parse(dbProduct.attributes)
|
||||
} else {
|
||||
attributes = dbProduct.attributes
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析 attributes 失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
this.product = {
|
||||
id: dbProduct.id || productId,
|
||||
merchant_id: merchantId,
|
||||
category_id: dbProduct.category_id || 'cat_001',
|
||||
name: dbProduct.name || '商品名称',
|
||||
description: dbProduct.description || '这是一个高品质的商品,具有优秀的性能和优美的外观设计。采用环保材料,经过严格质检,保证用户的使用体验。',
|
||||
images: images,
|
||||
price: productPrice,
|
||||
original_price: (dbProduct.original_price != null && !isNaN(Number(dbProduct.original_price))) ? Number(dbProduct.original_price) : ((dbProduct.market_price != null && !isNaN(Number(dbProduct.market_price))) ? Number(dbProduct.market_price) : null),
|
||||
stock: stock,
|
||||
sales: sales,
|
||||
status: 1,
|
||||
created_at: dbProduct.created_at || '2024-01-01',
|
||||
// 药品相关字段
|
||||
specification: attributes.specification || dbProduct.specification || null,
|
||||
usage: attributes.usage || dbProduct.usage || null,
|
||||
side_effects: attributes.side_effects || dbProduct.side_effects || null,
|
||||
precautions: attributes.precautions || dbProduct.precautions || null,
|
||||
expiry_date: attributes.expiry_date || dbProduct.expiry_date || null,
|
||||
storage_conditions: attributes.storage_conditions || dbProduct.storage_conditions || null,
|
||||
approval_number: attributes.approval_number || dbProduct.approval_number || null,
|
||||
tags: dbProduct.tags ? (typeof dbProduct.tags === 'string' ? JSON.parse(dbProduct.tags) : dbProduct.tags) : []
|
||||
} as ProductType
|
||||
console.log('页面 product 对象已更新:', this.product)
|
||||
console.log('商品图片数组:', this.product.images)
|
||||
console.log('商品价格:', this.product.price, '库存:', this.product.stock, '销量:', this.product.sales)
|
||||
}
|
||||
} else {
|
||||
console.log('数据库无数据或加载失败,使用模拟数据')
|
||||
// 数据库无数据时,使用原有模拟逻辑
|
||||
const generatePriceFromId = (id: string): number => {
|
||||
let hash = 0
|
||||
for (let i = 0; i < id.length; i++) {
|
||||
hash = (hash << 5) - hash + id.charCodeAt(i)
|
||||
hash |= 0
|
||||
}
|
||||
const price = 50 + Math.abs(hash % 450)
|
||||
return parseFloat(price.toFixed(2))
|
||||
}
|
||||
|
||||
const basePrice = options.price ? parseFloat(options.price) : generatePriceFromId(productId)
|
||||
const originalPrice = options.originalPrice ? parseFloat(options.originalPrice) : parseFloat((basePrice * 1.2).toFixed(2))
|
||||
|
||||
const productName = options.name ? decodeURIComponent(options.name) : (() => {
|
||||
const productNames = ['高品质运动休闲鞋', '时尚简约双肩背包', '多功能智能手环', '便携式蓝牙音箱', '全自动雨伞', '抗菌防螨床上四件套', '不锈钢保温杯', '无线充电器', '高清行车记录仪', '智能体脂秤']
|
||||
const nameIndex = Math.abs(productId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % productNames.length
|
||||
return productNames[nameIndex]
|
||||
})()
|
||||
|
||||
const productImage = options.image ? decodeURIComponent(options.image) : '/static/product1.jpg'
|
||||
|
||||
const sales = 1000 + Math.abs(productId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % 5000
|
||||
const stock = 50 + Math.abs(productId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % 200
|
||||
|
||||
this.product = {
|
||||
id: productId,
|
||||
merchant_id: 'merchant_' + (Math.abs(productId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % 5 + 1).toString().padStart(3, '0'),
|
||||
category_id: 'cat_' + (Math.abs(productId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % 10 + 1).toString().padStart(3, '0'),
|
||||
name: productName,
|
||||
description: '这是一个高品质的商品,具有优秀的性能和优美的外观设计。采用环保材料,经过严格质检,保证用户的使用体验。',
|
||||
images: [productImage, '/static/product2.jpg', '/static/product3.jpg'],
|
||||
price: basePrice,
|
||||
original_price: originalPrice,
|
||||
stock: stock,
|
||||
sales: sales,
|
||||
status: 1,
|
||||
created_at: '2024-01-15'
|
||||
}
|
||||
console.error('Failed to load product detail:', e)
|
||||
// Fallback to options if available
|
||||
this.product.id = productId
|
||||
this.product.name = options.name ? decodeURIComponent(options.name) : '未知商品'
|
||||
this.product.price = options.price ? parseFloat(options.price) : 0
|
||||
this.product.images = options.image ? [decodeURIComponent(options.image)] : ['/static/default-product.png']
|
||||
}
|
||||
|
||||
// 尝试加载真实商户信息
|
||||
// Load Merchant and SKUs
|
||||
if (this.product.merchant_id) {
|
||||
await this.loadMerchantInfo(this.product.merchant_id)
|
||||
}
|
||||
if (this.product.id) {
|
||||
this.loadProductSkus(this.product.id)
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
},
|
||||
|
||||
async loadMerchantInfo(merchantId: string) {
|
||||
let realMerchantLoaded = false
|
||||
// 只有当 ID 是 UUID 格式(包含-)或者是真实数据时才尝试查询
|
||||
if (this.product.merchant_id && (this.product.merchant_id.includes('-') || !this.product.merchant_id.startsWith('merchant_'))) {
|
||||
console.log('尝试加载商户信息:', this.product.merchant_id)
|
||||
if (merchantId.includes('-') || !merchantId.startsWith('merchant_')) {
|
||||
try {
|
||||
const shop = await supabaseService.getShopByMerchantId(this.product.merchant_id)
|
||||
const shop = await supabaseService.getShopByMerchantId(merchantId)
|
||||
if (shop) {
|
||||
console.log('加载到商户信息:', shop.shop_name)
|
||||
|
||||
// 确保字段存在,避免 undefined 导致构造失败
|
||||
this.merchant = {
|
||||
id: shop.id || '',
|
||||
user_id: shop.merchant_id || '',
|
||||
shop_name: shop.shop_name || '未命名店铺',
|
||||
id: shop.id,
|
||||
user_id: shop.merchant_id,
|
||||
shop_name: shop.shop_name,
|
||||
shop_logo: shop.shop_logo || '/static/default-shop.png',
|
||||
shop_banner: shop.shop_banner || '/static/default-banner.png',
|
||||
shop_description: shop.description || '',
|
||||
contact_name: shop.contact_name || '店主',
|
||||
contact_phone: shop.contact_phone || '',
|
||||
shop_status: 1,
|
||||
// 优先使用 avg_rating,没有则使用默认值
|
||||
rating: shop.rating_avg !== undefined && shop.rating_avg !== null ? shop.rating_avg : 4.8,
|
||||
// 使用 order_count 或 product_count 作为销量/活跃度指标,如果没有则默认 0
|
||||
total_sales: shop.total_sales !== undefined ? shop.total_sales : (shop.order_count !== undefined ? shop.order_count : 0),
|
||||
rating: shop.rating_avg || 5.0,
|
||||
total_sales: shop.total_sales || 0,
|
||||
created_at: shop.created_at || new Date().toISOString()
|
||||
} as MerchantType
|
||||
realMerchantLoaded = true
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载商户信息失败', e)
|
||||
console.error('Load shop failed', e)
|
||||
}
|
||||
}
|
||||
|
||||
if (!realMerchantLoaded) {
|
||||
// 根据商家ID生成不同的商家信息
|
||||
const merchantIndex = Math.abs(this.product.merchant_id.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % 5
|
||||
const merchantIndex = Math.abs(merchantId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)) % 5
|
||||
const shopNames = ['优质好店', '品牌直营店', '官方旗舰店', '专卖店', '精品小店']
|
||||
const shopDescriptions = [
|
||||
'专注品质生活',
|
||||
'品牌官方直营,正品保障',
|
||||
'厂家直销,价格优惠',
|
||||
'专注本领域十年老店',
|
||||
'用心服务每一位顾客'
|
||||
]
|
||||
const contactNames = ['店主小王', '店长小李', '经理小张', '客服小赵', '老板小钱']
|
||||
|
||||
this.merchant = {
|
||||
id: this.product.merchant_id,
|
||||
user_id: 'user_' + (merchantIndex + 1).toString().padStart(3, '0'),
|
||||
id: merchantId,
|
||||
user_id: 'user_mock_' + merchantIndex,
|
||||
shop_name: shopNames[merchantIndex],
|
||||
shop_logo: '/static/shop-logo.png',
|
||||
shop_banner: '/static/shop-banner.png',
|
||||
shop_description: shopDescriptions[merchantIndex],
|
||||
contact_name: contactNames[merchantIndex],
|
||||
contact_phone: '138' + (10000000 + merchantIndex * 1111111).toString().substring(0, 8),
|
||||
shop_description: '优质服务,正品保障',
|
||||
contact_name: '店主',
|
||||
contact_phone: '',
|
||||
shop_status: 1,
|
||||
rating: 4.5 + (merchantIndex * 0.1),
|
||||
total_sales: 10000 + merchantIndex * 5000,
|
||||
created_at: '2023-06-01'
|
||||
}
|
||||
rating: 4.8,
|
||||
total_sales: 999,
|
||||
created_at: '2023-01-01'
|
||||
} as MerchantType
|
||||
}
|
||||
|
||||
this.loadProductSkus(productId)
|
||||
},
|
||||
|
||||
async loadProductSkus(productId: string) {
|
||||
@@ -674,32 +509,9 @@ export default {
|
||||
console.error('Fetch SKUs error', e)
|
||||
}
|
||||
|
||||
// 模拟加载商品SKU数据
|
||||
const basePrice = this.product.price
|
||||
|
||||
// 使用 productId 作为前缀生成唯一的 SKU ID,防止不同商品的 SKU ID 冲突
|
||||
this.productSkus = [
|
||||
{
|
||||
id: `${productId}_sku_001`,
|
||||
product_id: productId,
|
||||
sku_code: 'SKU001',
|
||||
specifications: { color: '红色', size: 'M' },
|
||||
price: basePrice,
|
||||
stock: 50,
|
||||
image_url: '/static/sku1.jpg',
|
||||
status: 1
|
||||
},
|
||||
{
|
||||
id: `${productId}_sku_002`,
|
||||
product_id: productId,
|
||||
sku_code: 'SKU002',
|
||||
specifications: { color: '蓝色', size: 'L' },
|
||||
price: parseFloat((basePrice * 1.1).toFixed(2)),
|
||||
stock: 30,
|
||||
image_url: '/static/sku2.jpg',
|
||||
status: 1
|
||||
}
|
||||
]
|
||||
// 如果没有从数据库加载到SKU,则不显示规格选择,直接作为无规格商品添加
|
||||
// 移除之前的Mock逻辑,因为Mock的ID不符合UUID格式会导致数据库错误
|
||||
},
|
||||
|
||||
onSwiperChange(e: any) {
|
||||
@@ -729,7 +541,7 @@ export default {
|
||||
},
|
||||
|
||||
async addToCart() {
|
||||
if (!this.selectedSkuId) {
|
||||
if (this.productSkus.length > 0 && !this.selectedSkuId) {
|
||||
uni.showToast({
|
||||
title: '请选择规格',
|
||||
icon: 'none'
|
||||
@@ -776,7 +588,7 @@ export default {
|
||||
},
|
||||
|
||||
buyNow() {
|
||||
if (!this.selectedSkuId) {
|
||||
if (this.productSkus.length > 0 && !this.selectedSkuId) {
|
||||
uni.showToast({
|
||||
title: '请选择规格',
|
||||
icon: 'none'
|
||||
@@ -784,7 +596,7 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
const sku = this.productSkus.find(s => s.id === this.selectedSkuId)
|
||||
const sku = this.selectedSkuId ? this.productSkus.find(s => s.id === this.selectedSkuId) : null
|
||||
|
||||
// 调试:打印价格信息
|
||||
console.log('立即购买 - 商品价格信息:')
|
||||
@@ -829,56 +641,53 @@ export default {
|
||||
},
|
||||
|
||||
checkFavoriteStatus(id: string) {
|
||||
const storedFavorites = uni.getStorageSync('favorites')
|
||||
if (storedFavorites) {
|
||||
try {
|
||||
const favorites = JSON.parse(storedFavorites as string) as any[]
|
||||
this.isFavorite = favorites.some(item => item.id === id)
|
||||
} catch (e) {
|
||||
console.error('Failed to parse favorites', e)
|
||||
}
|
||||
}
|
||||
// console.log('product-detail checkFavoriteStatus id:', id)
|
||||
this.checkFavorite(id)
|
||||
},
|
||||
|
||||
async checkFavorite(id: string) {
|
||||
const isFav = await supabaseService.checkFavorite(id)
|
||||
this.isFavorite = isFav
|
||||
},
|
||||
|
||||
toggleFavorite() {
|
||||
const storedFavorites = uni.getStorageSync('favorites')
|
||||
let favorites: any[] = []
|
||||
async toggleFavorite() {
|
||||
if (!this.product.id) return
|
||||
|
||||
if (storedFavorites) {
|
||||
try {
|
||||
favorites = JSON.parse(storedFavorites as string) as any[]
|
||||
} catch (e) {
|
||||
console.error('Failed to parse favorites', e)
|
||||
}
|
||||
// 显示loading
|
||||
uni.showLoading({ title: '处理中' })
|
||||
|
||||
try {
|
||||
// 记录操作前的状态
|
||||
const wasFavorite = this.isFavorite
|
||||
|
||||
// 执行切换,返回的是最新的状态(true=已收藏,false=未收藏)
|
||||
const isNowFavorite = await supabaseService.toggleFavorite(this.product.id)
|
||||
uni.hideLoading()
|
||||
|
||||
if (isNowFavorite !== wasFavorite) {
|
||||
// 状态发生了改变,说明操作成功
|
||||
this.isFavorite = isNowFavorite
|
||||
uni.showToast({
|
||||
title: isNowFavorite ? '收藏成功' : '已取消收藏',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
// 状态未改变,说明操作失败
|
||||
uni.showToast({
|
||||
title: '操作失败',
|
||||
icon: 'none'
|
||||
})
|
||||
// 确保状态同步
|
||||
this.checkFavoriteStatus(this.product.id)
|
||||
}
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
console.error('Toggle favorite failed', e)
|
||||
uni.showToast({
|
||||
title: '操作异常',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isFavorite) {
|
||||
// 取消收藏
|
||||
favorites = favorites.filter(item => item.id !== this.product.id)
|
||||
uni.showToast({
|
||||
title: '已取消收藏',
|
||||
icon: 'none'
|
||||
})
|
||||
} else {
|
||||
// 添加收藏
|
||||
favorites.push({
|
||||
id: this.product.id,
|
||||
name: this.product.name,
|
||||
price: this.product.price,
|
||||
original_price: this.product.original_price, // 保存原价
|
||||
image: this.product.images[0],
|
||||
sales: this.product.sales,
|
||||
shopId: this.merchant.id,
|
||||
shopName: this.merchant.shop_name
|
||||
})
|
||||
uni.showToast({
|
||||
title: '收藏成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
uni.setStorageSync('favorites', JSON.stringify(favorites))
|
||||
this.isFavorite = !this.isFavorite
|
||||
},
|
||||
|
||||
goToHome() {
|
||||
|
||||
Reference in New Issue
Block a user