Files
medical-mall/pages/main/cart-search/cart-search.uvue

1209 lines
26 KiB
Plaintext

<template>
<view class="cart-search-page">
<view class="search-header" :style="{ paddingTop: statusBarHeight + 'px', paddingRight: searchHeaderRightPadding + 'px' }">
<view class="back-btn" @click="goBack">
<text class="back-icon">鈥?/text>
</view>
<view class="search-input-wrap">
<text class="search-icon">鈱?/text>
<input
class="search-input"
v-model="keyword"
placeholder="鎼滅储璐墿杞﹀晢鍝?
confirm-type="search"
:focus="true"
@confirm="doSearch"
/>
<view v-if="keyword.length > 0" class="clear-keyword" @click="clearKeyword">
<text class="clear-keyword-text">脳</text>
</view>
</view>
<view class="search-btn" @click="doSearch">
<text class="search-btn-text">鎼滅储</text>
</view>
</view>
<scroll-view v-if="!hasSearched" class="search-content" :scroll-y="true" :show-scrollbar="false">
<view class="history-section">
<view class="section-header">
<text class="section-title">鍘嗗彶鎼滅储</text>
<text class="clear-history" @click="clearSearchHistory">娓呯┖</text>
</view>
<view v-if="searchHistory.length > 0" class="history-list">
<view
v-for="item in searchHistory"
:key="item"
class="history-chip"
@click="useSearchWord(item)"
>
<text class="history-chip-text">{{ item }}</text>
</view>
</view>
<view v-else class="empty-history">
<text class="empty-history-text">鏆傛棤鍘嗗彶鎼滅储</text>
</view>
</view>
<view class="discover-section">
<view class="section-header">
<text class="section-title">鎼滅储鍙戠幇</text>
</view>
<view class="discover-grid">
<view
v-for="item in searchDiscoverWords"
:key="item"
class="discover-item"
@click="useSearchWord(item)"
>
<text class="discover-text">{{ item }}</text>
</view>
</view>
</view>
</scroll-view>
<scroll-view v-else class="search-result-content" :scroll-y="true" :show-scrollbar="false" :lower-threshold="120" @scrolltolower="handleResultScrollToLower">
<view v-if="matchedCartItems.length > 0" class="cart-match-section">
<view class="result-section-title-wrap">
<text class="result-section-title">璐墿杞﹀唴鐩稿叧鍟嗗搧</text>
</view>
<view class="cart-result-list">
<view
v-for="item in matchedCartItems"
:key="item.id"
class="cart-result-card"
>
<view class="item-select" @click="toggleSelect(item.id)">
<text v-if="item.selected" class="selected-icon">鉁?/text>
<text v-else class="unselected-icon"></text>
</view>
<image class="item-image" :src="item.image" mode="aspectFill" @click="goToProductDetailFromCart(item)" />
<view class="result-item-info">
<text class="result-shop-name">{{ item.shopName }}</text>
<text class="item-name" :lines="1">{{ item.name }}</text>
<text class="item-spec">{{ item.spec }}</text>
<view class="item-footer">
<text class="item-price">楼{{ item.price }}</text>
<view class="quantity-control">
<text class="quantity-btn" @click="decreaseQuantity(item.id)">-</text>
<text class="quantity-value">{{ item.quantity }}</text>
<text class="quantity-btn" @click="increaseQuantity(item.id)">+</text>
</view>
</view>
</view>
</view>
</view>
</view>
<view v-else class="no-cart-result">
<view class="warning-row">
<text class="warning-icon">!</text>
<text class="warning-text">{{ noCartResultText }}</text>
</view>
</view>
<view class="recommend-search-section">
<view class="recommend-title-wrap">
<view class="line"></view>
<text class="recommend-title">{{ matchedCartItems.length > 0 ? '涓轰綘鎼滅储鍏ㄧ珯鍟嗗搧' : '涓轰綘鎼滅储鍏ㄩ儴鍟嗗搧' }}</text>
<view class="line"></view>
</view>
<GuessYouLike
title="猜你喜欢"
:pageSize="8"
:excludeProductIds="matchedProductIds"
:loadMoreKey="guessLoadMoreKey"
@productClick="goToRecommendProductDetail"
/>
<view class="bottom-safe-space"></view>
</view>
</scroll-view>
<view v-if="hasSearched" class="fixed-cart-settlement-bar">
<view class="settlement-inner">
<view class="settlement-left" @click="toggleSelectAllInSearch">
<view class="select-circle" :class="{ 'select-circle-active': allSearchSelected }">
<text v-if="allSearchSelected" class="select-check">鉁?/text>
</view>
<text class="select-all-text">鍏ㄩ€?/text>
</view>
<view class="settlement-right">
<view class="total-info">
<text class="total-label">鍚堣:</text>
<text class="total-price">楼{{ searchTotalPrice }}</text>
</view>
<button class="checkout-btn" :class="{ 'checkout-btn-disabled': searchSelectedCount == 0 }" @click="goToCheckoutFromSearch">
鍘荤粨绠?{{ searchSelectedCount }})
</button>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { computed, ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { supabaseService, type CartItem as SupabaseCartItem, type Product } from '@/utils/supabaseService.uts'
import { goToLogin } from '@/utils/utils.uts'
import GuessYouLike from '@/components/mall/GuessYouLike/GuessYouLike.uvue'
const CART_SEARCH_HISTORY_KEY = 'cart_search_history'
type LocalCartItem = {
id: string
shopId: string
shopName: string
name: string
productName: string
skuName: string
specName: string
merchantName: string
brandName: string
price: number
originalPrice: number
memberPrice: number
image: string
spec: string
quantity: number
selected: boolean
productId: string
skuId: string
merchantId: string
}
type ProductItem = {
id: string
name: string
price: number
image: string
shopName: string
salesText: string
merchantId: string
skuId: string
}
const keyword = ref<string>('')
const hasSearched = ref<boolean>(false)
const searchHistory = ref<Array<string>>([])
const searchDiscoverList = ref<Array<string>>([
'鏃犱汉鏈?,
'姘存澂',
'鎵嬫満',
'澶╃劧娉夋按',
'鎸夋懇浠?,
'鎽勫儚澶?,
'鑰虫満',
'鍋滆溅鍦鸿澶?,
'楗枡',
'iPhone'
])
const cartItems = ref<Array<LocalCartItem>>([])
const guessLoadMoreKey = ref<number>(0)
const isLoading = ref<boolean>(false)
const statusBarHeight = ref<number>(0)
const updatingItems = ref<Set<string>>(new Set())
const navBarRight = ref<number>(12)
const searchDiscoverWords = computed<Array<string>>(() => {
if (searchDiscoverList.value.length > 0) {
return searchDiscoverList.value
}
return ['鏃犱汉鏈?, '姘存澂', '鎵嬫満', '澶╃劧娉夋按']
})
const safeLower = (value: string): string => {
return value.toLowerCase()
}
const matchedCartItems = computed<Array<LocalCartItem>>(() => {
const q = keyword.value.trim().toLowerCase()
if (q == '') {
return []
}
return cartItems.value.filter((item: LocalCartItem) => {
const title = safeLower(item.name)
const name = safeLower(item.name)
const productName = safeLower(item.productName)
const skuName = safeLower(item.skuName)
const specName = safeLower(item.specName)
const shopName = safeLower(item.shopName)
const merchantName = safeLower(item.merchantName)
const brandName = safeLower(item.brandName)
return title.indexOf(q) >= 0
|| name.indexOf(q) >= 0
|| productName.indexOf(q) >= 0
|| skuName.indexOf(q) >= 0
|| specName.indexOf(q) >= 0
|| shopName.indexOf(q) >= 0
|| merchantName.indexOf(q) >= 0
|| brandName.indexOf(q) >= 0
})
})
const matchedProductIds = computed<Array<string>>(() => {
const ids: Array<string> = []
for (let i = 0; i < matchedCartItems.value.length; i++) {
const item = matchedCartItems.value[i]
const productId = item.productId !== '' ? item.productId : item.id
if (productId !== '' && ids.indexOf(productId) < 0) {
ids.push(productId)
}
}
return ids
})
const searchSelectedItems = computed<Array<LocalCartItem>>(() => {
return matchedCartItems.value.filter((item: LocalCartItem) => item.selected == true)
})
const searchSelectedCount = computed((): number => {
return searchSelectedItems.value.length
})
const searchTotalPrice = computed((): string => {
let total = 0
searchSelectedItems.value.forEach((item: LocalCartItem) => {
const finalPrice = item.memberPrice > 0 && item.memberPrice < item.price ? item.memberPrice : item.price
total += finalPrice * item.quantity
})
return total.toFixed(2)
})
const allSearchSelected = computed((): boolean => {
if (matchedCartItems.value.length == 0) return false
return matchedCartItems.value.every((item: LocalCartItem) => item.selected == true)
})
const noCartResultText = computed((): string => {
if (cartItems.value.length == 0) {
return '璐墿杞︿负绌猴紝鏆傛棤鐩稿叧鍟嗗搧'
}
return '鎮ㄧ殑璐墿杞﹂噷娌℃湁鐩稿叧鍟嗗搧'
})
const searchHeaderRightPadding = computed((): number => {
if (navBarRight.value > 12) {
return navBarRight.value
}
return 12
})
const getItemById = (itemId: string): LocalCartItem | null => {
const index = cartItems.value.findIndex((item: LocalCartItem) => item.id == itemId)
if (index == -1) return null
return cartItems.value[index]
}
const loadSearchHistory = () => {
const cache = uni.getStorageSync(CART_SEARCH_HISTORY_KEY)
if (cache == null || cache == '') {
searchHistory.value = []
return
}
if (Array.isArray(cache)) {
searchHistory.value = cache as Array<string>
return
}
if (typeof cache == 'string') {
try {
const parsed = JSON.parse(cache) as Array<string>
searchHistory.value = parsed
} catch (e) {
console.error('瑙f瀽鎼滅储鍘嗗彶澶辫触:', e)
searchHistory.value = []
}
}
}
const saveSearchHistory = (word: string) => {
const text = word.trim()
if (text == '') return
let list = searchHistory.value.filter((item: string) => item != text)
list.unshift(text)
if (list.length > 10) {
list = list.slice(0, 10)
}
searchHistory.value = list
uni.setStorageSync(CART_SEARCH_HISTORY_KEY, JSON.stringify(list))
}
const clearSearchHistory = () => {
searchHistory.value = []
uni.removeStorageSync(CART_SEARCH_HISTORY_KEY)
}
const loadCartData = async () => {
isLoading.value = true
try {
let memberDiscount = 1.0
try {
const memberInfo = await supabaseService.getUserMemberInfo()
const discountRaw = memberInfo.get('discount')
if (discountRaw != null) {
memberDiscount = discountRaw as number
}
} catch (e) {
console.log('鑾峰彇浼氬憳淇℃伅澶辫触锛屼娇鐢ㄩ粯璁ゆ姌鎵?', e)
}
const supabaseCartItems = await supabaseService.getCartItems()
cartItems.value = supabaseCartItems.map((item: SupabaseCartItem): LocalCartItem => {
const originalPrice = item.product_price ?? 0
let memberPrice = 0
if (memberDiscount > 0 && memberDiscount < 1 && originalPrice > 0) {
memberPrice = Math.round(originalPrice * memberDiscount * 100) / 100
}
const productName = item.product_name ?? '鏈煡鍟嗗搧'
const specName = item.product_specification ?? '鏍囧噯瑙勬牸'
return {
id: item.id,
shopId: item.shop_id ?? 'default_shop',
shopName: item.shop_name ?? '鍟嗗煄浼橀€?,
name: productName,
productName: productName,
skuName: specName,
specName: specName,
merchantName: item.shop_name ?? '鍟嗗煄浼橀€?,
brandName: '',
price: originalPrice,
originalPrice: originalPrice,
memberPrice: memberPrice,
image: item.product_image ?? '/static/images/default.png',
spec: specName,
quantity: item.quantity ?? 1,
selected: item.selected ?? false,
productId: item.product_id ?? '',
skuId: item.sku_id ?? '',
merchantId: item.merchant_id ?? ''
}
})
} catch (e) {
console.error('鍔犺浇璐墿杞︽悳绱㈡暟鎹け璐?', e)
cartItems.value = []
} finally {
isLoading.value = false
}
}
const doSearch = async () => {
const q = keyword.value.trim()
if (q == '') {
uni.showToast({
title: '璇疯緭鍏ユ悳绱㈠叧閿瘝',
icon: 'none'
})
return
}
hasSearched.value = true
saveSearchHistory(q)
}
const useSearchWord = (word: string) => {
keyword.value = word
doSearch()
}
const goBack = () => {
uni.navigateBack()
}
const clearKeyword = () => {
keyword.value = ''
hasSearched.value = false
guessLoadMoreKey.value = 0
}
const toggleSelect = async (itemId: string) => {
const index = cartItems.value.findIndex((item: LocalCartItem) => item.id == itemId)
if (index == -1) return
const newSelected = !cartItems.value[index].selected
cartItems.value[index].selected = newSelected
cartItems.value = [...cartItems.value]
const success = await supabaseService.updateCartItemSelection(itemId, newSelected)
if (!success) {
cartItems.value[index].selected = !newSelected
cartItems.value = [...cartItems.value]
uni.showToast({ title: '缃戠粶寮傚父锛岃閲嶈瘯', icon: 'none' })
}
}
const increaseQuantity = async (itemId: string) => {
if (updatingItems.value.has(itemId)) return
const index = cartItems.value.findIndex((item: LocalCartItem) => item.id == itemId)
if (index == -1) return
updatingItems.value.add(itemId)
const newQuantity = cartItems.value[index].quantity + 1
cartItems.value[index].quantity = newQuantity
cartItems.value = [...cartItems.value]
const success = await supabaseService.updateCartItemQuantity(itemId, newQuantity)
updatingItems.value.delete(itemId)
if (!success) {
cartItems.value[index].quantity = newQuantity - 1
cartItems.value = [...cartItems.value]
uni.showToast({ title: '鏇存柊澶辫触', icon: 'none' })
}
}
const decreaseQuantity = async (itemId: string) => {
if (updatingItems.value.has(itemId)) return
const index = cartItems.value.findIndex((item: LocalCartItem) => item.id == itemId)
if (index == -1) return
if (cartItems.value[index].quantity <= 1) {
uni.showToast({ title: '鏈€灏戜繚鐣?浠讹紝鍙繑鍥炶喘鐗╄溅鍒犻櫎', icon: 'none' })
return
}
updatingItems.value.add(itemId)
const newQuantity = cartItems.value[index].quantity - 1
cartItems.value[index].quantity = newQuantity
cartItems.value = [...cartItems.value]
const success = await supabaseService.updateCartItemQuantity(itemId, newQuantity)
updatingItems.value.delete(itemId)
if (!success) {
cartItems.value[index].quantity = newQuantity + 1
cartItems.value = [...cartItems.value]
uni.showToast({ title: '鏇存柊澶辫触', icon: 'none' })
}
}
const toggleSelectAllInSearch = async () => {
const checked = !allSearchSelected.value
const ids: Array<string> = []
matchedCartItems.value.forEach((item: LocalCartItem) => {
item.selected = checked
ids.push(item.id)
})
cartItems.value = [...cartItems.value]
if (ids.length == 0) return
const success = await supabaseService.batchUpdateCartItemSelection(ids, checked)
if (!success) {
matchedCartItems.value.forEach((item: LocalCartItem) => {
item.selected = !checked
})
cartItems.value = [...cartItems.value]
uni.showToast({ title: '鎿嶄綔澶辫触', icon: 'none' })
}
}
const goToCheckoutFromSearch = () => {
if (searchSelectedCount.value == 0) {
uni.showToast({
title: '璇烽€夋嫨鍟嗗搧',
icon: 'none'
})
return
}
const selectedItems = searchSelectedItems.value.map((item: LocalCartItem) => {
return {
id: item.id,
product_id: item.productId,
sku_id: item.skuId,
product_name: item.name,
shop_id: item.shopId,
shop_name: item.shopName,
merchant_id: item.merchantId,
product_image: item.image,
sku_specifications: item.spec,
price: item.price,
quantity: item.quantity
}
})
uni.setStorageSync('checkout_type', 'cart')
try {
uni.setStorageSync('checkout_items', JSON.stringify(selectedItems))
} catch (e) {
console.error('瀛樺偍缁撶畻鏁版嵁澶辫触', e)
uni.showToast({ title: '绯荤粺寮傚父锛岃閲嶈瘯', icon: 'none' })
return
}
uni.navigateTo({
url: '/pages/mall/consumer/checkout'
})
}
const goToProductDetailFromCart = (item: LocalCartItem) => {
const productId = item.productId == '' ? item.id : item.productId
let paramsArr: Array<string> = []
paramsArr.push('id=' + encodeURIComponent(productId))
paramsArr.push('productId=' + encodeURIComponent(productId))
paramsArr.push('price=' + item.price)
paramsArr.push('originalPrice=' + item.originalPrice)
paramsArr.push('name=' + encodeURIComponent(item.name))
paramsArr.push('image=' + encodeURIComponent(item.image))
uni.navigateTo({
url: '/pages/mall/consumer/product-detail?' + paramsArr.join('&')
})
}
const goToProductDetail = (product: ProductItem) => {
let url = '/pages/mall/consumer/product-detail?id=' + encodeURIComponent(product.id)
url += '&productId=' + encodeURIComponent(product.id)
url += '&price=' + product.price
url += '&name=' + encodeURIComponent(product.name)
url += '&image=' + encodeURIComponent(product.image)
uni.navigateTo({ url })
}
const goToRecommendProductDetail = (productId: string) => {
if (productId === '') {
return
}
uni.navigateTo({
url: '/pages/mall/consumer/product-detail?id=' + encodeURIComponent(productId) + '&productId=' + encodeURIComponent(productId)
})
}
const handleResultScrollToLower = () => {
guessLoadMoreKey.value = guessLoadMoreKey.value + 1
}
onLoad((options: UTSJSONObject) => {
const systemInfo = uni.getSystemInfoSync()
statusBarHeight.value = systemInfo.statusBarHeight ?? 0
// #ifdef MP-WEIXIN
try {
const menuButton = uni.getMenuButtonBoundingClientRect()
if (menuButton != null) {
navBarRight.value = (systemInfo.screenWidth - menuButton.left) + 10
}
} catch (e) {
console.log('鑾峰彇鑳跺泭鎸夐挳淇℃伅澶辫触:', e)
navBarRight.value = 96
}
// #endif
loadSearchHistory()
loadCartData()
const word = options.getString('keyword')
if (word != null && word != '') {
const decodedWord = decodeURIComponent(word)
keyword.value = decodedWord != null ? decodedWord : word
doSearch()
}
})
</script>
<style>
.cart-search-page {
width: 100%;
height: 100%;
background-color: #f5f5f5;
display: flex;
flex-direction: column;
overflow: hidden;
}
.search-header {
height: 56px;
padding: 0 12px;
background-color: #ffffff;
display: flex;
flex-direction: row;
align-items: center;
box-sizing: content-box;
border-bottom: 1px solid #f1f1f1;
}
.back-btn {
width: 36px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
font-size: 34px;
color: #222222;
line-height: 34px;
}
.search-input-wrap {
flex: 1;
height: 38px;
border-radius: 20px;
background-color: #f5f5f5;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 12px;
min-width: 0;
}
.search-icon {
font-size: 15px;
color: #999999;
margin-right: 6px;
}
.search-input {
flex: 1;
height: 38px;
font-size: 15px;
color: #222222;
background-color: transparent;
border: none;
padding: 0;
margin: 0;
}
.clear-keyword {
width: 24px;
height: 24px;
border-radius: 12px;
background-color: #dddddd;
display: flex;
align-items: center;
justify-content: center;
}
.clear-keyword-text {
font-size: 16px;
color: #666666;
line-height: 16px;
}
.search-btn {
height: 36px;
padding: 0 14px;
margin-left: 8px;
border-radius: 18px;
background-color: #ff5000;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.search-btn-text {
color: #ffffff;
font-size: 14px;
font-weight: 600;
white-space: nowrap;
}
.search-content,
.search-result-content {
flex: 1;
height: 0;
background-color: #f5f5f5;
}
.history-section,
.discover-section {
padding: 18px 16px 0 16px;
background-color: #ffffff;
}
.discover-section {
margin-top: 12px;
padding-bottom: 18px;
}
.section-header {
height: 32px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.section-title {
font-size: 16px;
color: #222222;
font-weight: 700;
}
.clear-history {
font-size: 13px;
color: #999999;
}
.history-list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding-top: 8px;
}
.history-chip {
height: 30px;
padding: 0 14px;
margin-right: 10px;
margin-bottom: 10px;
border-radius: 15px;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
}
.history-chip-text {
font-size: 14px;
color: #333333;
}
.empty-history {
padding: 20px 0 12px 0;
display: flex;
justify-content: center;
}
.empty-history-text {
font-size: 14px;
color: #999999;
}
.discover-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
padding-top: 8px;
}
.discover-item {
width: 48%;
height: 44px;
margin-bottom: 8px;
border-radius: 6px;
background-color: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
}
.discover-text {
font-size: 14px;
color: #333333;
}
.cart-match-section {
padding-top: 12px;
background-color: #f5f5f5;
}
.result-section-title-wrap {
padding: 0 16px 10px 16px;
}
.result-section-title {
font-size: 16px;
color: #222222;
font-weight: 700;
}
.cart-result-list {
padding: 0 12px;
}
.cart-result-card {
background-color: #ffffff;
border-radius: 12px;
padding: 12px;
margin-bottom: 12px;
display: flex;
flex-direction: row;
align-items: center;
}
.result-item-info {
flex: 1;
display: flex;
flex-direction: column;
height: 76px;
justify-content: space-between;
overflow: hidden;
}
.result-shop-name {
font-size: 12px;
color: #999999;
margin-bottom: 2px;
}
.item-select {
width: 30px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 6px;
flex-shrink: 0;
}
.selected-icon {
width: 18px;
height: 18px;
background-color: #ff5000;
color: #ffffff;
border-radius: 9px;
text-align: center;
line-height: 18px;
font-size: 12px;
}
.unselected-icon {
width: 18px;
height: 18px;
border: 1px solid #dddddd;
border-radius: 9px;
}
.item-image {
width: 76px;
height: 76px;
border-radius: 8px;
margin-right: 10px;
flex-shrink: 0;
}
.item-name {
font-size: 14px;
color: #222222;
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
}
.item-spec {
font-size: 12px;
color: #999999;
}
.item-footer {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
width: 100%;
}
.item-price {
font-size: 16px;
color: #ff5000;
font-weight: 700;
}
.quantity-control {
display: flex;
flex-direction: row;
align-items: center;
background-color: #f5f5f5;
border-radius: 12px;
overflow: hidden;
height: 28px;
}
.quantity-btn {
width: 28px;
height: 28px;
text-align: center;
line-height: 28px;
font-size: 16px;
color: #333333;
background-color: #eeeeee;
}
.quantity-value {
min-width: 36px;
text-align: center;
font-size: 14px;
line-height: 28px;
color: #333333;
}
.no-cart-result {
padding: 54px 16px 28px 16px;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.warning-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.warning-icon {
width: 22px;
height: 22px;
border-radius: 11px;
background-color: #ff7a00;
color: #ffffff;
font-size: 16px;
text-align: center;
line-height: 22px;
margin-right: 8px;
}
.warning-text {
font-size: 17px;
color: #666666;
font-weight: 500;
}
.recommend-search-section {
padding: 18px 12px 0 12px;
}
.recommend-title-wrap {
height: 36px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.line {
width: 70px;
height: 1px;
background-color: #dddddd;
}
.recommend-title {
font-size: 15px;
color: #999999;
margin: 0 12px;
}
.recommend-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.recommend-card {
width: 49%;
margin-bottom: 12px;
border-radius: 12px;
background-color: #ffffff;
overflow: hidden;
}
.recommend-image {
width: 100%;
height: 180px;
background-color: #eeeeee;
}
.recommend-info {
padding: 8px;
}
.recommend-shop-tag {
font-size: 11px;
color: #ff5000;
margin-bottom: 4px;
}
.recommend-name {
font-size: 15px;
color: #222222;
line-height: 21px;
height: 42px;
overflow: hidden;
}
.recommend-sales {
font-size: 12px;
color: #999999;
margin-top: 6px;
}
.recommend-price-row {
margin-top: 8px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.recommend-price {
font-size: 20px;
color: #ff5000;
font-weight: 700;
}
.recommend-cart-btn {
width: 32px;
height: 32px;
border-radius: 16px;
background-color: #fff2e8;
display: flex;
align-items: center;
justify-content: center;
}
.recommend-cart-icon {
font-size: 16px;
line-height: 16px;
}
.fixed-cart-settlement-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: #ffffff;
border-top: 1px solid #eeeeee;
z-index: 999;
padding-bottom: var(--window-bottom);
}
.settlement-inner {
height: 64px;
padding: 0 14px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.settlement-left {
display: flex;
flex-direction: row;
align-items: center;
flex-shrink: 0;
}
.select-circle {
width: 20px;
height: 20px;
border-radius: 10px;
border: 1px solid #dddddd;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.select-circle-active {
background-color: #ff5000;
border-color: #ff5000;
}
.select-check {
font-size: 12px;
color: #ffffff;
}
.select-all-text {
font-size: 14px;
color: #333333;
margin-left: 8px;
}
.settlement-right {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
flex: 1;
min-width: 0;
}
.total-info {
display: flex;
flex-direction: row;
align-items: baseline;
margin-right: 12px;
}
.total-label {
font-size: 14px;
color: #666666;
}
.total-price {
font-size: 20px;
color: #ff5000;
font-weight: 700;
margin-left: 3px;
}
.checkout-btn {
height: 44px;
min-width: 126px;
padding: 0 20px;
border-radius: 24px;
background-color: #ff5000;
color: #ffffff;
font-size: 16px;
font-weight: 700;
line-height: 44px;
border: none;
margin: 0;
}
.checkout-btn-disabled {
background-color: #ffb6a0;
}
.bottom-safe-space {
height: 92px;
}
@media screen and (max-width: 375px) {
.search-header {
padding-left: 10px;
}
.search-btn {
padding: 0 10px;
}
.recommend-image {
height: 160px;
}
.recommend-price,
.total-price {
font-size: 18px;
}
.checkout-btn {
min-width: 110px;
padding: 0 14px;
font-size: 14px;
}
}
</style>