潘超林 2 veckor sedan
förälder
incheckning
fd3f3f49eb
7 ändrade filer med 831 tillägg och 287 borttagningar
  1. 40 0
      api/index.js
  2. 469 0
      api/request.js
  3. 2 2
      app.config.js
  4. 55 45
      manifest.json
  5. 4 4
      pages/index/index.vue
  6. 255 225
      pages/index/pay.vue
  7. 6 11
      pages/index/paySuccess.vue

+ 40 - 0
api/index.js

@@ -0,0 +1,40 @@
+import Request from "./request.js";
+let request = Request.http;
+export default {
+    // 查询店铺信息
+    getStoreInfoByScan(data) {
+        return request({
+            url: "/user/offlineOrder/getStoreInfoByScan",
+            method: "get",
+            data: data,
+        });
+    },
+    weChatH5Login(data) {
+        return request({
+            url: "/user/base/weChatH5Login",
+            method: "get",
+            data: data,
+        });
+    },
+
+    payOrder(data) {
+        return request({
+            url: "/user/offlineOrder/payOrder",
+            method: "post",
+            data: data,
+            header: {
+                'Content-Type': 'application/json'
+            }
+        });
+    },
+
+
+    byStore(data) {
+        return request({
+            url: "/user/voucher/list/byStore",
+            method: "get",
+            data: data,
+
+        });
+    },
+}

+ 469 - 0
api/request.js

@@ -0,0 +1,469 @@
+/**
+ * @Description: request 封装(支持流式请求,修复onComplete兼容性问题)
+ * @Version: 1.0.4
+ * @author: 
+ * @Date: 2025-08-25
+ */
+import { requestConfig } from '../app.config.js'
+import api from '@/api/index.js'
+// import { TextDecoder } from 'text-encoding';
+
+class Request {
+	constructor() {
+		this.isRefreshing = false; // 是否正在刷新token的标记
+		this.subscribers = []; // 缓存等待token刷新的请求
+		this.tokenKey = 'token';
+		this.refreshTokenKey = 'refresh_token';
+
+		// 绑定方法确保this上下文
+		this.http = this.http.bind(this);
+		this.streamHttp = this.streamHttp.bind(this);
+		this.refreshToken = this.refreshToken.bind(this);
+		this.buildRequestConfig = this.buildRequestConfig.bind(this);
+		this.handleError = this.handleError.bind(this);
+	}
+
+	// 获取token
+	getToken() {
+		return uni.getStorageSync(this.tokenKey);
+	}
+
+	// 获取刷新token
+	getRefreshToken() {
+		return uni.getStorageSync(this.refreshTokenKey);
+	}
+
+	// 保存token
+	saveToken(token) {
+		uni.setStorageSync(this.tokenKey, token);
+	}
+
+	// 保存刷新token
+	saveRefreshToken(refreshToken) {
+		uni.setStorageSync(this.refreshTokenKey, refreshToken);
+	}
+
+	// 清除token
+	clearToken() {
+		uni.removeStorageSync(this.tokenKey);
+		uni.removeStorageSync(this.refreshTokenKey);
+	}
+
+	// 触发用户信息刷新
+	triggerUserInfoRefresh() {
+		uni.$emit("userinfoRefresh", true);
+	}
+
+	// 添加等待token刷新的请求
+	addSubscriber(callback) {
+		this.subscribers.push(callback);
+	}
+
+	// 执行等待中的请求
+	resolveSubscribers() {
+		this.subscribers.forEach(callback => callback());
+		this.subscribers = [];
+	}
+
+	// 无感刷新token
+	async refreshToken() {
+		if (this.isRefreshing) {
+			// 如果正在刷新,返回一个Promise等待刷新完成
+			return new Promise(resolve => {
+				this.addSubscriber(() => resolve(this.http(...arguments)));
+			});
+		}
+
+		this.isRefreshing = true;
+
+		try {
+			const refreshToken = this.getRefreshToken();
+			if (!refreshToken) {
+				throw new Error('刷新令牌不存在');
+			}
+
+			const res = await api.login({
+				grant_type: 'refresh',
+				refresh_token: refreshToken,
+				client_type: 0,
+			});
+
+			if (res.code === 200) {
+				this.saveToken(`Bearer ${res.data.access_token}`);
+				this.saveRefreshToken(res.data.refresh_token);
+				this.triggerUserInfoRefresh();
+				this.resolveSubscribers();
+				return true;
+			} else {
+				throw new Error(res.msg || '令牌刷新失败');
+			}
+		} catch (error) {
+			console.error('令牌刷新错误:', error);
+			this.clearToken();
+			uni.redirectTo({
+				url:
+					"/pages/index/index?shopId=" + uni.getStorageSync('shopId'),
+			});
+			return false;
+		} finally {
+			// 延迟释放刷新标记,避免并发请求问题
+			setTimeout(() => {
+				this.isRefreshing = false;
+			}, 1000);
+		}
+	}
+
+	// 处理请求错误
+	handleError(error, param, isStream = false) {
+		if (error.code === 501) {
+			// 令牌过期,尝试刷新
+			return this.refreshToken().then(refreshed => {
+				if (refreshed) {
+					// 刷新成功后重试请求,区分普通和流式请求
+					return isStream ? this.streamHttp(param) : this.http(param);
+				}
+				throw error; // 刷新失败,抛出错误
+			});
+		}
+		throw error; // 其他错误直接抛出
+	}
+
+	// 构建请求配置
+	buildRequestConfig(param) {
+		const {
+			url,
+			method = 'GET',
+			data,
+			params,
+			header = {},
+			responseType = 'text',
+			type,
+			enableChunked,
+			timeout
+
+		} = param;
+
+		// 合并请求头
+		const headers = {
+			'Content-Type': 'application/x-www-form-urlencoded',
+			...header
+		};
+		console.log(headers);
+
+		// 添加授权信息
+		const token = this.getToken();
+		// if (token && !headers['Authorization']) {
+		// 	headers['Authorization'] = 'Bearer ' + token;
+		// }
+
+		// 流式请求需要特殊处理
+		if (param.isStream) {
+			headers['Accept'] = 'text/event-stream';
+		}
+		console.log(requestConfig);
+
+		// 构建请求URL
+		const BaseUrl = requestConfig.BaseUrl;
+		const requestUrl = BaseUrl + url;
+
+		return {
+			url: requestUrl,
+			data: data || params,
+			method,
+			dataType: 'json',
+			responseType,
+			header: headers,
+			enableChunked,
+			timeout: timeout,
+		};
+	}
+
+	// 主请求方法(普通请求)
+	http(param) {
+		return new Promise((resolve, reject) => {
+			try {
+				const requestConfig = this.buildRequestConfig(param);
+				// 从参数中获取是否显示错误提示的标志
+				const showToast = param.showToast !== undefined ? param.showToast : true;
+				let isAborted = false;
+
+				// 创建请求任务
+				const requestTask = uni.request({
+					...requestConfig,
+					success: (res) => {
+						if (isAborted) return;
+
+						// HTTP状态码检查	
+						if (res.statusCode !== 200) {
+							const error = new Error(
+								`API错误: ${res.data.error || res.statusCode}`);
+							error.response = res;
+							if (showToast) uni.$u.toast(error.message);
+							reject(error);
+							return;
+						}
+
+						// 业务逻辑错误处理
+						if (res.data.code !== 200) {
+							if (res.data.code === 501) {
+								// 令牌过期,处理刷新
+								// this.handleError({ code: 501 }, param)
+								// 	.then(refreshedRes => resolve(refreshedRes))
+								// 	.catch(err => reject(err));
+								localStorage.clear();
+								uni.reLaunch({
+									url:
+										"/pages/index/index?shopId=" + uni.getStorageSync('shopId'),
+								});	
+								localStorage.clear();
+							} else if (res.data.code === 400 && res.data.msg === '登录凭证不为空') {
+								const error = new Error(res.data.msg);
+								error.response = res;
+								localStorage.clear();
+								// if (showToast) {
+								uni.reLaunch({
+									url:
+										"/pages/index/index?shopId=" + uni.getStorageSync('shopId'),
+								});
+								// }
+								reject(error);
+							} else {
+								const error = new Error(res.data.msg || '请求失败');
+								if (showToast) uni.$u.toast(error.message);
+								reject(res);
+							}
+							return;
+						}
+
+						// 正常响应
+						resolve(res.data);
+					},
+					fail: (err) => {
+						if (isAborted) return;
+						const error = new Error('网络异常, 请检查网络连接');
+						error.originalError = err;
+						if (showToast) uni.$u.toast(error.message);
+						reject(error);
+					}
+				});
+
+				// 终止请求的方法
+				const abort = () => {
+					isAborted = true;
+					if (requestTask.abort) {
+						console.log('中断请求成功!');
+						requestTask.abort();
+					}
+					if (typeof param.onAbort === 'function') {
+						param.onAbort();
+					}
+				};
+
+				// 暴露终止方法
+				if (typeof param.onInit === 'function') {
+					param.onInit(abort);
+				}
+			} catch (error) {
+				// 统一错误处理
+				console.error('请求处理错误:', error);
+				error.isRequestError = true;
+				reject(error);
+			}
+		});
+	}
+
+	// 流式请求方法
+	streamHttp(param) {
+		return new Promise((resolve, reject) => {
+			// 标记为流式请求
+			param.isStream = true;
+			const requestConfig = this.buildRequestConfig(param);
+			const showToast = param.showToast !== undefined ? param.showToast : true;
+			let isAborted = false;
+			let complete = false;
+			let lastChunkTime = 0; // 记录最后一次接收数据的时间
+
+			// 设置超时检测,无数据传输时判断为结束
+			const timeoutInterval = 500000; // 5分钟无数据则视为结束
+			const checkTimeout = () => {
+				if (complete || isAborted) return;
+
+				const now = Date.now();
+				if (lastChunkTime > 0 && now - lastChunkTime > timeoutInterval) {
+					// 超时,视为请求完成
+					finish();
+				} else {
+					// 继续检测
+					setTimeout(checkTimeout, 1000);
+				}
+			};
+
+			// 创建请求任务
+			const requestTask = uni.request({
+				...requestConfig,
+				// 流式请求需要设置响应类型为arraybuffer
+				responseType: 'arraybuffer',
+				success: (res) => {
+					if (res.statusCode !== 200) {
+						const error = new Error(`API错误: ${res.statusCode}`);
+						error.response = res;
+						if (showToast) uni.$u.toast(error.message);
+						reject(error);
+						return;
+					}
+				},
+				fail: (err) => {
+					if (isAborted) return;
+					const error = new Error('网络异常, 请检查网络连接');
+					error.originalError = err;
+					if (showToast) uni.$u.toast(error.message);
+					reject(error);
+				}
+			});
+
+			// 处理流式数据
+			// const decoder = new TextDecoder('utf-8');
+
+			// 检查请求任务是否支持onChunkReceived方法
+			if (typeof requestTask.onChunkReceived !== 'function') {
+				reject(new Error('当前环境不支持流式请求'));
+				return;
+			}
+
+			// 监听数据块
+			requestTask.onChunkReceived((response) => {
+				if (isAborted || complete) return;
+
+				// 更新最后接收数据的时间
+				lastChunkTime = Date.now();
+
+				// 处理token过期情况
+				if (response.statusCode === 401 || (response.data && response.data.code === 501)) {
+					this.handleError({ code: 501 }, param, true)
+						.then(() => {
+							// 刷新成功后会重新发起请求,这里终止当前流
+							abort();
+						})
+						.catch(err => {
+							if (!complete) {
+								complete = true;
+								reject(err);
+							}
+						});
+					return;
+				}
+
+				// 解码二进制数据
+				const chunk = this.decodeUtf8(response.data)
+				// const chunk = decoder.decode(response.data, { stream: true });
+				// 检查是否是结束标记(根据实际后端约定调整)
+				if (chunk.includes('[DONE]') || chunk.includes('</stream>') || chunk.includes('result')) {
+					// 调用流式回调处理最后一块数据
+					if (typeof param.onChunk === 'function') {
+						param.onChunk(chunk.replace(/\[DONE\]|<\/stream>/g, ''), response);
+					}
+					finish();
+					return;
+				}
+
+				// 调用流式回调处理数据
+				if (typeof param.onChunk === 'function') {
+					param.onChunk(chunk, response);
+				}
+			});
+
+			// 监听请求头接收
+			if (typeof requestTask.onHeadersReceived === 'function') {
+				requestTask.onHeadersReceived((response) => {
+					if (response.statusCode === 200 && typeof param.onOpen === 'function') {
+						param.onOpen(response);
+						// 收到响应头后开始超时检测
+						lastChunkTime = Date.now();
+						setTimeout(checkTimeout, 1000);
+					}
+				});
+			} else {
+				// 如果不支持onHeadersReceived,直接开始超时检测
+				setTimeout(checkTimeout, 1000);
+			}
+
+			// 终止请求的方法
+			const abort = () => {
+				isAborted = true;
+				if (requestTask.abort) {
+					requestTask.abort();
+				}
+				if (typeof param.onAbort === 'function') {
+					param.onAbort();
+				}
+			};
+
+			// 完成回调
+			const finish = () => {
+				if (complete) return;
+				complete = true;
+				if (typeof param.onComplete === 'function') {
+					param.onComplete();
+				}
+				resolve();
+			};
+
+			// 暴露终止方法
+			if (typeof param.onInit === 'function') {
+				param.onInit(abort);
+			}
+		});
+	}
+	// 新增:手动实现 UTF-8 解码(替换 TextDecoder)
+	decodeUtf8(arrayBuffer) {
+		const uint8Array = new Uint8Array(arrayBuffer);
+		let str = '';
+		let i = 0;
+		const len = uint8Array.length;
+
+		while (i < len) {
+			const byte = uint8Array[i];
+			let codePoint;
+
+			// 单字节字符(0-127)
+			if (byte < 0x80) {
+				codePoint = byte;
+				i += 1;
+			}
+			// 双字节字符(128-2047)
+			else if (byte >= 0xC0 && byte < 0xE0) {
+				codePoint = ((byte & 0x1F) << 6) | (uint8Array[i + 1] & 0x3F);
+				i += 2;
+			}
+			// 三字节字符(2048-65535)
+			else if (byte >= 0xE0 && byte < 0xF0) {
+				codePoint = ((byte & 0x0F) << 12) | ((uint8Array[i + 1] & 0x3F) << 6) | (uint8Array[i + 2] & 0x3F);
+				i += 3;
+			}
+			// 四字节字符(Unicode 扩展平面)
+			else if (byte >= 0xF0 && byte < 0xF8) {
+				codePoint = ((byte & 0x07) << 18) | ((uint8Array[i + 1] & 0x3F) << 12) | ((uint8Array[i + 2] & 0x3F) << 6) | (uint8Array[i + 3] & 0x3F);
+				i += 4;
+			}
+			// 无效字节(跳过)
+			else {
+				i += 1;
+				continue;
+			}
+
+			// 处理四字节字符的代理对
+			if (codePoint <= 0xFFFF) {
+				str += String.fromCharCode(codePoint);
+			} else {
+				codePoint -= 0x10000;
+				const high = (codePoint >> 10) & 0x3FF;
+				const low = codePoint & 0x3FF;
+				str += String.fromCharCode(0xD800 + high, 0xDC00 + low);
+			}
+		}
+
+		return str;
+	}
+}
+
+export default new Request();

+ 2 - 2
app.config.js

@@ -3,8 +3,8 @@
  */
 export const requestConfig = {
 	/**接口请求地址 */
-	// BaseUrl: 'http://192.168.3.97:9001/api/',
-	BaseUrl: 'https://app.sxdirectpurchase.com/api/',
+	BaseUrl: '/api',
+	// BaseUrl: 'https://app.sxdirectpurchase.com/api/',
 	/**微信信息*/
 	/**授权回调地址 */
 	// 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理

+ 55 - 45
manifest.json

@@ -1,28 +1,28 @@
 {
-    "name" : "扫码支付",
-    "appid" : "__UNI__793C1C8",
-    "description" : "",
-    "versionName" : "1.0.0",
-    "versionCode" : "100",
-    "transformPx" : false,
+    "name": "扫码支付",
+    "appid": "__UNI__793C1C8",
+    "description": "",
+    "versionName": "1.0.0",
+    "versionCode": "100",
+    "transformPx": false,
     /* 5+App特有相关 */
-    "app-plus" : {
-        "usingComponents" : true,
-        "nvueStyleCompiler" : "uni-app",
-        "compilerVersion" : 3,
-        "splashscreen" : {
-            "alwaysShowBeforeRender" : true,
-            "waiting" : true,
-            "autoclose" : true,
-            "delay" : 0
+    "app-plus": {
+        "usingComponents": true,
+        "nvueStyleCompiler": "uni-app",
+        "compilerVersion": 3,
+        "splashscreen": {
+            "alwaysShowBeforeRender": true,
+            "waiting": true,
+            "autoclose": true,
+            "delay": 0
         },
         /* 模块配置 */
-        "modules" : {},
+        "modules": {},
         /* 应用发布信息 */
-        "distribute" : {
+        "distribute": {
             /* android打包配置 */
-            "android" : {
-                "permissions" : [
+            "android": {
+                "permissions": [
                     "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                     "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
                     "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
@@ -41,44 +41,54 @@
                 ]
             },
             /* ios打包配置 */
-            "ios" : {},
+            "ios": {},
             /* SDK配置 */
-            "sdkConfigs" : {}
+            "sdkConfigs": {}
         }
     },
     /* 快应用特有相关 */
-    "quickapp" : {},
+    "quickapp": {},
     /* 小程序特有相关 */
-    "mp-weixin" : {
-        "appid" : "",
-        "setting" : {
-            "urlCheck" : false
+    "mp-weixin": {
+        "appid": "",
+        "setting": {
+            "urlCheck": false
         },
-        "usingComponents" : true
+        "usingComponents": true
     },
-    "mp-alipay" : {
-        "usingComponents" : true
+    "mp-alipay": {
+        "usingComponents": true
     },
-    "mp-baidu" : {
-        "usingComponents" : true
+    "mp-baidu": {
+        "usingComponents": true
     },
-    "mp-toutiao" : {
-        "usingComponents" : true
+    "mp-toutiao": {
+        "usingComponents": true
     },
-    "uniStatistics" : {
-        "enable" : false
+    "uniStatistics": {
+        "enable": false
     },
-    "vueVersion" : "2",
-    "h5" : {
-        "devServer" : {
-            "host" : "0.0.0.0",
-            "port" : 80
+    "vueVersion": "2",
+    "h5": {
+        "devServer": {
+            "port": 80,
+            "disableHostCheck": true,
+            "proxy": {
+                "/api": {
+                    "target": "http://192.168.124.38:30000",
+                    "changeOrigin": true,
+                    "secure": false,
+                    "pathRewrite": {
+                        "^/api": ""
+                    }
+                }
+            },
+            "https": false
         },
-        "router" : {
-            "base" : "./",
-            "mode" : "hash"
+        "router": {
+            "base": "./",
+            "mode": "hash"
         }
     }
 }
-/* ios打包配置 *//* SDK配置 */
-
+/* ios打包配置 */ /* SDK配置 */

+ 4 - 4
pages/index/index.vue

@@ -21,8 +21,9 @@
 			<view class="agreement-wrap">
 				<u-radio-group v-model="radiovalue">
 					<u-radio value="1" size="30" name="1" iconSize="25" activeColor="#409EFF">
-						<text class="agreement-text">授权同意 <text @click="toAgreement" style="color: #1677FF;">《用户服务协议》</text> 和 <text
-								@click="toPolicy" style="color: #1677FF;">《隐私协议》</text></text>
+						<text class="agreement-text">授权同意 <text @click="toAgreement"
+								style="color: #1677FF;">《用户服务协议》</text> 和 <text @click="toPolicy"
+								style="color: #1677FF;">《隐私协议》</text></text>
 					</u-radio>
 				</u-radio-group>
 			</view>
@@ -97,8 +98,7 @@ export default {
 		},
 		wxLink() {
 			/*微信授权登录*/
-			let redirect_uri = encodeURIComponent(requestConfig.wx_redirect_uri + '?shopId=' + this.shopId + '&uid=' +
-				this.uid)
+			let redirect_uri = encodeURIComponent(requestConfig.wx_redirect_uri + '?shopId=' + this.shopId)
 			let url = `https://open.weixin.qq.com/connect/oauth2/authorize?
 							appid=${requestConfig.wx_appid}
 							&redirect_uri=${redirect_uri}

+ 255 - 225
pages/index/pay.vue

@@ -1,18 +1,18 @@
 <template>
 	<view class="login-main">
 		<view style="width: 100%">
-			<view style="width: 100%;height: 270rpx;">
-				<image class="img" src="../../static/images/payBack.png" style="width: 100%;height: 100%;"></image>
+			<view style="width: 100%; height: 270rpx">
+				<image class="img" src="../../static/images/payBack.png" style="width: 100%; height: 100%"></image>
 			</view>
 		</view>
 		<view class="main">
 			<view class="login-main-content">
-				<image class="img" :src="shopInfo.store_logo_url
-					? shopInfo.store_logo_url
+				<image class="img" :src="shopInfo.shopLogoUrl
+					? shopInfo.shopLogoUrl
 					: '/static/images/error.jpeg'
 					" mode=""></image>
 				<h4 class="shopName">
-					陕西天枢云 {{ shopInfo ? shopInfo.store_name : "" }}
+					{{ shopInfo ? shopInfo.shopName : "" }}
 				</h4>
 			</view>
 
@@ -25,10 +25,10 @@
 				</view>
 				<view class="login-contont-button">
 					<button class="btn" @click="Pay">立即支付</button>
-					<view style="padding: 0px 30rpx;">
-						<view style="margin-top: 66rpx;background: #FFF7F6;">
+					<view style="padding: 0px 30rpx">
+						<view style="margin-top: 66rpx; background: #fff7f6">
 							<u-cell-group :border="false">
-								<u-cell title="代金券折扣" value="可使用4个" :border="false"></u-cell>
+								<u-cell title="代金券折扣" value="可使用4个" :border="false" isLink @click="voucher"></u-cell>
 							</u-cell-group>
 						</view>
 
@@ -36,50 +36,53 @@
 							支付成功后,次日将有随机奖励红包以及店铺代金券,可抵现金花,AI天枢云小程序领取
 						</view>
 					</view>
-
 				</view>
 			</view>
 		</view>
-		<u-popup :zIndex="200" :overlayStyle="{ zIndex: 200 }" :show="showPhone" @close="close" @open="open"
-			:safeAreaInsetTop="true" round="20">
-			<view class="popup">
-				<view class="header">
-					<h4>绑定手机号</h4>
-					<p class="tip">注意:首次登录,需绑定手机号才可成功领取农商网红包</p>
+
+
+		<u-popup :show="showPopup" mode="bottom" :round="20">
+			<view class="coupon-popup">
+				<view class="popup-header">
+					<text class="title">店铺代金券</text>
+					<u-icon name="close" size="22" @click="showPopup = false" />
 				</view>
-				<view class="main">
-					<view style="height: 70rpx">
-						<u--input placeholder="请输入手机号" type="number" border="surround" v-model="phone"
-							style="background: #f4f4f4; height: 100%" />
-					</view>
-					<view style="margin-top: 20px; height: 70rpx">
-						<u--input placeholder="验证码" border="surround" v-model="yzm"
-							style="background: #f4f4f4; height: 100%">
-							<template slot="suffix">
-								<u-code ref="uCode" @change="codeChange" seconds="60" changeText="X秒重新获取"></u-code>
-								<!-- <u-button @tap="getCode" :text="tips" type="success" size="mini"></u-button> -->
-								<text class="yzm" @tap="getCode">{{
-									tips ? tips : "发送验证码"
-								}}</text>
-							</template>
-						</u--input>
+
+				<view class="coupon-list">
+					<view class="coupon-item" :class="item.status === 0 ? 'disabled' : 'active'"
+						v-for="(item, index) in couponList" :key="index" @click="selectCoupon(index)">
+						<view class="left">
+							<view class="tag" :class="item.type === 1 ? 'independent' : 'chain'">
+								{{ item.type === 1 ? '独立券' : '连锁券' }}
+							</view>
+							<view class="price">
+								<text class="yen">¥</text>
+								<text class="num">{{ item.price }}</text>
+								<text class="tip">{{ item.desc }}</text>
+							</view>
+							<view class="info">
+								<text>{{ item.time }}</text>
+								<text>{{ item.scope }}</text>
+							</view>
+						</view>
+						<view class="right">
+							<u-radio :checked="selectIndex === index" disabled :custom-style="radioStyle" />
+						</view>
 					</view>
 				</view>
-				<view class="footer">
-					<u-button type="primary" class="btn" text="确定" @click="submitOk"></u-button>
-				</view>
 			</view>
 		</u-popup>
+
 	</view>
 </template>
 
 <script>
+import api from "@/api/index.js";
 import { requestConfig } from "@/app.config.js";
-import axios from "axios";
 export default {
 	data() {
 		return {
-			showPhone: false,
+			showPopup: false,
 			requestConfig: requestConfig,
 			code: "",
 			appid: "",
@@ -89,230 +92,258 @@ export default {
 				fontWeight: "bold",
 				fontSize: "40px",
 			},
-			phone: "",
-			yzm: "",
-			tips: null,
 			price: null,
 			shopId: "",
 			shopInfo: {},
 			localUserInfo: {},
-			uid: "",
+			couponList: []
 		};
 	},
 	onLoad(options) {
-		this.shopId = options.shopId
-		this.uid = options.uid || ''
-		let info = localStorage.getItem('weChatUserInfo');
-		this.localUserInfo = JSON.parse(info)
+		this.shopId = options.shopId;
+		localStorage.setItem("shopId", this.shopId);
+		let info = localStorage.getItem("weChatUserInfo");
+		this.localUserInfo = JSON.parse(info);
 		if (this.localUserInfo) {
-			this.vidTokenExist()
-		} else {
 			this.getShopInfo();
+		} else {
 			this.getInfo();
 		}
 	},
 	methods: {
-		async vidTokenExist() {
-			let res = await axios.get(
-				`${requestConfig.BaseUrl}user/app/v1/user/vidTokenExist`,
-				{
-					headers: {
-						token: `${this.localUserInfo.token}`,
-					},
-				},
-			);
-			if (res.data.code == 200) {
-				this.userInfo = this.localUserInfo;
-				this.getShopInfo();
-			} else {
-				uni.$u.toast("登录已过期,请重新登录!");
-				localStorage.removeItem("weChatUserInfo");
-				setTimeout(() => {
-					uni.redirectTo({
-						url:
-							"/pages/index/index?shopId=" + this.shopId + "&uid=" + this.uid,
-					});
-				}, 1000);
-			}
+		voucher() {
+			this.showPopup = true;
+			console.log(this.showPopup);
+			// api
+			// 	.byStore({
+			// 		currPage: 1,
+			// 		pageSize: 999,
+			// 		storeId: this.shopId,
+			// 	})
+			// 	.then((res) => {
+			// 		if (res.code == 200) {
+			// 			this.couponList = res.data;
+			// 		} else {
+			// 			uni.$u.toast(res.msg);
+			// 		}
+			// 	});
 		},
-
-		validateInput(e, num) {
-			const inputTypeNum = /[^\d]/g; //数字
-			switch (num) {
-				case 1:
-					//要写nextTick 不然无效
-					this.$nextTick(() => {
-						this.listData.integral = e.replace(inputTypeNum, "");
-					});
-					break;
-			}
+		getInfo() {
+			let code = this.GetQueryString("code");
+			localStorage.removeItem("token");
+			localStorage.removeItem("weChatUserInfo");
+			api
+				.weChatH5Login({
+					code: code,
+				})
+				.then((res) => {
+					console.log(res);
+					if (res.code == 200) {
+						this.userInfo = res.data;
+						localStorage.setItem("token", this.userInfo.token);
+						localStorage.setItem(
+							"weChatUserInfo",
+							JSON.stringify(this.userInfo),
+						);
+						if (this.userInfo.bindPhoneStatus == 0) {
+							this.showPhone = true;
+						} else {
+							this.showPhone = false;
+						}
+						this.getShopInfo();
+					} else {
+						uni.$u.toast("获取微信登录信息失败,请重新登录!");
+					}
+				});
 		},
-
 		async getShopInfo() {
-			let res = await axios.get(
-				`${requestConfig.BaseUrl}user/app/v1/store/getStoreInfoByScan?shopId=${this.shopId}${this.uid ? "&uid=" + this.uid : ""}`,
-				{
-					headers: {
-						token: `${this.userInfo.token}`,
-					},
-				},
-			);
-			if (res.data.code == 200) {
-				this.shopInfo = res.data.data;
-			} else {
-				uni.$u.toast(res.data.msg);
-			}
-		},
-
-		async submitOk() {
-			if (this.phone == "") {
-				uni.$u.toast("请输入手机号");
-			} else if (this.yzm == "") {
-				uni.$u.toast("请输入验证码");
-			}
-			const res = await axios.post(
-				`${requestConfig.BaseUrl}user/app/v1/user/bindPhone?mpOpenid=${this.userInfo.mpOpenid}&phone=${this.phone}&code=${this.yzm}&unionid=${this.userInfo.unionid}`,
-			);
-			if (res.data.code == 200) {
-				uni.$u.toast("绑定手机号成功");
-				this.userInfo = res.data.data;
-				this.showPhone = false;
-				this.getShopInfo();
-			} else {
-				uni.$u.toast("绑定手机号失败!");
-			}
-		},
-		codeChange(text) {
-			this.tips = text;
-		},
-		async getCode() {
-			if (this.$refs.uCode.canGetCode) {
-				const res = await axios.post(
-					`${requestConfig.BaseUrl}third/app/v1/third/getSMSCode?phone=${this.phone}`,
-				);
-				uni.showLoading({
-					title: "正在获取验证码",
+			api
+				.getStoreInfoByScan({
+					shopId: this.shopId,
+				})
+				.then((res) => {
+					if (res.code == 200) {
+						this.shopInfo = res.data;
+					} else {
+						uni.$u.toast(res.msg);
+					}
 				});
-				setTimeout(() => {
-					uni.hideLoading();
-					uni.$u.toast("验证码已发送");
-					this.$refs.uCode.start();
-				}, 2000);
-			} else {
-				uni.$u.toast("倒计时结束后再发送");
-			}
 		},
 		async Pay() {
 			uni.showLoading({
 				title: "支付中",
 			});
-			// uni.hideLoading();
-			// window.open(`${requestConfig.redirectOpen}pages/index/paySuccess`)
-
 			if (!this.price) {
 				uni.$u.toast("请输入支付金额!");
 			}
-			let res = await axios.get(
-				`${requestConfig.BaseUrl}order/app/v1/buyer/order/createOfflineOrder
-					?shopId=${this.shopId}&price=${this.price}${this.uid ? "&uid=" + this.uid : ""}`,
-				{
-					headers: {
-						token: `${this.userInfo.token}`,
-					},
-				},
-			);
-			if (res.data.code == 200) {
-				//post请求
-				let data = {
-					orderId: res.data.data, //订单id
-					orderType: 11, //订单类型  -1--其他 2-司机保证金 3-商品交易  4-线下交易
-					payKinds: 0, //支付类型  0-微信  1-支付宝
-					payMeth: 6, //5-微信小程序支付  6-微信H5支付 7-支付宝app支付
-				};
-				const pay = await axios.post(
-					`${requestConfig.BaseUrl}order/app/v1/buyer/order/offlineOrderPay
-						`,
-					data,
-					{
-						headers: {
-							Token: `${this.userInfo.token}`,
-						},
-					},
-				);
-				if (pay.data.code == 200) {
-					let res = JSON.parse(pay.data.data.result);
-					console.log(res);
-					WeixinJSBridge.invoke(
-						"getBrandWCPayRequest",
-						{
-							// 公众号名称,由商户传入
-							appId: res.appId,
-							// 时间戳,自1970年以来的秒数
-							timeStamp: res.timeStamp,
-							// 随机串
-							nonceStr: res.nonceStr,
-							package: res.package,
-							// 微信签名方式:
-							signType: res.signType,
-							// 微信签名
-							paySign: res.paySign,
-						},
-						function (res) {
-							if (res.err_msg == "get_brand_wcpay_request:ok") {
-								// 使用以上方式判断前端返回,
-								// 微信团队郑重提示:
-								uni.hideLoading();
-								window.location.href = requestConfig.redirectOpen;
-								// res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
-							} else {
-								uni.hideLoading();
-								uni.$u.toast("支付失败!");
-							}
-						},
-					);
-				} else {
+			api
+				.payOrder({
+					shopType: this.shopInfo.shopType,
+					shopUserId: this.shopInfo.shopUserId,
+					shopId: this.shopInfo.shopId,
+					payAmount: Number(this.price),
+					payWay: 6,
+					userId: this.localUserInfo.userId
+				})
+				.then((res) => {
+					if (res.code == 200) {
+						WeixinJSBridge.invoke(
+							"getBrandWCPayRequest",
+							{
+								// 公众号名称,由商户传入
+								appId: res.data.appId,
+								// 时间戳,自1970年以来的秒数
+								timeStamp: res.data.timeStamp,
+								// 随机串
+								nonceStr: res.data.nonceStr,
+								package: res.data.package,
+								// 微信签名方式:
+								signType: res.data.signType,
+								// 微信签名
+								paySign: res.data.paySign,
+							},
+							function (res) {
+								if (res.err_msg == "get_brand_wcpay_request:ok") {
+									// 使用以上方式判断前端返回,
+									// 微信团队郑重提示:
+									uni.hideLoading();
+									// window.location.href = requestConfig.redirectOpen;
+									uni.navigateTo({
+										url: `/pages/index/paySuccess`,
+									});
+									// res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
+								} else {
+									uni.hideLoading();
+									uni.$u.toast("支付失败!");
+								}
+							},
+						);
+					} else {
+						uni.$u.toast(res.msg);
+					}
+				}).catch((err) => {
 					uni.hideLoading();
-					uni.$u.toast("支付失败!");
-				}
-			} else {
-				uni.$u.toast("线下订单创建失败!");
-			}
-		},
-		async getInfo() {
-			let code = this.GetQueryString("code");
-			const res = await axios.post(
-				`${requestConfig.BaseUrl}user/app/v1/user/weChatH5Login?code=${code}`,
-			);
-			if (res.data.code == 200) {
-				this.userInfo = res.data.data;
-				localStorage.setItem("weChatUserInfo", JSON.stringify(this.userInfo));
-				if (this.userInfo.bindPhoneStatus == 0) {
-					this.showPhone = true;
-				} else {
-					this.showPhone = false;
-					this.getShopInfo();
-				}
-			} else {
-				uni.$u.toast("获取微信登录信息失败,请重新登录!");
-				// localStorage.removeItem('weChatUserInfo');
-				// setTimeout(() => {
-				// 	uni.redirectTo({
-				// 		url: '/pages/index/index?shopId=' + this.shopId + '&uid=' + this.uid
-				// 	})
-				// }, 1000)
-			}
+					let msg = err.msg || "";
+					let errStr = msg.match(/[\u4e00-\u9fa5\/]+/)?.[0] || "支付失败";
+					uni.$u.toast(errStr);
+				});
 		},
+
 		GetQueryString(name) {
 			var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
 			var r = window.location.search.substr(1).match(reg);
 			if (r != null) return unescape(r[2]);
 			return null;
 		},
+		validateInput(e, num) {
+			const inputTypeNum = /[^\d]/g; //数字
+			// switch (num) {
+			// 	case 1:
+			// 		//要写nextTick 不然无效
+			// 		this.$nextTick(() => {
+			// 			this.price = e.replace(inputTypeNum, "");
+			// 		});
+			// 		break;
+			// }
+		},
 	},
 };
 </script>
 
 <style lang="scss">
+.coupon-popup {
+	padding: 30rpx;
+	height: 1000rpx;
+	box-sizing: border-box;
+}
+
+.popup-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	font-size: 32rpx;
+	font-weight: bold;
+	margin-bottom: 30rpx;
+}
+
+.coupon-list {
+	height: calc(100% - 100rpx);
+	overflow-y: auto;
+}
+
+.coupon-item {
+	background: #fff;
+	border-radius: 16rpx;
+	padding: 24rpx;
+	margin-bottom: 20rpx;
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	border: 2rpx solid #eee;
+}
+
+.coupon-item.active {
+	border-color: #ff4d4f;
+	background: #fffbf4;
+}
+
+.coupon-item.disabled {
+	opacity: 0.5;
+}
+
+.left {
+	flex: 1;
+}
+
+.tag {
+	font-size: 22rpx;
+	color: #fff;
+	padding: 4rpx 12rpx;
+	border-radius: 6rpx;
+	margin-bottom: 12rpx;
+}
+
+.independent {
+	background: #5c8dff;
+}
+
+.chain {
+	background: #ff7d00;
+}
+
+.price {
+	display: flex;
+	align-items: baseline;
+	margin-bottom: 12rpx;
+}
+
+.yen {
+	font-size: 28rpx;
+	color: #ff4d4f;
+}
+
+.num {
+	font-size: 44rpx;
+	font-weight: bold;
+	color: #ff4d4f;
+	margin: 0 10rpx;
+}
+
+.tip {
+	font-size: 24rpx;
+	color: #999;
+}
+
+.info {
+	font-size: 24rpx;
+	color: #999;
+	line-height: 1.6;
+}
+
+.right {
+	padding-left: 20rpx;
+}
+
 ::v-deep .u-cell__title {
 	flex: none !important;
 }
@@ -355,7 +386,7 @@ export default {
 
 		.btn {
 			width: 100%;
-			background: linear-gradient(152deg, #6F9DFD 0%, #1B71F2 100%);
+			background: linear-gradient(152deg, #6f9dfd 0%, #1b71f2 100%);
 			border-radius: 46rpx;
 			border: none;
 		}
@@ -392,7 +423,6 @@ export default {
 }
 
 .login-main {
-
 	background: url("../../static/images/payBack.png");
 	background-size: 100% 100%;
 	width: 100%;
@@ -410,7 +440,7 @@ export default {
 		margin-top: 20px;
 		width: 95%;
 		height: 90rpx;
-		background: linear-gradient(152deg, #6F9DFD 0%, #1B71F2 100%);
+		background: linear-gradient(152deg, #6f9dfd 0%, #1b71f2 100%);
 		border-radius: 44rpx;
 		color: #fff;
 	}

+ 6 - 11
pages/index/paySuccess.vue

@@ -1,16 +1,10 @@
 <template>
   <view class="login-main">
-    <image
-      src="../../static/images/success.png"
-      mode=""
-      style="width: 300px; margin-left: 25px"
-    ></image>
+    <image src="../../static/images/success.png" mode="" style="width: 300px; margin-left: 25px"></image>
     <span style="font-weight: 600; font-size: 44rpx; color: #333333">支付成功</span>
-    <view style="margin-top: 20px">
-		奖励红包,次日到账,可进入农商直采小程序查看
-    <!--  已返
-      <span style="color: red">{{ requestConfig.pay }}元</span>
-      红包,可进入农商网小程序查看 -->
+    <view style="margin-top: 20px;text-align: center;">
+      次日将有返现红包及店铺代金券,可抵现金花
+      可进入AI天枢云小程序查看
     </view>
     <view style="margin-top: 20px">
       <button class="btn">查看红包</button>
@@ -29,7 +23,7 @@ export default {
       radiovalue: 0,
     };
   },
-  onLoad() {},
+  onLoad() { },
   methods: {},
 };
 </script>
@@ -46,6 +40,7 @@ export default {
   border-radius: 44rpx;
   color: #fff;
 }
+
 .radioText {
   font-weight: 500;
   font-size: 24rpx;