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