consumer模块完成度95%,准备部署消费者端测试
This commit is contained in:
@@ -1,6 +1,31 @@
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
import type { AkReqResponse } from '@/uni_modules/ak-req/index.uts'
|
||||
|
||||
const OLD_URL = '192.168.1.61:18000'
|
||||
const NEW_URL = '119.146.131.237:9126'
|
||||
|
||||
function fixImageUrl(url: string | null): string {
|
||||
if (url == null) return ''
|
||||
if (url.indexOf(OLD_URL) >= 0) {
|
||||
return url.replace(OLD_URL, NEW_URL)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
function fixImageUrls(urls: any): string[] {
|
||||
if (urls == null) return []
|
||||
if (Array.isArray(urls)) {
|
||||
const result: string[] = []
|
||||
const arr = urls as any[]
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const fixed = fixImageUrl(arr[i] as string)
|
||||
if (fixed !== '') result.push(fixed)
|
||||
}
|
||||
return result
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
// 使用单例 Supabase 客户端
|
||||
// const supa = createClient(SUPA_URL, SUPA_KEY)
|
||||
|
||||
@@ -107,7 +132,8 @@ function parseProductFromRaw(item: any): Product {
|
||||
return []
|
||||
}
|
||||
|
||||
const mainImageUrl = getSafeString('main_image_url')
|
||||
const mainImageUrl = fixImageUrl(getSafeString('main_image_url'))
|
||||
const imageUrls = fixImageUrls(getSafeStringArray('image_urls'))
|
||||
|
||||
return {
|
||||
id: getSafeString('id'),
|
||||
@@ -119,7 +145,7 @@ function parseProductFromRaw(item: any): Product {
|
||||
market_price: getSafeNumber('market_price'),
|
||||
main_image_url: mainImageUrl,
|
||||
image_url: mainImageUrl,
|
||||
images: getSafeStringArray('image_urls'),
|
||||
images: imageUrls,
|
||||
category_id: getSafeString('category_id'),
|
||||
brand_id: getSafeString('brand_id'),
|
||||
merchant_id: getSafeString('merchant_id'),
|
||||
@@ -617,7 +643,7 @@ class SupabaseService {
|
||||
name: (typeof nameVal == 'string') ? (nameVal as string) : '',
|
||||
icon: icon,
|
||||
description: (typeof descVal == 'string') ? (descVal as string) : '',
|
||||
color: (typeof colorVal == 'string') ? (colorVal as string) : '#4CAF50',
|
||||
color: (typeof colorVal == 'string') ? (colorVal as string) : '#ff5000',
|
||||
level: 1,
|
||||
slug: (typeof slugVal == 'string') ? (slugVal as string) : ''
|
||||
}
|
||||
@@ -674,7 +700,7 @@ class SupabaseService {
|
||||
name: safeGetString(itemObj, 'name'),
|
||||
icon: icon,
|
||||
description: safeGetString(itemObj, 'description'),
|
||||
color: safeGetString(itemObj, 'color').length > 0 ? safeGetString(itemObj, 'color') : '#4CAF50',
|
||||
color: safeGetString(itemObj, 'color').length > 0 ? safeGetString(itemObj, 'color') : '#ff5000',
|
||||
level: 2,
|
||||
parent_id: safeGetString(itemObj, 'parent_id'),
|
||||
slug: safeGetString(itemObj, 'slug')
|
||||
@@ -1055,7 +1081,23 @@ class SupabaseService {
|
||||
}
|
||||
if (statusNum !== 1) continue
|
||||
|
||||
shops.push(item as Shop)
|
||||
// 手动创建 Shop 对象,避免安卓端类型转换错误
|
||||
const shop: Shop = {
|
||||
id: shopObj.getString('id') ?? '',
|
||||
merchant_id: shopObj.getString('merchant_id') ?? '',
|
||||
shop_name: shopObj.getString('shop_name') ?? '',
|
||||
shop_logo: shopObj.getString('shop_logo'),
|
||||
shop_banner: shopObj.getString('shop_banner'),
|
||||
description: shopObj.getString('description'),
|
||||
contact_name: shopObj.getString('contact_name'),
|
||||
contact_phone: shopObj.getString('contact_phone'),
|
||||
rating_avg: shopObj.getNumber('rating_avg'),
|
||||
total_sales: shopObj.getNumber('total_sales'),
|
||||
product_count: shopObj.getNumber('product_count'),
|
||||
total_sales_count: shopObj.getNumber('total_sales_count'),
|
||||
created_at: shopObj.getString('created_at')
|
||||
}
|
||||
shops.push(shop)
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -1317,7 +1359,7 @@ class SupabaseService {
|
||||
const item = JSON.parse(JSON.stringify(rawData[i])) as UTSJSONObject
|
||||
const images: string[] = []
|
||||
|
||||
const mainImageUrl = item.getString('main_image_url')
|
||||
const mainImageUrl = fixImageUrl(item.getString('main_image_url'))
|
||||
if (mainImageUrl != null && mainImageUrl !== '') {
|
||||
images.push(mainImageUrl)
|
||||
}
|
||||
@@ -1329,7 +1371,8 @@ class SupabaseService {
|
||||
const arr = imageUrlsRaw as string[]
|
||||
if (arr.length > 0 && images.length === 0) {
|
||||
for (let j = 0; j < arr.length; j++) {
|
||||
images.push(arr[j])
|
||||
const fixedUrl = fixImageUrl(arr[j])
|
||||
if (fixedUrl !== '') images.push(fixedUrl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1338,11 +1381,13 @@ class SupabaseService {
|
||||
const parsed = JSON.parse(rawUrlStr)
|
||||
if (Array.isArray(parsed) && images.length === 0) {
|
||||
for (let j = 0; j < parsed.length; j++) {
|
||||
images.push(parsed[j] as string)
|
||||
const fixedUrl = fixImageUrl(parsed[j] as string)
|
||||
if (fixedUrl !== '') images.push(fixedUrl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (images.indexOf(rawUrlStr) === -1) images.push(rawUrlStr)
|
||||
const fixedUrl = fixImageUrl(rawUrlStr)
|
||||
if (fixedUrl !== '' && images.indexOf(fixedUrl) === -1) images.push(fixedUrl)
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
@@ -1415,8 +1460,15 @@ class SupabaseService {
|
||||
}
|
||||
|
||||
console.log(`Merchant products found: ${(response.data as any[]).length}`)
|
||||
|
||||
const viewData = response.data as any[]
|
||||
const parsedProducts: Product[] = []
|
||||
for (let i = 0; i < viewData.length; i++) {
|
||||
parsedProducts.push(parseProductFromRaw(viewData[i]))
|
||||
}
|
||||
|
||||
return {
|
||||
data: response.data as Product[],
|
||||
data: parsedProducts,
|
||||
total: response.total ?? 0,
|
||||
page,
|
||||
limit,
|
||||
@@ -1482,7 +1534,7 @@ class SupabaseService {
|
||||
const item = JSON.parse(JSON.stringify(rawData[i])) as UTSJSONObject
|
||||
const images: string[] = []
|
||||
|
||||
const mainImageUrl = item.getString('main_image_url')
|
||||
const mainImageUrl = fixImageUrl(item.getString('main_image_url'))
|
||||
if (mainImageUrl != null && mainImageUrl !== '') {
|
||||
images.push(mainImageUrl)
|
||||
}
|
||||
@@ -1494,7 +1546,8 @@ class SupabaseService {
|
||||
const arr = imageUrlsRaw as string[]
|
||||
if (arr.length > 0 && images.length === 0) {
|
||||
for (let j = 0; j < arr.length; j++) {
|
||||
images.push(arr[j])
|
||||
const fixedUrl = fixImageUrl(arr[j])
|
||||
if (fixedUrl !== '') images.push(fixedUrl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1503,11 +1556,13 @@ class SupabaseService {
|
||||
const parsed = JSON.parse(rawUrlStr)
|
||||
if (Array.isArray(parsed) && images.length === 0) {
|
||||
for (let j = 0; j < parsed.length; j++) {
|
||||
images.push(parsed[j] as string)
|
||||
const fixedUrl = fixImageUrl(parsed[j] as string)
|
||||
if (fixedUrl !== '') images.push(fixedUrl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (images.indexOf(rawUrlStr) === -1) images.push(rawUrlStr)
|
||||
const fixedUrl = fixImageUrl(rawUrlStr)
|
||||
if (fixedUrl !== '' && images.indexOf(fixedUrl) === -1) images.push(fixedUrl)
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
@@ -1580,8 +1635,15 @@ class SupabaseService {
|
||||
}
|
||||
|
||||
console.log(`Shop products found: ${(response.data as any[]).length}`)
|
||||
|
||||
const viewData = response.data as any[]
|
||||
const parsedProducts: Product[] = []
|
||||
for (let i = 0; i < viewData.length; i++) {
|
||||
parsedProducts.push(parseProductFromRaw(viewData[i]))
|
||||
}
|
||||
|
||||
return {
|
||||
data: response.data as Product[],
|
||||
data: parsedProducts,
|
||||
total: response.total ?? 0,
|
||||
page,
|
||||
limit,
|
||||
@@ -2122,19 +2184,33 @@ class SupabaseService {
|
||||
if (typeof specRaw === 'string') {
|
||||
productSpec = specRaw
|
||||
} else if (specRaw instanceof UTSJSONObject) {
|
||||
const keys = UTSJSONObject.keys(specRaw)
|
||||
const parts: string[] = []
|
||||
for(let k = 0; k < keys.length; k++) {
|
||||
let val = specRaw.get(keys[k])
|
||||
if (val != null) {
|
||||
parts.push(`${keys[k]}: ${val}`)
|
||||
const keys = ['规格', '颜色', '尺码', '容量', '版本', '型号']
|
||||
const result: string[] = []
|
||||
for (let k = 0; k < keys.length; k++) {
|
||||
const key = keys[k]
|
||||
const val = specRaw.get(key)
|
||||
if (val != null && val !== '') {
|
||||
result.push(`${val}`)
|
||||
}
|
||||
}
|
||||
productSpec = parts.join('; ')
|
||||
if (result.length > 0) {
|
||||
productSpec = result.join(' ')
|
||||
} else {
|
||||
// Fallback for other keys
|
||||
const allKeys = UTSJSONObject.keys(specRaw)
|
||||
const parts: string[] = []
|
||||
for(let k = 0; k < allKeys.length; k++) {
|
||||
let val = specRaw.get(allKeys[k])
|
||||
if (val != null) {
|
||||
parts.push(`${val}`)
|
||||
}
|
||||
}
|
||||
productSpec = parts.join(' ')
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let jsonStr = JSON.stringify(specRaw)
|
||||
productSpec = jsonStr.replace(/["{}]/g, '').replace(/,/g, '; ')
|
||||
productSpec = jsonStr.replace(/["{}]/g, '').replace(/,/g, ' ').replace(/:/g, ' ')
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
@@ -2148,23 +2224,37 @@ class SupabaseService {
|
||||
|
||||
const specRaw = sObj.get('specifications')
|
||||
if (specRaw != null) {
|
||||
// 优先使用SKU的规格
|
||||
// 优先使用SKU的规格
|
||||
if (typeof specRaw === 'string') {
|
||||
productSpec = specRaw
|
||||
} else if (specRaw instanceof UTSJSONObject) {
|
||||
const keys = UTSJSONObject.keys(specRaw)
|
||||
const parts: string[] = []
|
||||
for(let k = 0; k < keys.length; k++) {
|
||||
let val = specRaw.get(keys[k])
|
||||
if (val != null) {
|
||||
parts.push(`${keys[k]}: ${val}`)
|
||||
const keys = ['规格', '颜色', '尺码', '容量', '版本', '型号']
|
||||
const result: string[] = []
|
||||
for (let k = 0; k < keys.length; k++) {
|
||||
const key = keys[k]
|
||||
const val = specRaw.get(key)
|
||||
if (val != null && val !== '') {
|
||||
result.push(`${val}`)
|
||||
}
|
||||
}
|
||||
productSpec = parts.join('; ')
|
||||
if (result.length > 0) {
|
||||
productSpec = result.join(' ')
|
||||
} else {
|
||||
// Fallback for other keys
|
||||
const allKeys = UTSJSONObject.keys(specRaw)
|
||||
const parts: string[] = []
|
||||
for(let k = 0; k < allKeys.length; k++) {
|
||||
let val = specRaw.get(allKeys[k])
|
||||
if (val != null) {
|
||||
parts.push(`${val}`)
|
||||
}
|
||||
}
|
||||
productSpec = parts.join(' ')
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let jsonStr = JSON.stringify(specRaw)
|
||||
productSpec = jsonStr.replace(/["{}]/g, '').replace(/,/g, '; ')
|
||||
productSpec = jsonStr.replace(/["{}]/g, '').replace(/,/g, ' ').replace(/:/g, ' ')
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
@@ -2379,23 +2469,29 @@ class SupabaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取与特定商家的聊天记录
|
||||
async getChatMessages(merchantId: string): Promise<ChatMessage[]> {
|
||||
// 获取与特定商家的聊天记录 (合并版本)
|
||||
async getChatMessages(merchantId: string, page: number = 1, pageSize: number = 20): Promise<ChatMessage[]> {
|
||||
try {
|
||||
console.log('[getChatMessages] 开始获取聊天记录,merchantId:', merchantId)
|
||||
console.log('[getChatMessages] 开始获取聊天记录,merchantId:', merchantId, 'page:', page)
|
||||
const userId = this.getCurrentUserId()
|
||||
if (userId == null) return []
|
||||
|
||||
const fromIndex = (page - 1) * pageSize
|
||||
const toIndex = fromIndex + pageSize - 1
|
||||
|
||||
// 使用 or 组合精确条件查询:(我发给商家) OR (商家发给我)
|
||||
const queryStr = `and(sender_id.eq.${userId},receiver_id.eq.${merchantId}),and(sender_id.eq.${merchantId},receiver_id.eq.${userId})`
|
||||
|
||||
const response = await supa
|
||||
.from('ml_chat_messages')
|
||||
.select('*')
|
||||
.or(`and(sender_id.eq.${userId},receiver_id.eq.${merchantId}),and(sender_id.eq.${merchantId},receiver_id.eq.${userId})`)
|
||||
.order('created_at', { ascending: false })
|
||||
.limit(50)
|
||||
.or(queryStr)
|
||||
.order('created_at', { ascending: false }) // 最新在前
|
||||
.range(fromIndex, toIndex)
|
||||
.execute()
|
||||
|
||||
|
||||
if (response.error != null) {
|
||||
console.error('获取聊天记录失败:', response.error)
|
||||
console.error('getChatMessages error:', response.error)
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -2413,16 +2509,14 @@ class SupabaseService {
|
||||
const getSafeString = (key: string): string => {
|
||||
const val = msgObj.get(key)
|
||||
if (val == null) return ''
|
||||
if (typeof val == 'string') return val
|
||||
return ''
|
||||
return val.toString()
|
||||
}
|
||||
|
||||
const getSafeBoolean = (key: string): boolean => {
|
||||
const val = msgObj.get(key)
|
||||
if (val == null) return false
|
||||
if (typeof val == 'boolean') return val
|
||||
if (typeof val == 'number') return (val as number) == 1
|
||||
return false
|
||||
if (typeof val == 'boolean') return val as boolean
|
||||
return (val.toString() == '1' || val.toString() == 'true')
|
||||
}
|
||||
|
||||
const msg: ChatMessage = {
|
||||
@@ -3018,6 +3112,94 @@ class SupabaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// 取消订单
|
||||
async cancelOrder(orderId: string): Promise<boolean> {
|
||||
try {
|
||||
const userId = this.getCurrentUserId()
|
||||
if (userId == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const response = await supa
|
||||
.from('ml_orders')
|
||||
.update({
|
||||
order_status: 5,
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.eq('id', orderId)
|
||||
.eq('user_id', userId)
|
||||
.execute()
|
||||
|
||||
if (response.error != null) {
|
||||
console.error('取消订单失败:', response.error)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('取消订单异常:', e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 删除订单
|
||||
async deleteOrder(orderId: string): Promise<boolean> {
|
||||
try {
|
||||
const userId = this.getCurrentUserId()
|
||||
if (userId == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const response = await supa
|
||||
.from('ml_orders')
|
||||
.delete()
|
||||
.eq('id', orderId)
|
||||
.eq('user_id', userId)
|
||||
.execute()
|
||||
|
||||
if (response.error != null) {
|
||||
console.error('删除订单失败:', response.error)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('删除订单异常:', e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 确认收货
|
||||
async confirmOrderReceived(orderId: string): Promise<boolean> {
|
||||
try {
|
||||
const userId = this.getCurrentUserId()
|
||||
if (userId == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const response = await supa
|
||||
.from('ml_orders')
|
||||
.update({
|
||||
order_status: 4,
|
||||
shipping_status: 3,
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.eq('id', orderId)
|
||||
.eq('user_id', userId)
|
||||
.execute()
|
||||
|
||||
if (response.error != null) {
|
||||
console.error('确认收货失败:', response.error)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('确认收货异常:', e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 删除地址
|
||||
async deleteAddress(addressId: string): Promise<boolean> {
|
||||
try {
|
||||
@@ -3202,14 +3384,23 @@ class SupabaseService {
|
||||
|
||||
const orderItems: UTSJSONObject[] = []
|
||||
console.log('[CreateOrder] orderData.items 类型:', typeof orderData.items, '是否数组:', Array.isArray(orderData.items))
|
||||
|
||||
if (orderData.items == null) {
|
||||
console.error('[CreateOrder] orderData.items 为 null!')
|
||||
return orderId
|
||||
}
|
||||
|
||||
const rawItems = orderData.items as any[]
|
||||
console.log('[CreateOrder] rawItems 长度:', rawItems.length)
|
||||
|
||||
if (rawItems.length === 0) {
|
||||
console.warn('[CreateOrder] rawItems 为空数组,没有商品项需要插入')
|
||||
return orderId
|
||||
}
|
||||
|
||||
for(let i = 0; i < rawItems.length; i++) {
|
||||
console.log('[CreateOrder] 处理商品项', i, '类型:', typeof rawItems[i])
|
||||
const rawItem = rawItems[i]
|
||||
const itemStr = JSON.stringify(rawItem)
|
||||
console.log('[CreateOrder] 商品项 JSON:', itemStr)
|
||||
const itemParsed = JSON.parse(itemStr)
|
||||
if (itemParsed == null) {
|
||||
console.error('[CreateOrder] 商品项解析失败')
|
||||
@@ -3334,7 +3525,6 @@ class SupabaseService {
|
||||
let grandTotal = 0.0
|
||||
for(let k = 0; k < groups.length; k++) {
|
||||
const g = JSON.parse(JSON.stringify(groups[k])) as UTSJSONObject
|
||||
// 安全获取 items 数组
|
||||
const gItemsRaw = g.get('items')
|
||||
if (gItemsRaw == null) continue
|
||||
const gItems = gItemsRaw as any[]
|
||||
@@ -3452,7 +3642,36 @@ class SupabaseService {
|
||||
const empty: any[] = []
|
||||
return empty
|
||||
}
|
||||
return data as any[]
|
||||
|
||||
// 修复订单项中的图片URL
|
||||
const orders = data as any[]
|
||||
for (let i = 0; i < orders.length; i++) {
|
||||
const order = orders[i]
|
||||
const orderStr = JSON.stringify(order)
|
||||
const orderObj = JSON.parse(orderStr) as UTSJSONObject
|
||||
const itemsRaw = orderObj.get('ml_order_items')
|
||||
if (itemsRaw != null && Array.isArray(itemsRaw)) {
|
||||
const items = itemsRaw as any[]
|
||||
for (let j = 0; j < items.length; j++) {
|
||||
const item = items[j]
|
||||
const itemStr = JSON.stringify(item)
|
||||
const itemObj = JSON.parse(itemStr) as UTSJSONObject
|
||||
const imgUrl = itemObj.getString('image_url')
|
||||
if (imgUrl != null) {
|
||||
itemObj['image_url'] = fixImageUrl(imgUrl)
|
||||
}
|
||||
const prodImg = itemObj.getString('product_image')
|
||||
if (prodImg != null) {
|
||||
itemObj['product_image'] = fixImageUrl(prodImg)
|
||||
}
|
||||
items[j] = itemObj
|
||||
}
|
||||
orderObj['ml_order_items'] = items
|
||||
orders[i] = orderObj
|
||||
}
|
||||
}
|
||||
|
||||
return orders
|
||||
} catch (error) {
|
||||
console.error('获取订单列表异常:', error)
|
||||
const empty: any[] = []
|
||||
@@ -3626,16 +3845,25 @@ class SupabaseService {
|
||||
// 提交售后申请
|
||||
async createRefund(data: any): Promise<RefundResponse> {
|
||||
try {
|
||||
console.log('[createRefund] 开始处理退款申请')
|
||||
const userId = this.getCurrentUserId()
|
||||
if (userId == null) return { success: false, message: '请先登录' }
|
||||
if (userId == null) {
|
||||
console.log('[createRefund] 用户未登录')
|
||||
return { success: false, message: '请先登录' }
|
||||
}
|
||||
|
||||
const d = JSON.parse(JSON.stringify(data)) as UTSJSONObject
|
||||
const orderId = d.getString('order_id')
|
||||
const orderId = d.getString('order_id') ?? ''
|
||||
const refundType = d.getNumber('refund_type')
|
||||
const refundReason = d.getString('refund_reason')
|
||||
const refundAmount = d.getNumber('refund_amount')
|
||||
const description = d.getString('description')
|
||||
const images = d.getArray('images')
|
||||
|
||||
console.log('[createRefund] orderId:', orderId)
|
||||
console.log('[createRefund] refundType:', refundType)
|
||||
console.log('[createRefund] refundReason:', refundReason)
|
||||
console.log('[createRefund] refundAmount:', refundAmount)
|
||||
|
||||
const payload = {
|
||||
user_id: userId,
|
||||
@@ -3649,16 +3877,38 @@ class SupabaseService {
|
||||
status: 1 // Pending
|
||||
}
|
||||
|
||||
console.log('[createRefund] 准备插入 ml_refunds')
|
||||
const response = await supa
|
||||
.from('ml_refunds')
|
||||
.insert(payload)
|
||||
.execute()
|
||||
|
||||
console.log('[createRefund] insert response.error:', response.error)
|
||||
|
||||
if (response.error != null) {
|
||||
console.error('提交售后失败:', response.error)
|
||||
return { success: false, message: '提交失败: ' + (response.error.message ?? '未知错误') }
|
||||
}
|
||||
|
||||
console.log('[createRefund] 插入成功,更新订单状态')
|
||||
// 更新订单状态为退款中
|
||||
const updateResponse = await supa
|
||||
.from('ml_orders')
|
||||
.update({
|
||||
order_status: 6, // 退款中
|
||||
updated_at: new Date().toISOString()
|
||||
})
|
||||
.eq('id', orderId)
|
||||
.execute()
|
||||
|
||||
console.log('[createRefund] update response.error:', updateResponse.error)
|
||||
|
||||
if (updateResponse.error != null) {
|
||||
console.error('更新订单状态失败:', updateResponse.error)
|
||||
// 不影响退款申请结果,只记录错误
|
||||
}
|
||||
|
||||
console.log('[createRefund] 完成,返回成功')
|
||||
return { success: true, message: '申请提交成功' }
|
||||
} catch (e) {
|
||||
console.error('提交售后异常:', e)
|
||||
@@ -4809,9 +5059,41 @@ class SupabaseService {
|
||||
return empty
|
||||
}
|
||||
|
||||
// 安全处理返回数据 - 安卓端可能是 UTSJSONObject 或 UTSArray
|
||||
const rawData: any[] = []
|
||||
const respData = response.data
|
||||
console.log('[getUserCoupons] 原始数据类型:', typeof respData, '是否数组:', Array.isArray(respData))
|
||||
if (respData != null) {
|
||||
if (Array.isArray(respData)) {
|
||||
const arr = respData as any[]
|
||||
console.log('[getUserCoupons] 数组长度:', arr.length)
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
rawData.push(arr[i])
|
||||
}
|
||||
} else if (respData instanceof UTSJSONObject) {
|
||||
// 单个对象情况,包装成数组
|
||||
console.log('[getUserCoupons] 单个对象,包装成数组')
|
||||
rawData.push(respData)
|
||||
} else {
|
||||
// 尝试 JSON 转换
|
||||
try {
|
||||
const parsed = JSON.parse(JSON.stringify(respData))
|
||||
console.log('[getUserCoupons] JSON转换后是否数组:', Array.isArray(parsed))
|
||||
if (Array.isArray(parsed)) {
|
||||
console.log('[getUserCoupons] 转换后数组长度:', parsed.length)
|
||||
for (let i = 0; i < parsed.length; i++) {
|
||||
rawData.push(parsed[i])
|
||||
}
|
||||
}
|
||||
} catch (parseErr) {
|
||||
console.error('解析优惠券数据异常:', parseErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('[getUserCoupons] 最终rawData长度:', rawData.length)
|
||||
|
||||
// 映射数据,将 template 的字段展平
|
||||
const coupons: UserCoupon[] = []
|
||||
const rawData = response.data as any[]
|
||||
for (let i = 0; i < rawData.length; i++) {
|
||||
const item = rawData[i]
|
||||
let template: any | null = null
|
||||
@@ -4861,19 +5143,21 @@ class SupabaseService {
|
||||
tMin = tObj.getNumber('min_spend') ?? 0
|
||||
}
|
||||
|
||||
const couponObj = new UTSJSONObject()
|
||||
couponObj.set('id', itemId)
|
||||
couponObj.set('user_id', itemUserId)
|
||||
couponObj.set('template_id', itemTmplId)
|
||||
couponObj.set('coupon_code', itemCode)
|
||||
couponObj.set('status', itemStatus)
|
||||
couponObj.set('received_at', itemRecv)
|
||||
couponObj.set('expire_at', itemExpire)
|
||||
couponObj.set('template_name', tName)
|
||||
couponObj.set('amount', tAmount)
|
||||
couponObj.set('min_spend', tMin)
|
||||
// 创建真正的 UserCoupon 对象,而不是 UTSJSONObject
|
||||
const couponItem: UserCoupon = {
|
||||
id: itemId,
|
||||
user_id: itemUserId,
|
||||
template_id: itemTmplId,
|
||||
coupon_code: itemCode,
|
||||
status: itemStatus,
|
||||
received_at: itemRecv,
|
||||
expire_at: itemExpire,
|
||||
template_name: tName,
|
||||
amount: tAmount,
|
||||
min_spend: tMin
|
||||
}
|
||||
|
||||
coupons.push(couponObj as UserCoupon)
|
||||
coupons.push(couponItem)
|
||||
}
|
||||
|
||||
return coupons
|
||||
@@ -5061,88 +5345,6 @@ class SupabaseService {
|
||||
// 聊天相关方法
|
||||
// ==========================================
|
||||
|
||||
// 获取特定会话的消息历史
|
||||
async getChatMessages(merchantId: string, page: number = 1, pageSize: number = 20): Promise<ChatMessage[]> {
|
||||
console.log('[getChatMessages] 开始获取聊天记录,merchantId:', merchantId, 'page:', page)
|
||||
const userId = this.getCurrentUserId()
|
||||
if (userId == null) {
|
||||
const empty: ChatMessage[] = []
|
||||
return empty
|
||||
}
|
||||
|
||||
// 计算分页 range
|
||||
const fromIndex = (page - 1) * pageSize
|
||||
const toIndex = fromIndex + pageSize - 1
|
||||
|
||||
try {
|
||||
// 使用 or 组合条件查询:(sender_id=me AND receiver_id=merchant) OR (sender_id=merchant AND receiver_id=me)
|
||||
// 注意:Supabase postgrest-js 的 .or() 语法如果是针对同一列很简单,针对复杂逻辑用 string syntax
|
||||
// 这里简化处理,如果不加 userId 过滤,全靠 RLS
|
||||
const response = await supa
|
||||
.from('ml_chat_messages')
|
||||
.select('*')
|
||||
.or(`sender_id.eq.${merchantId},receiver_id.eq.${merchantId}`)
|
||||
.order('created_at', { ascending: false })
|
||||
.range(fromIndex, toIndex)
|
||||
.execute()
|
||||
|
||||
if (response.error != null) {
|
||||
console.error('getChatMessages error:', response.error)
|
||||
const empty: ChatMessage[] = []
|
||||
return empty
|
||||
}
|
||||
|
||||
const rawData = response.data
|
||||
if (rawData == null) {
|
||||
const empty: ChatMessage[] = []
|
||||
return empty
|
||||
}
|
||||
|
||||
const messages: ChatMessage[] = []
|
||||
const rawList = rawData as any[]
|
||||
console.log('[getChatMessages] 获取到消息数量:', rawList.length)
|
||||
|
||||
for (let i = 0; i < rawList.length; i++) {
|
||||
const item = rawList[i]
|
||||
const msgObj = JSON.parse(JSON.stringify(item)) as UTSJSONObject
|
||||
|
||||
const getSafeString = (key: string): string => {
|
||||
const val = msgObj.get(key)
|
||||
if (val == null) return ''
|
||||
if (typeof val == 'string') return val
|
||||
return ''
|
||||
}
|
||||
|
||||
const getSafeBoolean = (key: string): boolean => {
|
||||
const val = msgObj.get(key)
|
||||
if (val == null) return false
|
||||
if (typeof val == 'boolean') return val
|
||||
if (typeof val == 'number') return (val as number) == 1
|
||||
return false
|
||||
}
|
||||
|
||||
const msg: ChatMessage = {
|
||||
id: getSafeString('id'),
|
||||
session_id: getSafeString('session_id'),
|
||||
sender_id: getSafeString('sender_id'),
|
||||
receiver_id: getSafeString('receiver_id'),
|
||||
content: getSafeString('content'),
|
||||
msg_type: getSafeString('msg_type'),
|
||||
is_read: getSafeBoolean('is_read'),
|
||||
is_from_user: getSafeBoolean('is_from_user'),
|
||||
extra_data: getSafeString('extra_data'),
|
||||
created_at: getSafeString('created_at')
|
||||
}
|
||||
messages.push(msg)
|
||||
}
|
||||
return messages
|
||||
} catch (e) {
|
||||
console.error('getChatMessages exception:', e)
|
||||
const empty: ChatMessage[] = []
|
||||
return empty
|
||||
}
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
async sendMessage(merchantId: string, content: string, msgType: string = 'text'): Promise<boolean> {
|
||||
// 确保 session 有效
|
||||
|
||||
Reference in New Issue
Block a user