20260227-1
This commit is contained in:
@@ -119,15 +119,12 @@
|
||||
class="guess-item"
|
||||
@click="viewProductDetail(item)"
|
||||
>
|
||||
<view class="guess-img-box">
|
||||
<image class="guess-img" :src="item.image" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="guess-info">
|
||||
<text class="guess-name">{{ item.name }}</text>
|
||||
<view class="guess-price-row">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-num">{{ item.price }}</text>
|
||||
<text class="sales-text">已售{{ item.sales }}</text>
|
||||
<image class="guess-img" :src="item.image" mode="aspectFill" />
|
||||
<text class="guess-name" :lines="2">{{ item.name }}</text>
|
||||
<view class="guess-bottom">
|
||||
<text class="guess-price">¥{{ item.price }}</text>
|
||||
<view class="guess-add-btn" @click.stop="addToCart(item)">
|
||||
<text class="guess-add-icon">+</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -206,21 +203,11 @@
|
||||
@click="viewProductDetail(product)"
|
||||
>
|
||||
<image class="product-image" :src="product.image" mode="aspectFill" />
|
||||
<view class="product-info">
|
||||
<text class="product-name">{{ product.name }}</text>
|
||||
<view class="product-tags-row" v-if="product.tag">
|
||||
<text class="product-tag">{{ product.tag }}</text>
|
||||
</view>
|
||||
<text class="product-spec">{{ product.specification }}</text>
|
||||
|
||||
<view class="product-bottom">
|
||||
<view class="price-box">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">{{ product.price }}</text>
|
||||
</view>
|
||||
<view class="add-cart-btn" @click.stop="addToCart(product)">
|
||||
<text class="cart-icon">+</text>
|
||||
</view>
|
||||
<text class="product-name" :lines="2">{{ product.name }}</text>
|
||||
<view class="product-bottom">
|
||||
<text class="product-price">¥{{ product.price }}</text>
|
||||
<view class="product-add-btn" @click.stop="addToCart(product)">
|
||||
<text class="add-icon">+</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -278,6 +265,7 @@ type GuessItemType = {
|
||||
price: number
|
||||
image: string
|
||||
sales: number
|
||||
merchant_id: string
|
||||
}
|
||||
|
||||
type SearchResultType = {
|
||||
@@ -288,6 +276,7 @@ type SearchResultType = {
|
||||
specification: string
|
||||
tag: string
|
||||
sales: number
|
||||
merchant_id: string
|
||||
}
|
||||
|
||||
type ShopResultType = {
|
||||
@@ -377,14 +366,23 @@ const loadData = async (): Promise<void> => {
|
||||
|
||||
try {
|
||||
loadSearchHistory()
|
||||
const hotProducts = await supabaseService.getHotProducts(30)
|
||||
|
||||
// 获取热销商品,失败时使用空数组
|
||||
let hotProducts: Product[] = []
|
||||
try {
|
||||
const hotResult = await supabaseService.getHotProducts(30)
|
||||
hotProducts = hotResult as Product[]
|
||||
} catch (hotError) {
|
||||
console.error('获取热销商品失败,使用空列表:', hotError)
|
||||
hotProducts = []
|
||||
}
|
||||
|
||||
const hotList: Array<HotSearchItemType> = []
|
||||
const limit1 = hotProducts.length < 10 ? hotProducts.length : 10
|
||||
for (let i: number = 0; i < limit1; i++) {
|
||||
const p = hotProducts[i] as UTSJSONObject
|
||||
const p = hotProducts[i]
|
||||
const item: HotSearchItemType = {
|
||||
keyword: p.getString('name') ?? '',
|
||||
keyword: p.name ?? '',
|
||||
hot: true
|
||||
}
|
||||
hotList.push(item)
|
||||
@@ -393,14 +391,15 @@ const loadData = async (): Promise<void> => {
|
||||
|
||||
const allItems: Array<GuessItemType> = []
|
||||
for (let i: number = 0; i < hotProducts.length; i++) {
|
||||
const p = hotProducts[i] as UTSJSONObject
|
||||
const saleCount = p.getNumber('sale_count')
|
||||
const p = hotProducts[i]
|
||||
const saleCount = p.sale_count
|
||||
const item: GuessItemType = {
|
||||
id: p.getString('id') ?? '',
|
||||
name: p.getString('name') ?? '',
|
||||
price: p.getNumber('base_price') ?? 0,
|
||||
image: p.getString('main_image_url') ?? '/static/default.jpg',
|
||||
sales: saleCount != null ? saleCount : 0
|
||||
id: p.id ?? '',
|
||||
name: p.name ?? '',
|
||||
price: p.base_price ?? 0,
|
||||
image: p.main_image_url ?? '/static/default.jpg',
|
||||
sales: saleCount != null ? saleCount : 0,
|
||||
merchant_id: p.merchant_id ?? ''
|
||||
}
|
||||
allItems.push(item)
|
||||
}
|
||||
@@ -410,7 +409,8 @@ const loadData = async (): Promise<void> => {
|
||||
|
||||
} catch (e) {
|
||||
console.error('Load data failed', e)
|
||||
isError.value = true
|
||||
// 不再显示错误页面,允许使用空数据
|
||||
isError.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,14 +517,14 @@ const performSearch = async (): Promise<void> => {
|
||||
const prodData = prodResp.data != null ? prodResp.data : []
|
||||
const resultList: Array<SearchResultType> = []
|
||||
for (let i: number = 0; i < prodData.length; i++) {
|
||||
const p = prodData[i] as UTSJSONObject
|
||||
const p = prodData[i] as Product
|
||||
let tag = ''
|
||||
const tagsRaw = p.get('tags')
|
||||
const tagsRaw = p.tags
|
||||
if (tagsRaw != null) {
|
||||
try {
|
||||
const tagsStr = p.getString('tags')
|
||||
const tagsStr = p.tags
|
||||
if (tagsStr != null) {
|
||||
const tags = JSON.parse(tagsStr)
|
||||
const tags = JSON.parse(tagsStr as string)
|
||||
if (Array.isArray(tags) && tags.length > 0) {
|
||||
const firstTag = tags[0]
|
||||
tag = firstTag != null ? (firstTag as string) : ''
|
||||
@@ -534,13 +534,14 @@ const performSearch = async (): Promise<void> => {
|
||||
}
|
||||
|
||||
const searchItem: SearchResultType = {
|
||||
id: p.getString('id') ?? '',
|
||||
name: p.getString('name') ?? '',
|
||||
image: p.getString('main_image_url') ?? '/static/default.jpg',
|
||||
price: p.getNumber('base_price') ?? 0,
|
||||
specification: p.getString('specification') ?? '标准规格',
|
||||
id: p.id ?? '',
|
||||
name: p.name ?? '',
|
||||
image: p.main_image_url ?? '/static/default.jpg',
|
||||
price: p.base_price ?? 0,
|
||||
specification: p.specification ?? '标准规格',
|
||||
tag: tag,
|
||||
sales: p.getNumber('sale_count') ?? 0
|
||||
sales: p.sale_count ?? 0,
|
||||
merchant_id: p.merchant_id ?? ''
|
||||
}
|
||||
resultList.push(searchItem)
|
||||
}
|
||||
@@ -599,21 +600,47 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
const onInput = (e: any) => {
|
||||
const eObj = e as UTSJSONObject
|
||||
const detailRaw = eObj.get('detail')
|
||||
const detail = detailRaw != null ? (detailRaw as UTSJSONObject) : (new UTSJSONObject())
|
||||
const val = detail.getString('value') ?? ''
|
||||
searchKeyword.value = val
|
||||
if (val == '') {
|
||||
showResults.value = false
|
||||
searchSuggestions.value = []
|
||||
return
|
||||
try {
|
||||
let val = ''
|
||||
// 处理 input 事件的不同事件对象格式
|
||||
if (e != null) {
|
||||
// UTSJSONObject 格式 (e.detail.value)
|
||||
if (e instanceof UTSJSONObject) {
|
||||
const eObj = e as UTSJSONObject
|
||||
const detailObj = eObj.get('detail')
|
||||
if (detailObj != null && detailObj instanceof UTSJSONObject) {
|
||||
const detail = detailObj as UTSJSONObject
|
||||
const v = detail.get('value')
|
||||
val = v != null ? (v as string) : ''
|
||||
}
|
||||
} else {
|
||||
// 尝试转换为 UTSJSONObject
|
||||
const eObj = JSON.parse(JSON.stringify(e)) as UTSJSONObject
|
||||
const detailObj = eObj.get('detail')
|
||||
if (detailObj != null) {
|
||||
const detail = detailObj as UTSJSONObject
|
||||
const v = detail.get('value')
|
||||
val = v != null ? (v as string) : ''
|
||||
} else {
|
||||
const v = eObj.get('value')
|
||||
val = v != null ? (v as string) : ''
|
||||
}
|
||||
}
|
||||
}
|
||||
searchKeyword.value = val
|
||||
if (val == '') {
|
||||
showResults.value = false
|
||||
searchSuggestions.value = []
|
||||
return
|
||||
}
|
||||
|
||||
if (suggestTimer > 0) clearTimeout(suggestTimer)
|
||||
suggestTimer = setTimeout(() => {
|
||||
fetchSuggestions(val)
|
||||
}, 300)
|
||||
} catch (err) {
|
||||
console.error('onInput error:', err)
|
||||
}
|
||||
|
||||
if (suggestTimer > 0) clearTimeout(suggestTimer)
|
||||
suggestTimer = setTimeout(() => {
|
||||
fetchSuggestions(val)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const clearSearch = () => {
|
||||
@@ -702,7 +729,8 @@ const loadMore = async (): Promise<void> => {
|
||||
price: p.getNumber('base_price') ?? 0,
|
||||
specification: p.getString('specification') ?? '标准规格',
|
||||
tag: tag,
|
||||
sales: p.getNumber('sale_count') ?? 0
|
||||
sales: p.getNumber('sale_count') ?? 0,
|
||||
merchant_id: p.getString('merchant_id') ?? ''
|
||||
}
|
||||
searchResults.value.push(searchItem)
|
||||
}
|
||||
@@ -738,11 +766,42 @@ const viewShopDetail = (shop: ShopResultType) => {
|
||||
})
|
||||
}
|
||||
|
||||
const addToCart = (product: SearchResultType | GuessItemType) => {
|
||||
uni.showToast({ title: '请选择规格', icon: 'none' })
|
||||
setTimeout(() => {
|
||||
viewProductDetail(product)
|
||||
}, 800)
|
||||
const addToCart = async (product: SearchResultType | GuessItemType) => {
|
||||
uni.showLoading({ title: '检查商品...' })
|
||||
try {
|
||||
// 统一转换为 UTSJSONObject 访问属性
|
||||
const prodObj = JSON.parse(JSON.stringify(product)) as UTSJSONObject
|
||||
const productId = prodObj.getString('id') ?? ''
|
||||
const merchantId = prodObj.getString('merchant_id') ?? ''
|
||||
|
||||
// 检查商品是否有SKU
|
||||
const skus = await supabaseService.getProductSkus(productId)
|
||||
uni.hideLoading()
|
||||
|
||||
if (skus.length > 0) {
|
||||
// 有规格,提示并跳转到商品详情页选择规格
|
||||
uni.showToast({ title: '请选择规格', icon: 'none' })
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/mall/consumer/product-detail?id=' + productId
|
||||
})
|
||||
}, 500)
|
||||
} else {
|
||||
// 无规格,直接加入购物车
|
||||
uni.showLoading({ title: '添加中...' })
|
||||
const success = await supabaseService.addToCart(productId, 1, '', merchantId)
|
||||
uni.hideLoading()
|
||||
if (success) {
|
||||
uni.showToast({ title: '已添加到购物车', icon: 'success' })
|
||||
} else {
|
||||
uni.showToast({ title: '添加失败,请先登录', icon: 'none' })
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('添加到购物车异常', e)
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: '操作异常', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
const openCamera = () => {
|
||||
@@ -1142,64 +1201,62 @@ const goBack = () => {
|
||||
}
|
||||
|
||||
.guess-item {
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
padding-bottom: 8px;
|
||||
width: 48%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.guess-img-box {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 100%;
|
||||
position: relative;
|
||||
background-color: #f0f0f0;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.guess-img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.guess-info {
|
||||
padding: 8px;
|
||||
height: 170px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 8px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.guess-name {
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
margin-bottom: 6px;
|
||||
margin-bottom: 5px;
|
||||
line-height: 1.4;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
line-height: 1.3;
|
||||
height: 34px; /* 限制2行高度 */
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.guess-price-row {
|
||||
.guess-bottom {
|
||||
display: flex;
|
||||
align-items: flex-end; /* REPLACED baseline */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 8px 8px;
|
||||
}
|
||||
|
||||
.price-symbol {
|
||||
font-size: 12px;
|
||||
color: #ff5000;
|
||||
}
|
||||
|
||||
.price-num {
|
||||
font-size: 16px;
|
||||
.guess-price {
|
||||
font-size: 15px;
|
||||
color: #ff5000;
|
||||
font-weight: bold;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.sales-text {
|
||||
font-size: 10px;
|
||||
color: #999;
|
||||
.guess-add-btn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: #ff5000;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.guess-add-icon {
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 搜索建议列表 */
|
||||
@@ -1312,84 +1369,61 @@ const goBack = () => {
|
||||
}
|
||||
|
||||
.result-item {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column; /* 垂直排列 */
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
width: 48%;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 120px; /* 调整图片高度 */
|
||||
border-radius: 4px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
height: 170px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 8px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-size: 13px; /* 减小字号 */
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
line-height: 1.3;
|
||||
height: 34px; /* 限制高度 */
|
||||
margin-bottom: 5px;
|
||||
line-height: 1.4;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.product-tags-row {
|
||||
margin-top: 2px;
|
||||
display: none; /* 隐藏标签以保持简洁 */
|
||||
}
|
||||
|
||||
.product-spec {
|
||||
display: none; /* 隐藏规格 */
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.product-bottom {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center; /* 垂直居中 */
|
||||
margin-top: 4px;
|
||||
align-items: center;
|
||||
padding: 0 8px 8px;
|
||||
}
|
||||
|
||||
.price-box {
|
||||
.product-price {
|
||||
font-size: 15px;
|
||||
color: #ff5000;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.price-symbol {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: 16px; /* 减小价格字号 */
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.add-cart-btn {
|
||||
.product-add-btn {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-color: #4CAF50;
|
||||
background-color: #ff5000;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cart-icon {
|
||||
.add-icon {
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user