Files
MER-2.2_2601/mer_uniapp/components/productWindow/index.vue
2026-03-08 20:07:52 +08:00

633 lines
17 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>
<view class="product-window"
:class="(attr.cartAttr === true ? 'on' : '') + ' ' + (iSbnt?'join':'') + ' ' + (iScart?'joinCart':'')">
<view class="textpic acea-row row-between-wrapper">
<view class="pictrue" @click="showImg()">
<image :src="attr.productSelect.image" class="rd-16rpx"></image>
</view>
<view class="text">
<view class="money">
<!-- 积分商品价格 -->
<PointsPrice v-if="productType===ProductTypeEnum.Integral" :pointsPrice="attr.productSelect"
:pointsGoodsStyle="hotPointsStyle"></PointsPrice>
<!-- 其他商品价格 -->
<svip-price v-else :svipIconStyle="svipIconStyle" :productPrice="productPrice"
:svipPriceStyle="svipPriceStyle" :priceColor="priceColor"></svip-price>
<view class="mt-52">
<text class="stock f-s-24" v-if='isShow'>
库存:{{ attr.productSelect.groupPrice&&attr.productSelect.stock>0?attr.productSelect.groupStock:attr.productSelect.stock }}</text>
<text class='stock f-s-24' v-if="limitNum">限量: {{attr.productSelect.quota}}</text>
</view>
</view>
</view>
<CloseIcon @handle-close="closeAttr"></CloseIcon>
</view>
<view class="rollTop" :class="attrHeight">
<view class="productWinList">
<view class="item" v-for="(item, indexw) in attr.productAttr" :key="indexw">
<view class="flex-between-center">
<view class="title">{{ item.attrName }}</view>
<!-- 如果传规格图片会出现规格样式切换选择-->
<view class="fs-24 text--w111-666 flex-y-center mr-32" v-show="gridShow == 1 && item.isShowImage" @tap="toggleGridAttr(0)">
<text class="iconfont icon-a-ic_Imageandtextsorting fs-28"></text>
<text class="pl-6 line-heightOne">列表</text>
</view>
<view class="fs-24 text--w111-666 flex-y-center mr-32" v-show="gridShow == 0 && item.isShowImage" @tap="toggleGridAttr(1)">
<text class="iconfont icon-a-ic_Picturearrangement fs-28"></text>
<text class="pl-6 line-heightOne">宫格</text>
</view>
</view>
<!-- 大图样式 isShowImage规格图是否展示-->
<view class="pl-32 mt-32" v-show="gridShow == 1 && item.isShowImage">
<scroll-view scroll-x="true" class="white-nowrap vertical-middle w-686"
show-scrollbar="false">
<view class="flex">
<view class="inline-block mr-12"
v-for="(itemn, indexn) in item.optionList"
:key="indexn"
@click="tapAttr(indexw, indexn)">
<view class="grid-item-box" :class="item.index === itemn.optionName ? 'grid-active' : ''">
<view class="w-full h-192 relative">
<image class="w-full h-192 block" :src="itemn.image" mode="aspectFill"></image>
<view class="proview-icon flex-center" @tap.stop="proviewImg(itemn.image)">
<text class="iconfont icon-ic_enlarge fs-24 text--w111-fff"></text>
</view>
</view>
<view class="flex-1 bg--w111-f5f5f5 tname text-center flex-center fs-24">{{itemn.optionName}}</view>
</view>
</view>
</view>
</scroll-view>
</view>
<!-- 小图样式 -->
<view v-show="(gridShow == 0 && item.isShowImage) || !item.isShowImage" class="listn acea-row row-middle">
<view class="itemn flex"
:class="item.index === itemn.optionName?'on':''"
v-for="(itemn, indexn) in item.optionList" @click="tapAttr(indexw, indexn,item)"
:key="indexn">
<image v-if="itemn.image && item.isShowImage" class="attr-img" :src="itemn.image" alt="" srcset="" />
<text class="option-name">{{ itemn.optionName }}</text>
</view>
</view>
</view>
</view>
<view class="cart acea-row row-between-wrapper">
<view class="title">数量</view>
<view class="limit-buy"
v-if="marketingType === ProductMarketingTypeEnum.Groupbuying&&!isProductType&&buyLimitNum>0">
{{`最多可购买(${buyLimitNum})`}}
</view>
<view class="carnum acea-row row-left">
<view v-if="!isProductType" class="item reduce text-center"
:class="attr.productSelect.cart_num <= 1 ? 'on' : ''" @click="CartNumDes">
-
</view>
<view class='item num text-center'>
<input type="number" pattern="[0-9]*" :always-embed="true" :adjust-position="true" cursor-spacing="50"
:disabled="isProductType" v-model="attr.productSelect.cart_num"
data-name="productSelect.cart_num" min="1" @input="bindCode" maxlength="3"></input>
</view>
<!-- 除拼团+++ -->
<view v-if="iSplus && !isProductType&&marketingType !== ProductMarketingTypeEnum.Groupbuying"
class="item plus text-center" :class="attr.productSelect.cart_num >= attr.productSelect.stock? 'on': ''"
@click="CartNumAdd(1)">
+
</view>
<!-- 拼团商品+++ -->
<view v-if="iSplus&&!isProductType&&marketingType === ProductMarketingTypeEnum.Groupbuying"
class="item plus" :class="attr.productSelect.cart_num >= buyLimitNum? 'on': ''"
@click="CartNumAdd(2)">
+
</view>
<!-- <view v-if="!iSplus && !isProductType" class='item plus'
:class='(attr.productSelect.cart_num >= attr.productSelect.quota) || (attr.productSelect.cart_num >= attr.productSelect.stock) || (attr.productSelect.cart_num >= attr.productSelect.num)? "on":""'
@click='CartNumAdd'>+</view> -->
</view>
</view>
</view>
<view class="joinBnt bg-color" v-if="iSbnt && attr.productSelect.stock>0 &&attr.productSelect.quota>0"
@click="goCat">我要参团</view>
<view class="joinBnt on"
v-else-if="(iSbnt && attr.productSelect.quota<=0)||(iSbnt &&attr.productSelect.stock<=0)">已售罄</view>
<view class="joinBnt bg-color" v-if="iScart && attr.productSelect.stock" @click="goCat">确定</view>
<!-- <view class="joinBnt bg-color" v-if="iSbnt && attr.productSelect.stock && attr.productSelect.quota" @click="goCat">确定</view> -->
<view class="joinBnt on" v-else-if="(iScart && !attr.productSelect.stock)">已售罄</view>
</view>
<view class="mask" @touchmove.prevent :hidden="attr.cartAttr === false" @click="closeAttr"></view>
</view>
</template>
<script>
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
import svipPrice from '@/components/svipPrice.vue';
import PointsPrice from '@/components/PointsPrice.vue';
import {
ProductTypeEnum,
ProductMarketingTypeEnum
} from "@/enums/productEnums";
import productAttr from '@/mixins/productAttr.js';
/**
* 积分商品推荐样式
*/
export const hotPointsStyle = {
iconStyle: {
width: '32rpx',
height: '32rpx'
},
priceStyle: {
fontSize: '32rpx',
},
unitStyle: {
fontSize: '28rpx',
},
}
export default {
mixins: [productAttr],
components: {
svipPrice,
PointsPrice
},
props: {
attr: {
type: Object,
default: () => {}
},
limitNum: {
type: Number,
value: 0
},
isShow: {
type: Number,
value: 0
},
iSbnt: {
type: Number,
value: 0
},
iSplus: {
type: Number,
value: 0
},
iScart: {
type: Number,
value: 0
},
// 商品类型 0=普通商品,1-积分商品,2-虚拟商品,4=视频号,5-云盘商品,6-卡密商品
productType: {
type: Number,
value: 0
},
//0=基础商品,1=秒杀,2=拼团
marketingType: {
type: Number,
value: 0
},
groupBuyActivityResponse: {
default: () => {}
},
// 是否是拼团、秒杀、积分商品,用红色不用主题色
isMarketingGoods: {
type: Boolean,
default: () => false
},
productPrice: {
type: Object,
default: () => {}
}
},
data() {
return {
gridShow: 1, //宫格还是列样式选择
ProductTypeEnum: ProductTypeEnum,
ProductMarketingTypeEnum: ProductMarketingTypeEnum,
hotPointsStyle: hotPointsStyle, //积分金额样式
//普通价格
svipPriceStyle: {
svipBox: {
height: '34rpx',
borderRadius: '60rpx 56rpx 56rpx 20rpx',
},
icon: {
fontSize: '23rpx',
height: '34rpx',
borderRadius: '16rpx 0 16rpx 2rpx'
},
price: {
fontSize: '44rpx'
},
svipPrice: {
fontSize: '27rpx'
}
},
//svip价格
svipIconStyle: {
svipBox: {
height: '34rpx',
borderRadius: '36rpx 40rpx 40rpx 0.4rpx',
},
price: {
fontSize: '44rpx'
},
svipPrice: {
fontSize: '22rpx'
}
},
urlDomain: this.$Cache.get("imgHost"),
checkedAttr: '', //选择的规格
};
},
mounted() {},
computed: {
attrHeight() {
const { productAttr } = this.attr;
if (!productAttr.length) return '';
// 检查是否有图片规格
const hasImage = productAttr.some(item => item.isShowImage);
if (!hasImage) return '';
// 根据规格数量和选项数量决定高度
const isMultiSpec = productAttr.length > 1;
const optionCount = productAttr[0].optionList.length || 0;
return (isMultiSpec || optionCount > 7) ? 'fixed-height64' : 'fixed-height45';
},
//是否是虚拟商品,云盘5
isProductType() {
return this.productType === 5;
},
//价格颜色
priceColor() {
return {
'color': this.isMarketingGoods ? '#e93323' : '',
}
},
buyLimitNum() {
if(!this.groupBuyActivityResponse) return;
let buyLimitCount = this.groupBuyActivityResponse.buyLimitCount
let groupStock = this.attr.productSelect.groupStock
let stock = this.attr.productSelect.stock
let oncQuota = this.groupBuyActivityResponse.oncQuota
let allQuota = this.groupBuyActivityResponse.allQuota
// 极端情况判断
if (oncQuota == 0 && allQuota != 0) {
oncQuota = allQuota
}
if (oncQuota == 0 && allQuota == 0) {
oncQuota = groupStock
allQuota = groupStock
}
if (buyLimitCount == -1) {
buyLimitCount = groupStock
}
let min = Math.min(buyLimitCount, groupStock, oncQuota, stock)
this.$emit('buyLimit', min);
return min
}
},
methods: {
// 点击贵供图查看图片
proviewImg(img){
uni.previewImage({
current: 0,
urls: [img]
});
},
//选择规格值样式
toggleGridAttr(type){
this.gridShow = type;
},
goCat: function() {
this.$emit('goCat');
},
/**
* 购物车手动输入数量
*
*/
bindCode: function(e) {
this.$emit('iptCartNum', this.attr.productSelect.cart_num);
},
closeAttr: function() {
this.$emit('myevent');
},
CartNumDes: function() {
this.$emit('ChangeCartNum', false);
},
CartNumAdd: function(type) {
this.$emit('ChangeCartNum', true, this.buyLimitNum, type);
},
tapAttr(indexw, indexn, item) {
this.$emit("attrVal", {
indexw: indexw,
indexn: indexn
});
this.$set(this.attr.productAttr[indexw], 'index', this.attr.productAttr[indexw].attrValues[indexn]);
let value = this.getCheckedValue().join(",");
this.checkedAttr = value
this.$emit("ChangeAttr", value);
},
showImg() {
this.$emit('getImg');
},
}
}
</script>
<style scoped lang="scss">
.grid-item-box{
width: 196rpx;
border: 2rpx solid #F5F5F5;
border-radius: 8rpx;
overflow: hidden;
image{
border-radius: 8rpx 8rpx 0 0;
}
.tname{
width: 196rpx;
border-radius: 0 0 8rpx 8rpx ;
padding: 4rpx 12rpx;
height: 74rpx;
line-height: 37rpx;
display: -webkit-box; /* 旧版弹性盒子 */
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2; /* 显示两行 */
-webkit-box-orient: vertical; /* 垂直方向排列 */
word-break: break-all; /* 允许单词断行 */
white-space: normal; /* 允许文字折行 */
}
}
.grid-active{
@include coupons_border_color(theme);
.tname{
@include main_color(theme);
@include coupons_light_color(theme);
}
}
.red-active{
border: 1px solid #e93323;
.tname{
color: #e93323;
background-color: #FFF6F6;
}
}
.proview-icon{
position: absolute;
top: 8rpx;
right: 8rpx;
width: 36rpx;
height: 36rpx;
background: rgba(51, 51, 51, 0.15);
border-radius: 50%;
}
.attr-img {
width: 48rpx;
height: 48rpx;
margin-right: 12rpx;
border-radius: 8rpx;
}
.product-window {
position: fixed;
bottom: 0;
width: 100%;
left: 0;
background-color: #fff;
z-index: 77;
border-radius: 40rpx 40rpx 0 0;
padding-bottom: 100rpx;
padding-bottom: calc(env(safe-area-inset-bottom) + 100rpx);
transform: translate3d(0, 100%, 0);
transition: all .2s cubic-bezier(0, 0, .25, 1);
}
.product-window.on {
transform: translate3d(0, 0, 0);
}
.product-window.join {
padding-bottom: 30rpx;
}
.product-window.joinCart {
padding-bottom: 30rpx;
z-index: 999;
}
.product-window .textpic {
padding: 0 130rpx 0 24rpx;
margin-top: 29rpx;
position: relative;
}
.product-window .textpic .pictrue {
width: 150rpx;
height: 150rpx;
}
.product-window .textpic .pictrue image {
width: 100%;
height: 100%;
}
.product-window .textpic .text {
width: 426rpx;
font-size: 28rpx;
color: #333333;
}
.product-window .textpic .text .money {
font-size: 28rpx;
color: #e93323;
}
.product-window .textpic .text .money .num {
font-family: PingFang SC;
font-size: 36rpx;
font-weight: 600;
}
.product-window .textpic .text .money .stock {
color: #999;
}
.product-window .rollTop {
min-height: 200rpx;
max-height: 64vh;
overflow: auto;
margin-top: 36rpx;
}
.fixed-height64 {
height: 64vh;
}
.fixed-height45 {
height: 45vh;
}
.product-window .productWinList .item~.item {
margin-top: 36rpx;
}
.product-window .productWinList .item .title {
width: 620rpx;
font-size: 28rpx;
color: #999;
padding: 0 32rpx;
}
.product-window .productWinList .item .listn {
padding: 0 32rpx 0 18rpx;
}
.product-window .productWinList .item .listn .itemn {
border: 1px solid #F2F2F2;
font-size: 26rpx;
color: #282828;
display: flex;
align-items: center;
border-radius: 8rpx;
margin: 20rpx 0 0 14rpx;
background-color: #F2F2F2;
min-height: 56rpx;
.attr-img{
margin: 0 -8rpx 0 4rpx;
}
.option-name{
margin: 4rpx 12rpx 4rpx;
}
}
.product-window .productWinList .item .listn .itemn.on {
@include main_color(theme);
@include coupons_border_color(theme);
@include cate-two-btn(theme);
}
.product-window .productWinList .item .listn .itemn.limit {
color: #999;
text-decoration: line-through;
}
.product-window .cart {
margin-top: 50rpx;
margin-bottom: 30rpx;
padding: 0 24rpx;
}
.product-window .cart .title {
font-size: 30rpx;
color: #999;
}
.product-window .cart .carnum {
height: 54rpx;
}
.product-window .cart .carnum view {
width: 84rpx;
height: 54rpx;
line-height: 54rpx;
color: #282828;
font-size: 45rpx;
}
.product-window .cart .carnum .reduce {
border-right: 0;
border-radius: 6rpx 0 0 6rpx;
line-height: 48rpx;
}
.product-window .cart .carnum .reduce.on {
// border-color: #e3e3e3;
color: #DEDEDE;
font-size: 44rpx;
}
.product-window .cart .carnum .plus {
border-left: 0;
border-radius: 0 6rpx 6rpx 0;
line-height: 46rpx;
}
.product-window .cart .carnum .plus.on {
border-color: #e3e3e3;
color: #dedede;
}
.product-window .cart .carnum .num {
background: rgba(242, 242, 242, 1);
font-size: 28rpx;
border-radius: 4rpx;
input {
display: -webkit-inline-box;
line-height: 54rpx;
height: 54rpx;
}
}
.product-window .joinBnt {
font-size: 30rpx;
width: 620rpx;
height: 86rpx;
border-radius: 50rpx;
text-align: center;
line-height: 86rpx;
color: #fff;
margin: 21rpx auto 0 auto;
}
.align-baseline {
align-items: baseline;
}
.product-window .joinBnt.on {
background-color: #bbb;
color: #fff;
}
.align-center {
align-items: center;
}
.vip_icon {
width: 44rpx;
height: 28rpx;
}
.vip_money {
background: #FFE7B9;
border-radius: 4px;
font-size: 22rpx;
color: #333;
line-height: 28rpx;
text-align: center;
padding: 0 6rpx;
box-sizing: border-box;
margin-left: -4rpx;
}
.pl-2 {
padding-left: 20rpx;
}
.limit-buy {
font-weight: 400;
font-size: 22rpx;
@include main_color(theme)
margin-left: 25%;
}
.groupOn {
background: #FCEAE9 !important;
border: 1px solid #E93323 !important;
color: #E93323 !important;
}
</style>