web-base-h5/pages/specialArea/list.vue

1119 lines
27 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.

<!--
* @Descripttion:
* @version:
* @Author: kBank
* @Date: 2022-11-21 15:11:22
-->
<template>
<view class="content">
<backIcon :diff="diff"></backIcon>
<view class="index_header">
<view>{{ titLabel }}</view>
</view>
<view class="shareImg" v-if="specialArea == 7" @click="goShare">
<u-icon name="share-square" size="24" color="#005BAC"> </u-icon>
</view>
<u-scroll-list
:indicator="false"
v-if="itemChildren.length > 1"
class="tabList_a"
>
<view class="tab">
<view
v-for="(item, index) in itemChildren"
:key="index"
@click="setSpecial(item)"
v-show="item.isShow"
:class="[specialArea == item.value ? 'actTab' : 'tab_i']"
>
<view>{{ item.label }}</view>
</view>
</view>
</u-scroll-list>
<view class="index_btm">
<!-- sangelxiu1 会员专区 隐藏分类-->
<view class="index_l" v-if="!newShareMember">
<view
v-for="item in oneList"
:class="['classIfy', oneId == item.pkId ? 'actOne' : '']"
@click="
((oneId = item.pkId),
getAllGoods(item.pkId),
getClassIfyTwo(item.pkId))
"
:key="item.pkId"
>{{ item.classifyName }}</view
>
</view>
<view :class="newShareMember ? 'index_r_2': 'index_r'">
<u-scroll-list :indicator="false" class="tabList">
<view class="tab">
<view
v-for="(item, index) in twoList"
:key="index"
@click="((twoId = item.pkId), getAllGoods1(item.pkId))"
:class="[twoId == item.pkId ? 'actTab' : 'tab_i']"
>
<view>{{ item.classifyName }}</view>
<!-- <view :class="[twoId == item.pkId ? 'heng' : 'heng1']"></view> -->
</view>
</view>
</u-scroll-list>
<view class="search">
<u--input
placeholder="请输入商品名称"
placeholderStyle="font-size:14px;"
prefixIcon="search"
shape="circle"
v-model="waresName"
border="none"
@confirm="getAllGoods1()"
prefixIconStyle="font-size: 22px;color: #909399"
></u--input>
</view>
<view class="goodList">
<view
v-for="item in goodList"
:key="item.waresCode"
class="goodList_i"
@tap="goDetails(item)"
>
<view style="display: flex; flex: 1">
<view
class="fly"
v-show="
item.preSaleStatus == 3 ||
item.isSale == 1 ||
(item.specialArea === 14 && !Number(item.inventory))
"
></view>
<view class="image-container">
<img :src="item.cover || item.cover1" class="cover" alt="" />
<!-- 三角形角标 -->
<view class="triangle-badge" v-if="item.warnMessage">
<view
class="triangle-badge-text"
:class="{
'text-2': item.warnMessage.length === 2,
'text-3': item.warnMessage.length === 3,
'text-4': item.warnMessage.length === 4,
}"
>
{{ item.warnMessage }}
</view>
</view>
</view>
<view class="goodList_ir">
<view>
<view>
<span
class="qzbq"
v-if="item.prefixLabelTarget != undefined"
>{{ item.prefixLabelTarget.label }}</span
>
<span style="font-weight: 500">{{ item.waresName }}</span>
</view>
</view>
<view>
<view
class="inventory-progress-container"
v-if="
item.useRatio &&
item.inventory !== undefined &&
item.specialArea == 14
"
>
<view class="inventory-progress-bar">
<view
class="inventory-progress-fill"
:style="{
width: getInventoryPercentage(item.inventory) + '%',
}"
:class="getProgressClass(item.inventory)"
>
<!-- 添加流动光效 -->
<view
class="progress-shine"
v-if="getInventoryPercentage(item.inventory) <= 30"
></view>
</view>
</view>
<view
class="inventory-percentage"
:class="getPercentageClass(item.inventory)"
>
剩余{{ getInventoryPercentage(item.inventory) }}%
</view>
</view>
<view class="goodList_ib">
<view>
<view
class="pv"
v-if="
specialArea != 18 &&
specialArea != 13 &&
specialArea != 31 &&
specialArea != 10
"
>
业绩:{{ item.waresAchieve | numberToCurrency }}
</view>
<view class="pv" v-if="specialArea == 10">
积分可抵扣:{{ item.deductMoney | numberToCurrency }}
</view>
<view
class="pv"
v-if="specialArea == 31 && userInfo.isMakerSpace == 0"
>
业绩:{{ item.waresAchieve | numberToCurrency }}
</view>
<view class="pv" v-if="specialArea == 13">
BV:{{ item.assAchieve | numberToCurrency }}
</view>
<view
v-if="specialArea == 31 && userInfo.isMakerSpace == 1"
>
{{ item.vipPrice | numberToCurrency }}
</view>
<view
v-if="
(specialArea == 31 && userInfo.isMakerSpace == 0) ||
specialArea != 31
"
>
{{ item.waresPrice | numberToCurrency }}
</view>
</view>
<template v-if="item.specialArea !== 14">
<img
@click.stop="addCar(item)"
v-show="
item.preSaleStatus != 3 &&
item.isSale != 1 &&
specialArea != 31
"
src="@/static/images/cart.png"
alt=""
/>
</template>
<template v-else>
<img
@click.stop="addCar(item)"
v-show="
item.preSaleStatus != 3 &&
item.isSale != 1 &&
Number(item.inventory)
"
src="@/static/images/cart.png"
alt=""
/>
</template>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<u-picker
:show="isCountry"
@cancel="isCountry = false"
@confirm="sureCountry"
:columns="countryList"
keyName="label"
></u-picker>
<selSpaceGoods ref="selSpaceGoods" @getCar="getCatLength"></selSpaceGoods>
<cartBall
ref="cart"
:carLength="shopCarLength"
:specialArea="specialArea"
></cartBall>
</view>
</template>
<script>
import backIcon from '@/components/backIcon.vue'
import cartBall from '@/components/cartBall.vue'
import { mapGetters, mapActions } from 'vuex'
import * as api from '@/config/goods'
import clTabbar from '@/components/cl-tabbar.vue'
import selSpaceGoods from '@/components/selSpaceGoods.vue'
export default {
components: {
'cl-tabbar': clTabbar,
backIcon,
cartBall,
selSpaceGoods,
},
computed: {},
filters: {
seles(value) {
if (value > 999) {
return 999 + '+'
} else {
return value
}
},
},
data() {
return {
newShareMember: false,
specialArea: 1,
oneList: [],
oneId: '',
twoList: [],
twoId: '',
goodList: [],
titLabel: '',
itemChildren: [],
diff: 0,
shopCarLength: false,
userInfo: {},
pkCountry: 1,
pkCountryLabel: '',
pkCountryImg: '',
countryList: [],
isCountry: false,
waresName: '',
}
},
onLoad(options) {
console.log(
'%c [ options ]-25',
'font-size:13px; background:#cb38d2; color:#ff7cff;',
options
)
if (JSON.parse(options.children).length > 0) {
let arr = []
if (options.childArea) {
this.specialArea = options.childArea
// this.diff = 1
} else {
JSON.parse(options.children).forEach(item => {
if (item.isShow) {
arr.push(item.value)
}
})
this.specialArea = arr[0]
// this.diff = 0
}
if (options.diff) {
this.diff = options.diff
}
} else {
this.specialArea = options.specialArea
}
this.titLabel = options.label
let tempArr = JSON.parse(options.children)
if (this.specialArea != 18) {
api.menuList().then(res => {
tempArr = tempArr.filter(item =>
res.data.find(ctem => ctem.menuKey == item.name)
)
this.itemChildren = tempArr
})
}
// 修改标题
uni.setNavigationBarTitle({
title: this.titLabel,
success: () => {},
})
// 获取一级分类并获取商品列表
// this.getClassIfy()
this.userInfo = uni.getStorageSync('User')
console.log(
'%c [ this.userInfo ]-242',
'font-size:13px; background:#cb38d2; color:#ff7cff;',
this.userInfo
)
if (this.specialArea == 1) {
if (uni.getStorageSync('pkCountry')) {
this.pkCountry = uni.getStorageSync('pkCountry')
} else {
this.pkCountry = this.userInfo.pkSettleCountry
uni.setStorageSync('pkCountry', this.pkCountry + '')
}
} else {
this.pkCountry = this.userInfo.pkSettleCountry
}
this.setSpecial({
value: this.specialArea,
})
},
onShow() {
this.newShareMember = uni.getStorageSync('User')?.loginType !== 0
let that = this
uni.$on('returnData', function (data) {
that.specialArea = data.value
that.setSpecial({
value: data.value,
})
})
// 获取国家
this.getJScountry()
this.$nextTick(() => {
this.$refs.cart.getCar()
})
},
onHide() {
this.$refs.cart.close()
this.setSmallCarLength(0)
},
beforeDestroy() {
console.log('beforeDestroy........?')
this.setSmallCarLength(0)
},
methods: {
...mapActions(['setSmallCarLength', 'setShopCarLength']),
changeCountry() {
this.isCountry = true
},
sureCountry(e) {
const { value } = e
this.pkCountry = value[0].id
this.pkCountryLabel = value[0].label
this.pkCountryImg = value[0].img
this.isCountry = false
uni.setStorageSync('pkCountry', this.pkCountry + '')
// 获取分类一级
this.getClassIfy()
this.$refs.cart.getCar()
},
getJScountry() {
api.currencyList().then(res => {
let data = res.data.map(item => {
return {
img: item.nationalFlag2,
id: item.pkId,
label: item.shortName,
}
})
this.countryList = [data]
this.countryList[0].forEach(item => {
if (item.id == this.pkCountry) {
this.pkCountryLabel = item.label
this.pkCountryImg = item.img
}
})
})
},
goShare() {
uni.navigateTo({
url: '/pages/specialArea/share?specialArea=7',
})
},
setSpecial(item) {
if (item.value == 21) {
// uni.navigateTo({
// url:
// '/pages/specialArea/haIndex?label=' +
// this.titLabel +
// '&specialArea=21&children=' +
// JSON.stringify(this.itemChildren),
// })
} else {
this.specialArea = item.value
this.getClassIfy()
}
},
addCar(item) {
let carList = {
pkCountry: this.pkCountry,
specialArea: item.specialArea,
number: 1,
waresCode: item.waresCode,
productGroup: item.productGroup,
}
if (
item.isMakerGift == 2 &&
(item.specialArea == 1 || item.specialArea == 3)
) {
this.$refs.selSpaceGoods.getData(carList)
} else {
api.addShopping(carList).then(res => {
if (res.code == 200) {
uni.showToast({
title: '购物车添加成功',
icon: 'success',
mask: true,
duration: 500,
})
setTimeout(() => {
this.$store
.dispatch('getCarLength', this.specialArea)
.then(res => {
this.shopCarLength = res.data.smallCount
})
}, 200)
}
})
}
},
getCatLength() {
this.$store.dispatch('getCarLength', this.specialArea).then(res => {
this.shopCarLength = res.data.smallCount
})
},
getClassIfy() {
api
.classifyList({
pkCountry: this.pkCountry,
specialArea: this.specialArea,
hierarchy: 0,
})
.then(res => {
// res.data.unshift({
// classifyName: '全部',
// pkId: '',
// })
this.oneList = res.data
this.oneId = this.oneList[0] ? this.oneList[0].pkId : ''
this.getClassIfyTwo(this.oneList[0].pkId)
this.getAllGoods(this.oneList[0].pkId)
})
},
// 获取分类二级
getClassIfyTwo(pkId) {
api
.classifyList({
specialArea: this.specialArea,
pkParent: pkId,
hierarchy: 1,
pkCountry: this.pkCountry,
})
.then(res => {
res.data.unshift({
classifyName: '全部',
pkId: pkId,
})
this.twoList = res.data
this.twoList = this.twoList.filter(item => 'classifyName' in item)
this.twoId = pkId
})
},
getAllGoods(id) {
api
.getAllGoods({
pkCountry: this.pkCountry,
specialArea: Number(this.specialArea),
pkAreaClassify: id ? id : '',
})
.then(res => {
this.goodList = res.data
this.goodList.forEach(item => {
if (item.waresName.length > 11) {
item.waresName = item.waresName.substring(0, 11) + '...'
}
})
})
},
getAllGoods1(id) {
api
.getAllGoods({
pkCountry: this.pkCountry,
specialArea: this.specialArea,
waresName: this.waresName,
pkAreaClassify: id ? id : this.oneId,
})
.then(res => {
this.goodList = res.data
this.goodList.forEach(item => {
if (item.waresName.length > 11) {
item.waresName = item.waresName.substring(0, 11) + '...'
}
})
})
},
goDetails(item) {
if (item.specialArea === 14 && !Number(item.inventory)) {
return
}
if (item.preSaleStatus != 3 && item.isSale != 1) {
uni.navigateTo({
url:
'/pages/specialArea/details?waresCode=' +
item.waresCode +
'&specialArea=' +
item.specialArea,
})
}
},
// 处理库存百分比,移除百分号并转换为数字
getInventoryPercentage(inventory) {
if (typeof inventory === 'string') {
// 移除百分号并转换为数字
const numStr = inventory.replace('%', '').trim()
const num = parseFloat(numStr)
return isNaN(num) ? 0 : Math.min(100, Math.max(0, num))
} else if (typeof inventory === 'number') {
// 如果是数字确保在0-100范围内
return Math.min(100, Math.max(0, inventory))
}
return 0
},
// 根据库存百分比返回对应的进度条样式类
getProgressClass(inventory) {
const percentage = this.getInventoryPercentage(inventory)
if (percentage >= 80) {
return 'progress-high'
} else if (percentage >= 60) {
return 'progress-medium-high'
} else if (percentage >= 40) {
return 'progress-medium'
} else if (percentage >= 20) {
return 'progress-low'
} else {
return 'progress-critical'
}
},
// 根据库存百分比返回百分比数字的样式类
getPercentageClass(inventory) {
const percentage = this.getInventoryPercentage(inventory)
if (percentage <= 20) {
return 'percentage-critical'
} else if (percentage <= 30) {
return 'percentage-urgent'
} else {
return 'percentage-normal'
}
},
},
}
</script>
<style lang="scss" scoped>
.index_header {
background: #fff;
font-size: 18px;
font-family:
PingFang SC-Semibold,
PingFang SC;
font-weight: 600;
color: #333333;
text-align: center;
padding: 10px 0;
}
.content {
background: #f9f9f9;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.tabList_a {
/* 二级分类标签容器样式 */
margin-bottom: 10rpx;
}
.index_btm {
flex: 1; // display: flex;
.index_l {
width: 198rpx;
padding: 10rpx 0;
font-size: 11px;
font-family:
PingFang SC-Regular,
PingFang SC;
font-weight: 400;
color: #000000;
overflow-y: auto;
display: flex;
flex-direction: column;
position: absolute;
height: 86vh;
background: #f2f2f2;
}
.index_r {
// flex: 1;
background: #fff;
margin-left: 198rpx; // padding: 20rpx;
// display: flex;
}
.index_r_2 {
// flex: 1;
background: #fff;
margin-left: 20rpx; // padding: 20rpx;
// display: flex;
}
}
.classIfy {
padding: 20rpx 20rpx;
margin: 20rpx 0;
font-size: 26rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #666666;
}
.actOne {
// border-left: 6rpx solid #005BAC;
color: #fff;
background: #005bac;
}
.tab {
display: flex;
align-items: center;
padding: 0 24rpx;
margin-top: 20rpx;
}
.tab_i {
// width: 120rpx;
text-align: center;
font-size: 14px;
font-weight: 600;
color: #999999;
margin-right: 28rpx;
white-space: nowrap;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f6f6f6;
color: #666;
border-radius: 200rpx;
padding: 0 20rpx;
display: flex;
justify-content: center;
align-items: center;
line-height: 1;
height: 58rpx;
box-sizing: border-box;
}
.actTab {
// width: 120rpx;
text-align: center;
font-size: 14px;
font-family:
PingFang SC-Semibold,
PingFang SC;
font-weight: 600;
// color: #005BAC;
background-color: #005bac;
color: #fff;
margin-right: 28rpx;
white-space: nowrap;
display: flex;
flex-direction: column;
align-items: center;
border-radius: 200rpx;
padding: 0 20rpx;
display: flex;
justify-content: center;
align-items: center;
line-height: 1;
height: 58rpx;
box-sizing: border-box;
}
.heng {
width: 24px;
height: 2px;
background: #005bac;
border-radius: 1px 1px 1px 1px;
margin-top: 4rpx;
}
.heng1 {
width: 24px;
height: 2px;
background: f9f9f9;
border-radius: 1px 1px 1px 1px;
margin-top: 4rpx;
}
.heng2 {
width: 24px;
height: 2px;
background: f9f9f9;
border-radius: 1px 1px 1px 1px;
margin-top: 4rpx;
}
::v-deep .u-scroll-list {
padding-bottom: 10rpx;
}
.zhan {
height: 200px;
}
.goodList {
padding: 0 20rpx;
height: calc(100vh - 320rpx);
overflow-y: auto;
.goodList_i {
// display: flex;
border-bottom: 1px solid #eee;
padding: 20rpx 0 10rpx;
position: relative;
.goodList_ir {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
font-size: 30rpx;
font-family: Microsoft YaHei;
font-weight: 400;
color: #333333;
margin-left: 24rpx;
.goodList_ib {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 32rpx;
font-family: Source Han Sans CN;
font-weight: 400;
color: #f82c1a;
img {
width: 60rpx;
height: 60rpx;
}
}
}
.fly {
position: absolute;
width: 100%;
height: 100%;
top: 0;
background: #eee;
opacity: 0.5;
}
}
.cover {
width: 200rpx;
height: 200rpx;
background: #ffffff;
border: 1px solid #eeeeee;
border-radius: 10rpx;
}
}
.pv {
font-size: 26rpx;
font-family: Source Han Sans CN;
font-weight: 400;
color: #999999;
}
.shareImg {
position: fixed;
margin: 14rpx 24rpx;
z-index: 9999;
right: 20rpx;
top: 5rpx;
}
.shareImg1 {
position: fixed;
margin: 14rpx 24rpx;
z-index: 1;
right: 10rpx;
top: 10rpx;
display: flex;
align-items: center;
img {
width: 40rpx;
height: 30rpx;
margin-right: 20rpx;
}
}
.qzbq {
background: #d61820;
border-radius: 2px 2px 2px 2px;
font-size: 10px;
// font-family: PingFang SC-Semibold, PingFang SC;
// font-weight: 600;
color: #ffffff;
padding: 0px 5px;
margin-right: 5px;
}
.search {
margin: 10rpx 20rpx;
padding: 10rpx;
background: #eeeeee;
border-radius: 20px;
font-size: 14px;
}
.image-container {
position: relative;
}
.triangle-badge {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
border-top: 100rpx solid #005bac;
border-right: 100rpx solid transparent;
border-radius: 10rpx 0 0 0;
z-index: 10;
}
.triangle-badge-text {
position: absolute;
color: #ffffff;
font-weight: 600;
line-height: 1;
transform: rotate(-45deg);
transform-origin: center;
white-space: nowrap;
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.2);
}
/* 2个字样式 */
.triangle-badge-text.text-2 {
top: -76rpx;
left: 10rpx;
font-size: 24rpx;
}
/* 3个字样式 */
.triangle-badge-text.text-3 {
top: -70rpx;
left: -2rpx;
font-size: 24rpx;
}
/* 4个字样式 */
.triangle-badge-text.text-4 {
top: -72rpx;
left: -4rpx;
font-size: 20rpx;
}
/* 库存进度条样式 - 升级版 */
.inventory-progress-container {
// margin-bottom: 10rpx;
display: flex;
align-items: center;
width: 100%;
.inventory-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-right: 10rpx;
// margin-bottom: 12rpx;
.inventory-label {
display: flex;
align-items: center;
font-size: 24rpx;
.fire-icon,
.warning-icon {
font-size: 28rpx;
margin-right: 8rpx;
animation: iconBounce 1.5s ease-in-out infinite;
}
.inventory-status {
color: #333;
}
}
}
.inventory-percentage {
font-size: 24rpx;
font-weight: 700;
font-family:
DIN Alternate,
Arial,
sans-serif;
&.percentage-critical {
color: #ff3742;
animation: percentageBlink 1s ease-in-out infinite;
text-shadow: 0 0 10rpx rgba(255, 55, 66, 0.3);
}
&.percentage-urgent {
color: #ff5252;
animation: percentageGlow 2s ease-in-out infinite;
}
&.percentage-normal {
color: #005bac;
}
}
.inventory-progress-bar {
width: 0;
flex: 1;
height: 18rpx;
margin-right: 10rpx;
background: rgba(0, 0, 0, 0.08);
border-radius: 12rpx;
overflow: hidden;
position: relative;
box-shadow: inset 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
.inventory-progress-fill {
height: 100%;
border-radius: 8rpx;
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
/* 进度条渐变色彩 */
&.progress-critical {
background: linear-gradient(
90deg,
#ff1744 0%,
#d50000 50%,
#ff1744 100%
);
box-shadow: 0 0 20rpx rgba(255, 23, 68, 0.4);
animation: criticalPulse 1.5s ease-in-out infinite;
}
&.progress-low {
background: linear-gradient(
90deg,
#ff5722 0%,
#e64a19 50%,
#ff5722 100%
);
box-shadow: 0 0 15rpx rgba(255, 87, 34, 0.3);
}
&.progress-medium {
background: linear-gradient(
90deg,
#ff9800 0%,
#f57c00 50%,
#ff9800 100%
);
box-shadow: 0 0 10rpx rgba(255, 152, 0, 0.2);
}
&.progress-medium-high {
background: linear-gradient(
90deg,
#2196f3 0%,
#1976d2 50%,
#2196f3 100%
);
box-shadow: 0 0 8rpx rgba(33, 150, 243, 0.2);
}
&.progress-high {
background: linear-gradient(
90deg,
#4caf50 0%,
#388e3c 25%,
#005bac 75%,
#003d82 100%
);
box-shadow: 0 0 8rpx rgba(0, 91, 172, 0.2);
}
/* 流动光效 */
.progress-shine {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.8) 50%,
transparent 100%
);
animation: shineFlow 2s ease-in-out infinite;
}
/* 高光效果 */
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 60%;
background: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.4) 0%,
rgba(255, 255, 255, 0.1) 50%,
transparent 100%
);
border-radius: 8rpx 8rpx 0 0;
}
}
}
}
/* 动画定义 */
@keyframes iconBounce {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.2);
}
}
@keyframes percentageBlink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.7;
}
}
@keyframes percentageGlow {
0%,
100% {
text-shadow: 0 0 5rpx rgba(255, 82, 82, 0.3);
}
50% {
text-shadow: 0 0 15rpx rgba(255, 82, 82, 0.6);
}
}
@keyframes criticalPulse {
0%,
100% {
box-shadow: 0 0 20rpx rgba(255, 23, 68, 0.4);
}
50% {
box-shadow: 0 0 30rpx rgba(255, 23, 68, 0.7);
}
}
@keyframes shineFlow {
0% {
left: -100%;
}
100% {
left: 100%;
}
}
</style>