Files
medical-mall/utils/supabaseService.uts
2026-02-02 17:34:31 +08:00

1407 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import supa from '@/components/supadb/aksupainstance.uts'
import type { AkReqResponse } from '@/uni_modules/ak-req/index.uts'
// 使用单例 Supabase 客户端
// const supa = createClient(SUPA_URL, SUPA_KEY)
// 类型定义
export interface Category {
id: string
name: string
icon: string
description: string
color: string
created_at?: string
}
export interface Product {
id: string
category_id: string
merchant_id: string
name: string
description?: string
specification?: string
price: number
base_price?: number
original_price?: number
market_price?: number
image?: string
main_image_url?: string
image_urls?: string // JSON string
manufacturer?: string
sales?: number
sale_count?: number
stock?: number
available_stock?: number
badge?: string
shop_id?: string
shop_name?: string
attributes?: string // JSON string
created_at?: string
expiry_date?: string
approval_number?: string
usage?: string
side_effects?: string
}
export interface Shop {
id: string
merchant_id: string
shop_name: string
shop_logo?: string
shop_banner?: string
description?: string
contact_name?: string
contact_phone?: string
rating_avg?: number
total_sales?: number
product_count?: number
total_sales_count?: number
created_at?: string
}
export interface CartItem {
id: string
user_id: string
product_id: string
sku_id?: string
quantity: number
selected: boolean
product_name?: string
product_image?: string
product_price?: number
product_specification?: string
shop_id?: string
shop_name?: string
created_at?: string
updated_at?: string
}
export interface UserAddress {
id: string
user_id: string
recipient_name: string
phone: string
province: string
city: string
district: string
detail_address: string
postal_code?: string
is_default: boolean
created_at?: string
updated_at?: string
}
export interface PaginatedResponse<T> {
data: T[]
total: number
page: number
limit: number
hasmore: boolean
}
export interface ProductSku {
id: string
product_id: string
sku_code: string
specifications: string // JSON string
price: number
market_price?: number
cost_price?: number
stock?: number
warning_stock?: number
image_url?: string
weight?: number
status?: number
created_at?: string
}
class SupabaseService {
// 获取当前用户ID
public getCurrentUserId(): string | null {
try {
// 优先从 Supabase 会话获取
const session = supa.getSession()
if (session && session.user) {
return session.user.getString('id')
}
// 后备:尝试从本地存储获取 (兼容旧逻辑)
const userId = uni.getStorageSync('user_id')
return userId ? userId as string : null
} catch (e) {
console.error('获取用户ID失败:', e)
return null
}
}
// 获取所有分类
async getCategories(): Promise<Category[]> {
try {
const response = await supa
.from('ml_categories')
.select('*')
.order('name', { ascending: true })
.execute()
if (response.error) {
console.error('获取分类失败:', response.error)
return []
}
return response.data as Category[]
} catch (error) {
console.error('获取分类异常:', error)
return []
}
}
// 获取指定分类的商品
async getProductsByCategory(
categoryId: string,
page: number = 1,
limit: number = 20
): Promise<PaginatedResponse<Product>> {
try {
const response = await supa
.from('ml_products')
.select('*', { count: 'exact' })
.eq('category_id', categoryId)
.order('sale_count', { ascending: false })
.page(page)
.limit(limit)
.execute()
if (response.error) {
console.error('获取商品失败:', response.error)
return {
data: [],
total: 0,
page,
limit,
hasmore: false
}
}
return {
data: response.data as Product[],
total: response.total || 0,
page,
limit,
hasmore: response.hasmore || false
}
} catch (error) {
console.error('获取商品异常:', error)
return {
data: [],
total: 0,
page,
limit,
hasmore: false
}
}
}
// 根据商品ID获取SKU列表
async getProductSkus(productId: string): Promise<ProductSku[]> {
try {
const response = await supa
.from('ml_product_skus')
.select('*')
.eq('product_id', productId)
.eq('status', 1)
.execute()
if (response.error) {
console.error('获取商品SKU失败:', response.error)
return []
}
return response.data as ProductSku[]
} catch (error) {
console.error('获取商品SKU异常:', error)
return []
}
}
// 搜索商品
async searchProducts(
keyword: string,
page: number = 1,
limit: number = 20,
sortBy: string = 'sales',
ascending: boolean = false
): Promise<PaginatedResponse<Product>> {
try {
let query = supa
.from('ml_products')
.select('*', { count: 'exact' })
.or(`name.ilike.%${keyword}%,manufacturer.ilike.%${keyword}%,specification.ilike.%${keyword}%`)
// 根据sortBy和ascending设置排序
if (sortBy === 'price') {
query = query.order('base_price', { ascending })
} else if (sortBy === 'sales' || sortBy === 'sale_count') {
query = query.order('sale_count', { ascending: false }) // 销量总是降序
} else {
// 默认按销量降序
query = query.order('sale_count', { ascending: false })
}
const response = await query
.page(page)
.limit(limit)
.execute()
if (response.error) {
console.error('搜索商品失败:', response.error)
return {
data: [],
total: 0,
page,
limit,
hasmore: false
}
}
return {
data: response.data as Product[],
total: response.total || 0,
page,
limit,
hasmore: response.hasmore || false
}
} catch (error) {
console.error('搜索商品异常:', error)
return {
data: [],
total: 0,
page,
limit,
hasmore: false
}
}
}
// 获取单个商品详情
async getProductById(productId: string): Promise<Product | null> {
try {
const response = await supa
.from('ml_products')
.select('*')
.eq('id', productId)
.single()
.executeAs<Product>()
if (response.error) {
console.error('获取商品详情失败:', response.error)
return null
}
return response.data as Product
} catch (error) {
console.error('获取商品详情异常:', error)
return null
}
}
// 根据商户ID获取店铺信息
async getShopByMerchantId(merchantId: string): Promise<Shop | null> {
try {
const response = await supa
.from('ml_shops')
.select('*')
.eq('merchant_id', merchantId)
.single()
.executeAs<Shop>()
if (response.error) {
console.error('获取店铺信息失败:', response.error)
return null
}
const data = response.data
if (Array.isArray(data)) {
if (data.length > 0) return data[0] as Shop
return null
}
return data as Shop
} catch (error) {
console.error('获取店铺信息异常:', error)
return null
}
}
// 根据商户ID获取商品列表
async getProductsByMerchantId(merchantId: string, page: number = 1, limit: number = 20): Promise<PaginatedResponse<Product>> {
try {
const response = await supa
.from('ml_products')
.select('*', { count: 'exact' })
.eq('merchant_id', merchantId)
.order('created_at', { ascending: false })
.page(page)
.limit(limit)
.execute()
if (response.error) {
console.error('获取商户商品失败:', response.error)
return {
data: [],
total: 0,
page,
limit,
hasmore: false
}
}
return {
data: response.data as Product[],
total: response.total || 0,
page,
limit,
hasmore: response.hasmore || false
}
} catch (error) {
console.error('获取商户商品异常:', error)
return {
data: [],
total: 0,
page,
limit,
hasmore: false
}
}
}
// 获取热销商品(按销量排序)
async getHotProducts(limit: number = 10): Promise<Product[]> {
try {
const response = await supa
.from('ml_products')
.select('*')
.order('sales', { ascending: false })
.limit(limit)
.execute()
if (response.error) {
console.error('获取热销商品失败:', response.error)
return []
}
return response.data as Product[]
} catch (error) {
console.error('获取热销商品异常:', error)
return []
}
}
// 获取按价格排序的商品(升序:从低到高)
async getProductsByPrice(limit: number = 10, ascending: boolean = true): Promise<Product[]> {
try {
const response = await supa
.from('ml_products')
.select('*')
.order('price', { ascending })
.limit(limit)
.execute()
if (response.error) {
console.error('获取价格排序商品失败:', response.error)
return []
}
return response.data as Product[]
} catch (error) {
console.error('获取价格排序商品异常:', error)
return []
}
}
// 获取新品(按创建时间排序,最新的在前)
async getProductsByNewest(limit: number = 10): Promise<Product[]> {
try {
const response = await supa
.from('ml_products')
.select('*')
.order('created_at', { ascending: false })
.limit(limit)
.execute()
if (response.error) {
console.error('获取新品失败:', response.error)
return []
}
return response.data as Product[]
} catch (error) {
console.error('获取新品异常:', error)
return []
}
}
// 获取推荐商品带badge的商品
async getRecommendedProducts(limit: number = 10): Promise<Product[]> {
try {
// 直接使用 neq 空字符串查询,忽略 null 值null 表示没有 badge不应被推荐
const response = await supa
.from('ml_products')
.select('*')
.neq('badge', '')
.order('sales', { ascending: false })
.limit(limit)
.execute()
if (response.error) {
console.error('获取推荐商品失败:', response.error)
return []
}
console.log('推荐商品查询结果条数:', response.data?.length || 0)
return response.data as Product[] || []
} catch (error) {
console.error('获取推荐商品异常:', error)
return []
}
}
// 获取特价商品badge为'特价'
async getDiscountProducts(limit: number = 10): Promise<Product[]> {
try {
const response = await supa
.from('ml_products')
.select('*')
.eq('badge', '特价')
.order('sales', { ascending: false })
.limit(limit)
.execute()
if (response.error) {
console.error('获取特价商品失败:', response.error)
return []
}
console.log('特价商品查询结果条数:', response.data?.length || 0)
return response.data as Product[] || []
} catch (error) {
console.error('获取特价商品异常:', error)
return []
}
}
// 获取当前用户的购物车商品(关联商品和店铺信息)
async getCartItems(): Promise<CartItem[]> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.warn('用户未登录,无法获取购物车')
return []
}
// 查询购物车表,并关联商品表(使用内联关联)
const response = await supa
.from('ml_shopping_cart')
.select(`
id,
user_id,
product_id,
sku_id,
quantity,
selected,
created_at,
updated_at,
ml_products!inner (
id,
name,
image,
price,
specification,
merchant_id
)
`)
.eq('user_id', userId)
.order('created_at', { ascending: false })
.execute()
if (response.error) {
console.error('获取购物车失败:', response.error)
return []
}
const cartData = response.data as any[]
// 调试日子:打印购物车数据第一条结构,确认产品字段名
if (cartData && Array.isArray(cartData) && cartData.length > 0) {
console.log('Cart Item Structure:', JSON.stringify(cartData[0]))
}
const merchantIds: string[] = []
if (cartData && Array.isArray(cartData)) {
for (const item of cartData) {
// PostgREST 返回的关联字段通常与表名一致
// 尝试获取ml_products如果为空则尝试products
let product = item['ml_products'] as any
if (!product) {
product = item['products'] as any
}
if (product && product.merchant_id && !merchantIds.includes(product.merchant_id)) {
merchantIds.push(product.merchant_id as string)
}
}
}
// 查询店铺信息
const shopMap = new Map<string, any>()
if (merchantIds.length > 0) {
const shopRes = await supa
.from('ml_shops')
.select('id, merchant_id, shop_name')
.in('merchant_id', merchantIds)
.execute()
if (!shopRes.error && shopRes.data != null) {
const shops = shopRes.data as any[]
for (const shop of shops) {
shopMap.set(shop.merchant_id as string, shop)
}
}
}
// 处理返回数据构建CartItem数组
const cartItems: CartItem[] = []
if (cartData && Array.isArray(cartData)) {
for (const item of cartData) {
let product = item['ml_products'] as any
if (!product) {
product = item['products'] as any
}
const merchantId = product?.merchant_id as string
const shopInfo = shopMap.get(merchantId)
cartItems.push({
id: item.id as string,
user_id: item.user_id as string,
product_id: item.product_id as string,
sku_id: item.sku_id as string,
quantity: item.quantity as number,
selected: item.selected as boolean,
product_name: product?.name as string,
product_image: product?.image as string,
product_price: product?.price as number,
product_specification: product?.specification as string,
shop_id: shopInfo ? (shopInfo['id'] as string) : (merchantId || 'unknown_shop'),
shop_name: shopInfo ? (shopInfo['shop_name'] as string) : '未知店铺',
created_at: item.created_at as string,
updated_at: item.updated_at as string
})
}
}
return cartItems
} catch (error) {
console.error('获取购物车异常:', error)
return []
}
}
// 添加商品到购物车
async addToCart(productId: string, quantity: number = 1, skuId?: string): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法添加商品到购物车')
return false
}
// 检查商品是否已在购物车中
// 注意:必须处理 sku_id 为空的情况,使用 is.null 过滤器
let query = supa
.from('ml_shopping_cart')
.select('*')
.eq('user_id', userId)
.eq('product_id', productId)
if (skuId && skuId.length > 0) {
query = query.eq('sku_id', skuId)
} else {
query = query.is('sku_id', null)
}
const existingResponse = await query.single().execute()
let existingItem: any | null = null
if (existingResponse.data != null) {
const rawData = existingResponse.data as any
if (Array.isArray(rawData)) {
if (rawData.length > 0) {
existingItem = rawData[0]
}
} else {
existingItem = rawData
}
}
let response
if (existingItem != null) {
// 商品已存在,更新数量
console.log('Found existing cart item:', JSON.stringify(existingItem))
// 确保 existingItem.id 存在
const itemId = existingItem['id']
const itemQty = existingItem['quantity']
if (itemId != null) {
const currentQty = typeof itemQty === 'number' ? itemQty : parseInt(String(itemQty || 0))
const newQty = currentQty + quantity
response = await supa
.from('ml_shopping_cart')
.update({
quantity: newQty,
updated_at: new Date().toISOString()
})
.eq('id', itemId)
.execute()
} else {
console.error('购物车已有商品但缺少ID无法更新. Data:', JSON.stringify(existingItem))
return false
}
} else {
// 商品不存在,添加新记录
response = await supa
.from('ml_shopping_cart')
.insert({
user_id: userId,
product_id: productId,
sku_id: skuId || null,
quantity: quantity,
selected: true,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
})
.execute()
}
if (response.error) {
console.error('添加商品到购物车失败:', response.error)
return false
}
return true
} catch (error) {
console.error('添加商品到购物车异常:', error)
return false
}
}
// 更新购物车商品数量
async updateCartItemQuantity(cartItemId: string, quantity: number): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法更新购物车')
return false
}
if (quantity < 1) {
// 数量小于1时删除商品
return await this.deleteCartItem(cartItemId)
}
const response = await supa
.from('ml_shopping_cart')
.update({
quantity: quantity,
updated_at: new Date().toISOString()
})
.eq('id', cartItemId)
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('更新购物车商品数量失败:', response.error)
return false
}
return true
} catch (error) {
console.error('更新购物车商品数量异常:', error)
return false
}
}
// 更新购物车商品选中状态
async updateCartItemSelection(cartItemId: string, selected: boolean): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法更新购物车')
return false
}
const response = await supa
.from('ml_shopping_cart')
.update({
selected: selected,
updated_at: new Date().toISOString()
})
.eq('id', cartItemId)
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('更新购物车商品选中状态失败:', response.error)
return false
}
return true
} catch (error) {
console.error('更新购物车商品选中状态异常:', error)
return false
}
}
// 批量更新购物车商品选中状态
async batchUpdateCartItemSelection(cartItemIds: string[], selected: boolean): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法更新购物车')
return false
}
const response = await supa
.from('ml_shopping_cart')
.update({
selected: selected,
updated_at: new Date().toISOString()
})
.eq('user_id', userId)
.in('id', cartItemIds)
.execute()
if (response.error) {
console.error('批量更新购物车商品选中状态失败:', response.error)
return false
}
return true
} catch (error) {
console.error('批量更新购物车商品选中状态异常:', error)
return false
}
}
// 删除购物车商品
async deleteCartItem(cartItemId: string): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法删除购物车商品')
return false
}
const response = await supa
.from('ml_shopping_cart')
.delete()
.eq('id', cartItemId)
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('删除购物车商品失败:', response.error)
return false
}
return true
} catch (error) {
console.error('删除购物车商品异常:', error)
return false
}
}
// 批量删除购物车商品
async batchDeleteCartItems(cartItemIds: string[]): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法删除购物车商品')
return false
}
const response = await supa
.from('ml_shopping_cart')
.delete()
.eq('user_id', userId)
.in('id', cartItemIds)
.execute()
if (response.error) {
console.error('批量删除购物车商品失败:', response.error)
return false
}
return true
} catch (error) {
console.error('批量删除购物车商品异常:', error)
return false
}
}
// 清空购物车
async clearCart(): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法清空购物车')
return false
}
const response = await supa
.from('ml_shopping_cart')
.delete()
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('清空购物车失败:', response.error)
return false
}
return true
} catch (error) {
console.error('清空购物车异常:', error)
return false
}
}
// 获取当前用户的所有地址
async getAddresses(): Promise<UserAddress[]> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.warn('用户未登录,无法获取地址')
return []
}
const response = await supa
.from('ml_user_addresses')
.select('*, recipient_name:receiver_name, phone:receiver_phone, detail_address:address_detail')
.eq('user_id', userId)
.order('is_default', { ascending: false })
.order('created_at', { ascending: false })
.execute()
if (response.error) {
console.error('获取地址失败:', response.error)
return []
}
return response.data as UserAddress[]
} catch (error) {
console.error('获取地址异常:', error)
return []
}
}
// 根据ID获取地址详情
async getAddressById(addressId: string): Promise<UserAddress | null> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.warn('用户未登录,无法获取地址')
return null
}
const response = await supa
.from('ml_user_addresses')
.select('*, recipient_name:receiver_name, phone:receiver_phone, detail_address:address_detail')
.eq('id', addressId)
.eq('user_id', userId)
.single()
.execute()
if (response.error) {
console.error('获取地址详情失败:', response.error)
return null
}
return response.data as UserAddress
} catch (error) {
console.error('获取地址详情异常:', error)
return null
}
}
// 添加新地址
async addAddress(address: {
recipient_name: string
phone: string
province: string
city: string
district: string
detail_address: string
postal_code?: string
is_default?: boolean
}): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法添加地址')
return false
}
// 如果设置为默认地址,需要先取消其他默认地址
if (address.is_default) {
await this.clearDefaultAddress(userId)
}
const response = await supa
.from('ml_user_addresses')
.insert({
user_id: userId,
receiver_name: address.recipient_name,
receiver_phone: address.phone,
province: address.province,
city: address.city,
district: address.district,
address_detail: address.detail_address,
postal_code: address.postal_code || null,
is_default: address.is_default || false,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
})
.execute()
if (response.error) {
console.error('添加地址失败:', response.error)
return false
}
return true
} catch (error) {
console.error('添加地址异常:', error)
return false
}
}
// 更新地址
async updateAddress(addressId: string, address: {
recipient_name?: string
phone?: string
province?: string
city?: string
district?: string
detail_address?: string
postal_code?: string
is_default?: boolean
}): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法更新地址')
return false
}
// 如果设置为默认地址,需要先取消其他默认地址
if (address.is_default) {
await this.clearDefaultAddress(userId)
}
// 构造更新数据,映射字段名到数据库列名
const updateData = {}
if (address.recipient_name != null) updateData['receiver_name'] = address.recipient_name
if (address.phone != null) updateData['receiver_phone'] = address.phone
if (address.province != null) updateData['province'] = address.province
if (address.city != null) updateData['city'] = address.city
if (address.district != null) updateData['district'] = address.district
if (address.detail_address != null) updateData['address_detail'] = address.detail_address
if (address.postal_code != null) updateData['postal_code'] = address.postal_code
if (address.is_default != null) updateData['is_default'] = address.is_default
updateData['updated_at'] = new Date().toISOString()
const response = await supa
.from('ml_user_addresses')
.update(updateData)
.eq('id', addressId)
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('更新地址失败:', response.error)
return false
}
return true
} catch (error) {
console.error('更新地址异常:', error)
return false
}
}
// 删除地址
async deleteAddress(addressId: string): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法删除地址')
return false
}
const response = await supa
.from('ml_user_addresses')
.delete()
.eq('id', addressId)
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('删除地址失败:', response.error)
return false
}
return true
} catch (error) {
console.error('删除地址异常:', error)
return false
}
}
// 清除默认地址(内部使用)
private async clearDefaultAddress(userId: string): Promise<void> {
try {
await supa
.from('ml_user_addresses')
.update({
is_default: false,
updated_at: new Date().toISOString()
})
.eq('user_id', userId)
.eq('is_default', true)
.execute()
} catch (error) {
console.error('清除默认地址异常:', error)
}
}
// 获取用户资料
async getUserProfile(): Promise<any | null> {
try {
const userId = this.getCurrentUserId()
if (!userId) return null
// 联合查询 auth user 和 profile
// 由于 Supabase auth table 不可直接访问,这里查询 ml_user_profiles
const response = await supa
.from('ml_user_profiles')
.select('*')
.eq('user_id', userId)
.single()
.execute()
if (response.error) {
// 如果不存在 profile可能只有 auth user这里暂时返回空或创建默认
return null
}
return response.data
} catch (e) {
return null
}
}
// 创建订单
async createOrder(orderData: {
merchant_id: string,
product_amount: number,
shipping_fee: number,
total_amount: number,
shipping_address: any,
items: any[]
}): Promise<string | null> {
try {
const userId = this.getCurrentUserId()
if (!userId) return null
// 生成订单号
const orderNo = 'ORD' + Date.now() + Math.floor(Math.random() * 1000)
// 1. 创建主订单
const orderResponse = await supa
.from('ml_orders')
.insert({
user_id: userId,
merchant_id: orderData.merchant_id,
order_no: orderNo,
product_amount: orderData.product_amount,
shipping_fee: orderData.shipping_fee,
total_amount: orderData.total_amount,
paid_amount: 0,
shipping_address: JSON.stringify(orderData.shipping_address),
order_status: 1, // 待付款
payment_status: 1, // 未支付
shipping_status: 1, // 未发货
created_at: new Date().toISOString()
})
.select()
.single()
.execute()
if (orderResponse.error) {
console.error('创建订单失败:', orderResponse.error)
return null
}
const orderId = orderResponse.data['id'] as string
// 2. 创建订单项
const orderItems = orderData.items.map((item: any) => ({
order_id: orderId,
product_id: item.product_id,
sku_id: item.sku_id || null,
product_name: item.product_name,
sku_name: item.sku_name || '',
specifications: item.specifications ? JSON.stringify(item.specifications) : '{}',
image_url: item.image_url,
price: item.price,
quantity: item.quantity,
total_amount: item.price * item.quantity,
created_at: new Date().toISOString()
}))
const itemsResponse = await supa
.from('ml_order_items')
.insert(orderItems)
.execute()
if (itemsResponse.error) {
console.error('创建订单项失败:', itemsResponse.error)
// 此时应该回滚订单,但这里简化处理
return null
}
// 3. 清除购物车中已购买的商品(如果是从购物车购买)
// 这一步通常在前端调用 removeCartItem 或在此处根据参数处理
return orderId
} catch (error) {
console.error('创建订单异常:', error)
return null
}
}
// 获取订单列表
async getOrders(status: number = 0): Promise<any[]> {
try {
const userId = this.getCurrentUserId()
if (!userId) return []
let query = supa
.from('ml_orders')
.select(`
*,
ml_order_items (*)
`)
.eq('user_id', userId)
.order('created_at', { ascending: false })
if (status > 0) {
query = query.eq('order_status', status)
}
const response = await query.execute()
if (response.error) {
console.error('获取订单列表失败:', response.error)
return []
}
return response.data || []
} catch (error) {
console.error('获取订单列表异常:', error)
return []
}
}
// 获取订单详情
async getOrderDetail(orderId: string): Promise<any | null> {
try {
const userId = this.getCurrentUserId()
if (!userId) return null
const response = await supa
.from('ml_orders')
.select(`
*,
ml_order_items (*),
ml_shops (shop_name, id)
`)
.eq('id', orderId)
.eq('user_id', userId)
.single()
.execute()
if (response.error) {
return null
}
return response.data
} catch (e) {
return null
}
}
// 收藏相关
async checkFavorite(productId: string): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) return false
const response = await supa
.from('ml_user_favorites')
.select('id')
.eq('user_id', userId)
.eq('target_id', productId)
.eq('target_type', 1) // 1 for product
.single()
.execute()
return !!response.data
} catch(e) {
return false
}
}
async toggleFavorite(productId: string): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) return false
// Check if exists
const exists = await this.checkFavorite(productId)
if (exists) {
// Delete
await supa
.from('ml_user_favorites')
.delete()
.eq('user_id', userId)
.eq('target_id', productId)
.eq('target_type', 1)
.execute()
return false // Now not favorite
} else {
// Add
await supa
.from('ml_user_favorites')
.insert({
user_id: userId,
target_id: productId,
target_type: 1,
created_at: new Date().toISOString()
})
.execute()
return true // Now favorite
}
} catch (e) {
return false
}
}
async getFavorites(): Promise<any[]> {
try {
const userId = this.getCurrentUserId()
if (!userId) return []
// 需要关联查询商品信息
const response = await supa
.from('ml_user_favorites')
.select(`
id,
target_id,
created_at,
ml_products!target_id (
id, name, image_urls, main_image_url, price, sales
)
`)
.eq('user_id', userId)
.eq('target_type', 1)
.order('created_at', { ascending: false })
.execute()
if (response.error) return []
return response.data || []
} catch (e) {
return []
}
}
async getAddressList(): Promise<UserAddress[]> {
try {
const userId = this.getCurrentUserId()
if (!userId) return []
const response = await supa
.from('ml_user_addresses')
.select('*, recipient_name:receiver_name, phone:receiver_phone, detail_address:address_detail')
.eq('user_id', userId)
.order('is_default', { ascending: false })
.order('created_at', { ascending: false })
.execute()
if (response.error) {
console.error('获取地址列表失败:', response.error)
return []
}
return response.data as UserAddress[]
} catch (e) {
console.error('获取地址列表异常:', e)
return []
}
}
// 设置默认地址
async setDefaultAddress(addressId: string): Promise<boolean> {
try {
const userId = this.getCurrentUserId()
if (!userId) {
console.error('用户未登录,无法设置默认地址')
return false
}
// 先取消所有默认地址
await this.clearDefaultAddress(userId)
// 设置新的默认地址
const response = await supa
.from('ml_user_addresses')
.update({
is_default: true,
updated_at: new Date().toISOString()
})
.eq('id', addressId)
.eq('user_id', userId)
.execute()
if (response.error) {
console.error('设置默认地址失败:', response.error)
return false
}
return true
} catch (error) {
console.error('设置默认地址异常:', error)
return false
}
}
}
// 导出单例实例
export const supabaseService = new SupabaseService()
// 默认导出
export default supabaseService