web-zk-h5/pages/shareArea/hiList.vue

638 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="contain">
<!-- Tab选项卡 -->
<view class="tab-container">
<view class="tab-wrapper">
<view
v-for="tab in tabs"
:key="tab.value"
class="tab-item"
:class="{ 'tab-active': activeTab === tab.value }"
@click="switchTab(tab.value)"
>
<text class="tab-text">{{ tab.label }}</text>
<view class="tab-line" v-if="activeTab === tab.value"></view>
</view>
</view>
</view>
<view class="goods-container">
<scroll-view
class="goodList"
scroll-y="true"
enhanced
:show-scrollbar="false"
>
<view v-for="item in goodList" :key="item.waresCode" class="goodList_i">
<img :src="item.cover1" class="cover" alt="" />
<view class="goodList_ir">
<view class="tit1">
{{ item.waresName }}
</view>
<view class="goodList_ib">
<view class="price-container">
<!-- <text class="currency">¥</text> -->
<text class="price">{{ formatCurrency(item.waresPrice) }}</text>
<text v-if="item.isSale === 1" class="sale-status">已售罄</text>
</view>
<!-- <img @click.stop="addCar(item)"
src="@/static/images/cart.png"
alt=""> -->
</view>
<!-- 数量控制区域 -->
<view class="quantity-section" v-if="item.isSale !== 1">
<view class="quantity-control">
<view
class="quantity-btn minus"
:class="{ disabled: item.quantity <= 1 }"
@click.stop="updateQuantity(item, -1)"
>
<text class="quantity-icon"></text>
</view>
<view class="quantity-display">
<text class="quantity-text">{{ item.quantity || 1 }}</text>
</view>
<view
class="quantity-btn plus"
@click.stop="updateQuantity(item, 1)"
>
<text class="quantity-icon">+</text>
</view>
</view>
<view class="toBuy" @click.stop="goBuy(item)">购买</view>
</view>
<!-- 禁售状态 -->
<view class="sold-out-section" v-if="item.isSale === 1">
<view class="sold-out-btn">暂时缺货</view>
</view>
</view>
</view>
<view class="list-bottom">
<text class="bottom-text"> 已显示全部商品 </text>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import * as api from '@/config/login.js'
import { setToken } from '@/config/auth.js'
import { formatCurrency } from '@/util/index.js'
export default {
data() {
return {
pkParent: '',
goodList: [],
placeParent: '',
activeTab: 43, // 默认选中北大甄选
tabs: [
{
label: '北大甄选',
value: 43,
},
{
label: '精品专区',
value: 41,
},
],
}
},
onLoad(options) {
this.pkParent = options.pkParent
this.getToken()
},
methods: {
formatCurrency,
getToken() {
api
.autoLogin({
pkParent: this.pkParent,
})
.then(res => {
setToken(res.data.access_token, res.data.expires_in)
uni.setStorageSync('regiest-login', '1')
this.getList()
this.getCode()
})
},
getCode() {
api.fansConvertCode(this.pkParent).then(res => {
this.placeParent = res.data
uni.setStorageSync('placeParent', this.placeParent)
})
},
getList() {
api
.queryWares({
shareMemberCode: this.pkParent,
specialArea: this.activeTab,
})
.then(res => {
// 为每个商品初始化quantity字段
this.goodList = res.data.map(item => ({
...item,
quantity: item.quantity || 1,
}))
})
},
switchTab(value) {
if (this.activeTab !== value) {
this.activeTab = value
this.goodList = [] // 清空当前列表
this.getList() // 重新获取数据
}
},
updateQuantity(item, change) {
const newQuantity = (item.quantity || 1) + change
if (newQuantity >= 1) {
// 使用Vue.set或直接赋值来确保响应式更新
this.$set(item, 'quantity', newQuantity)
}
},
goBuy(item) {
const params = {
...item,
pkParent: this.pkParent,
specialArea: this.activeTab,
}
uni.navigateTo({
url: '/pages/shareArea/hiOrder?allData=' + JSON.stringify(item),
})
},
},
}
</script>
<style lang="scss" scoped>
.contain {
background: #f8fafc;
min-height: 100vh;
display: flex;
flex-direction: column;
}
// Tab选项卡样式 - 简约大气设计
.tab-container {
// background: #ffffff;
padding: 0;
position: relative;
z-index: 4;
// 顶部装饰线
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3rpx;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
}
.tab-wrapper {
display: flex;
position: relative;
// background: #ffffff;
// padding: 32rpx 24rpx 24rpx;
.tab-item {
flex: 1;
position: relative;
cursor: pointer;
padding: 24rpx 32rpx;
text-align: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
.tab-text {
font-size: 32rpx;
font-weight: 500;
color: #64748b;
transition: all 0.3s ease;
position: relative;
z-index: 2;
}
.tab-line {
display: none;
}
// 悬停效果
&:hover:not(.tab-active) {
.tab-text {
color: #475569;
transform: translateY(-1rpx);
}
}
&.tab-active {
background: rgba(102, 126, 234, 0.08);
.tab-text {
color: #667eea;
font-weight: 600;
}
// 选中指示器 - 底部完整宽度线条
&::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3rpx;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
}
}
&:active {
transform: scale(0.98);
}
}
}
}
// 商品容器区域
.goods-container {
// flex: 1;
background: #f8fafc;
padding: 24rpx 24rpx 0;
position: relative;
z-index: 3;
.section-title {
text-align: center;
margin-bottom: 24rpx;
padding: 20rpx 0;
.title-text {
display: block;
color: #1e293b;
font-size: 32rpx;
font-weight: 600;
margin-bottom: 8rpx;
}
.title-desc {
display: block;
color: #64748b;
font-size: 24rpx;
}
}
}
// 商品列表滚动区域
.goodList {
// height: calc(100vh - 400rpx);
padding: 0 8rpx;
.goodList_i {
display: flex;
background: #ffffff;
border-radius: 24rpx;
margin-bottom: 24rpx;
padding: 32rpx;
box-shadow: 0 4rpx 20rpx rgba(102, 126, 234, 0.08);
border: 1rpx solid rgba(102, 126, 234, 0.08);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
animation: slideInUp 0.6s ease-out both;
opacity: 0;
&:hover {
transform: translateY(-6rpx);
box-shadow: 0 16rpx 40rpx rgba(102, 126, 234, 0.2);
border-color: rgba(102, 126, 234, 0.15);
}
.cover {
width: 240rpx;
height: 240rpx;
background: #f8fafc;
border: 1rpx solid #e2e8f0;
border-radius: 16rpx;
flex-shrink: 0;
overflow: hidden;
}
.goodList_ir {
margin-left: 24rpx;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.tit1 {
color: #1e293b;
font-size: 32rpx;
font-weight: 600;
line-height: 1.4;
margin-bottom: 16rpx;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.sales {
color: #64748b;
font-size: 24rpx;
font-weight: 400;
margin-bottom: 16rpx;
}
.goodList_ib {
margin-bottom: 24rpx;
.price-container {
display: flex;
align-items: baseline;
justify-content: space-between;
.currency {
color: #ff6b35;
font-size: 24rpx;
font-weight: 600;
margin-right: 4rpx;
}
.price {
color: #ff6b35;
font-size: 36rpx;
font-weight: 700;
}
.sale-status {
color: #ef4444;
font-size: 24rpx;
font-weight: 500;
background: rgba(239, 68, 68, 0.1);
padding: 4rpx 12rpx;
border-radius: 12rpx;
border: 1rpx solid rgba(239, 68, 68, 0.2);
}
}
img {
width: 56rpx;
height: 56rpx;
}
}
// 数量控制区域
.quantity-section {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16rpx;
.quantity-control {
display: flex;
align-items: center;
background: #f8fafc;
border-radius: 20rpx;
border: 1rpx solid #e2e8f0;
overflow: hidden;
.quantity-btn {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
transition: all 0.2s ease;
cursor: pointer;
.quantity-icon {
font-size: 32rpx;
font-weight: 600;
color: #667eea;
}
&.minus {
&.disabled {
opacity: 0.3;
cursor: not-allowed;
.quantity-icon {
color: #9ca3af;
}
}
}
&:not(.disabled):active {
background: #f1f5f9;
transform: scale(0.95);
}
}
.quantity-display {
min-width: 80rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ffffff;
border-left: 1rpx solid #e2e8f0;
border-right: 1rpx solid #e2e8f0;
.quantity-text {
font-size: 28rpx;
font-weight: 600;
color: #1f2937;
}
}
}
}
// 禁售状态区域
.sold-out-section {
display: flex;
justify-content: flex-end;
.sold-out-btn {
background: #f3f4f6;
color: #9ca3af;
padding: 16rpx 32rpx;
text-align: center;
border-radius: 12rpx;
font-size: 24rpx;
font-weight: 500;
border: 1rpx solid #e5e7eb;
cursor: not-allowed;
}
}
.toBuy {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
padding: 16rpx 24rpx;
text-align: center;
border-radius: 12rpx;
font-size: 24rpx;
font-weight: 600;
border: none;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
box-shadow: 0 2rpx 8rpx rgba(102, 126, 234, 0.2);
flex-shrink: 0;
min-width: 120rpx;
&::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.2),
transparent
);
transition: left 0.5s;
}
&:hover {
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
transform: translateY(-1rpx);
box-shadow: 0 4rpx 12rpx rgba(102, 126, 234, 0.3);
&::before {
left: 100%;
}
}
&:active {
transform: scale(0.95) translateY(0);
}
}
}
}
.list-bottom {
text-align: center;
padding: 40rpx 0 60rpx;
.bottom-text {
color: #64748b;
font-size: 24rpx;
}
}
}
// 动画定义
@keyframes slideIn {
from {
transform: scaleX(0);
opacity: 0;
}
to {
transform: scaleX(1);
opacity: 1;
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-50rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(40rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes pulse {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.02);
}
}
@keyframes promoBreathe {
0%,
100% {
transform: scale(1);
box-shadow: 0 8rpx 24rpx rgba(255, 107, 53, 0.4);
}
50% {
transform: scale(1.05);
box-shadow: 0 12rpx 32rpx rgba(255, 107, 53, 0.6);
}
}
@keyframes shimmer {
0% {
left: -100%;
}
50% {
left: -100%;
}
100% {
left: 100%;
}
}
// 商品卡片延迟动画
.goodList_i:nth-child(1) {
animation-delay: 0.1s;
}
.goodList_i:nth-child(2) {
animation-delay: 0.2s;
}
.goodList_i:nth-child(3) {
animation-delay: 0.3s;
}
.goodList_i:nth-child(4) {
animation-delay: 0.4s;
}
.goodList_i:nth-child(5) {
animation-delay: 0.5s;
}
.goodList_i:nth-child(n + 6) {
animation-delay: 0.6s;
}
</style>