fix: 更新多个组件样式和功能以提升用户体验

- 在 myCollect.vue 中优化收藏页面的布局和样式,增加主题支持
- 在 searchPage.vue 中修复搜索组件的输入值设置逻辑
- 在 coupon/index.vue 中重构优惠券列表的展示逻辑,提升可用性
- 在 m-search-revision.vue 中调整搜索组件的样式和功能,增加清除图标的交互
- 在 pages.json 中禁用下拉刷新功能以改善性能
This commit is contained in:
Yer11214
2026-07-09 16:34:22 +08:00
parent f727e01ef0
commit 41e8cff749
9 changed files with 861 additions and 579 deletions

View File

@@ -1,84 +1,109 @@
<template>
<div class="wrapper">
<u-tabs
class="coupon-tabs"
:list="list"
:scrollable="false"
:lineColor="lightColor"
:activeStyle="{ color: lightColor }"
v-model:current="current"
>
</u-tabs>
<div class="empty" v-if="couponsList.length <= 0">
<u-empty text="暂无优惠券" mode="coupon"></u-empty>
</div>
<view class="coupon-item" v-for="(item, index) in couponsList" :key="index">
<view class="left">
<view class="wave-line">
<view class="wave" v-for="(item, index) in 12" :key="index"></view>
</view>
<view class="message">
<view>
<span v-if="item.couponType == 'DISCOUNT'">{{ item.discount }}</span>
<span v-else>{{ item.price }}</span>
</view>
<view>{{unitPrice(item.consumeThreshold) }}元可用</view>
</view>
<view class="circle circle-top"></view>
<view class="circle circle-bottom"></view>
</view>
<view class="right">
<view class="desc">
<view v-if="item.scopeType">
<span v-if="item.scopeType == 'ALL' && item.storeId == '0'">全平台</span>
<span v-if="item.scopeType == 'PORTION_GOODS_CATEGORY'">仅限品类</span>
<view v-else
>{{
item.storeName == "platform" ? "全平台" : item.storeName + "店铺"
}}使用</view
>
</view>
<view class="reason" v-if="item.reason">{{ item.reason }}</view>
<view class="end-time">有效期至:{{ item.endTime }}</view>
</view>
<view
class="receive"
v-if="current == 0 && !routerVal.selectedCoupon.includes(item.id)"
@click="clickWay(item)"
>
<text>立即</text><br />
<text>使用</text>
</view>
<view class="used" v-if="current == 0 && routerVal.selectedCoupon.includes(item.id)" @click="clickWay(item)">
<text>取消</text><br />
<text>使用</text>
</view>
<view class="bg-quan"></view>
</view>
<view class="b-content" :style="themeStyle">
<view class="coupon-tabs">
<u-tabs
:list="list"
:scrollable="false"
:inactiveStyle="{ color: '#333' }"
v-model:current="current"
:lineColor="lightColor"
:activeStyle="{ color: lightColor }"
></u-tabs>
</view>
</div>
<scroll-view class="list-scroll-content" scroll-y>
<u-empty
mode="coupon"
text="暂无优惠券"
v-if="couponsList.length <= 0"
></u-empty>
<view
class="coupon-card"
:class="{ 'coupon-used': current != 0 }"
v-for="(item, index) in couponsList"
:key="item.id || index"
>
<view class="coupon-card-left">
<text class="coupon-price-symbol" v-if="item.couponType != 'DISCOUNT'">¥</text>
<text class="coupon-price-value">
{{ item.couponType == 'DISCOUNT' ? item.discount + '折' : unitPrice(item.price) }}
</text>
</view>
<view class="coupon-divider"></view>
<view class="coupon-card-right">
<view class="coupon-info">
<text class="coupon-card-name">
<template v-if="item.scopeType == 'ALL' && item.storeId == '0'">全平台</template>
<template v-else-if="item.scopeType == 'PORTION_GOODS_CATEGORY'">仅限品类</template>
<template v-else>
{{ item.storeName == 'platform' ? '全平台' : (item.storeName || '') + '店铺' }}
</template>
使用
</text>
<text class="coupon-card-desc">{{ unitPrice(item.consumeThreshold) }}元可用</text>
<text class="coupon-card-time" v-if="item.reason">{{ item.reason }}</text>
<text class="coupon-card-time" v-if="item.endTime">有效期至:{{ item.endTime }}</text>
</view>
<view
class="coupon-status-btn"
v-if="current == 0 && !isSelected(item)"
@click="clickWay(item)"
>
立即使用
</view>
<view
class="coupon-status-btn cancel"
v-else-if="current == 0 && isSelected(item)"
@click="clickWay(item)"
>
取消使用
</view>
<view class="coupon-status-btn disabled" v-else>
不可用
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { useCoupon } from '@/api/trade.js'
import { unitPrice } from '@/utils/filters.js'
import { getThemeStyle } from '@/utils/theme'
const store = useStore()
const lightColor = computed(() => store.getters.lightColor)
const themeStyle = computed(() => getThemeStyle(store.state.theme))
const current = ref(0)
const list = [
{ name: '可用优惠券' },
{ name: '不可用优惠券' },
]
const couponsList = ref<any[]>([])
const routerVal = ref<Record<string, any>>({})
const routerVal = ref<Record<string, any>>({
selectedCoupon: [],
way: '',
})
onLoad((options) => {
routerVal.value = options || {}
const selectedCoupon = options?.selectedCoupon
let selected: string[] = []
if (Array.isArray(selectedCoupon)) {
selected = selectedCoupon
} else if (typeof selectedCoupon === 'string' && selectedCoupon) {
selected = selectedCoupon.split(',')
}
routerVal.value = {
...(options || {}),
selectedCoupon: selected,
}
})
watch(current, (val) => {
@@ -88,17 +113,17 @@ watch(current, (val) => {
})
onMounted(() => {
init()
couponsList.value = store.state.canUseCoupons || []
})
function init() {
couponsList.value = store.state.canUseCoupons
function isSelected(coupon: any) {
return (routerVal.value.selectedCoupon || []).includes(coupon.id)
}
function clickWay(coupon: any) {
useCoupon({
memberCouponId: coupon.id,
used: !routerVal.value.selectedCoupon.includes(coupon.id),
used: !isSelected(coupon),
way: routerVal.value.way,
}).then((res) => {
if (res.data.success) {
@@ -113,160 +138,186 @@ function clickWay(coupon: any) {
})
}
</script>
<style scoped lang="scss">
.desc {
height: 220rpx;
flex: 2;
<style lang="scss" scoped>
.b-content {
background: #f7f8fa;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.end-time,
.reason {
color: #999;
line-height: 1.5;
font-size: 24rpx;
}
.empty {
margin-top: 20px;
text-align: center;
.coupon-tabs {
background: #fff;
height: 88rpx;
box-shadow: 0 1rpx 8rpx rgba(0, 0, 0, 0.04);
position: relative;
z-index: 2;
flex-shrink: 0;
}
.wrapper {
background: #f9f9f9;
:deep(.u-tabs),
:deep(.u-tabs__wrapper),
:deep(.u-tabs__wrapper__scroll-view-wrapper),
:deep(.u-tabs__wrapper__scroll-view),
:deep(.u-tabs__wrapper__nav) {
background: #fff;
height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item) {
min-height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item__text) {
color: #333;
font-size: 28rpx;
}
.list-scroll-content {
flex: 1;
height: 0;
width: 100%;
padding: 24rpx;
box-sizing: border-box;
}
.coupon-card {
display: flex;
align-items: stretch;
background: #fff;
border-radius: 24rpx;
margin-bottom: 24rpx;
position: relative;
border: 1rpx solid #f0f1f5;
overflow: hidden;
.coupon-tabs {
width: 100%;
background: #fff;
&:active {
transform: scale(0.98);
}
&::before,
&::after {
content: '';
position: absolute;
width: 32rpx;
height: 32rpx;
background: #f7f8fa;
border-radius: 50%;
left: 204rpx;
z-index: 2;
box-shadow: inset 0 0 0 1rpx #eceef2;
}
&::before {
top: -16rpx;
}
&::after {
bottom: -16rpx;
}
&.coupon-used {
.coupon-card-left {
background: linear-gradient(135deg, #f5f5f5 0%, #eeeeee 100%);
color: #999;
}
}
}
.coupon-item {
.coupon-card-left {
width: 220rpx;
min-height: 180rpx;
display: flex;
align-items: center;
height: 220rpx;
margin: 20rpx;
justify-content: center;
flex-shrink: 0;
color: #ff3b30;
position: relative;
background: linear-gradient(135deg, #fff5f5 0%, #ffecec 100%);
}
.left {
height: 100%;
width: 260rpx;
background-color: $light-color;
position: relative;
.message {
color: $font-color-white;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
margin-top: 40rpx;
.coupon-price-symbol {
font-size: 32rpx;
font-weight: 700;
margin-right: 4rpx;
}
view:nth-child(1) {
font-weight: bold;
font-size: 60rpx;
}
.coupon-price-value {
font-size: 56rpx;
font-weight: 900;
line-height: 1;
letter-spacing: -1rpx;
}
view:nth-child(2) {
font-size: $font-sm;
}
}
.coupon-divider {
position: absolute;
left: 220rpx;
top: 24rpx;
bottom: 24rpx;
width: 0;
border-left: 2rpx dashed #eceef2;
}
.wave-line {
height: 220rpx;
width: 8rpx;
position: absolute;
top: 0;
left: 0;
background-color: $light-color;
overflow: hidden;
.coupon-card-right {
flex: 1;
padding: 32rpx 32rpx 32rpx 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
gap: 20rpx;
background: #fff;
}
.wave {
width: 8rpx;
height: 16rpx;
background-color: #ffffff;
border-radius: 0 16rpx 16rpx 0;
margin-top: 4rpx;
}
}
.circle {
width: 40rpx;
height: 40rpx;
background-color: $bg-color;
position: absolute;
border-radius: 50%;
z-index: 111;
}
.circle-top {
top: -20rpx;
right: -20rpx;
}
.circle-bottom {
bottom: -20rpx;
right: -20rpx;
}
.coupon-info {
display: flex;
flex-direction: column;
gap: 12rpx;
flex: 1;
min-width: 0;
}
.coupon-card-name {
font-size: 30rpx;
color: #111;
font-weight: 700;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.coupon-card-desc {
font-size: 24rpx;
color: #8a8f99;
font-weight: 500;
}
.coupon-card-time {
font-size: 22rpx;
color: #b0b3bf;
}
.coupon-status-btn {
flex-shrink: 0;
padding: 16rpx 28rpx;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: 700;
color: #fff;
background: linear-gradient(135deg, var(--theme-light, #ff6b35), var(--theme-primary, #ff4b2b));
&:active {
opacity: 0.9;
}
.right {
display: flex;
justify-content: space-between;
align-items: center;
width: 450rpx;
font-size: $font-sm;
height: 220rpx;
background-color: #ffffff;
overflow: hidden;
position: relative;
> view:nth-child(1) {
color: #666666;
margin-left: 20rpx;
&.cancel {
background: #333;
}
> view:nth-child(1) {
color: #ff6262;
font-size: 30rpx;
}
}
.receive {
color: #ffffff;
background-color: $main-color;
border-radius: 50%;
width: 86rpx;
height: 86rpx;
text-align: center;
margin-right: 30rpx;
vertical-align: middle;
padding-top: 8rpx;
position: relative;
z-index: 2;
}
.used {
color: #ffffff;
background-color: black;
border-radius: 50%;
width: 86rpx;
height: 86rpx;
text-align: center;
margin-right: 30rpx;
vertical-align: middle;
padding-top: 8rpx;
position: relative;
z-index: 2;
}
.bg-quan {
width: 244rpx;
height: 244rpx;
border: 6rpx solid $main-color;
border-radius: 50%;
opacity: 0.1;
color: $main-color;
text-align: center;
padding-top: 30rpx;
font-size: 130rpx;
position: absolute;
right: -54rpx;
bottom: -60rpx;
}
&.disabled {
background: #ccc;
}
}
</style>

View File

@@ -1,29 +1,42 @@
<template>
<view class="content">
<view class="page" :style="themeStyle">
<u-navbar
title="收藏"
:fixed="true"
:placeholder="true"
:border="false"
:auto-back="true"
title=""
></u-navbar>
<view class="tabs-wrap">
<u-tabs
:list="navList"
:scrollable="false"
:lineColor="lightColor"
:activeStyle="{ color: lightColor, fontWeight: '600' }"
:inactiveStyle="{ color: '#666' }"
v-model:current="tabCurrentIndex"
@change="onTabChange"
></u-tabs>
</view>
<scroll-view
class="list-scroll"
scroll-y
enable-back-to-top
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
@scrolltolower="loadMore"
>
<template #center>
<view class="slot-wrap">
<u-tabs
:lineColor="lightColor"
:activeStyle="{ color: lightColor }"
class="collect-tabs"
:list="navList"
:scrollable="false"
v-model:current="tabCurrentIndex"
></u-tabs>
</view>
</template>
</u-navbar>
<view class="collect-body">
<!-- 显示商品栏 -->
<!-- 商品 -->
<view v-if="tabCurrentIndex === 0" class="tab-content">
<u-empty style="margin-top: 40rpx" text="暂无收藏商品数据" mode="favor" v-if="goodsEmpty"></u-empty>
<u-empty
v-if="!goodsLoading && goodsEmpty"
class="empty-box"
text="暂无收藏商品"
mode="favor"
></u-empty>
<template v-else>
<u-swipe-action
v-for="(item, index) in goodsList"
@@ -34,26 +47,34 @@
@open="openSwipeItem(item, 'goods')"
:show="item.selected"
:options="swipeOptions"
@click="removeGoodsCollection(item, index)"
@click="removeGoodsCollection(item)"
:name="index"
>
<view class="goods" @click="goGoodsDetail(item)">
<u-image width="131rpx" height="131rpx" :src="item.image" mode="aspectFit">
<u-image width="140rpx" height="140rpx" radius="12rpx" :src="item.image" mode="aspectFill">
<template #loading><u-loading-icon></u-loading-icon></template>
</u-image>
<view class="goods-intro">
<view class="goods-name">{{ item.goodsName }}</view>
<view class="goods-sn">{{ item.goods_sn }}</view>
<view class="goods-name wes-2">{{ item.goodsName }}</view>
<view class="goods-price">{{ unitPrice(item.price) }}</view>
</view>
</view>
</u-swipe-action-item>
</u-swipe-action>
<view class="load-status" v-if="goodsList.length">
{{ goodsFinished ? '没有更多了' : goodsLoading ? '加载中...' : '上拉加载更多' }}
</view>
</template>
</view>
<!-- 显示收藏的店铺栏 -->
<!-- 店铺 -->
<view v-else class="tab-content">
<u-empty style="margin-top: 40rpx" text="暂无收藏店铺数据" mode="favor" v-if="storeEmpty"></u-empty>
<u-empty
v-if="!storeLoading && storeEmpty"
class="empty-box"
text="暂无收藏店铺"
mode="favor"
></u-empty>
<template v-else>
<u-swipe-action
v-for="(item, index) in storeList"
@@ -68,36 +89,51 @@
:name="index"
>
<view class="store" @click="goStoreMainPage(item.id)">
<view class="intro">
<view class="store-logo">
<u-image width="102rpx" height="102rpx" :src="item.storeLogo" :alt="item.storeName"
mode="aspectFit">
<template #loading><u-loading-icon></u-loading-icon></template>
</u-image>
</view>
<view class="store-name">
<view>{{ item.storeName }}</view>
<u-tag size="mini" type="error" :color="mainColor" v-if="item.selfOperated"
text="自营" mode="plain" shape="circle" />
</view>
<view class="store-collect">
<view>进店逛逛</view>
</view>
<view class="store-logo">
<u-image
width="96rpx"
height="96rpx"
shape="circle"
:src="item.storeLogo"
mode="aspectFill"
>
<template #loading><u-loading-icon></u-loading-icon></template>
</u-image>
</view>
<view class="store-info">
<view class="store-name-row">
<text class="store-name wes">{{ item.storeName }}</text>
<u-tag
v-if="item.selfOperated"
size="mini"
type="error"
:color="mainColor"
text="自营"
plain
shape="circle"
/>
</view>
<view class="store-tip">左滑可取消收藏</view>
</view>
<view class="store-enter">进店逛逛</view>
</view>
</u-swipe-action-item>
</u-swipe-action>
<view class="load-status" v-if="storeList.length">
{{ storeFinished ? '没有更多了' : storeLoading ? '加载中...' : '上拉加载更多' }}
</view>
</template>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { onShow, onReachBottom, onPullDownRefresh } from '@dcloudio/uni-app'
import { onShow } from '@dcloudio/uni-app'
import { useStore } from '@/store'
import { unitPrice } from '@/utils/filters.js'
import { getThemeStyle } from '@/utils/theme'
import {
getGoodsCollection,
getStoreCollection,
@@ -109,6 +145,7 @@ const store = useStore()
const lightColor = computed(() => store.getters.lightColor)
const mainColor = computed(() => store.getters.mainColor)
const themeStyle = computed(() => getThemeStyle(store.state.theme))
const swipeOptions = computed(() => [
{
@@ -119,55 +156,93 @@ const swipeOptions = computed(() => [
const tabCurrentIndex = ref(0)
const navList = ref([
{ name: '商品(0)', params: { pageNumber: 1, pageSize: 10 } },
{ name: '店铺(0)', params: { pageNumber: 1, pageSize: 10 } },
{ name: '商品(0)' },
{ name: '店铺(0)' },
])
const goodsParams = ref({ pageNumber: 1, pageSize: 10 })
const storeParams = ref({ pageNumber: 1, pageSize: 10 })
const goodsEmpty = ref(false)
const storeEmpty = ref(false)
const goodsList = ref<any[]>([])
const storeList = ref<any[]>([])
const goodsLoading = ref(false)
const storeLoading = ref(false)
const goodsFinished = ref(false)
const storeFinished = ref(false)
const refreshing = ref(false)
const inited = ref(false)
onShow(() => {
reloadOrLoadMore('reload')
})
onReachBottom(() => {
reloadOrLoadMore('next')
})
onPullDownRefresh(() => {
if (tabCurrentIndex.value === 0) {
navList.value[0].params.pageNumber = 1
goodsList.value = []
fetchGoodsList()
} else {
navList.value[1].params.pageNumber = 1
storeList.value = []
fetchStoreList()
if (!inited.value) {
inited.value = true
reloadAll()
return
}
reloadCurrent()
})
function hideLoadingIfNeeded() {
if (store.state.isShowToast) uni.hideLoading()
}
function reloadOrLoadMore(type: 'reload' | 'next') {
if (type === 'next') {
navList.value[tabCurrentIndex.value].params.pageNumber++
if (tabCurrentIndex.value === 0) {
fetchGoodsList()
} else {
fetchStoreList()
}
return
function onTabChange(e: any) {
const index = typeof e === 'number' ? e : e?.index
if (typeof index === 'number') {
tabCurrentIndex.value = index
}
navList.value[0].params.pageNumber = 1
navList.value[1].params.pageNumber = 1
if (tabCurrentIndex.value === 0 && !goodsList.value.length && !goodsEmpty.value) {
reloadGoods()
}
if (tabCurrentIndex.value === 1 && !storeList.value.length && !storeEmpty.value) {
reloadStore()
}
}
function onRefresh() {
refreshing.value = true
reloadCurrent()
}
function loadMore() {
if (tabCurrentIndex.value === 0) {
if (goodsLoading.value || goodsFinished.value || goodsEmpty.value) return
goodsParams.value.pageNumber++
fetchGoodsList()
} else {
if (storeLoading.value || storeFinished.value || storeEmpty.value) return
storeParams.value.pageNumber++
fetchStoreList()
}
}
function reloadAll() {
reloadGoods()
reloadStore()
}
function reloadCurrent() {
if (tabCurrentIndex.value === 0) {
reloadGoods()
} else {
reloadStore()
}
}
function reloadGoods() {
goodsParams.value.pageNumber = 1
goodsFinished.value = false
goodsEmpty.value = false
storeEmpty.value = false
goodsList.value = []
storeList.value = []
fetchGoodsList()
}
function reloadStore() {
storeParams.value.pageNumber = 1
storeFinished.value = false
storeEmpty.value = false
storeList.value = []
fetchStoreList()
}
@@ -182,9 +257,7 @@ function openSwipeItem(val: any, type: 'goods' | 'store') {
function removeGoodsCollection(val: any) {
deleteGoodsCollection(val.skuId).then((res) => {
if (res.statusCode === 200) {
goodsList.value = []
navList.value[0].params.pageNumber = 1
fetchGoodsList()
reloadGoods()
}
})
}
@@ -192,9 +265,7 @@ function removeGoodsCollection(val: any) {
function removeStoreCollection(val: any) {
deleteStoreCollection(val.id).then((res) => {
if (res.statusCode === 200) {
storeList.value = []
navList.value[1].params.pageNumber = 1
fetchStoreList()
reloadStore()
}
})
}
@@ -212,183 +283,210 @@ function goStoreMainPage(id: string) {
}
function fetchGoodsList() {
if (goodsLoading.value) return
goodsLoading.value = true
uni.showLoading({ title: '加载中' })
getGoodsCollection(navList.value[0].params, 'GOODS')
getGoodsCollection(goodsParams.value, 'GOODS')
.then((res) => {
goodsLoading.value = false
refreshing.value = false
hideLoadingIfNeeded()
uni.stopPullDownRefresh()
if (res.data.success) {
const data = res.data.result
navList.value[0].name = `商品(${data.total})`
goodsEmpty.value = data.total === 0
if (data.records?.length) {
const records = data.records.map((item: any) => ({ ...item, selected: false }))
navList.value[0].name = `商品(${data.total || 0})`
goodsEmpty.value = !data.total
const records = (data.records || []).map((item: any) => ({
...item,
selected: false,
}))
if (goodsParams.value.pageNumber === 1) {
goodsList.value = records
} else {
goodsList.value.push(...records)
}
goodsFinished.value =
!records.length || goodsList.value.length >= (data.total || 0)
}
})
.catch(() => {
goodsLoading.value = false
refreshing.value = false
hideLoadingIfNeeded()
uni.stopPullDownRefresh()
})
}
function fetchStoreList() {
if (storeLoading.value) return
storeLoading.value = true
uni.showLoading({ title: '加载中' })
getStoreCollection(navList.value[1].params, 'STORE')
getStoreCollection(storeParams.value, 'STORE')
.then((res) => {
storeLoading.value = false
refreshing.value = false
hideLoadingIfNeeded()
uni.stopPullDownRefresh()
if (res.data.success) {
const data = res.data.result
navList.value[1].name = `店铺(${data.total})`
storeEmpty.value = data.total === 0
if (data.records?.length) {
const records = data.records.map((item: any) => ({ ...item, selected: false }))
navList.value[1].name = `店铺(${data.total || 0})`
storeEmpty.value = !data.total
const records = (data.records || []).map((item: any) => ({
...item,
selected: false,
}))
if (storeParams.value.pageNumber === 1) {
storeList.value = records
} else {
storeList.value.push(...records)
}
storeFinished.value =
!records.length || storeList.value.length >= (data.total || 0)
}
})
.catch(() => {
storeLoading.value = false
refreshing.value = false
hideLoadingIfNeeded()
uni.stopPullDownRefresh()
})
}
</script>
<style lang="scss">
page,
.content {
background: $page-color-base;
height: 100%;
}
page {
background: #f8f8f8;
height: 100%;
}
</style>
.content {
width: 100%;
<style lang="scss" scoped>
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: #f8f8f8;
box-sizing: border-box;
}
.tabs-wrap {
flex-shrink: 0;
background: #fff;
border-bottom: 1rpx solid #f0f0f0;
}
.list-scroll {
flex: 1;
height: 0;
min-height: 0;
}
.tab-content {
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
}
.empty-box {
margin-top: 120rpx;
}
.collect-swipe,
:deep(.u-swipe-action),
:deep(.u-swipe-action-item),
:deep(.u-swipe-action-item__content) {
width: 100%;
}
:deep(.u-swipe-action-item__content) {
overflow: hidden;
}
.goods {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
padding: 24rpx;
margin-top: 16rpx;
background: #fff;
.goods-intro {
flex: 1;
min-width: 0;
margin-left: 24rpx;
display: flex;
flex-direction: column;
min-height: 100vh;
justify-content: space-between;
min-height: 140rpx;
}
.slot-wrap {
flex: 1;
display: flex;
justify-content: center;
padding: 0 20rpx;
box-sizing: border-box;
.goods-name {
font-size: 28rpx;
color: #333;
line-height: 1.4;
}
.collect-tabs {
width: 100%;
.goods-price {
margin-top: 16rpx;
font-size: 32rpx;
font-weight: 600;
color: var(--theme-light, #ff6b35);
}
}
.collect-body {
flex: 1;
width: 100%;
}
.store {
display: flex;
align-items: center;
box-sizing: border-box;
width: calc(100% - 32rpx);
margin: 16rpx auto 0;
padding: 24rpx;
background: #fff;
border-radius: 16rpx;
}
.tab-content {
width: 100%;
}
.store-logo {
flex-shrink: 0;
width: 96rpx;
height: 96rpx;
border-radius: 50%;
overflow: hidden;
background: #f5f5f5;
}
:deep(.u-tabs),
:deep(.u-tabs__wrapper),
:deep(.u-tabs__wrapper__scroll-view-wrapper),
:deep(.u-tabs__wrapper__scroll-view),
:deep(.u-tabs__wrapper__nav) {
width: 100%;
}
.store-info {
flex: 1;
min-width: 0;
margin: 0 20rpx;
}
.collect-swipe,
:deep(.u-swipe-action),
:deep(.u-swipe-action-item),
:deep(.u-swipe-action-item__content) {
width: 100%;
}
.store-name-row {
display: flex;
align-items: center;
gap: 12rpx;
}
:deep(.u-swipe-action-item__content) {
overflow: hidden;
}
.store-name {
max-width: 360rpx;
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.goods {
background-color: #fff;
border-bottom: 1px solid $border-color-light;
min-height: 190rpx;
box-sizing: border-box;
display: flex;
align-items: center;
padding: 30rpx 20rpx;
margin-top: 20rpx;
width: 100%;
.store-tip {
margin-top: 10rpx;
font-size: 22rpx;
color: #999;
}
.goods-intro {
flex: 1;
min-width: 0;
font-size: $font-base;
line-height: 48rpx;
margin-left: 30rpx;
.store-enter {
flex-shrink: 0;
padding: 12rpx 20rpx;
border-radius: 100px;
border: 1rpx solid var(--theme-light, #ff6b35);
color: var(--theme-light, #ff6b35);
font-size: 24rpx;
}
.goods-name {
line-height: 1.4em;
font-size: 24rpx;
max-height: 2.8em;
overflow: hidden;
color: #666;
}
.goods-sn {
color: #cccccc;
font-size: 24rpx;
}
.goods-price {
color: $light-color;
}
}
}
.store {
background-color: #fff;
border: 1px solid $border-color-light;
border-radius: 16rpx;
margin: 20rpx 10rpx;
width: calc(100% - 20rpx);
box-sizing: border-box;
.intro {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx 0 40rpx;
min-height: 170rpx;
.store-logo {
width: 102rpx;
height: 102rpx;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
}
.store-name {
flex: 1;
min-width: 0;
margin-left: 30rpx;
line-height: 2em;
:first-child {
font-size: $font-base;
}
}
.store-collect {
flex-shrink: 0;
border-left: 1px solid $border-color-light;
padding-left: 20rpx;
text-align: center;
color: #999;
font-size: $font-sm;
}
}
}
.load-status {
padding: 24rpx 0 8rpx;
text-align: center;
font-size: 24rpx;
color: #999;
}
</style>

View File

@@ -15,7 +15,6 @@
<mSearch
ref="mSearchRef"
class="mSearch-input-box"
:show-clear="false"
@clickLeft="back"
:mode="2"
:placeholder="defaultKeyword"
@@ -271,7 +270,7 @@ import storage from '@/utils/storage'
const store = useStore()
const { proxy } = getCurrentInstance()!
const mSearchRef = ref<InstanceType<typeof mSearch> | null>(null)
const mSearchRef = ref<any>(null)
const empty = ref(false)
const scrollTop = ref(0)
@@ -806,7 +805,7 @@ function doSearch(searchKeyword: string | false) {
isShowSeachGoods.value = true
if (mSearchRef.value) {
mSearchRef.value.isShowSeachGoods = true
mSearchRef.value.inputVal = resolvedKeyword
mSearchRef.value.setInputValue(resolvedKeyword)
}
params.value.keyword = keyword.value
params.value.pageNumber = 1

View File

@@ -247,6 +247,26 @@ page {
position: relative;
z-index: 10;
background: #ffffff;
height: 88rpx;
box-shadow: 0 1rpx 8rpx rgba(0, 0, 0, 0.04);
}
:deep(.u-tabs),
:deep(.u-tabs__wrapper),
:deep(.u-tabs__wrapper__scroll-view-wrapper),
:deep(.u-tabs__wrapper__scroll-view),
:deep(.u-tabs__wrapper__nav) {
background: #fff;
height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item) {
min-height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item__text) {
color: #333;
font-size: 28rpx;
}
.box-content {
margin: 20rpx 0;

View File

@@ -1,6 +1,12 @@
<template>
<div class="page">
<u-navbar :auto-back="false" @leftClick="back" left-icon-color="#fff" :bg-color="background.backgroundColor" :border="false">
<div class="page" :style="themeStyle">
<u-navbar
:auto-back="false"
@leftClick="back"
left-icon-color="#fff"
:bg-color="background.backgroundColor"
:border="false"
>
</u-navbar>
<div class="wrapper-box">
@@ -9,62 +15,64 @@
<div class="bargain">
<div class="flex bargain-item">
<div class="goods-img">
<u-image width="200" height="200" :src="bargainDetail.thumbnail"></u-image>
<u-image width="200rpx" height="200rpx" :src="bargainDetail.thumbnail"></u-image>
</div>
<div class="goods-config">
<div class="goods-title wes-2">
{{bargainDetail.goodsName}}
{{ bargainDetail.goodsName }}
</div>
<div class="flex price-box">
<div class="purchase-price">
当前:<span>{{ activityData.surplusPrice == 0 ? bargains.purchasePrice : unitPrice(activityData.surplusPrice)}}</span>
</div>
<div class="max-price">原价:<span>{{unitPrice(bargainDetail.price)}}</span>
当前:<text>{{ activityData.surplusPrice == 0 ? bargains.purchasePrice : unitPrice(activityData.surplusPrice) }}</text>
</div>
<div class="max-price">原价:<text>{{ unitPrice(bargainDetail.price) }}</text></div>
</div>
<div class="tips">{{bargainDetail.sellingPoint}}</div>
<div class="tips">{{ bargainDetail.sellingPoint }}</div>
</div>
</div>
<!-- 砍价进度 -->
<div class="bargain-progress">
<u-line-progress class="line" :active-color="lightColor" striped striped-active :percent="totalPercent">
<u-line-progress
class="line"
:active-color="lightColor"
:percentage="totalPercent"
:show-text="false"
height="12"
>
</u-line-progress>
<div class="flex tips">
<div>已砍{{cutPrice}}</div>
<div>还剩{{activityData.surplusPrice}}</div>
<div>已砍{{ cutPrice }}</div>
<div>还剩{{ activityData.surplusPrice }}</div>
</div>
</div>
<!-- 参与砍价 -->
<div class="bargaining" v-if="!activityData.pass && activityData.status!='END'" @click="shareBargain">
<div class="bargaining" v-if="!activityData.pass && activityData.status != 'END'" @click="shareBargain">
邀请砍价
</div>
<!-- 立即购买 -->
<div v-else>
<div v-if="activityData.status!='END'" class="buy" @click="getGoodsDetail">
<div v-if="activityData.status != 'END'" class="buy" @click="getGoodsDetail">
立即购买
</div>
</div>
<!-- 我要开团 -->
<div class="start" v-if="activityData.memberId != loginUser.id" @click="startOpenGroup">我要开团
</div>
<div class="start" v-if="activityData.memberId != loginUser.id" @click="startOpenGroup">我要开团</div>
</div>
</div>
<!-- 帮砍列表 -->
<div class="box box2">
<div class="bargain">
<div class="bargain-title">帮忙砍</div>
<div class="user-item flex" v-if="logData.length !=0 " v-for="(item,index) in logData" :key="index">
<div class="user-item flex" v-if="logData.length != 0" v-for="(item, index) in logData" :key="index">
<div>
<u-image width="75" shape="circle" height="75" :src="item.kanjiaMemberFace"></u-image>
<u-image width="75rpx" shape="circle" height="75rpx" :src="item.kanjiaMemberFace"></u-image>
</div>
<div class="user-config flex">
<div class="user-name">
<div>{{noPassByName(item.kanjiaMemberName)}}</div>
<div>{{ noPassByName(item.kanjiaMemberName) }}</div>
<div>使出吃的奶劲儿</div>
</div>
<div class="save">砍掉<span>{{unitPrice(item.kanjiaPrice)}}</span></div>
<div class="save">砍掉<text>{{ unitPrice(item.kanjiaPrice) }}</text></div>
</div>
</div>
</div>
@@ -76,36 +84,61 @@
<view class="u-content">
<u-parse :content="bargainDetail.mobileIntro" :tag-style="style"></u-parse>
</view>
</div>
</div>
<!-- 砍价 -->
<u-modal title="恭喜您砍掉了" v-model:show="Bargaining" mask-close-able :show-confirm-button="false"
:title-style="{color: lightColor}">
<u-modal
title="恭喜您砍掉了"
v-model:show="Bargaining"
:close-on-click-overlay="true"
:show-confirm-button="false"
>
<view class="slot-content">
<u-count-to :start-val="0" ref="uCountToRef" font-size="100" :color="lightColor" :end-val="kanjiaPrice"
:decimals="2" :autoplay="autoplay"></u-count-to><span class="price"></span>
<u-count-to
:start-val="0"
ref="uCountToRef"
font-size="100"
:color="lightColor"
:end-val="kanjiaPrice"
:decimals="2"
:autoplay="autoplay"
></u-count-to>
<text class="price"></text>
</view>
</u-modal>
<!-- 帮砍 -->
<u-modal :show-title="false" v-model:show="helpBargainFlage" :show-confirm-button="false">
<u-modal title=" " v-model:show="helpBargainFlage" :show-confirm-button="false">
<view class="help-bargain" @click="handleClickHelpBargain">
<u-image width="100%" height="600rpx"
src="https://lilishop-oss.oss-cn-beijing.aliyuncs.com/91631d5a66c7426bbe3f7d644ee41946.jpeg"></u-image>
<u-image
width="100%"
height="600rpx"
src="https://lilishop-oss.oss-cn-beijing.aliyuncs.com/91631d5a66c7426bbe3f7d644ee41946.jpeg"
></u-image>
<u-image class="help" width="300rpx" height="80rpx" src="/pages/promotion/static/help-bargain.png"></u-image>
</view>
</u-modal>
<!-- 分享 -->
<shares @close="closeShare" :link="share()" type="kanjia" :thumbnail="bargainDetail.thumbnail"
:goodsName="bargainDetail.goodsName" v-if="shareFlage " />
<shares
@close="closeShare"
:link="share()"
type="kanjia"
:thumbnail="bargainDetail.thumbnail"
:goodsName="bargainDetail.goodsName"
v-if="shareFlage"
/>
<!-- 购买 -->
<popupGoods ref="popupGoodsRef" :buyMask="maskFlag" @closeBuy="closePopupBuy" :goodsDetail="bargainDetail"
:goodsSpec="goodsSpec" v-if="bargainDetail.id " @handleClickSku="getGoodsDetail" />
<popupGoods
ref="popupGoodsRef"
:buyMask="maskFlag"
@closeBuy="closePopupBuy"
:goodsDetail="bargainDetail"
:goodsSpec="goodsSpec"
v-if="bargainDetail.id"
@handleClickSku="getGoodsDetail"
/>
</div>
</div>
</template>
@@ -128,10 +161,12 @@ import {
import shares from '@/components/m-share/index'
import config from '@/config/config'
import { unitPrice, noPassByName, isLogin } from '@/utils/filters.js'
import { getThemeStyle } from '@/utils/theme'
const store = useStore()
const lightColor = computed(() => store.getters.lightColor)
const themeStyle = computed(() => getThemeStyle(store.state.theme))
const style = ref({
img: 'display:block',
@@ -205,8 +240,7 @@ watch(
(val) => {
if (val) {
totalPercent.value =
100 -
Math.floor((val.surplusPrice / bargainDetail.value.price) * 100)
100 - Math.floor((val.surplusPrice / bargainDetail.value.price) * 100)
cutPrice.value = (
bargainDetail.value.price - activityData.value.surplusPrice
).toFixed(2)
@@ -324,32 +358,44 @@ async function openActivity() {
}
}
</script>
<style lang="scss">
page {
background-color: $light-color !important;
background-color: var(--theme-light, #ff6b35) !important;
}
</style>
<style lang="scss" scoped>
.page {
min-height: 100vh;
box-sizing: border-box;
padding-bottom: 40rpx;
}
.slot-content {
display: flex;
align-items: flex-end;
justify-content: center;
margin: 20rpx 0 80rpx 0;
}
.price {
margin-left: 10rpx;
color: $light-color;
color: var(--theme-light, #ff6b35);
}
.price-box {
align-items: center;
padding: 10rpx 0;
}
.wrapper-box {
background: url("https://lili-system.oss-cn-beijing.aliyuncs.com/kanjia.png");
background-repeat: no-repeat;
background-size: 100% 100%;
height: 506rpx;
background: url('https://lili-system.oss-cn-beijing.aliyuncs.com/kanjia.png') no-repeat top center;
background-size: 100% 506rpx;
width: 100%;
box-sizing: border-box;
padding-top: 420rpx;
padding-bottom: 40rpx;
}
.box {
@@ -357,99 +403,92 @@ page {
border-radius: 20rpx;
position: relative;
width: 94%;
margin: 0 auto;
margin: 0 auto 20rpx;
overflow: hidden;
> .bargain {
padding: 32rpx;
}
}
.box1 {
top: 560rpx;
}
.box2 {
top: 580rpx;
}
.box3 {
top: 600rpx;
}
.box4 {
top: 620 rpx;
height: 200rpx;
}
.bargain-item {
align-items: center;
}
.goods-img {
flex-shrink: 0;
}
.goods-config {
flex: 1;
min-width: 0;
margin-left: 20rpx;
> .goods-title {
font-weight: bold;
font-size: 28rpx;
color: #333;
line-height: 1.4;
}
}
.max-price,
.purchase-price {
font-size: 24rpx;
color: #999;
}
.max-price {
margin-left: 10rpx;
text-decoration: line-through;
}
.purchase-price {
color: $main-color;
> span {
color: var(--theme-primary, #ff3c2a);
> text {
font-size: 32rpx;
font-weight: bold;
}
}
.bargaining,
.buy,
.start {
font-size: 24rpx;
width: 80%;
margin: 50rpx auto 0 auto;
margin: 50rpx auto 0;
text-align: center;
font-size: 30rpx;
padding: 18rpx;
border-radius: 100px;
box-sizing: border-box;
}
.start {
border: 1rpx solid $main-color;
color: $main-color;
border: 1rpx solid var(--theme-primary, #ff3c2a);
color: var(--theme-primary, #ff3c2a);
}
.bargaining,
.buy {
font-size: 24rpx;
color: #fff;
width: 80%;
margin: 50rpx auto 0 auto;
text-align: center;
font-size: 30rpx;
background-image: linear-gradient(
25deg,
$main-color,
$light-color,
$aider-light-color
var(--theme-primary, #ff3c2a),
var(--theme-light, #ff6b35),
var(--theme-aider, #ff9f28)
);
padding: 18rpx;
border-radius: 100px;
animation: mymove 5s infinite;
-webkit-animation: mymove 5s infinite; /*Safari and Chrome*/
animation-direction: alternate; /*轮流反向播放动画。*/
animation-timing-function: ease-in-out; /*动画的速度曲线*/
/* Safari 和 Chrome */
-webkit-animation: mymove 5s infinite;
-webkit-animation-direction: alternate; /*轮流反向播放动画。*/
-webkit-animation-timing-function: ease-in-out; /*动画的速度曲线*/
animation-direction: alternate;
animation-timing-function: ease-in-out;
}
@keyframes mymove {
0% {
transform: scale(1); /*开始为原始大小*/
transform: scale(1);
}
25% {
transform: scale(1.1); /*放大1.1倍*/
transform: scale(1.1);
}
50% {
transform: scale(1);
@@ -458,65 +497,80 @@ page {
transform: scale(1.1);
}
}
.line {
margin: 20rpx 0;
}
.tips {
font-size: 24rpx;
color: #999;
justify-content: space-between;
}
.bargain-progress {
margin: 20rpx 0;
}
.bargain-title {
font-size: 32rpx;
font-weight: bold;
color: $light-color;
color: var(--theme-light, #ff6b35);
text-align: center;
margin-bottom: 40rpx;
}
.user-item {
margin: 40rpx 0;
align-items: center;
}
.user-config {
margin-left: 20rpx;
flex: 8;
flex: 1;
min-width: 0;
align-items: center;
justify-content: space-between;
> .user-name {
flex: 1;
min-width: 0;
> div:nth-of-type(1) {
font-size: 28rpx;
max-width: 300rpx;
overflow: hidden;
word-wrap: normal;
white-space: nowrap;
text-overflow: ellipsis;
}
> div:nth-last-of-type(1) {
font-size: 24rpx;
color: #999;
}
}
}
.save {
color: $light-color;
> span {
flex-shrink: 0;
color: var(--theme-light, #ff6b35);
> text {
font-weight: bold;
}
}
.mobile-intro {
.u-content {
overflow: hidden;
max-width: 100%;
}
@keyframes fontMove {
0% {
transform: scale(1); /*开始为原始大小*/
transform: scale(1);
}
25% {
transform: scale(1.1); /*放大1.1倍*/
transform: scale(1.1);
}
50% {
transform: scale(1);
@@ -531,19 +585,13 @@ page {
justify-content: center;
flex-direction: column;
align-items: center;
> .help {
margin-bottom: 40rpx;
border-radius: 20rpx;
margin-top: 40rpx;
> .help {
margin: 40rpx 0;
border-radius: 20rpx;
animation: fontMove 5s infinite;
-webkit-animation: fontMove 5s infinite; /*Safari and Chrome*/
animation-direction: alternate; /*轮流反向播放动画。*/
animation-timing-function: ease-in-out; /*动画的速度曲线*/
/* Safari 和 Chrome */
-webkit-animation: fontMove 5s infinite;
-webkit-animation-direction: alternate; /*轮流反向播放动画。*/
-webkit-animation-timing-function: ease-in-out; /*动画的速度曲线*/
animation-direction: alternate;
animation-timing-function: ease-in-out;
}
}
</style>

View File

@@ -4,7 +4,10 @@
<u-tabs
:list="list"
:scrollable="false"
:inactiveStyle="{ color: '#333' }"
v-model:current="current"
:lineColor="lightColor"
:activeStyle="{ color: lightColor }"
@change="change"
></u-tabs>
<view v-if="showLoading" style="width:500rpx;margin:0 auto;text-align: center;height:800rpx;line-height: 800rpx;">
@@ -183,9 +186,27 @@ function getMessage() {
})
}
</script>
<style>
<style lang="scss" scoped>
.foot {
position: fixed;
bottom: 0;
}
:deep(.u-tabs),
:deep(.u-tabs__wrapper),
:deep(.u-tabs__wrapper__scroll-view-wrapper),
:deep(.u-tabs__wrapper__scroll-view),
:deep(.u-tabs__wrapper__nav) {
background: #fff;
height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item) {
min-height: 88rpx;
}
:deep(.u-tabs__wrapper__nav__item__text) {
color: #333;
font-size: 28rpx;
}
</style>