绿满眶商城微信小程序-uniapp
peng
1 天以前 9653f4faa20699a2d9a03391f4a6175ff8ce59c3
Merge branch 'dev_fix_sub' into user_action

# Conflicts:
# pages/tabbar/user/my.vue
4个文件已修改
2个文件已添加
523 ■■■■■ 已修改文件
api/members.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/store-coupon.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/order/myOrder.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/storeClaim/store-claim.vue 365 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabbar/user/my.vue 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/members.js
@@ -481,3 +481,10 @@
        data:params
    });
}
export function bindMemberAndStore(params){
  return http.request({
    url: '/lmk/member/bindMemberAndStore',
    method: Method.PUT,
    data:params
  });
}
api/store-coupon.js
New file
@@ -0,0 +1,27 @@
import { http, Method } from "@/utils/request.js";
/**
 * 根据店铺优惠券关联ID获取优惠券详情
 * @param {string|number} storeCoupRef - 店铺优惠券关联ID
 * @returns {Promise} 返回优惠券详情
 */
export function getStoreCouponDetail(storeCoupRef) {
  return http.request({
    url: `/lmk/store/coupon/${storeCoupRef}`,
    method: Method.GET,
    needToken: true,
  });
}
/**
 * 领取店铺优惠券
 * @param {string|number} storeCoupRef - 店铺优惠券关联ID
 * @returns {Promise} 返回领取结果
 */
export function claimStoreCoupon(storeCoupRef) {
  return http.request({
    url: `/lmk/store/coupon/${storeCoupRef}`,
    method: Method.POST,
    needToken: true,
  });
}
pages.json
@@ -198,6 +198,7 @@
    //   "path": "pages/tabbar/user/my",
    //   "style": {
    //     "navigationBarTextStyle": "white",
    //     "navigationBarTextStyle": "white",
    //     "enablePullDownRefresh": true,
    //     "navigationStyle": "custom",
    //     "componentPlaceholder": {
@@ -2247,7 +2248,27 @@
          }
        }
      ]
    }
    },
    {
      "root": "pages/storeClaim",
      "pages": [{
          "path" : "store-claim",
          "style" :
          {
              "navigationBarTitleText" : "优惠卷领取",
            "componentPlaceholder":{
                "u-card": "view",
                "u-navbar": "view",
                "u-tag": "view",
                "u-icon": "view",
                "u-button": "view",
                "u-empty": "view"
            }
          }
      }]
    }
  ],
  "globalStyle": {
    "navigationBarTextStyle": "black",
pages/order/myOrder.vue
@@ -175,6 +175,14 @@
                  </u-button> -->
                </view>
              </view>
                <view style="display: flex;justify-content: space-around;">
                    <view class="" @click="callPhone">
                         客服热线: 028-84472936
                    </view>
                    <view class="" @click="copyToClipboard">
                         客服微信: meiyikuang
                    </view>
                </view>
            </view>
          </view>
          <uni-load-more :status="tabItem.loadStatus"></uni-load-more>
@@ -419,6 +427,29 @@
    },
  },
  methods: {
      copyToClipboard(){
          uni.setClipboardData({
              data:'meiyikuang',
              success() {
                  uni.showToast({
                title: '复制成功',
                icon: 'none'
                  })
              }
          })
      },
      callPhone(){
          uni.showModal({
              title:'确认联系客服吗?',
              success(e) {
                  if(e.confirm){
                      uni.makePhoneCall({
                          phoneNumber:'028-84472936'
                      })
                  }
              }
          })
      },
      openCouponPackage(order){
          console.log(order)
        uni.navigateTo({
pages/storeClaim/store-claim.vue
New file
@@ -0,0 +1,365 @@
<template>
    <view class="container">
        <!-- 优惠券卡片 -->
        <view class="coupon-card" v-if="couponInfo.storeCoupRef">
            <u-card :border="false" :head-style="{ padding: '30rpx' }" :body-style="{ padding: '0 30rpx 30rpx' }">
                <!-- 头部:店铺信息 -->
                <view slot="head" class="card-head">
                    <view class="store-info">
                        <u-icon name="home" size="36" color="#999"></u-icon>
                        <text class="store-name">{{ couponInfo.storeName }}</text>
                    </view>
                    <u-tag v-if="couponInfo.claimStatus === 'NOT_CLAIM'" text="未领取" type="warning" mode="plain" size="mini" />
                    <u-tag v-else-if="couponInfo.claimStatus === 'CLAIM'" text="已领取" type="success" mode="plain" size="mini" />
                    <u-tag v-else text="已过期" type="info" mode="plain" size="mini" />
                </view>
                <!-- 主体:优惠券信息 -->
                <view slot="body" class="card-body">
                    <view class="coupon-title">
                        <text class="title">{{ couponInfo.couponName }}</text>
                        <text class="coupon-no">编号:{{ couponInfo.couponNo }}</text>
                    </view>
                    <view class="coupon-desc" v-if="couponInfo.couponDesc">
                        <text class="desc">{{ couponInfo.couponDesc }}</text>
                    </view>
                    <view class="coupon-rule" v-if="couponInfo.couponRule">
                        <text class="rule-title">使用规则:</text>
                        <text class="rule-content">{{ couponInfo.couponRule }}</text>
                    </view>
                    <view class="coupon-time" v-if="couponInfo.startTime && couponInfo.endTime">
                        <u-icon name="clock" size="28" color="#999"></u-icon>
                        <text class="time-text">有效期:{{ formatDate(couponInfo.startTime) }} 至 {{ formatDate(couponInfo.endTime) }}</text>
                    </view>
                    <view class="coupon-condition" v-if="couponInfo.consumeThreshold > 0">
                        <u-icon name="coupon" size="28" color="#999"></u-icon>
                        <text class="condition-text">满{{ formatAmount(couponInfo.consumeThreshold) }}元可用</text>
                    </view>
                </view>
                <!-- 底部:操作按钮 -->
                <view slot="foot" class="card-foot">
                    <u-button
                        :type="couponInfo.claimStatus === 'NOT_CLAIM' ? 'primary' : 'default'"
                        :disabled="couponInfo.claimStatus !== 'NOT_CLAIM'"
                        :loading="loading"
                        @click="claimCoupon"
                        :ripple="true"
                        :hair-line="false"
                    >
                        {{ couponInfo.claimStatus === 'NOT_CLAIM' ? '立即领取' : couponInfo.claimStatus === 'CLAIM' ? '已领取' : '已过期' }}
                    </u-button>
                </view>
            </u-card>
        </view>
        <!-- 空状态 -->
        <view class="empty-state" v-else>
            <u-empty text="优惠券信息不存在" mode="coupon" :icon-size="200"></u-empty>
        </view>
        <!-- 使用说明 -->
        <view class="instructions">
            <view class="instructions-title">
                <u-icon name="info-circle" size="28" color="#999"></u-icon>
                <text class="title-text">使用说明</text>
            </view>
            <view class="instructions-content">
                <text class="content-text">1. 优惠券仅限在指定店铺使用\n2. 每个用户限领一张\n3. 优惠券不可兑换现金\n4. 请在有效期内使用</text>
            </view>
        </view>
        <!-- 空白占位 -->
        <view class="placeholder"></view>
    </view>
</template>
<script>
    import { getStoreCouponDetail, claimStoreCoupon } from '@/api/store-coupon.js';
    import { formatPrice } from '@/utils/Foundation.js';
    export default {
        data() {
            return {
                loading: false,
                storeCoupRef: '', // 店铺优惠券关联ID
                couponInfo: {
                    id: "",
                    storeCoupRef: "",
                    storeId: "",
                    storeName: "",
                    couponId: "",
                    couponName: "",
                    couponNo: "",
                    couponAmount: 0, // 优惠金额
                    couponDesc: "", // 优惠券描述
                    couponRule: "", // 使用规则
                    startTime: "", // 开始时间
                    endTime: "", // 结束时间
                    consumeThreshold: 0, // 消费门槛
                    claimStatus: "NOT_CLAIM", // 领取状态
                }
            }
        },
        onShow() {
        this.getCouponDetail(this.storeCoupRef);
        },
        onLoad(options) {
            // 获取传递的店铺优惠券关联ID
            if (options.storeCoupRef) {
                this.storeCoupRef = options.storeCoupRef;
                this.getCouponDetail(options.storeCoupRef);
            } else if (options.id) {
                // 兼容旧参数
                this.storeCoupRef = options.id;
                this.getCouponDetail(options.id);
            }else if(options.q){
                // 双重解码:微信对URL进行了两次编码
                const decodedUrl = decodeURIComponent(decodeURIComponent(options.q));
                console.log('原始URL:', decodedUrl);
                // 解析URL中的查询参数
                const params = this.parseUrlParams(decodedUrl);
                this.storeCoupRef = params.id;
                this.getCouponDetail(this.storeCoupRef);
            }
             else {
                this.$u.toast('参数错误');
            }
        },
        methods: {
            // 解析URL参数
            parseUrlParams(url) {
                const params = {};
                // 处理可能存在的hash(如果有的话)
                const cleanUrl = url.split('#')[0];
                const queryStr = cleanUrl.split('?')[1] || '';
                queryStr.split('&').forEach(pair => {
                    const [key, value] = pair.split('=');
                    if (key) {
                        // 如果值存在,则解码,否则设为空字符串
                        params[key] = value ? decodeURIComponent(value) : '';
                    }
                });
                return params;
            },
            // 格式化金额
            formatAmount(amount) {
                if (!amount) return '0';
                return formatPrice(parseFloat(amount));
            },
            // 格式化日期
            formatDate(dateStr) {
                if (!dateStr) return '';
                return dateStr.split(' ')[0];
            },
            // 获取优惠券详情
            async getCouponDetail(storeCoupRef) {
                uni.showLoading({
                    title: '加载中...'
                });
                try {
                    const res = await getStoreCouponDetail(storeCoupRef);
                    console.log(JSON.stringify(res))
                    if (res.data.code === 200) {
                        this.couponInfo = {
                            ...this.couponInfo,
                            ...res.data.data,
                            couponAmount: res.data.data.couponAmount || 0,
                            consumeThreshold: res.data.data.consumeThreshold || 0
                        };
                    } else {
                        this.$u.toast(res.data.message || '获取优惠券详情失败');
                    }
                } catch (err) {
                    this.$u.toast('获取优惠券详情失败,请稍后重试');
                    console.error('获取优惠券详情失败:', err);
                } finally {
                    uni.hideLoading();
                }
            },
            // 领取优惠券
            async claimCoupon() {
                if (this.couponInfo.claimStatus !== 'NOT_CLAIM') {
                    return;
                }
                // 确认领取
                uni.showModal({
                    title: '提示',
                    content: `确定要领取"${this.couponInfo.couponName}"优惠券吗?`,
                    success: (res) => {
                        if (res.confirm) {
                            this.doClaimCoupon();
                        }
                    }
                });
            },
            // 执行领取优惠券操作
            async doClaimCoupon() {
                this.loading = true;
                try {
                    // 调用领取优惠券接口
                    const res = await claimStoreCoupon(this.storeCoupRef);
                    if (res.data.code === 200) {
                        this.$u.toast('领取成功');
                        this.couponInfo.claimStatus = 'CLAIM';
                        // 延迟返回上一页,让用户看到领取成功的提示
                        setTimeout(() => {
                            uni.navigateBack();
                        }, 1500);
                    } else {
                        this.$u.toast(res.data.message || '领取失败');
                    }
                } catch (err) {
                    this.$u.toast('领取失败,请稍后重试');
                    console.error('领取优惠券失败:', err);
                } finally {
                    this.loading = false;
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
.container {
    background-color: #f5f5f5;
    min-height: 100vh;
}
.coupon-card {
    margin: 20rpx;
}
.card-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.store-info {
    display: flex;
    align-items: center;
}
.store-name {
    margin-left: 10rpx;
    font-size: 32rpx;
    font-weight: bold;
    color: #333;
}
.card-body {
    padding-top: 20rpx;
}
.coupon-title {
    margin-bottom: 30rpx;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
}
.title {
    font-size: 36rpx;
    font-weight: bold;
    color: #333;
}
.coupon-no {
    font-size: 24rpx;
    color: #999;
    margin-left: 20rpx;
}
.coupon-desc {
    margin-bottom: 30rpx;
}
.desc {
    font-size: 28rpx;
    color: #666;
}
.coupon-rule {
    margin-bottom: 30rpx;
}
.rule-title {
    font-size: 28rpx;
    color: #333;
    font-weight: bold;
}
.rule-content {
    font-size: 26rpx;
    color: #666;
}
.coupon-time, .coupon-condition {
    display: flex;
    align-items: center;
    margin-bottom: 20rpx;
}
.time-text, .condition-text {
    font-size: 24rpx;
    color: #999;
    margin-left: 10rpx;
}
.card-foot {
    padding: 20rpx 0;
}
.instructions {
    background-color: #ffffff;
    margin: 20rpx;
    padding: 30rpx;
    border-radius: 16rpx;
}
.instructions-title {
    display: flex;
    align-items: center;
    margin-bottom: 20rpx;
}
.title-text {
    margin-left: 10rpx;
    font-size: 30rpx;
    font-weight: bold;
    color: #333;
}
.instructions-content {
    padding-left: 40rpx;
}
.content-text {
    font-size: 26rpx;
    color: #666;
    line-height: 1.6;
}
.placeholder {
    height: 40rpx;
}
.empty-state {
    margin-top: 200rpx;
}
</style>
pages/tabbar/user/my.vue
@@ -140,7 +140,7 @@
import '@/pages/subComponents/uview-components/uview-ui';
import tool from "@/pages/tabbar/user/utils/tool.vue";
import { getSTSToken } from "@/api/common.js";
import { getCouponsNum, getFootprintNum } from "@/api/members.js";
import { getCouponsNum, getFootprintNum,bindMemberAndStore } from "@/api/members.js";
import { getUserWallet } from "@/api/members";
import configs from '@/config/config'
import storage from '@/utils/storage.js'
@@ -173,6 +173,51 @@
        }
    };
  },
  onLoad(option) {
    console.log('-----------分享出的数据---------->', option)
    let shareStoreId = null;
    let shareTime = null;
    // 检查是否存在q参数
    if (option.q) {
      // 双重解码:微信对URL进行了两次编码
      const decodedUrl = decodeURIComponent(decodeURIComponent(option.q));
      console.log('原始URL:', decodedUrl);
      // 解析URL中的查询参数
      const params = this.parseUrlParams(decodedUrl);
      shareStoreId = params.shareStoreId;
      try {
        // 将数据存储到本地缓存
        uni.setStorageSync('shareStoreId', shareStoreId);
        //创建一个扫码的时间
        // 获取当前时间并格式化为 yyyy-MM-dd HH:mm:ss
        const now = new Date();
        const year = now.getFullYear();
        const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,需要+1
        const day = String(now.getDate()).padStart(2, '0');
        const hours = String(now.getHours()).padStart(2, '0');
        const minutes = String(now.getMinutes()).padStart(2, '0');
        const seconds = String(now.getSeconds()).padStart(2, '0');
        shareTime = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
        uni.setStorageSync('shareTime', shareTime);
        console.log('数据存储成功');
      } catch (e) {
        console.error('存储失败:', e);
      }
    }else{
      shareStoreId = uni.getStorageSync('shareStoreId');
      shareStoreId = uni.getStorageSync('shareTime');
      console.log('从缓存读取参数:', { shareStoreId, shareTime });
      // this.bindMemberAndStore(shareStoreId, shareTime)
      if (shareStoreId && shareTime) {
        console.log('检测到有效参数,调用后端接口');
        this.bindMemberAndStore(shareStoreId, shareTime);
      } else {
        console.log('无有效参数,执行正常逻辑');
      }
    }
    this.initCOS()
  onUnload() {
    let    param = this.actionParam;
    if (this.sendOnShow)return
@@ -198,7 +243,7 @@
            param.sessionId = this.pageSessionNo
            userAction(param)
        }
      })
      })
    this.userInfo = this.$options.filters.isLogin() || {};
    if (this.$options.filters.isLogin("auth")) {
      this.getUserOrderNum();
@@ -223,6 +268,27 @@
  mounted() { },
  methods: {
    async bindMemberAndStore(shareStoreId, shareTime){
      let form ={
        shareStoreId: shareStoreId,
        shareTime: shareTime
      }
      // let form ={
      //               shareStoreId: "1376433565247471616",
      //               shareTime: "2025-09-26 16:18:00"
      // }
      try {
        const res = await bindMemberAndStore(form);
        if(res.statusCode === 200){
          //清除缓存
          uni.removeStorageSync('shareStoreId');
          uni.removeStorageSync('shareTime');
        }
      }
      catch(error) {
        console.error('出错:', error);
      };
    },
      // goTOSuccess(){
      //          uni.redirectTo({
      //             url:"/pages/cart/payment/success?paymentMethod=WECHAT" +