对接优惠券弹窗

This commit is contained in:
gyq
2025-09-26 10:55:45 +08:00
parent 84f782afa1
commit c6dbd6d62b
9 changed files with 3263 additions and 2771 deletions

318
components/coupon-modal.vue Normal file
View File

@@ -0,0 +1,318 @@
<!-- 首页优惠券弹窗 -->
<template>
<up-popup :show="show" bgColor="transparent">
<view class="container">
<view class="content">
<image class="bg" src="https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/4/6520f3cfae594480aa2e612ff4ad121c.png" mode="widthFix"></image>
<view class="swiper-wrap">
<swiper class="swiper" @change="swiperChange">
<swiper-item class="swiper-item" v-for="(item, index) in couponList" :key="index">
<view class="item" v-for="val in item" :key="val.id">
<image
class="item-bg"
src="https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/4/105b29907c274f9e84e14b9ddb867356.png"
mode="aspectFill"
></image>
<view class="info-wrap">
<view class="info">
<view class="name name1" v-if="val.couponType == 1">
<text class="t1">{{ val.discountAmount }}</text>
<text class="t2">{{ val.fullAmount }}可用</text>
</view>
<view class="name name2" v-if="val.couponType == 2">
<text class="t1">商品兑换{{ val.discountNum }}</text>
<text class="t2">{{ val.fullAmount }}可用</text>
</view>
<view class="name name2" v-if="val.couponType == 3">
<text class="t1">{{ val.discountRate }}折券</text>
<text class="t2">{{ val.fullAmount }}可用</text>
</view>
<view class="name name2" v-if="val.couponType == 4">
<text class="t1">第二件半价券</text>
<text class="t2">{{ val.fullAmount }}可用</text>
</view>
<view class="name name2" v-if="val.couponType == 6">
<text class="t1">买一送一券</text>
<text class="t2">{{ val.fullAmount }}可用</text>
</view>
<view class="title">
{{ val.title }}
</view>
<view class="time">
<view class="row">
<text class="t">
有效期至{{ dayjs(item.validStartTime || new Date()).format('YYYY.M.D') }} -
{{ dayjs(item.validEndTime || new Date()).format('YYYY.M.D') }}
</text>
</view>
</view>
</view>
<view class="lq-btn">
<view class="lb" @click="getHandle">
<text class="t">立即</text>
<text class="t">领取</text>
</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
<view class="dot-wrap">
<view class="page-btn">
<up-icon name="arrow-left" :color="swiperIndex == 0 ? '#fa746a' : '#f6171b'" size="16"></up-icon>
</view>
<view class="page-wrap">
<text class="t" :class="{ active: swiperIndex == index }" v-for="(item, index) in couponList.length" :key="index">{{ item }}</text>
</view>
<view class="page-btn">
<up-icon name="arrow-right" :color="swiperIndex == couponList.length - 1 ? '#fa746a' : '#f6171b'" size="16"></up-icon>
</view>
</view>
</view>
<view class="btn-wrap" @click="getHandle">
<image class="btn-img" src="https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/4/a7ea3211baf84cc8b77171d4f88c7f9e.png" mode="widthFix"></image>
<text class="t">全部领取{{ couponCount }}</text>
</view>
<view class="close" @click="getHandle">
<up-icon name="close-circle" size="34" color="#fff"></up-icon>
</view>
</view>
</view>
</up-popup>
</template>
<script setup>
import _ from 'lodash';
import dayjs from 'dayjs';
import { onMounted, ref } from 'vue';
import { getCouponPopup, receivePopUp } from '@/common/api/member.js';
const couponCount = ref(0);
const swiperIndex = ref(0);
const couponList = ref([]);
const show = ref(false);
const props = defineProps({
getMode: {
type: String,
default: 'eat'
}
});
// 轮播图滑动
function swiperChange(e) {
swiperIndex.value = e.detail.current;
}
// 优惠券弹窗
async function getCouponPopupAjax() {
try {
const res = await getCouponPopup({ getMode: props.getMode });
if (res.length) {
show.value = true;
couponCount.value = res.length;
couponList.value = _.chunk(res, 3);
}
} catch (error) {
console.log(error);
}
}
// 领取
async function getHandle() {
try {
uni.showLoading({
title: '领取中...',
mask: true
});
const res = await receivePopUp({
getMode: props.getMode
});
show.value = false;
uni.showToast({
title: '已领取,请在我的优惠券中查看',
icon: 'none'
});
} catch (err) {
console.log(err);
}
uni.hideLoading();
}
onMounted(() => {
getCouponPopupAjax();
});
</script>
<style scoped lang="scss">
.container {
width: 100vw;
height: 100vh;
position: relative;
display: flex;
align-items: center;
justify-content: center;
padding-top: 10vh;
.content {
width: 94vw;
position: relative;
padding-left: 24upx;
.close {
position: absolute;
left: 50%;
bottom: -100upx;
transform: translateX(-50%);
}
.bg {
width: 100%;
height: 100%;
}
.swiper-wrap {
width: 64%;
height: 70%;
position: absolute;
left: 18%;
top: 96upx;
.swiper {
width: 100%;
height: 90%;
background-color: #fff;
.swiper-item {
width: 100%;
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: repeat(3, 1fr);
grid-column-gap: 0;
grid-row-gap: 12upx;
.item {
background-color: #e20410;
border-radius: 12upx;
padding: 12upx;
position: relative;
.item-bg {
width: 100%;
height: 100%;
}
.info-wrap {
width: 100%;
height: 100%;
padding: 20upx;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
.info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 8upx;
.name {
font-size: 32upx;
font-weight: bold;
color: #fff;
.t1 {
font-size: 32upx;
font-weight: bold;
color: #fff;
margin-right: 8upx;
}
.t2 {
font-size: 20upx;
color: #fff;
}
}
.title {
font-size: 28upx;
color: #fff;
font-weight: bold;
}
.time {
display: flex;
.row {
height: 30upx;
padding: 0 8upx;
background-color: #fff;
border-radius: 8upx;
display: flex;
align-items: center;
.t {
font-size: 10px;
color: #c50914;
}
}
}
}
.lq-btn {
.lb {
$size: 80upx;
width: $size;
height: $size;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #fe413d;
.t {
color: #fff;
font-size: 20upx;
font-weight: bold;
}
}
}
}
}
}
}
.dot-wrap {
width: 100%;
height: 10%;
display: flex;
align-items: center;
justify-content: center;
gap: 20upx;
.page-wrap {
display: flex;
align-items: center;
gap: 20upx;
&.disabled {
.t {
color: #fa746a;
}
}
.t {
font-size: 28upx;
color: #fa746a;
&.active {
color: #f6171b;
font-weight: bold;
}
}
}
}
}
.btn-wrap {
width: 60%;
position: absolute;
left: 20%;
bottom: 38upx;
.btn-img {
width: 100%;
}
.t {
font-size: 42upx;
font-weight: bold;
color: #b43a14;
position: absolute;
top: 44%;
left: 54%;
white-space: nowrap;
transform: translate(-50%, -50%);
}
}
}
}
</style>