完成consumer端同步

This commit is contained in:
2026-05-14 15:28:09 +08:00
parent 612fb3d360
commit 0ffbc53902
197 changed files with 92657 additions and 7564 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -88,17 +88,40 @@
<view class="product-image-wrapper">
<image
class="product-image"
:src="product.main_image_url"
:src="getProductCover(product)"
mode="aspectFill"
/>
</view>
<text class="product-name" :lines="2">{{ product.name }}</text>
<view v-if="getProductCardTags(product).length > 0" class="product-card-tags">
<text
v-for="(tag, index) in getProductCardTags(product)"
:key="product.id + '-tag-' + index"
class="product-card-tag"
>
{{ tag }}
</text>
</view>
<text class="product-name" :lines="2">{{ getProductTitle(product) }}</text>
<text v-if="getProductHighlight(product) !== ''" class="product-highlight">{{ getProductHighlight(product) }}</text>
<view v-if="getProductServiceTags(product).length > 0" class="product-service-tags">
<text
v-for="(tag, index) in getProductServiceTags(product)"
:key="product.id + '-service-' + index"
class="product-service-tag"
>
{{ tag }}
</text>
</view>
<view class="product-bottom">
<text class="product-price">¥{{ product.base_price ?? product.price ?? 0 }}</text>
<view class="price-stack">
<text class="product-price">¥{{ formatProductPrice(product) }}</text>
<text v-if="showMarketPrice(product)" class="product-market-price">¥{{ formatMarketPrice(product) }}</text>
</view>
<view class="product-add-btn" @click.stop="addToCart(product)">
<text class="add-icon">+</text>
</view>
</view>
<text v-if="getProductSalesText(product) !== ''" class="product-sales-text">{{ getProductSalesText(product) }}</text>
</view>
</view>
@@ -110,7 +133,7 @@
<!-- 空状态 - 仅在非加载状态且无商品时显示 -->
<view v-else class="empty-state">
<text class="empty-icon"><EFBFBD></text>
<text class="empty-icon">🛍️</text>
<text class="empty-text">暂无相关商品</text>
<text class="empty-desc">该分类下暂无商品,敬请期待</text>
</view>
@@ -129,6 +152,7 @@ import { ref, onMounted } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import supabaseService from '@/utils/supabaseService.uts'
import type { Product } from '@/utils/supabaseService.uts'
import { goToLogin } from '@/utils/utils.uts'
type LocalCategory = {
id: string
@@ -177,6 +201,66 @@ const currentCategoryDesc = ref('')
// 页面参数
const pageParams = ref<any>({})
function getProductCover(product: Product): string {
if (product.main_image_url != null && product.main_image_url !== '') return product.main_image_url
if (product.images != null && product.images.length > 0 && product.images[0] !== '') return product.images[0]
if (product.image_url != null && product.image_url !== '') return product.image_url
return '/static/images/default.png'
}
function getProductTitle(product: Product): string {
if (product.short_title != null && product.short_title !== '') return product.short_title
if (product.name != null && product.name !== '') return product.name
return product.id ?? ''
}
function getProductCardTags(product: Product): string[] {
if (product.card_tags != null && product.card_tags.length > 0) return product.card_tags.slice(0, 2)
const fallback: string[] = []
if (product.is_hot === true) fallback.push('热卖')
if (product.is_new === true && fallback.length < 2) fallback.push('新品')
if (product.is_featured === true && fallback.length < 2) fallback.push('精选')
return fallback
}
function getProductServiceTags(product: Product): string[] {
if (product.service_tags != null && product.service_tags.length > 0) return product.service_tags.slice(0, 3)
return [] as string[]
}
function getProductHighlight(product: Product): string {
if (product.selling_points != null && product.selling_points.length > 0 && product.selling_points[0] !== '') {
return product.selling_points[0]
}
if (product.subtitle != null && product.subtitle !== '') return product.subtitle
return ''
}
function getProductSalesText(product: Product): string {
if (product.display_sales_text != null && product.display_sales_text !== '') return product.display_sales_text
const sales = product.sale_count ?? 0
if (sales >= 100000) return '已售10万+'
if (sales >= 10000) return '已售' + (sales / 10000).toFixed(1) + '万件'
if (sales > 0) return '已售' + sales.toString() + '件'
return ''
}
function formatProductPrice(product: Product): string {
const price = product.base_price ?? product.price ?? 0
return parseFloat(price.toString()).toFixed(2)
}
function formatMarketPrice(product: Product): string {
const price = product.market_price ?? product.original_price ?? 0
return parseFloat(price.toString()).toFixed(2)
}
function showMarketPrice(product: Product): boolean {
const marketPrice = product.market_price ?? product.original_price ?? 0
const salePrice = product.base_price ?? product.price ?? 0
return marketPrice > 0 && marketPrice > salePrice
}
// 加载商品数据
async function loadProducts(): Promise<void> {
if (loading.value) return
@@ -648,6 +732,11 @@ onLoad((options: any) => {
// 添加到购物车
async function addToCart(product: Product): Promise<void> {
const userId = supabaseService.getCurrentUserId()
if (userId == null || userId === '') {
goToLogin('/pages/main/category')
return
}
uni.showLoading({ title: '检查商品...' })
try {
const pid = (product.id ?? '').toString()
@@ -700,7 +789,7 @@ async function addToCart(product: Product): Promise<void> {
// 导航函数
function navigateToSearch(): void { uni.navigateTo({ url: '/pages/mall/consumer/search' }) }
function navigateToCart(): void { uni.navigateTo({ url: '/pages/main/cart' }) }
function navigateToCart(): void { uni.switchTab({ url: '/pages/main/cart' }) }
function navigateToProduct(product: Product): void {
const id = (product.id ?? '').toString()
if (id === '') return
@@ -719,7 +808,7 @@ function onCamera(): void {
uni.chooseImage({
count: 1,
sourceType: ['camera'],
success: (res) => {
success: (res: ChooseImageSuccess) => {
console.log('相机拍摄成功:', res.tempFilePaths[0])
uni.showToast({
title: '已拍摄,正在识别...',
@@ -742,7 +831,7 @@ function onCamera(): void {
// 扫码功能
function onScan(): void {
uni.scanCode({
success: (res) => {
success: (res: ScanCodeSuccess) => {
console.log('扫码成功:', res)
uni.showToast({
title: '扫码成功: ' + res.result,
@@ -1084,6 +1173,58 @@ function onScan(): void {
padding: 0 8px;
}
.product-card-tags {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 8px 8px 0;
}
.product-card-tag {
height: 28rpx;
line-height: 28rpx;
padding: 0 8rpx;
border-radius: 8rpx;
font-size: 18rpx;
font-weight: 700;
color: #fff7d1;
background: #e1251b;
margin-right: 6rpx;
margin-bottom: 4rpx;
}
.product-highlight {
font-size: 20rpx;
line-height: 28rpx;
color: #7a7a7a;
padding: 0 8px;
margin-bottom: 6rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.product-service-tags {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 0 8px;
margin-bottom: 6rpx;
}
.product-service-tag {
height: 28rpx;
line-height: 28rpx;
padding: 0 8rpx;
border-radius: 8rpx;
font-size: 18rpx;
font-weight: 600;
color: #12b76a;
background: #ecfdf3;
margin-right: 6rpx;
margin-bottom: 4rpx;
}
.product-bottom {
display: flex;
flex-direction: row;
@@ -1092,12 +1233,33 @@ function onScan(): void {
padding: 0 8px 8px;
}
.price-stack {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.product-price {
font-size: 15px;
color: #ff5000;
font-weight: bold;
}
.product-market-price {
font-size: 20rpx;
line-height: 1.2;
color: #9a9a9a;
text-decoration: line-through;
margin-top: 4rpx;
}
.product-sales-text {
font-size: 20rpx;
line-height: 28rpx;
color: #8f8f8f;
padding: 0 8px 12px;
}
.product-add-btn {
width: 24px;
height: 24px;
@@ -1550,4 +1712,3 @@ function onScan(): void {
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -222,6 +222,8 @@ import { ref, reactive, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { supabaseService, type Notification, type ChatMessage, type ChatRoom } from '@/utils/supabaseService.uts'
type ModalSuccessResult = { confirm: boolean; cancel: boolean }
// 定义消息项类型
type MessageItem = {
id: string,
@@ -543,7 +545,7 @@ const startQuickService = (category: string) => {
const startNewChat = () => {
uni.showActionSheet({
itemList: ['用药咨询', '处方咨询', '副作用咨询', '药品配送', '其他问题'],
success: (res) => {
success: (res: ShowActionSheetSuccess) => {
const categories = ['用药咨询', '处方咨询', '副作用咨询', '药品配送', '其他问题']
const category = categories[res.tapIndex]
startQuickService(category)

File diff suppressed because it is too large Load Diff