Browse Source

苹果内购

ck@123911.net 1 tuần trước cách đây
mục cha
commit
46bb00d975

+ 364 - 361
pages/makedetail/intelligentLifeChart.vue

@@ -73,7 +73,7 @@
 				<view class="bom-box-bg">
 					<c-lottie ref="cLottieRef" :src='"/static/lottie/xiaomeng.json"' class="icon-img" height="108rpx"
 						width="112rpx" :loop="true" :autoPlay="false"></c-lottie>
-						
+
 				</view>
 				<!-- 底部输入区 -->
 				<view class="input-bar">
@@ -105,406 +105,409 @@
 	</view>
 </template>
 <script>
-import websocket from '@/common/websocket.js';
-
-export default {
-	data() {
-		return {
-			question: '',
-			answer: '',
-			displayText: '',
-			isComplete: false,
-			isLoading: false,
-			error: null,
-			retryCount: 0,
-			maxRetries: 3,
-			timer: null,
-			lastResponseTime: 0,
-			timeout: 30000,
-			typingSpeed: 50,
-			messages: [],
-			lastAiIndex: -1,
-			keyboardHeight: 0,
-			statusBarHeight: 0,
-			windowBottom: 0,
-			toView: '',
-			showToBottomBtn: false,
-			textareaHeight: 0,
-			isConnected: false,
-			isStartGenerating: false,
-			countdown: 0,
-		};
-	},
-	methods: {
-		scrollToBottom() {
-			this.toView = '';
-			this.$nextTick(() => {
-				this.toView = 'bottom-anchor';
-			});
+	import websocket from '@/common/websocket.js';
+
+	export default {
+		data() {
+			return {
+				question: '',
+				answer: '',
+				displayText: '',
+				isComplete: false,
+				isLoading: false,
+				error: null,
+				retryCount: 0,
+				maxRetries: 3,
+				timer: null,
+				lastResponseTime: 0,
+				timeout: 30000,
+				typingSpeed: 50,
+				messages: [],
+				lastAiIndex: -1,
+				keyboardHeight: 0,
+				statusBarHeight: 0,
+				windowBottom: 0,
+				toView: '',
+				showToBottomBtn: false,
+				textareaHeight: 0,
+				isConnected: false,
+				isStartGenerating: false,
+				countdown: 0,
+			};
 		},
-		async initWebSocket() {
-			if (this.isConnected) return;
-
-			try {
-				await websocket.connect('wss://e.zhichao.art/Gapi/Work/streamAnswer', {
-					uuid: getApp().globalData.uuid
+		methods: {
+			scrollToBottom() {
+				this.toView = '';
+				this.$nextTick(() => {
+					this.toView = 'bottom-anchor';
 				});
+			},
+			async initWebSocket() {
+				if (this.isConnected) return;
 
-				this.isConnected = true;
-
-				// 设置消息处理回调
-				websocket.onMessage((data) => {
-					console.log("data:", data);
-					if (this.isLoading) {
-						if (data.includes('[DONE]')) {
-							this.completeAnswer();
-						} else if (data == 'PING' || data == 'PONG') {
-							// 心跳消息   忽略
-						} else if (data.includes('ID:')) {
-							// 提取ID
-							const aiMsg = this.messages[this.lastAiIndex];
-							if (aiMsg) {
-								aiMsg.startGeneratingId = data.split(':')[1];
-							}
-						} else if (data.includes('OKOKOK')) {
-							const aiMsg = this.messages[this.lastAiIndex];
-							if (aiMsg) {
-								aiMsg.isStartGenerating = true;
-							}
-							this.isStartGenerating = true;
-							this.countdownFun(20);
-						} else {
-							const aiMsg = this.messages[this.lastAiIndex];
-							if (aiMsg) {
-								aiMsg.isStartGenerating = false;
-								this.displayText += data;
-								this.answer += data;
-								aiMsg.content += data;
-								this.retryCount = 0;
-								this.lastResponseTime = Date.now();
-								this.scrollToBottom();
+				try {
+					await websocket.connect('wss://e.zhichao.art/Gapi/Work/streamAnswer', {
+						uuid: getApp().globalData.uuid
+					});
+
+					this.isConnected = true;
+
+					// 设置消息处理回调
+					websocket.onMessage((data) => {
+						console.log("data:", data);
+						if (this.isLoading) {
+							if (data.includes('[DONE]')) {
+								this.completeAnswer();
+							} else if (data == 'PING' || data == 'PONG') {
+								// 心跳消息   忽略
+							} else if (data.includes('ID:')) {
+								// 提取ID
+								const aiMsg = this.messages[this.lastAiIndex];
+								if (aiMsg) {
+									aiMsg.startGeneratingId = data.split(':')[1];
+								}
+							} else if (data.includes('OKOKOK')) {
+								const aiMsg = this.messages[this.lastAiIndex];
+								if (aiMsg) {
+									aiMsg.isStartGenerating = true;
+								}
+								this.isStartGenerating = true;
+								this.countdownFun(20);
+							} else {
+								const aiMsg = this.messages[this.lastAiIndex];
+								if (aiMsg) {
+									aiMsg.isStartGenerating = false;
+									this.displayText += data;
+									this.answer += data;
+									aiMsg.content += data;
+									this.retryCount = 0;
+									this.lastResponseTime = Date.now();
+									this.scrollToBottom();
+								}
 							}
 						}
-					}
-				});
+					});
+
+					// 设置错误处理回调
+					websocket.onError((error) => {
+						console.error('WebSocket错误:', error);
+						this.isConnected = false;
+						this.handleError(error);
+					});
 
-				// 设置错误处理回调
-				websocket.onError((error) => {
-					console.error('WebSocket错误:', error);
+					// 设置关闭处理回调
+					websocket.onClose(() => {
+						console.log('WebSocket已关闭');
+						this.isConnected = false;
+						this.isLoading = false;
+					});
+
+				} catch (error) {
+					console.error('WebSocket初始化失败:', error);
 					this.isConnected = false;
 					this.handleError(error);
-				});
+				}
+			},
+			async startStreamAnswer(content) {
+				if (!content.trim()) {
+					uni.showToast({
+						title: '请输入问题',
+						icon: 'none'
+					});
+					return;
+				}
 
-				// 设置关闭处理回调
-				websocket.onClose(() => {
-					console.log('WebSocket已关闭');
-					this.isConnected = false;
-					this.isLoading = false;
-				});
+				// 检查连接状态,如果断开则重连
+				if (!this.isConnected) {
+					try {
+						await this.initWebSocket();
+					} catch (error) {
+						console.error('重连失败:', error);
+						uni.showToast({
+							title: '连接已断开,请重试',
+							icon: 'none'
+						});
+						return;
+					}
+				}
 
-			} catch (error) {
-				console.error('WebSocket初始化失败:', error);
-				this.isConnected = false;
-				this.handleError(error);
-			}
-		},
-		async startStreamAnswer(content) {
-			if (!content.trim()) {
-				uni.showToast({
-					title: '请输入问题',
-					icon: 'none'
+				this.resetState();
+				this.messages.push({
+					role: 'user',
+					content
 				});
-				return;
-			}
 
-			// 检查连接状态,如果断开则重连
-			if (!this.isConnected) {
 				try {
-					await this.initWebSocket();
+					this.isLoading = true;
+					let aiMsg = {
+						role: 'ai',
+						content: '',
+						isStartGenerating: false,
+						startGeneratingId: 0
+					};
+					this.messages.push(aiMsg);
+					this.lastAiIndex = this.messages.length - 1;
+
+					// 发送消息
+					websocket.send(content);
+
 				} catch (error) {
-					console.error('重连失败:', error);
+					console.error('发送消息失败:', error);
+					this.handleError(error);
+				}
+			},
+			onSend() {
+				if (!this.question.trim() || this.isLoading) return;
+				this.startStreamAnswer(this.question);
+				this.question = '';
+			},
+			resetState() {
+				this.answer = '';
+				this.displayText = '';
+				this.isComplete = false;
+				this.error = null;
+				this.retryCount = 0;
+				this.lastResponseTime = Date.now();
+			},
+			handleError(error) {
+				if (this.retryCount < this.maxRetries) {
+					this.retryCount++;
+					this.retryRequest();
+				} else {
+					this.error = '请求失败,请稍后重试';
+					this.isLoading = false;
 					uni.showToast({
-						title: '连接已断开,请重试',
+						title: this.error,
 						icon: 'none'
 					});
-					return;
 				}
-			}
-
-			this.resetState();
-			this.messages.push({ role: 'user', content });
-
-			try {
-				this.isLoading = true;
-				let aiMsg = {
-					role: 'ai',
-					content: '',
-					isStartGenerating: false,
-					startGeneratingId: 0
-				};
-				this.messages.push(aiMsg);
-				this.lastAiIndex = this.messages.length - 1;
-
-				// 发送消息
-				websocket.send(content);
-
-			} catch (error) {
-				console.error('发送消息失败:', error);
-				this.handleError(error);
-			}
-		},
-		onSend() {
-			if (!this.question.trim() || this.isLoading) return;
-			this.startStreamAnswer(this.question);
-			this.question = '';
-		},
-		resetState() {
-			this.answer = '';
-			this.displayText = '';
-			this.isComplete = false;
-			this.error = null;
-			this.retryCount = 0;
-			this.lastResponseTime = Date.now();
-		},
-		handleError(error) {
-			if (this.retryCount < this.maxRetries) {
-				this.retryCount++;
-				this.retryRequest();
-			} else {
-				this.error = '请求失败,请稍后重试';
-				this.isLoading = false;
+			},
+			retryRequest() {
 				uni.showToast({
-					title: this.error,
+					title: `正在重试 (${this.retryCount}/${this.maxRetries})`,
 					icon: 'none'
 				});
-			}
-		},
-		retryRequest() {
-			uni.showToast({
-				title: `正在重试 (${this.retryCount}/${this.maxRetries})`,
-				icon: 'none'
-			});
-			setTimeout(() => {
-				this.startStreamAnswer(this.question);
-			}, 1000 * this.retryCount);
-		},
-		completeAnswer() {
-			this.isComplete = true;
-			this.isLoading = false;
-		},
-		stopStreamAnswer() {
-			if (this.timer) {
-				clearTimeout(this.timer);
-				this.timer = null;
-			}
-			this.isLoading = false;
-		},
-		checkTimeout() {
-			if (Date.now() - this.lastResponseTime > this.timeout) {
-				this.handleError(new Error('请求超时'));
-			}
-		},
+				setTimeout(() => {
+					this.startStreamAnswer(this.question);
+				}, 1000 * this.retryCount);
+			},
+			completeAnswer() {
+				this.isComplete = true;
+				this.isLoading = false;
+			},
+			stopStreamAnswer() {
+				if (this.timer) {
+					clearTimeout(this.timer);
+					this.timer = null;
+				}
+				this.isLoading = false;
+			},
+			checkTimeout() {
+				if (Date.now() - this.lastResponseTime > this.timeout) {
+					this.handleError(new Error('请求超时'));
+				}
+			},
 
-		goBack() {
-			uni.navigateBack({
-				delta: 1
-			});
-		},
-		onChatScroll(e) {
-			const threshold = 600; // 离底部100px以内不显示按钮
-			const {
-				scrollHeight,
-				scrollTop
-			} = e.detail;
-			const clientHeight = e.detail.clientHeight || e.detail.height || 0;
-			if (scrollHeight - scrollTop - clientHeight > threshold) {
-				this.showToBottomBtn = true;
-			} else {
-				this.showToBottomBtn = false;
-			}
-		},
-		onTextareaInput(e) {
-			console.log(e.detail);
-
-			// 获取textarea的实际高度
-			const query = uni.createSelectorQuery().in(this);
-			query.select('.input-box').boundingClientRect(data => {
-				if (data) {
-					// 将px转换为rpx (假设设计稿是750rpx宽度)
-					const height = (data.height * 750) / uni.getSystemInfoSync().windowWidth;
-					// 减去基础高度90rpx,得到额外增加的高度
-					this.textareaHeight = Math.max(0, height - 90);
-					// 滚动到底部
-					this.scrollToBottom();
+			goBack() {
+				uni.navigateBack({
+					delta: 1
+				});
+			},
+			onChatScroll(e) {
+				const threshold = 600; // 离底部100px以内不显示按钮
+				const {
+					scrollHeight,
+					scrollTop
+				} = e.detail;
+				const clientHeight = e.detail.clientHeight || e.detail.height || 0;
+				if (scrollHeight - scrollTop - clientHeight > threshold) {
+					this.showToBottomBtn = true;
+				} else {
+					this.showToBottomBtn = false;
 				}
-			}).exec();
-		},
-		retrieveHistoricalRecords() {
-			uni.request({
-				url: this.$apiHost + '/Work/streamAnswerLast',
-				method: 'GET',
-				header: {
-					'content-type': 'application/json',
-					'sign': getApp().globalData.headerSign
-				},
-				data: {
-					uuid: getApp().globalData.uuid,
-					task_type: 2
-				},
-				success: (res) => {
-					console.log("获取历史记录:", res.data.list);
-					if (res.data.success === "yes" && res.data.list) {
-						this.messages = res.data.list
-						if (res && res.data && res.data.list && res.data.list.length > 0) {
-							this.showToBottomBtn = true
+			},
+			onTextareaInput(e) {
+				console.log(e.detail);
+
+				// 获取textarea的实际高度
+				const query = uni.createSelectorQuery().in(this);
+				query.select('.input-box').boundingClientRect(data => {
+					if (data) {
+						// 将px转换为rpx (假设设计稿是750rpx宽度)
+						const height = (data.height * 750) / uni.getSystemInfoSync().windowWidth;
+						// 减去基础高度90rpx,得到额外增加的高度
+						this.textareaHeight = Math.max(0, height - 90);
+						// 滚动到底部
+						this.scrollToBottom();
+					}
+				}).exec();
+			},
+			retrieveHistoricalRecords() {
+				uni.request({
+					url: this.$apiHost + '/Work/streamAnswerLast',
+					method: 'GET',
+					header: {
+						'content-type': 'application/json',
+						'sign': getApp().globalData.headerSign
+					},
+					data: {
+						uuid: getApp().globalData.uuid,
+						task_type: 2
+					},
+					success: (res) => {
+						console.log("获取历史记录:", res.data.list);
+						if (res.data.success === "yes" && res.data.list) {
+							this.messages = res.data.list
+							if (res && res.data && res.data.list && res.data.list.length > 0) {
+								this.showToBottomBtn = true
+							}
+						} else {
+							this.messages = []
 						}
-					} else {
-						this.messages = []
+					},
+					fail: (err) => {
+						console.log('获取历史记录失败', err);
+						uni.showToast({
+							title: '获取历史记录失败',
+							icon: 'none'
+						});
 					}
-				},
-				fail: (err) => {
-					console.log('获取历史记录失败', err);
-					uni.showToast({
-						title: '获取历史记录失败',
-						icon: 'none'
-					});
-				}
-			})
-		},
-		// 重新计算元素高度
-		recalculateHeights() {
-			// 重新计算textarea高度
-			const query = uni.createSelectorQuery().in(this);
-			query.select('.input-box').boundingClientRect(data => {
-				if (data) {
-					const height = (data.height * 750) / uni.getSystemInfoSync().windowWidth;
-					this.textareaHeight = Math.max(0, height - 90);
-				}
-			}).exec();
-		},
-		countdownFun(n) {
-			if (this.timer) {
-				clearInterval(this.timer);
-			}
-			this.countdown = n;
-			// 倒计时
-			this.timer = setInterval(() => {
-				this.countdown--;
-				if (this.countdown <= 0) {
+				})
+			},
+			// 重新计算元素高度
+			recalculateHeights() {
+				// 重新计算textarea高度
+				const query = uni.createSelectorQuery().in(this);
+				query.select('.input-box').boundingClientRect(data => {
+					if (data) {
+						const height = (data.height * 750) / uni.getSystemInfoSync().windowWidth;
+						this.textareaHeight = Math.max(0, height - 90);
+					}
+				}).exec();
+			},
+			countdownFun(n) {
+				if (this.timer) {
 					clearInterval(this.timer);
 				}
-			}, 1000);
-		},
-		goPage(page) {
-			uni.navigateTo({
-				url: page,
-			});
-		},
-		newChar() {
-			this.$refs["DialogBox"]
-				.confirm({
-					title: "是否创建新对话",
-					content: "立即结束当前对话内容,开启新的对话?",
-					DialogType: "inquiry",
-					btn1: "取消",
-					btn2: "确定",
-					animation: 0,
-				})
-				.then(() => {
-					websocket.send('clear');
-					this.retrieveHistoricalRecords()
+				this.countdown = n;
+				// 倒计时
+				this.timer = setInterval(() => {
+					this.countdown--;
+					if (this.countdown <= 0) {
+						clearInterval(this.timer);
+					}
+				}, 1000);
+			},
+			goPage(page) {
+				uni.navigateTo({
+					url: page,
 				});
+			},
+			newChar() {
+				this.$refs["DialogBox"]
+					.confirm({
+						title: "是否创建新对话",
+						content: "立即结束当前对话内容,开启新的对话?",
+						DialogType: "inquiry",
+						btn1: "取消",
+						btn2: "确定",
+						animation: 0,
+					})
+					.then(() => {
+						websocket.send('clear');
+						this.retrieveHistoricalRecords()
+					});
 
-		},
-		switchToNormal() {
-			this.$refs["DialogBox"]
-				.confirm({
-					title: "是否切回常规模式",
-					content: "切换至普通常规模式进行创作?",
-					DialogType: "inquiry",
-					btn1: "取消",
-					btn2: "确定",
-					animation: 0,
-				})
-				.then(() => {
-					this.goPage('/pages/makedetail/makeImgDetail')
-				});
+			},
+			switchToNormal() {
+				this.$refs["DialogBox"]
+					.confirm({
+						title: "是否切回常规模式",
+						content: "切换至普通常规模式进行创作?",
+						DialogType: "inquiry",
+						btn1: "取消",
+						btn2: "确定",
+						animation: 0,
+					})
+					.then(() => {
+						this.goPage('/pages/makedetail/makeImgDetail')
+					});
 
-		}
-	},
-	async created() {
-		await this.initWebSocket();
-		this.retrieveHistoricalRecords();
-		this.timer = setInterval(() => {
-			if (this.isLoading) {
-				this.checkTimeout();
 			}
-		}, 1000);
+		},
+		async created() {
+			await this.initWebSocket();
+			this.retrieveHistoricalRecords();
+			this.timer = setInterval(() => {
+				if (this.isLoading) {
+					this.checkTimeout();
+				}
+			}, 1000);
 
-		uni.onKeyboardHeightChange(res => {
-			this.keyboardHeight = res.height;
-			if (res.height === 0) {
-				this.$refs.cLottieRef.call('stop')
-			} else {
-				this.$refs.cLottieRef.call('play')
+			uni.onKeyboardHeightChange(res => {
+				this.keyboardHeight = res.height;
+				if (res.height === 0) {
+					this.$refs.cLottieRef.call('stop')
+				} else {
+					this.$refs.cLottieRef.call('play')
 
-			}
-			this.$nextTick(() => {
-				this.recalculateHeights();
-				this.scrollToBottom();
+				}
+				this.$nextTick(() => {
+					this.recalculateHeights();
+					this.scrollToBottom();
+				});
 			});
-		});  
 
-		const systemInfo = uni.getSystemInfoSync();
-		this.statusBarHeight = systemInfo.statusBarHeight;
-		this.windowBottom = systemInfo.safeAreaInsets ? systemInfo.safeAreaInsets.bottom : 0;
-	},
+			const systemInfo = uni.getSystemInfoSync();
+			this.statusBarHeight = systemInfo.statusBarHeight;
+			this.windowBottom = systemInfo.safeAreaInsets ? systemInfo.safeAreaInsets.bottom : 0;
+		},
 
-	beforeDestroy() {
-		websocket.close();
-		this.stopStreamAnswer();
+		beforeDestroy() {
+			websocket.close();
+			this.stopStreamAnswer();
+		}
 	}
-}
 </script>
 
 <style lang="scss">
-@import './intelligentLifeChart.scss';
-
-.to-bottom-btn {
-	position: fixed;
-	right: 50%;
-	transform: translateX(50%);
-	bottom: 20rpx;
-	width: 60rpx;
-	height: 60rpx;
-	bottom: 220rpx;
-	z-index: 999;
-	opacity: .75;
-	transition: opacity 0.2s;
-}
-
-.ai-bubble-row {
-	display: flex;
-	align-items: flex-start;
-}
-
-.ai-avatar {
-	width: 60rpx;
-	height: 60rpx;
-	border-radius: 50%;
-	margin-right: 20rpx;
-	border: solid 2rpx rgb(238, 238, 238, .3);
-	display: flex;
-	align-items: flex-end;
-	justify-content: center;
-
-	image {
-		width: 52rpx;
-		height: 52rpx;
+	@import './intelligentLifeChart.scss';
+
+	.to-bottom-btn {
+		position: fixed;
+		right: 50%;
+		transform: translateX(50%);
+		bottom: 20rpx;
+		width: 60rpx;
+		height: 60rpx;
+		bottom: 220rpx;
+		z-index: 999;
+		opacity: .75;
+		transition: opacity 0.2s;
 	}
-}
 
-.ai-bubble-content {
-	flex: 1;
-}
+	.ai-bubble-row {
+		display: flex;
+		align-items: flex-start;
+	}
+
+	.ai-avatar {
+		width: 60rpx;
+		height: 60rpx;
+		border-radius: 50%;
+		margin-right: 20rpx;
+		border: solid 2rpx rgba(238, 238, 238, .3);
+		display: flex;
+		align-items: flex-end;
+		justify-content: center;
+
+		image {
+			width: 52rpx;
+			height: 52rpx;
+		}
+	}
+
+	.ai-bubble-content {
+		flex: 1;
+	}
 </style>tyle>

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 691 - 600
pages/makedetail/intelligentMusicProduction.vue


+ 125 - 4
pages/vip/M_purchase.vue

@@ -37,11 +37,11 @@
           </view>
         </view>
 
-        <view class="jinchu">
+        <view v-if="!isIOS" class="jinchu">
           <text>{{ $t("txt.支付方式") }}</text>
         </view>
 
-        <view v-if="isWeChatPay" class="mingxiList" @click="selPay('wechat')">
+        <view v-if="isWeChatPay && !isIOS" class="mingxiList" @click="selPay('wechat')">
           <view class="left">
             <image
               class="icon"
@@ -65,7 +65,7 @@
           </view>
         </view>
         <!-- <view class="line"></view> -->
-        <view class="mingxiList" @click="selPay('alipay')">
+        <view v-if="!isIOS" class="mingxiList" @click="selPay('alipay')">
           <view class="left">
             <image
               class="icon"
@@ -151,7 +151,9 @@ export default {
         { label: '购买记录', type: 'vipRecord' }
       ],
       isSubmitting: false,
-      lastClickTime: 0
+      lastClickTime: 0,
+      isIOS: false, // 是否为iOS系统
+      currentOrderId: "" // 当前苹果内购订单ID
     };
   },
   onLoad() {
@@ -167,6 +169,7 @@ export default {
     // }, 200);
   },
   onShow() {
+    this.checkPlatform();
     this.loadData();
     let that = this;
   },
@@ -215,6 +218,12 @@ export default {
       }
       this.isSubmitting = true;
       let that = this;
+      
+      // iOS系统使用苹果内购
+      if (this.isIOS) {
+        this.submitAppleIap();
+        return;
+      }
       uni.request({
         url: this.$apiHost + "/Order/submit",
         data: {
@@ -396,6 +405,118 @@ export default {
         this.is_agree = 0;
       }
     },
+    // 检查平台类型
+    checkPlatform() {
+      const systemInfo = uni.getSystemInfoSync();
+      this.isIOS = systemInfo.platform === 'ios';
+      console.log('当前平台:', systemInfo.platform, '是否为iOS:', this.isIOS);
+    },
+    // 苹果内购提交
+    submitAppleIap() {
+      let that = this;
+      
+      // 先创建订单
+      uni.request({
+        url: this.$apiHost + "/AppleIap/submit",
+        data: {
+          uuid: getApp().globalData.uuid,
+          product_id: this.tid,
+        },
+        header: {
+          "content-type": "application/json",
+        },
+        success: (res) => {
+          console.log("苹果内购订单创建:", res.data);
+          if (res.data.success == "yes") {
+            that.currentOrderId = res.data.order_id;
+            // 调用苹果内购
+            that.requestApplePayment(res.data.apple_product_id);
+          } else {
+            uni.showToast({
+              title: res.data.msg || "创建订单失败",
+              icon: "none",
+            });
+            that.isSubmitting = false;
+          }
+        },
+        fail: (err) => {
+          console.log("创建苹果内购订单失败:", err);
+          uni.showToast({
+            title: "网络错误,请重试",
+            icon: "none"
+          });
+          that.isSubmitting = false;
+        }
+      });
+    },
+    // 调用苹果内购
+    requestApplePayment(productId) {
+      let that = this;
+      
+      // 请求苹果内购
+      uni.requestPayment({
+        provider: 'appleiap',
+        orderInfo: {
+          productId: productId
+        },
+        success: function (res) {
+          console.log('苹果内购支付成功:', res);
+          // 验证收据
+          that.verifyAppleReceipt(res.transactionReceipt, res.transactionIdentifier);
+        },
+        fail: function (err) {
+          console.log('苹果内购支付失败:', err);
+          uni.showToast({
+            title: '支付失败',
+            icon: 'none'
+          });
+          that.isSubmitting = false;
+        }
+      });
+    },
+    // 验证苹果收据
+    verifyAppleReceipt(receiptData, transactionId) {
+      let that = this;
+      
+      uni.request({
+        url: that.$apiHost + "/AppleIap/verify",
+        method: 'POST',
+        data: {
+          uuid: getApp().globalData.uuid,
+          order_id: that.currentOrderId,
+          receipt_data: receiptData,
+          transaction_id: transactionId
+        },
+        header: {
+          "content-type": "application/json",
+        },
+        success: (res) => {
+          console.log("苹果收据验证结果:", res.data);
+          if (res.data.success == "yes") {
+            uni.showToast({
+              title: "充值成功",
+              icon: "success",
+            });
+            // 刷新M币数量
+            that.loadData();
+          } else {
+            uni.showToast({
+              title: res.data.msg || "验证失败",
+              icon: "none",
+            });
+          }
+          that.isSubmitting = false;
+        },
+        fail: (err) => {
+          console.log("验证苹果收据失败:", err);
+          uni.showToast({
+            title: "验证失败,请联系客服",
+            icon: "none"
+          });
+          that.isSubmitting = false;
+        }
+      });
+    },
   },
 };
 </script>

+ 124 - 0
pages/vip/index.vue

@@ -236,6 +236,8 @@ export default {
 			linkid: '',
 			lastClickTime: 0,
 			isSubmitting: false,
+			isIOS: false, // 是否为iOS系统
+			currentOrderId: "", // 当前苹果内购订单ID
 		}
 	},
 	computed: {
@@ -243,10 +245,12 @@ export default {
 	},
 	onShow() {
 		this.isSubmitting = false;
+		this.checkPlatform(); // 检查平台类型
 	},
 	onLoad() {
 		// 获取用户信息,检查是否为VIP
 		this.getUserInfo();
+		this.checkPlatform(); // 检查平台类型
 	},
 	onReady() {
 		// 页面渲染完成后获取vip-privileges的高度
@@ -388,6 +392,13 @@ export default {
 				return;
 			}
 			this.isSubmitting = true;
+			
+			// iOS系统直接使用苹果内购
+			if (this.isIOS) {
+				this.submitAppleIap();
+				return;
+			}
+			
 			this.$refs.paymentPopup.open();
 			this.isSubmitting = false;
 		},
@@ -612,6 +623,119 @@ export default {
 				this.is_agree = 0;
 			}
 		},
+		// 检查平台类型
+		checkPlatform() {
+			const systemInfo = uni.getSystemInfoSync();
+			this.isIOS = systemInfo.platform === 'ios';
+			console.log('当前平台:', systemInfo.platform, '是否为iOS:', this.isIOS);
+		},
+		// 苹果内购提交
+		submitAppleIap() {
+			let that = this;
+			
+			// 先创建订单
+			uni.request({
+				url: this.$apiHost + "/AppleIap/submit",
+				data: {
+					uuid: getApp().globalData.uuid,
+					product_id: this.priceOptions[this.selectedPrice].id,
+					type: "buyVip",
+				},
+				header: {
+					"content-type": "application/json",
+				},
+				success: (res) => {
+					console.log("苹果内购VIP订单创建:", res.data);
+					if (res.data.success == "yes") {
+						that.currentOrderId = res.data.order_id;
+						// 调用苹果内购
+						that.requestApplePayment(res.data.apple_product_id);
+					} else {
+						uni.showToast({
+							title: res.data.msg || "创建订单失败",
+							icon: "none",
+						});
+						that.isSubmitting = false;
+					}
+				},
+				fail: (err) => {
+					console.log("创建苹果内购VIP订单失败:", err);
+					uni.showToast({
+						title: "网络错误,请重试",
+						icon: "none"
+					});
+					that.isSubmitting = false;
+				}
+			});
+		},
+		// 调用苹果内购
+		requestApplePayment(productId) {
+			let that = this;
+			
+			// 请求苹果内购
+			uni.requestPayment({
+				provider: 'appleiap',
+				orderInfo: {
+					productId: productId
+				},
+				success: function (res) {
+					console.log('苹果内购VIP支付成功:', res);
+					// 验证收据
+					that.verifyAppleReceipt(res.transactionReceipt, res.transactionIdentifier);
+				},
+				fail: function (err) {
+					console.log('苹果内购VIP支付失败:', err);
+					uni.showToast({
+						title: '支付失败',
+						icon: 'none'
+					});
+					that.isSubmitting = false;
+				}
+			});
+		},
+		// 验证苹果收据
+		verifyAppleReceipt(receiptData, transactionId) {
+			let that = this;
+			
+			uni.request({
+				url: that.$apiHost + "/AppleIap/verify",
+				method: 'POST',
+				data: {
+					uuid: getApp().globalData.uuid,
+					order_id: that.currentOrderId,
+					receipt_data: receiptData,
+					transaction_id: transactionId
+				},
+				header: {
+					"content-type": "application/json",
+				},
+				success: (res) => {
+					console.log("苹果VIP收据验证结果:", res.data);
+					if (res.data.success == "yes") {
+						uni.showToast({
+							title: "开通成功",
+							icon: "success",
+						});
+						// 刷新用户信息
+						that.getUserInfo();
+					} else {
+						uni.showToast({
+							title: res.data.msg || "验证失败",
+							icon: "none",
+						});
+					}
+					that.isSubmitting = false;
+				},
+				fail: (err) => {
+					console.log("验证苹果VIP收据失败:", err);
+					uni.showToast({
+						title: "验证失败,请联系客服",
+						icon: "none"
+					});
+					that.isSubmitting = false;
+				}
+			});
+		},
 	}
 }
 </script>

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác