ソースを参照

新增优惠券领取界面

haiyang 5 日 前
コミット
33d5a5c7a6

+ 2 - 1
pages.config.ts

@@ -33,7 +33,8 @@ export default defineUniPages({
         'window': {
             'enableShareAppMessage': true,
             'enableShareTimeline': true,
-        }
+        },
+        'navigateToMiniProgramAppIdList': ['wxab9634bf98628a03'],
     },
     // tabbar 的配置统一在 “./src/tabbar/config.ts” 文件中
     'tabBar': tabBar as any,

+ 0 - 17
src/api/foo-alova.ts

@@ -1,17 +0,0 @@
-import { API_DOMAINS, http } from '@/http/alova'
-
-export interface IFoo {
-  id: number
-  name: string
-}
-
-export function foo() {
-  return http.Get<IFoo>('/foo', {
-    params: {
-      name: '菲鸽',
-      page: 1,
-      pageSize: 10,
-    },
-    meta: { domain: API_DOMAINS.SECONDARY }, // 用于切换请求地址
-  })
-}

+ 9 - 0
src/api/receiveCoupon.ts

@@ -0,0 +1,9 @@
+import { http } from '@/http/alova'
+
+export function getReceiveCouponDetail(couponId: string) {
+    return http.Get('/couponCenter/APP/shareRecord/queryTemplateBySendUserId', {
+        params: {
+            id: couponId,
+        }
+    })
+}

+ 281 - 0
src/components/ReceiveCoupon.vue

@@ -0,0 +1,281 @@
+<script lang="ts" setup>
+import CouponBtnBg from '@img/receiveCoupon/button.png'
+import CouponImg from '@img/receiveCoupon/coupon-bg.png'
+
+const props = defineProps({
+    coupon: {
+        type: Object,
+        default: () => ({
+            ruleReductionAmount: '0',
+            ruleMinSpendAmount: '0',
+        }),
+    },
+})
+const emit = defineEmits(['button-click'])
+const coupon = computed(() => props.coupon)
+
+const category = computed(() => {
+    const relatedType = props.coupon.relatedType
+    if (relatedType === '1') {
+        return `限${props.coupon.relatedName}分类商品使用`
+    }
+    else {
+        return `限${props.coupon.relatedName}商品使用`
+    }
+})
+
+function handleButtonClick() {
+    emit('button-click')
+}
+</script>
+
+<template>
+    <view class="discount-coupon">
+        <view class="coupon-container">
+            <view class="coupon-content">
+                <image class="coupon-bg" :src="CouponImg" mode="aspectFit" />
+                <view class="coupon-content-layout">
+                    <view class="coupon-content-text-content">
+                        <view v-if="coupon.type === '2'" class="coupon-content-text-title">
+                            <view class="coupon-amount">
+                                <view class="coupon-amount-count-number">
+                                    {{ coupon.ruleDiscountRate }}
+                                </view>
+                                <view class="coupon-amount-count-unit">
+                                    折
+                                </view>
+                            </view>
+                            <view class="coupon-type">
+                                <view style="font-size: 18rpx;">
+                                    COUPON
+                                </view>
+                                <view style="font-size: 34rpx;">
+                                    折扣券
+                                </view>
+                                <view style="font-size:18rpx;">
+                                    最高优惠{{ coupon.ruleDiscountCapAmount }}元
+                                </view>
+                            </view>
+                        </view>
+                        <view v-else class="coupon-content-text-title">
+                            <view class="coupon-amount">
+                                <view class="coupon-amount-count-icon">
+                                    ¥
+                                </view>
+                                <view class="coupon-amount-count-number">
+                                    {{ coupon?.ruleReductionAmount || '0' }}
+                                </view>
+                            </view>
+                            <view class="coupon-type">
+                                <view style="font-size: 18rpx;">
+                                    YUAN
+                                </view>
+                                <view style="font-size: 34rpx;">
+                                    满减券
+                                </view>
+                                <view style="font-size:18rpx;">
+                                    COUPON
+                                </view>
+                            </view>
+                        </view>
+                        <view class="coupon-content-text-cart">
+                            {{ category }}
+                        </view>
+                        <view class="coupon-content-text-amount">
+                            订单满{{ coupon?.ruleMinSpendAmount }}元可用此券
+                        </view>
+                    </view>
+                </view>
+            </view>
+            <button class="coupon-button" hover-class="none" @click="handleButtonClick">
+                <image class="coupon-btn-bg" :src="CouponBtnBg" mode="aspectFit" />
+                <view class="coupon-btn-text">
+                    立即领取
+                </view>
+            </button>
+        </view>
+    </view>
+</template>
+
+<style lang="scss" scoped>
+.discount-coupon {
+    // width: 670rpx;
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    // position: relative;
+    overflow: hidden;
+    // top: 50%;
+    // left: 50%;
+    // transform: translate(-50%, -50%);
+    background-color: rgba(0, 0, 0, 0.5);
+    z-index: 99999;
+
+    .coupon-container {
+        position: relative;
+        height: inherit;
+        width: inherit;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+
+        .coupon-content {
+            position: relative;
+            width: 100%;
+            height: 638rpx;
+
+            .coupon-bg {
+                position: absolute;
+                left: 50%;
+                transform: translate(-50%, -30%);
+                width: 149%;
+                height: 149%;
+                z-index: 10;
+                object-fit: cover;
+            }
+
+            .coupon-content-layout {
+                position: absolute;
+                left: 50%;
+                transform: translate(-46%, 45%);
+                z-index: 11;
+                width: 400rpx;
+                height: 370rpx;
+
+                .coupon-content-text-content {
+                    width: 347rpx;
+                    height: 206rpx;
+                    margin-top: 125rpx;
+                    margin-left: 31rpx;
+
+                    display: flex;
+                    flex-direction: column;
+                    align-items: center;
+                    justify-content: center;
+                    gap: 12rpx;
+
+                    color: #ffffff;
+
+                    .coupon-content-text-title {
+                        display: flex;
+                        flex-direction: row;
+                        flex-wrap: nowrap;
+                        gap: 29rpx;
+
+                        .coupon-amount {
+                            display: flex;
+                            flex-direction: row;
+                            flex-wrap: nowrap;
+                            align-items: baseline;
+                            justify-content: end;
+
+                            .coupon-amount-count-number {
+                                font-weight: 400;
+                                font-size: 89rpx;
+                                color: #ffffff;
+                            }
+
+                            .coupon-amount-count-unit {
+                                font-weight: 500;
+                                font-size: 31rpx;
+                                color: #f62a2a;
+                                background: #ffffff;
+                                border-radius: 50%;
+                                border: 3px solid #f62a2a;
+                                padding: 8rpx;
+                                margin-left: -19rpx;
+                            }
+
+                            .coupon-amount-count-icon {
+                                font-weight: 400;
+                                font-size: 43rpx;
+                                color: #ffffff;
+                            }
+                        }
+
+                        .coupon-type {
+                            display: flex;
+                            flex-direction: column;
+                            justify-content: space-evenly;
+                            gap: 6rpx;
+                            font-weight: 400;
+                            font-size: 18rpx;
+                            color: #ffffff;
+                        }
+                    }
+
+                    .coupon-content-text-cart {
+                        padding: 8rpx 38rpx;
+                        background-color: #ffffff;
+                        font-weight: 500;
+                        font-size: 24rpx;
+                        color: #f62a2a;
+                    }
+
+                    .coupon-content-text-amount {
+                        font-weight: 400;
+                        font-size: 24rpx;
+                        color: #ffffff;
+                    }
+                }
+            }
+        }
+
+        .coupon-button {
+            position: relative;
+            width: 254rpx;
+            height: 75rpx;
+            left: 50%;
+            transform: translate(-43%, -83%);
+            z-index: 99999;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+
+            // 去除button默认样式
+            background-color: transparent;
+            border: none;
+            padding: 0;
+            margin: 0;
+            outline: none;
+            cursor: pointer;
+            -webkit-appearance: none; // 移除浏览器默认样式
+            -moz-appearance: none;
+            appearance: none;
+
+            // 去除uni-app button默认样式
+            &::after {
+                display: none; // 移除默认边框
+            }
+
+            .coupon-btn-bg {
+                position: absolute;
+                width: 100%;
+                height: 110%;
+                z-index: 10;
+                object-fit: cover;
+                pointer-events: none; // 确保文字不阻挡点击事件
+            }
+
+            .coupon-btn-text {
+                position: absolute;
+                z-index: 11;
+
+                height: 34rpx;
+                width: 138rpx;
+
+                text-align: center;
+                font-weight: bolder;
+                font-size: 34rpx;
+                color: #bd521e;
+                line-height: 30rpx;
+                padding-bottom: 14rpx;
+                background: linear-gradient(180deg, #fffadc 0%, #ffef8d 100%);
+                -webkit-background-clip: text;
+                -webkit-text-fill-color: transparent;
+                pointer-events: none; // 确保文字不阻挡点击事件
+            }
+        }
+    }
+}
+</style>

+ 11 - 9
src/hooks/useShare.ts

@@ -11,6 +11,7 @@ export interface ShareOptions {
     shareType?: 'INVITE' | 'COUPON' | string
     showLoading?: boolean
     imageSource?: 'LOCAL' | 'REMOTE'
+    pathParamKey?: string
 }
 
 interface ShareInfo {
@@ -25,10 +26,11 @@ interface ShareInfo {
 const defaultOptions: Required<ShareOptions> = {
     title: '领券省心,消费超值,优质生活轻松开启!',
     path: '/pages/index/index',
-    imageUrl: '/static/images/share.jpg',
+    imageUrl: '/static/images/share.png',
     shareType: 'INVITE',
     showLoading: true,
     imageSource: 'LOCAL',
+    pathParamKey: 'shareRecordId',
 }
 
 /**
@@ -38,9 +40,9 @@ const defaultOptions: Required<ShareOptions> = {
  */
 export function useShare(initOptions: ShareOptions = {}) {
     /**
-                                   * 获取分享配置 - 可以直接在onShareAppMessage中调用
-                                   * @returns 完整的分享配置
-                                   */
+                                           * 获取分享配置 - 可以直接在onShareAppMessage中调用
+                                           * @returns 完整的分享配置
+                                           */
     const getShareConfig = async (customOption?: ShareOptions, extraParams?): Promise<WechatMiniprogram.Page.ICustomShareContent | {}> => {
         // 合并默认配置和自定义配置
         const options = { ...defaultOptions, ...initOptions, ...customOption }
@@ -88,7 +90,7 @@ export function useShare(initOptions: ShareOptions = {}) {
 
             if (res !== '' && res !== null && res !== 'null') {
                 // 拼接分享路径
-                const sharePath = `${options.path}${options.path.includes('?') ? '&' : '?'}shareRecordId=${res}`
+                const sharePath = `${options.path}${options.path.includes('?') ? '&' : '?'}${options.pathParamKey}=${res}`
                 let imageUrl = ''
                 if (options.imageSource === 'LOCAL') {
                     imageUrl = options.imageUrl
@@ -96,7 +98,7 @@ export function useShare(initOptions: ShareOptions = {}) {
                 else {
                     imageUrl = `${import.meta.env.VITE_SERVER_BASEURL}${import.meta.env.VITE_SERVER_RESOURCE_BASEURL}/${options.imageUrl}`
                 }
-                console.log(imageUrl)
+                console.log(sharePath)
                 return {
                     title: options.title,
                     path: sharePath,
@@ -124,9 +126,9 @@ export function useShare(initOptions: ShareOptions = {}) {
     }
 
     /**
-                                   * 获取朋友圈分享配置 - 可以直接在onShareTimeline中调用
-                                   * @returns 完整的朋友圈分享配置
-                                   */
+                                           * 获取朋友圈分享配置 - 可以直接在onShareTimeline中调用
+                                           * @returns 完整的朋友圈分享配置
+                                           */
     const getTimelineShareConfig = async (): Promise<WechatMiniprogram.Page.ICustomShareTimelineContent | {}> => {
         const config = await getShareConfig() as WechatMiniprogram.Page.ICustomShareContent
         return {

+ 2 - 0
src/pages-A/discountcouponList/index.vue

@@ -55,6 +55,8 @@ onLoad((options) => {
 const { getShareConfig: getShareCouponConfig } = useShare({
     shareType: 'COUPON',
     imageSource: 'REMOTE',
+    path: '/pages/receiveCoupon/index',
+    pathParamKey: 'couponShareRecordId',
 })
 
 // #ifdef MP-WEIXIN

+ 2 - 0
src/pages-A/spendAndSaveCouponList/index.vue

@@ -40,6 +40,8 @@ const {
 const { getShareConfig: getShareCouponConfig } = useShare({
     shareType: 'COUPON',
     imageSource: 'REMOTE',
+    path: '/pages/receiveCoupon/index',
+    pathParamKey: 'couponShareRecordId',
 })
 
 // #ifdef MP-WEIXIN

+ 2 - 0
src/pages/index/index.vue

@@ -109,6 +109,8 @@ const { getShareConfig } = useShare()
 const { getShareConfig: getShareCouponConfig } = useShare({
     shareType: 'COUPON',
     imageSource: 'REMOTE',
+    path: '/pages/receiveCoupon/index',
+    pathParamKey: 'couponShareRecordId',
 })
 
 // #ifdef MP-WEIXIN

+ 97 - 0
src/pages/receiveCoupon/index.vue

@@ -0,0 +1,97 @@
+<script setup lang="ts">
+import { useRequest } from 'alova/client'
+import { ref } from 'vue'
+import { getReceiveCouponDetail } from '@/api/receiveCoupon'
+import ReceiveCoupon from '@/components/ReceiveCoupon.vue'
+
+// 页面配置
+definePage({
+    style: {
+        navigationBarTitleText: '领取优惠券',
+        navigationStyle: 'custom',
+    },
+})
+
+// 优惠券详情数据
+const couponDetail = ref(null)
+
+const { data, loading, error, send } = useRequest(arg => getReceiveCouponDetail(arg), {
+    immediate: false,
+})
+
+// 页面加载时获取优惠券详情
+onLoad((options) => {
+    console.log(options)
+    const templateId = options.couponShareRecordId as string
+    send(templateId)
+})
+
+// 格式化日期
+function formatDate(dateStr: string) {
+    const date = new Date(dateStr)
+    const year = date.getFullYear()
+    const month = String(date.getMonth() + 1).padStart(2, '0')
+    const day = String(date.getDate()).padStart(2, '0')
+    return `${year}-${month}-${day}`
+}
+
+function navigateToMiniProgram() {
+    uni.navigateToMiniProgram({
+        appId: 'wxab9634bf98628a03',
+        path: 'pages/index/index',
+        envVersion: 'release',
+        success(res) {
+            console.log('打开成功', res)
+        },
+        fail(res) {
+            console.log('打开失败', res)
+        }
+    })
+}
+</script>
+
+<template>
+    <view class="container">
+        <!-- 加载中 -->
+        <view v-if="loading" class="loading">
+            <uni-loading-spinner type="snake" size="40" />
+            <text class="loading-text">加载中...</text>
+        </view>
+
+        <!-- 错误信息 -->
+        <view v-else-if="error" class="error">
+            <text class="error-text">{{ error }}</text>
+        </view>
+
+        <view v-if="!!data">
+            <ReceiveCoupon :coupon="data" @button-click="navigateToMiniProgram" />
+        </view>
+    </view>
+</template>
+
+<style scoped>
+.container {}
+
+.loading {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    height: 60vh;
+}
+
+.loading-text {
+    margin-top: 20rpx;
+    color: #999;
+    font-size: 28rpx;
+}
+
+.error {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 60vh;
+    color: #ff4444;
+    font-size: 32rpx;
+}
+</style>

+ 1 - 0
src/router/config.ts

@@ -23,6 +23,7 @@ export const EXCLUDE_LOGIN_PATH_LIST = [
     LOGIN_PAGE,
     '/pages/xxx/index', // 示例值
     '/pages-sub/xxx/index', // 示例值
+    '/pages/receiveCoupon/index',
     ...excludeLoginPathList, // 都是以 / 开头的 path
 ]
 

BIN
src/static/images/receiveCoupon/button.png


BIN
src/static/images/receiveCoupon/coupon-bg.png


BIN
src/static/images/share.jpg


BIN
src/static/images/share.png