consumerm模块完成度90%,完善消费者和商家端数据库表,商品、聊天、订单数据对接好了supabase,和商家端对接了聊天功能,安卓端编译通过了css样式,剩余几个页面在处理函数规范问题

This commit is contained in:
cyh666666
2026-02-24 17:17:49 +08:00
parent e2f1dfb097
commit e606c597ca
174 changed files with 37917 additions and 4444 deletions

View File

@@ -1,6 +1,7 @@
<!-- 消费者端 - 商品详情页 -->
<template>
<view class="product-detail-page">
<scroll-view class="page-scroll" scroll-y="true">
<!-- 商品图片轮播 -->
<view class="product-images">
<swiper class="image-swiper" :indicator-dots="true" :autoplay="false" @change="onSwiperChange">
@@ -23,7 +24,7 @@
<!-- 店铺信息 -->
<view class="shop-info" @click="goToShop">
<image :src="merchant.shop_logo || '/static/default-shop.png'" class="shop-logo" />
<image :src="merchant.shop_logo ?? '/static/default-shop.png'" class="shop-logo" />
<view class="shop-details">
<text class="shop-name" @click.stop="goToShop">{{ merchant.shop_name }}</text>
<view class="shop-stats-row">
@@ -67,7 +68,7 @@
<!-- 规格选择 -->
<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-selected">{{ selectedSpec ?? '请选择规格' }}</text>
<text class="spec-arrow">></text>
</view>
@@ -94,7 +95,7 @@
<!-- 商品详情 -->
<view class="product-description">
<view class="section-title">商品详情</view>
<text class="description-text">{{ product.description || '暂无详细描述' }}</text>
<text class="description-text">{{ product.description ?? '暂无详细描述' }}</text>
<!-- 商品详情图片 -->
<view class="detail-images" v-if="product.images && product.images.length > 0">
<image v-for="(img, index) in product.images"
@@ -105,6 +106,7 @@
@click="previewImage(index)" />
</view>
</view>
</scroll-view>
<!-- 底部操作栏 -->
<view class="bottom-actions">
@@ -136,7 +138,7 @@
<text class="spec-title">选择规格</text>
<text class="close-btn" @click="hideSpecModal">×</text>
</view>
<view class="spec-list">
<scroll-view class="spec-list" direction="vertical">
<view v-for="sku in productSkus" :key="sku.id"
class="spec-item"
:class="{ active: selectedSkuId === sku.id }"
@@ -145,7 +147,7 @@
<text class="spec-price">¥{{ sku.price }}</text>
<text class="spec-stock">库存{{ sku.stock }}</text>
</view>
</view>
</scroll-view>
</view>
</view>
@@ -156,7 +158,7 @@
<text class="params-title">商品参数</text>
<text class="close-btn" @click="hideParamsModal">×</text>
</view>
<view class="params-list">
<scroll-view class="params-list" direction="vertical">
<view class="params-item" v-if="product.specification">
<text class="params-label">规格</text>
<text class="params-value">{{ product.specification }}</text>
@@ -189,7 +191,7 @@
<text class="params-label">标签</text>
<text class="params-value">{{ product.tags.join(', ') }}</text>
</view>
</view>
</scroll-view>
</view>
</view>
@@ -272,7 +274,7 @@ export default {
}
},
onLoad(options: any) {
const productId = options.productId as string || options.id as string
const productId = (options['productId'] ?? options['id']) as string
const productPrice = options.price ? parseFloat(options.price) : null
const productOriginalPrice = options.originalPrice ? parseFloat(options.originalPrice) : null
@@ -370,7 +372,7 @@ export default {
uni.showLoading({ title: '加载中...' })
try {
const dbProductResponse = await supabaseService.getProductById(productId)
let dbProduct: any = null
let dbProduct: any | null = null
if (Array.isArray(dbProductResponse) && dbProductResponse.length > 0) {
dbProduct = dbProductResponse[0]
} else if (dbProductResponse && !Array.isArray(dbProductResponse)) {
@@ -381,25 +383,25 @@ export default {
// Map DB product to local product
this.product = {
id: dbProduct.id,
merchant_id: dbProduct.merchant_id || dbProduct.shop_id || '',
category_id: dbProduct.category_id || '',
merchant_id: dbProduct.merchant_id ?? dbProduct.shop_id ?? '',
category_id: dbProduct.category_id ?? '',
name: dbProduct.name,
description: dbProduct.description || '',
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,
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(),
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,
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
@@ -482,15 +484,15 @@ export default {
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_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,
rating: shop.rating_avg || 5.0,
total_sales: shop.total_sales || 0,
created_at: shop.created_at || new Date().toISOString()
rating: shop.rating_avg ?? 5.0,
total_sales: shop.total_sales ?? 0,
created_at: shop.created_at ?? new Date().toISOString()
} as MerchantType
realMerchantLoaded = true
}
@@ -547,7 +549,7 @@ export default {
specifications: specs,
price: sku.price,
stock: sku.stock !== undefined ? sku.stock : 0,
image_url: sku.image_url || '',
image_url: sku.image_url != null ? sku.image_url : '',
status: sku.status !== undefined ? sku.status : 1
} as ProductSkuType
})
@@ -560,7 +562,7 @@ export default {
// 新增:加载优惠券
async loadCoupons() {
if (!this.product.merchant_id) return
if (this.product.merchant_id == '') return
// Safety check for cached service definition
// @ts-ignore
if (typeof supabaseService.fetchShopCoupons === 'function') {
@@ -574,12 +576,12 @@ export default {
// 新增:联系客服(商家)
contactMerchant() {
if (!supabaseService.getCurrentUserId()) {
if (supabaseService.getCurrentUserId() == '') {
uni.navigateTo({ url: '/pages/auth/login' })
return
}
// Navigate to chat
const merchId = this.merchant.user_id || this.merchant.id || this.product.merchant_id;
const merchId = this.merchant.user_id ?? this.merchant.id ?? this.product.merchant_id;
uni.navigateTo({
url: `/pages/mall/consumer/chat?merchantId=${merchId}&merchantName=${this.merchant.shop_name}`
})
@@ -596,7 +598,7 @@ export default {
// 新增:领取优惠券
async claimCoupon(coupon: any) {
const userId = supabaseService.getCurrentUserId()
if (!userId) {
if (userId == '') {
uni.navigateTo({ url: '/pages/auth/login' })
return
}
@@ -621,7 +623,7 @@ export default {
},
formatDate(dateStr: string): string {
if (!dateStr) return ''
if (dateStr == '') return ''
const date = new Date(dateStr)
return `${date.getFullYear()}.${date.getMonth()+1}.${date.getDate()}`
},
@@ -729,7 +731,7 @@ export default {
},
async toggleFavorite() {
if (!this.product.id) return
if (this.product.id == '') return
uni.showLoading({ title: '处理中' })
try {
@@ -830,8 +832,15 @@ export default {
<style>
.product-detail-page {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 120rpx;
flex: 1;
display: flex;
flex-direction: column;
}
.page-scroll {
flex: 1;
height: 0;
width: 100%;
}
.product-images {
@@ -881,7 +890,7 @@ export default {
.original-price {
font-size: 28rpx;
color: #999;
text-decoration: line-through;
text-decoration-line: line-through;
}
.product-name {
@@ -991,15 +1000,18 @@ export default {
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
justify-content: flex-end;
flex-direction: column;
z-index: 1000;
}
.popup-content {
background-color: #fff;
width: 100%;
max-height: 80vh;
border-radius: 20rpx 20rpx 0 0;
padding: 30rpx;
display: flex;
flex-direction: column;
max-height: 1000rpx;
}
.popup-header {
display: flex;
@@ -1019,7 +1031,7 @@ export default {
color: #999;
}
.coupon-list-scroll {
max-height: 60vh;
flex: 1;
}
.coupon-item {
display: flex;
@@ -1168,6 +1180,7 @@ export default {
.product-description {
background-color: #fff;
padding: 30rpx;
padding-bottom: 140rpx;
margin-bottom: 20rpx;
}
@@ -1259,16 +1272,19 @@ export default {
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
justify-content: flex-end; /* UVUE 推荐用 flex 布局对齐 */
flex-direction: column;
z-index: 999;
}
.spec-content {
background-color: #fff;
width: 100%;
max-height: 80vh;
border-radius: 20rpx 20rpx 0 0;
padding: 30rpx;
display: flex;
flex-direction: column;
max-height: 1000rpx;
}
.spec-header {
@@ -1287,8 +1303,7 @@ export default {
}
.spec-list {
max-height: 60vh;
overflow-y: auto;
flex: 1;
}
.spec-item {
@@ -1333,7 +1348,6 @@ export default {
color: #333;
font-weight: bold;
margin-bottom: 15rpx;
display: block;
}
.function-content {
@@ -1391,16 +1405,19 @@ export default {
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: flex-end;
justify-content: flex-end; /* UVUE 推荐用 flex 布局对齐 */
flex-direction: column;
z-index: 1000;
}
.params-content {
background-color: #fff;
width: 100%;
max-height: 80vh;
border-radius: 20rpx 20rpx 0 0;
padding: 30rpx;
display: flex;
flex-direction: column;
max-height: 1000rpx;
}
.params-header {
@@ -1420,8 +1437,7 @@ export default {
}
.params-list {
max-height: 60vh;
overflow-y: auto;
flex: 1;
}
.params-item {
@@ -1473,8 +1489,6 @@ export default {
flex: 1;
margin-right: 0;
text-align: center;
white-space: normal;
word-break: break-word;
padding: 0 10rpx;
}
@@ -1482,4 +1496,4 @@ export default {
margin-left: 20rpx;
}
}
</style>
</style>