From c6bddd39c91f2d411316a78ed27b466488c2a39e Mon Sep 17 00:00:00 2001 From: peng <peng.com> Date: 星期二, 30 九月 2025 17:38:39 +0800 Subject: [PATCH] 店铺扫码领取抽奖机会 --- api/store-coupon.js | 25 +++ pages.json | 17 ++ pages/storeClaim/storePrizeClaim.vue | 401 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+), 0 deletions(-) diff --git a/api/store-coupon.js b/api/store-coupon.js index b1dddb5..7f5b46f 100644 --- a/api/store-coupon.js +++ b/api/store-coupon.js @@ -24,4 +24,29 @@ method: Method.POST, needToken: true, }); +} +/** + * 鏍规嵁搴楅摵浼樻儬鍒稿叧鑱擨D鑾峰彇浼樻儬鍒歌鎯� + * @param {string|number} storeCoupRef - 搴楅摵浼樻儬鍒稿叧鑱擨D + * @returns {Promise} 杩斿洖浼樻儬鍒歌鎯� + */ +export function getStorePrize(storeCoupRef) { + return http.request({ + url: `/lmk/store/prize/${storeCoupRef}`, + method: Method.GET, + needToken: true, + }); +} + +/** + * 棰嗗彇搴楅摵浼樻儬鍒� + * @param {string|number} storeCoupRef - 搴楅摵浼樻儬鍒稿叧鑱擨D + * @returns {Promise} 杩斿洖棰嗗彇缁撴灉 + */ +export function claimPrize(storeCoupRef) { + return http.request({ + url: `/lmk/store/prize/${storeCoupRef}`, + method: Method.POST, + needToken: true, + }); } \ No newline at end of file diff --git a/pages.json b/pages.json index ec3cfe2..f95be17 100644 --- a/pages.json +++ b/pages.json @@ -2272,6 +2272,23 @@ } } + }, + { + "path" : "storePrizeClaim", + "style" : + { + "navigationBarTitleText" : "棰嗗彇鎶藉鏈轰細", + "componentPlaceholder":{ + "u-card": "view", + "u-navbar": "view", + "u-tag": "view", + "u-icon": "view", + "u-button": "view", + "u-empty": "view", + "u-image":"view" + + } + } }] } diff --git a/pages/storeClaim/storePrizeClaim.vue b/pages/storeClaim/storePrizeClaim.vue new file mode 100644 index 0000000..4a3a526 --- /dev/null +++ b/pages/storeClaim/storePrizeClaim.vue @@ -0,0 +1,401 @@ +<template> + <view class="container"> + <!-- 鎶藉鏈轰細鍗$墖 --> + <view class="prize-card" v-if="prizeInfo.id"> + <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">{{ prizeInfo.storeName || '榛樿搴楅摵' }}</text> + </view> + <u-tag v-if="prizeInfo.claimStatus === 'NOT_CLAIM'" text="鏈鍙�" type="warning" mode="plain" size="mini" /> + <u-tag v-else-if="prizeInfo.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="cover-image" v-if="prizeInfo.activityCover"> + <u-image + :src="prizeInfo.activityCover" + width="100%" + height="300rpx" + mode="aspectFill" + border-radius="10" + :fade="true" + duration="450" + ></u-image> + </view> + + <view class="prize-title"> + <text class="title">{{ prizeInfo.activityName || prizeInfo.prizeName || '鎶藉鏈轰細' }}</text> + </view> + + <view class="prize-desc" v-if="prizeInfo.activityDes || prizeInfo.prizeDesc"> + <text class="desc">{{ prizeInfo.activityDes || prizeInfo.prizeDesc }}</text> + </view> + + <view class="prize-rule" v-if="prizeInfo.prizeRule"> + <text class="rule-title">浣跨敤璇存槑锛�</text> + <text class="rule-content">{{ prizeInfo.prizeRule }}</text> + </view> + + <view class="prize-time" v-if="prizeInfo.beginTime && prizeInfo.endTime"> + <u-icon name="clock" size="28" color="#999"></u-icon> + <text class="time-text">鏈夋晥鏈燂細{{ formatDate(prizeInfo.beginTime) }} 鑷� {{ formatDate(prizeInfo.endTime) }}</text> + </view> + </view> + + <!-- 搴曢儴锛氭搷浣滄寜閽� --> + <view slot="foot" class="card-foot"> + <u-button + :type="prizeInfo.claimStatus === 'NOT_CLAIM' ? 'primary' : 'default'" + :disabled="prizeInfo.claimStatus !== 'NOT_CLAIM'" + :loading="loading" + @click="claimPrize" + :ripple="true" + :hair-line="false" + > + {{ prizeInfo.claimStatus === 'NOT_CLAIM' ? '绔嬪嵆棰嗗彇' : prizeInfo.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. 璇峰湪鏈夋晥鏈熷唴浣跨敤</text> + </view> + </view> + + <!-- 绌虹櫧鍗犱綅 --> + <view class="placeholder"></view> + </view> +</template> + +<script> + import { getStorePrize, claimPrize } from '@/api/store-coupon.js'; + + export default { + data() { + return { + loading: false, + prizeId: '', // 鎶藉鏈轰細ID + prizeInfo: { + id: "", + storeId: "", + storeName: "", + activityName: "", // 娲诲姩鍚嶇О + prizeName: "鎶藉鏈轰細", + prizeNo: "", + activityDes: "", // 娲诲姩鎻忚堪 + prizeDesc: "鑾峰緱涓�娆℃娊濂栨満浼氾紝鍙湪鎸囧畾娲诲姩涓娇鐢�", // 鎶藉鏈轰細鎻忚堪 + prizeRule: "姣忔鎶藉娑堣�椾竴娆℃娊濂栨満浼氾紝鎶戒腑濂栧搧鍚庨渶鍙婃椂棰嗗彇", // 浣跨敤瑙勫垯 + beginTime: "", // 寮�濮嬫椂闂� + endTime: "", // 缁撴潫鏃堕棿 + claimStatus: "NOT_CLAIM", // 棰嗗彇鐘舵�� + activityCover: "", // 灏侀潰鍥剧墖 + enableStatus: "ON" // 鍚敤鐘舵�� + } + } + }, + onShow() { + if (this.prizeId) { + this.getPrizeDetail(this.prizeId); + } + }, + onLoad(options) { + console.log('椤甸潰鍙傛暟:', JSON.stringify(options)); + // 鑾峰彇浼犻�掔殑鎶藉鏈轰細ID + if (options.id) { + this.prizeId = options.id; + this.getPrizeDetail(options.id); + } else if(options.q){ + // 鍙岄噸瑙g爜锛氬井淇″URL杩涜浜嗕袱娆$紪鐮� + const decodedUrl = decodeURIComponent(decodeURIComponent(options.q)); + console.log('鍘熷URL:', decodedUrl); + + // 瑙f瀽URL涓殑鏌ヨ鍙傛暟 + const params = this.parseUrlParams(decodedUrl); + this.prizeId = params.id; + this.getPrizeDetail(this.prizeId); + } else { + this.$u.toast('鍙傛暟閿欒'); + } + }, + methods: { + // 瑙f瀽URL鍙傛暟 + parseUrlParams(url) { + const params = {}; + // 澶勭悊鍙兘瀛樺湪鐨刪ash锛堝鏋滄湁鐨勮瘽锛� + 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; + }, + + // 鏍煎紡鍖栨棩鏈� + formatDate(dateStr) { + if (!dateStr) return ''; + // 澶勭悊甯︽椂鍖虹殑鏃堕棿鏍煎紡 + const date = new Date(dateStr); + if (isNaN(date.getTime())) { + // 濡傛灉鏃ユ湡瑙f瀽澶辫触锛岃繑鍥炲師濮嬪瓧绗︿覆鐨勬棩鏈熼儴鍒� + return dateStr.split('T')[0]; + } + // 鏍煎紡鍖栦负 YYYY-MM-DD + 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}`; + }, + + // 鑾峰彇鎶藉鏈轰細璇︽儏 + async getPrizeDetail(prizeId) { + uni.showLoading({ + title: '鍔犺浇涓�...' + }); + + try { + console.log('璇锋眰濂栧搧璇︽儏锛孖D:', prizeId); + const res = await getStorePrize(prizeId); + console.log('鎺ュ彛杩斿洖鏁版嵁:', JSON.stringify(res)); + + if (res.statusCode === 200) { + // 鏍规嵁浣犳彁渚涚殑鎺ュ彛鏁版嵁缁撴瀯澶勭悊 + if (res.data && res.data.code === 200 && res.data.data) { + this.prizeInfo = { + ...this.prizeInfo, + ...res.data.data, + // 纭繚瀛楁鏄犲皠姝g‘ + id: res.data.data.id || "", + storeId: res.data.data.storeId || "", + storeName: res.data.data.storeName || "榛樿搴楅摵", + activityName: res.data.data.activityName || "鎶藉娲诲姩", + prizeName: res.data.data.prizeName || "鎶藉鏈轰細", + prizeNo: res.data.data.no || "", + activityDes: res.data.data.activityDes || "鑾峰緱涓�娆℃娊濂栨満浼氾紝鍙湪鎸囧畾娲诲姩涓娇鐢�", + prizeDesc: res.data.data.prizeDesc || "鑾峰緱涓�娆℃娊濂栨満浼氾紝鍙湪鎸囧畾娲诲姩涓娇鐢�", + beginTime: res.data.data.beginTime || res.data.data.startTime || "", + endTime: res.data.data.endTime || "", + activityCover: res.data.data.activityCover || "", + enableStatus: res.data.data.enableStatus || "ON", + claimStatus: "NOT_CLAIM" // 榛樿涓烘湭棰嗗彇鐘舵�� + }; + console.log('璁剧疆鍚庣殑prizeInfo:', JSON.stringify(this.prizeInfo)); + } else { + this.$u.toast(res.data.message || '鑾峰彇鎶藉鏈轰細璇︽儏澶辫触'); + } + } else { + this.$u.toast(res.data.message); + } + } catch (err) { + this.$u.toast('鑾峰彇鎶藉鏈轰細璇︽儏澶辫触锛岃绋嶅悗閲嶈瘯'); + console.error('鑾峰彇鎶藉鏈轰細璇︽儏澶辫触:', err.message); + } finally { + uni.hideLoading(); + } + }, + + // 棰嗗彇鎶藉鏈轰細 + async claimPrize() { + if (this.prizeInfo.claimStatus !== 'NOT_CLAIM') { + this.$u.toast('璇ユ娊濂栨満浼氭棤娉曢鍙�'); + return; + } + + // 纭棰嗗彇 + uni.showModal({ + title: '鎻愮ず', + content: `纭畾瑕侀鍙�"${this.prizeInfo.activityName || this.prizeInfo.prizeName || '鏈鎶藉鏈轰細'}"鍚楋紵`, + success: (res) => { + if (res.confirm) { + this.doClaimPrize(); + } + } + }); + }, + + // 鎵ц棰嗗彇鎶藉鏈轰細鎿嶄綔 + async doClaimPrize() { + this.loading = true; + try { + // 璋冪敤棰嗗彇鎶藉鏈轰細鎺ュ彛 + const res = await claimPrize(this.prizeId); + console.log('棰嗗彇鎺ュ彛杩斿洖:', JSON.stringify(res)); + + // 鏍规嵁鎺ュ彛杩斿洖澶勭悊缁撴灉 + if (res.statusCode === 200) { + // 妫�鏌ヨ繑鍥炵殑鏁版嵁缁撴瀯 + if (res.data && res.data.code === 200) { + this.$u.toast('棰嗗彇鎴愬姛'); + this.prizeInfo.claimStatus = 'CLAIM'; + + // 寤惰繜杩斿洖涓婁竴椤碉紝璁╃敤鎴风湅鍒伴鍙栨垚鍔熺殑鎻愮ず + setTimeout(() => { + uni.navigateBack(); + }, 1500); + } else { + this.$u.toast(res.data.message || '棰嗗彇澶辫触'); + } + } else { + this.$u.toast('棰嗗彇澶辫触: ' + (res.data.message || '鏈煡閿欒')); + } + } catch (err) { + this.$u.toast('棰嗗彇澶辫触锛岃绋嶅悗閲嶈瘯'); + console.error('棰嗗彇鎶藉鏈轰細澶辫触:', err.message); + } finally { + this.loading = false; + } + } + } + } +</script> + +<style lang="scss" scoped> +.container { + background-color: #f5f5f5; + min-height: 100vh; +} + +.prize-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; +} + +.cover-image { + margin-bottom: 30rpx; +} + +.prize-title { + margin-bottom: 30rpx; + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.title { + font-size: 36rpx; + font-weight: bold; + color: #333; +} + +.prize-desc { + margin-bottom: 30rpx; +} + +.desc { + font-size: 28rpx; + color: #666; +} + +.prize-rule { + margin-bottom: 30rpx; +} + +.rule-title { + font-size: 28rpx; + color: #333; + font-weight: bold; +} + +.rule-content { + font-size: 26rpx; + color: #666; +} + +.prize-time { + display: flex; + align-items: center; + margin-bottom: 20rpx; +} + +.time-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> \ No newline at end of file -- Gitblit v1.8.0