dedsudiyu vor 1 Woche
Commit
6ce8b284ed

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+node_modules
+unpackage

+ 60 - 0
App.vue

@@ -0,0 +1,60 @@
+<script>
+	// import { browserDetection } from '@/utils/auth';
+	export default {
+		onLaunch: function() {
+			// console.log('App onLaunch')
+		},
+		onShow: function() {
+			// console.log('App Show')
+			// browserDetection();
+		},
+		onHide: function() {
+			// console.log('App Hide')
+		},
+	}
+</script>
+
+<style lang="stylus">
+	html,
+	body {
+		width: 100%;
+		height: 100%;
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		overflow: hidden;
+		background: #f5f5f5;
+		font-family: PingFang SC;
+		font-weight: 400;
+		font-size: 30rpx;
+		color: #333;
+
+		uni-app {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			overflow: hidden;
+
+			uni-page {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				overflow: hidden;
+
+				uni-page-wrapper {
+					flex: 1;
+					display: flex;
+					flex-direction: column;
+					overflow: hidden;
+
+					uni-page-body {
+						flex: 1;
+						display: flex;
+						flex-direction: column;
+						overflow: hidden;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 85 - 0
api/index.js

@@ -0,0 +1,85 @@
+import { apiResquest,apiResquestForm,apiResquestJsonList,apiResquestFormVideo,apiResquestTimer } from '@/api/request/request.js'
+
+
+//【调试总开关】:设为 true 使用假数据,设为 false 调用真实接口
+const USE_MOCK = true; 
+
+// 模拟后端返回的 Promise 结构(让前端调用时和真实接口完全一样)
+const mockResponse = (data) => {
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve({
+				data: {
+					code: 200,
+					message: "success",
+					data: data
+				},
+				statusCode: 200
+      });
+    }, 500); // 模拟 500毫秒 的网络延迟,让 loading 效果也能调试到
+  });
+};
+
+// 登录
+export const login = (data) => {
+  if (USE_MOCK) {
+    return mockResponse({
+			token:'123456',
+			phone:'13333333333',
+		});
+  }
+  return apiResquest({
+    url: `/demo/demo/demo1`,
+    method: 'POST',
+    data: { ...data }
+  })
+};
+
+// 获取用户信息
+export const getUserInfo = (data) => {
+  if (USE_MOCK) {
+    return mockResponse({
+      userName:'张三',
+			phone:'13333333333',
+			points:'999',
+    });
+  }
+
+  return apiResquest({
+    url: `/demo/demo/demo2`,
+    method: 'GET',
+    data: data,
+  })
+};
+
+// 获取商品信息
+export const getCommodityInfo = (data) => {
+  if (USE_MOCK) {
+    return mockResponse({
+      name:'康师傅红烧牛肉面',
+			price:'500',
+    });
+  }
+
+  return apiResquest({
+    url: `/demo/demo/demo2`,
+    method: 'GET',
+    data: data,
+  })
+};
+
+// 兑换商品
+export const exchangeGoods = (data) => {
+  if (USE_MOCK) {
+		const randomBit = Math.round(Math.random());
+    return mockResponse({
+      state:randomBit,
+    });
+  }
+
+  return apiResquest({
+    url: `/demo/demo/demo2`,
+    method: 'GET',
+    data: data,
+  })
+};

+ 6 - 0
api/request/config.js

@@ -0,0 +1,6 @@
+const config = {
+	base_url: 'https://192.168.166.11/api', //安科院
+}
+export {
+	config
+}

+ 461 - 0
api/request/request.js

@@ -0,0 +1,461 @@
+import {
+	config
+} from './config.js'
+import {
+	tansParams
+} from "./util.js";
+
+export const apiResquest = (prams) => {
+	return new Promise((resolve, reject) => {
+		let url = config.base_url + prams.url;
+		uni.showLoading({
+			title: '加载中',
+			mask: true
+		});
+		// get请求映射params参数
+		if (prams.method === 'GET' && prams.data) {
+			url = url + '?' + tansParams(prams.data);
+			url = url.slice(0, -1);
+			prams.data = {};
+		}
+
+		return uni.request({
+			timeout:10000,
+			url: url,
+			data: {
+				...prams.data
+			},
+			method: prams.method,
+			header: {
+				'content-type': 'application/json;charset=utf-8',
+				'Authorization': uni.getStorageSync('token')
+			},
+			success: (res) => {
+				// 成功
+				uni.hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code == 200) {
+						resolve(res);
+					} else if (res.data.code == 401) {
+						loginTimeout();
+					} else {
+						uni.showToast({
+							mask: true,
+							icon: "none",
+							position: "center",
+							title: res.data.message,
+							duration: 2000
+						});
+						resolve(res);
+					}
+				} else if (res.statusCode == 401) {
+					loginTimeout();
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: '连接异常,请联系管理员.',
+						duration: 2000
+					});
+					resolve(res);
+				}
+			},
+			fail: (err) => {
+				// 失败
+				uni.hideLoading()
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: '出错啦~请联系管理员!',
+					duration: 2000
+				});
+			},
+			complete: () => {
+				// 完成
+			}
+		});
+	})
+}
+
+export const apiResquestOutside = (prams) => {
+	return new Promise((resolve, reject) => {
+		let url =  prams.url;
+		uni.showLoading({
+			title: '加载中',
+			mask: true
+		});
+		// get请求映射params参数
+		if (prams.method === 'GET' && prams.data) {
+			url = url + '?' + tansParams(prams.data);
+			url = url.slice(0, -1);
+			prams.data = {};
+		}
+
+		return uni.request({
+			timeout:10000,
+			url: url,
+			data: {
+				...prams.data
+			},
+			method: prams.method,
+			header: {
+				'content-type': 'application/json;charset=utf-8',
+				'Authorization': uni.getStorageSync('token')
+			},
+			success: (res) => {
+				// 成功
+				uni.hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code == 200) {
+						resolve(res);
+					} else if (res.data.code == 401) {
+						loginTimeout();
+					} else {
+						uni.showToast({
+							mask: true,
+							icon: "none",
+							position: "center",
+							title: res.data.message,
+							duration: 2000
+						});
+						resolve(res);
+					}
+				} else if (res.statusCode == 401) {
+					loginTimeout();
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: '连接异常,请联系管理员.',
+						duration: 2000
+					});
+					resolve(res);
+				}
+			},
+			fail: (err) => {
+				// 失败
+				uni.hideLoading()
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: '出错啦~请联系管理员!',
+					duration: 2000
+				});
+			},
+			complete: () => {
+				// 完成
+			}
+		});
+	})
+}
+export const apiResquestForm = (prams) => {
+	return new Promise((resolve, reject) => {
+		let url = config.base_url + prams.url;
+		uni.showLoading({
+			title: '加载中',
+			mask: true
+		});
+		// get请求映射params参数
+		if (prams.method === 'GET' && prams.data) {
+			url = url + '?' + tansParams(prams.data);
+			url = url.slice(0, -1);
+			prams.data = {};
+		}
+		return uni.request({
+			timeout:10000,
+			url: url,
+			data: {
+				...prams.data
+			},
+			method: prams.method,
+			header: {
+				'content-type': 'application/x-www-form-urlencoded',
+				'Authorization': uni.getStorageSync('token')
+			},
+			success: (res) => {
+				// 成功
+				uni.hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code == 200) {
+						resolve(res);
+					} else if (res.data.code == 401) {
+						loginTimeout();
+					} else {
+						uni.showToast({
+							mask: true,
+							icon: "none",
+							position: "center",
+							title: res.data.message,
+							duration: 2000
+						});
+						resolve(res);
+					}
+				} else if (res.statusCode == 401) {
+					loginTimeout();
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: '连接异常,请联系管理员.',
+						duration: 2000
+					});
+					resolve(res);
+				}
+			},
+			fail: (err) => {
+				// 失败
+				uni.hideLoading()
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: '出错啦~请联系管理员!',
+					duration: 2000
+				});
+			},
+			complete: () => {
+				// 完成
+			}
+		});
+	})
+}
+export const apiResquestJsonList = (prams) => {
+	return new Promise((resolve, reject) => {
+		let url = config.base_url + prams.url;
+		uni.showLoading({
+			title: '加载中',
+			mask: true
+		});
+		// get请求映射params参数
+		if (prams.method === 'GET' && prams.data) {
+			url = url + '?' + tansParams(prams.data);
+			url = url.slice(0, -1);
+			prams.data = {};
+		}
+		return uni.request({
+			timeout:10000,
+			url: url,
+			data: prams.data,
+			method: prams.method,
+			header: {
+				'content-type': 'application/json',
+				'Authorization': uni.getStorageSync('token')
+			},
+			success: (res) => {
+				// 成功
+				uni.hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code == 200) {
+						resolve(res);
+					} else if (res.data.code == 401) {
+						loginTimeout();
+					} else {
+						uni.showToast({
+							mask: true,
+							icon: "none",
+							position: "center",
+							title: res.data.message,
+							duration: 2000
+						});
+						resolve(res);
+					}
+				} else if (res.statusCode == 401) {
+					loginTimeout();
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: '连接异常,请联系管理员.',
+						duration: 2000
+					});
+					resolve(res);
+				}
+			},
+			fail: (err) => {
+				// 失败
+				uni.hideLoading()
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: '出错啦~请联系管理员!',
+					duration: 2000
+				});
+			},
+			complete: () => {
+				// 完成
+			}
+		});
+	})
+}
+export const apiResquestFormVideo = (prams) => {
+	return new Promise((resolve, reject) => {
+		let url = uni.getStorageSync('cameraExtranetAgent') + prams.url;
+		uni.showLoading({
+			title: '加载中',
+			mask: true
+		});
+		// get请求映射params参数
+		if (prams.method === 'GET' && prams.data) {
+			url = url + '?' + tansParams(prams.data);
+			url = url.slice(0, -1);
+			prams.data = {};
+		}
+		return uni.request({
+			timeout:10000,
+			url: url,
+			data: {
+				...prams.data
+			},
+			method: prams.method,
+			header: {
+				'content-type': 'application/x-www-form-urlencoded',
+				'Authorization': uni.getStorageSync('token')
+			},
+			success: (res) => {
+				// 成功
+				uni.hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code == 200) {
+						resolve(res);
+					} else if (res.data.code == 401) {
+						loginTimeout();
+					} else {
+						uni.showToast({
+							mask: true,
+							icon: "none",
+							position: "center",
+							title: res.data.message,
+							duration: 2000
+						});
+						resolve(res);
+					}
+				} else if (res.statusCode == 401) {
+					loginTimeout();
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: '连接异常,请联系管理员.',
+						duration: 2000
+					});
+					resolve(res);
+				}
+			},
+			fail: (err) => {
+				// 失败
+				uni.hideLoading()
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: '出错啦~请联系管理员!',
+					duration: 2000
+				});
+			},
+			complete: () => {
+				// 完成
+			}
+		});
+	})
+}
+export const apiResquestTimer = (prams) => {
+	return new Promise((resolve, reject) => {
+		let url = config.base_url + prams.url;
+		// get请求映射params参数
+		if (prams.method === 'GET' && prams.data) {
+			url = url + '?' + tansParams(prams.data);
+			url = url.slice(0, -1);
+			prams.data = {};
+		}
+
+		return uni.request({
+			timeout:10000,
+			url: url,
+			data: {
+				...prams.data
+			},
+			method: prams.method,
+			header: {
+				'content-type': 'application/json;charset=utf-8',
+				'Authorization': uni.getStorageSync('token')
+			},
+			success: (res) => {
+				// 成功
+				uni.hideLoading()
+				if (res.statusCode == 200) {
+					if (res.data.code == 200) {
+						resolve(res);
+					} else if (res.data.code == 401) {
+						loginTimeout();
+					} else {
+						uni.showToast({
+							mask: true,
+							icon: "none",
+							position: "center",
+							title: res.data.message,
+							duration: 2000
+						});
+						resolve(res);
+					}
+				} else if (res.statusCode == 401) {
+					loginTimeout();
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: '连接异常,请联系管理员.',
+						duration: 2000
+					});
+					resolve(res);
+				}
+			},
+			fail: (err) => {
+				// 失败
+				uni.hideLoading()
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: '出错啦~请联系管理员!',
+					duration: 2000
+				});
+			},
+			complete: () => {
+				// 完成
+			}
+		});
+	})
+}
+//登录超时-退出至登录页面
+export function loginTimeout(params) {
+	uni.showToast({
+		mask: true,
+		icon: "none",
+		position: "center",
+		title: "登录超时,请重新登录~",
+		duration: 2000
+	});
+	uni.removeStorageSync('token');
+	uni.removeStorageSync('userId');
+	uni.removeStorageSync('userType');
+	setTimeout(function() {
+		if(uni.getStorageSync('patrolLoginType')){
+			uni.redirectTo({
+				url: '/pages/views/login/patrolLogin',
+			});
+		}else{
+			uni.redirectTo({
+				url: '/pages/views/login/login',
+			});
+		}
+	}, 2000);
+}

+ 21 - 0
api/request/util.js

@@ -0,0 +1,21 @@
+export function tansParams(params) {
+    let result = ''
+    for (const propName of Object.keys(params)) {
+        const value = params[propName];
+        var part = encodeURIComponent(propName) + "=";
+        if (value !== null && typeof (value) !== "undefined") {
+            if (typeof value === 'object') {
+                for (const key of Object.keys(value)) {
+                    if (value[key] !== null && typeof (value[key]) !== 'undefined') {
+                        let params = propName + '[' + key + ']';
+                        var subPart = encodeURIComponent(params) + "=";
+                        result += subPart + encodeURIComponent(value[key]) + "&";
+                    }
+                }
+            } else {
+                result += part + encodeURIComponent(value) + "&";
+            }
+        }
+    }
+    return result
+}

+ 20 - 0
index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+        CSS.supports('top: constant(a)'))
+      document.write(
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+    </script>
+    <title></title>
+    <!--preload-links-->
+    <!--app-context-->
+  </head>
+  <body>
+    <div id="app"><!--app-html--></div>
+    <script type="module" src="/main.js"></script>
+  </body>
+</html>

+ 22 - 0
main.js

@@ -0,0 +1,22 @@
+import App from './App'
+
+// #ifndef VUE3
+import Vue from 'vue'
+import './uni.promisify.adaptor'
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+  ...App
+})
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue'
+export function createApp() {
+  const app = createSSRApp(App)
+  return {
+    app
+  }
+}
+// #endif

+ 77 - 0
manifest.json

@@ -0,0 +1,77 @@
+{
+    "name" : "vendingMachine",
+    "appid" : "__UNI__7205E64",
+    "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
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "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\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "3",
+    "h5" : {
+        "router" : {
+            "base" : "/h5/"
+        }
+    }
+}

+ 26 - 0
package-lock.json

@@ -0,0 +1,26 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "@zxing/library": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmmirror.com/@zxing/library/-/library-0.23.0.tgz",
+      "integrity": "sha512-6fkkoFwP8CHxl6ugnPsj74PLJgX2iRv5zczGAyt5OBzQgxFhuhF0NCEc4t4OvSr8xAv2MRLlI0Iu9ZGDZQ2urA==",
+      "requires": {
+        "@zxing/text-encoding": "~0.9.0",
+        "ts-custom-error": "^3.3.1"
+      }
+    },
+    "@zxing/text-encoding": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmmirror.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
+      "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
+      "optional": true
+    },
+    "ts-custom-error": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmmirror.com/ts-custom-error/-/ts-custom-error-3.3.1.tgz",
+      "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A=="
+    }
+  }
+}

+ 44 - 0
pages.json

@@ -0,0 +1,44 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/login",
+			"style": {
+				"navigationBarTitleText": "登录"
+			}
+		},
+		{
+			"path": "pages/home",
+			"style": {
+				"navigationBarTitleText": "首页"
+			}
+		},
+		{
+			"path": "pages/commodityInfo",
+			"style": {
+				"navigationBarTitleText": "商品信息"
+			}
+		},
+		{
+			"path": "pages/scanCodePage",
+			"style": {
+				"navigationBarTitleText": "扫码"
+			}
+		},
+		{
+			"path": "pages/warning",
+			"style": {
+				"navigationBarTitleText": "提示"
+			}
+		}
+	],
+	"globalStyle": {
+		// "navigationBarTextStyle": "black",
+		// "navigationBarTitleText": "vendingMachine",
+		// "navigationBarBackgroundColor": "#F8F8F8",
+		// "backgroundColor": "#F8F8F8"
+		"navigationStyle": "custom",
+		"navigationBarTextStyle": "white", //导航文字颜色
+		"navigationBarBackgroundColor": "#0183FA" //导航背景色
+	},
+	"uniIdRouter": {}
+}

+ 243 - 0
pages/commodityInfo.vue

@@ -0,0 +1,243 @@
+<!-- 商品信息 -->
+<template>
+	<view class="commodityInfo">
+		<view class="commodityInfo-page" v-if="pageType == 1">
+			<view class="flex-null-1"></view>
+			<view class="product-content">
+				<img class="product-img" src="@/static/icon_dhli.png">
+				<view class="product-name">{{ commodityData.name }}</view>
+				<view class="product-price">
+					<text class="price-value">{{ commodityData.price?commodityData.price+' 积分':'' }}</text>
+				</view>
+			</view>
+			<view class="flex-null-2"></view>
+			<view class="clickButton" @click="clickButton()">立即兑换</view>
+			<view class="flex-null-1"></view>
+		</view>
+		<view class="commodityInfo-page" v-if="pageType == 2">
+			<img class="remind-img" v-if="state==1" src="@/static/icon_kcxq_cg.png">
+			<img class="remind-img" v-if="state!=1" src="@/static/icon_kcxq_sb.png">
+			<view class="commodity-message">{{state==1?'兑换成功':'兑换失败'}}</view>
+			<view class="flex-null-2"></view>
+			<view class="clickButton" @click="bottomButton()">{{state==1?'返回':'重试'}}</view>
+			<view class="flex-null-1"></view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		getCommodityInfo,
+		exchangeGoods
+	} from '@/api/index';
+	import { browserDetection,safeToNumber } from '@/utils/auth';
+	export default {
+		data() {
+			return {
+				pageType: '',
+				mid: "",
+				sid: "",
+				pid: "",
+				pri: "",
+				commodityData: {
+					name: '',
+					price: '',
+				},
+				state: '',
+			}
+		},
+		onLoad(option) {
+			let self = this;
+			if (option.q) {
+				let text = decodeURIComponent(option.q)
+				text = text.replace('"', '')
+				text = text.replace('"', '')
+				let list = text.split("?")[1].split("&");
+				for (let i = 0; i < list.length; i++) {
+					let newList = list[i].split("=");
+					if (newList[0] == 'mid') {
+						self.mid = newList[1];
+					} else if (newList[0] == 'sid') {
+						self.sid = newList[1];
+					} else if (newList[0] == 'pid') {
+						self.pid = newList[1];
+					} else if (newList[0] == 'pri') {
+						self.pri = newList[1];
+					}
+				}
+				this.getCommodityInfo();
+			} else {
+				uni.showToast({
+					mask: true,
+					icon: "none",
+					position: "center",
+					title: "请扫描正确的二维码",
+					duration: 2000
+				});
+				setTimeout(() => {
+					uni.navigateBack();
+				}, 2000);
+			}
+		},
+		onShow() {
+			browserDetection();
+		},
+		methods: {
+			async getCommodityInfo() {
+				let obj = {
+					token: uni.getStorageSync('token'),
+					phone: uni.getStorageSync('phone'),
+				}
+				const {
+					data
+				} = await getCommodityInfo(obj)
+				if (data.code == 200) {
+					this.$set(this, 'commodityData', data.data);
+					this.$set(this, 'pageType', 1);
+				}
+			},
+			clickButton() {
+				let self = this;
+				const numA = safeToNumber(uni.getStorageSync('points'))
+				const numB = safeToNumber(this.commodityData.price);
+				console.log('numA',numA)
+				console.log('numB',numB)
+				if(numB>numA){
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: "积分不足",
+						duration: 2000
+					});
+					return
+				}
+				
+				uni.showModal({
+					title: '提示',
+					content: '确认兑换?',
+					success: function(res) {
+						if (res.confirm) {
+							self.exchangeGoods();
+						}
+					}
+				});
+			},
+			async exchangeGoods() {
+				let obj = {
+					token: uni.getStorageSync('token'),
+					phone: uni.getStorageSync('phone'),
+					mid: this.mid,
+					sid: this.sid,
+					pid: this.pid,
+					pri: this.pri,
+				}
+				const {
+					data
+				} = await exchangeGoods(obj)
+				if (data.code == 200) {
+					this.$set(this, 'state', data.data.state);
+					this.$set(this, 'pageType', 2);
+				}
+			},
+			bottomButton(){
+				if(this.state == 1){
+					uni.redirectTo({
+						url: '/pages/home',
+					});
+				}else{
+					this.clickButton();
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="stylus" scoped>
+	.commodityInfo {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		overflow: hidden;
+		background: url(../static/back2.png);
+		background-size: 100% 100%;
+
+		.commodityInfo-page {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			overflow: hidden;
+
+			.flex-null-1 {
+				flex: 1;
+			}
+
+			.flex-null-2 {
+				flex: 4;
+			}
+
+			.product-content {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: center;
+				padding: 60rpx 0;
+				text-align: center;
+				.product-img{
+					width:200rpx;
+					height:200rpx;
+					margin:0 auto 60rpx;
+				}
+				.product-name {
+					font-size: 40rpx;
+					font-weight: 700;
+					color: #222;
+					line-height: 1.4;
+					margin-bottom: 30rpx;
+				}
+
+				.product-price {
+					font-size: 56rpx;
+					font-weight: 700;
+					color: #e74c3c;
+					text-shadow: 0 2rpx 4rpx rgba(231, 76, 60, 0.2);
+					animation: pulse 2s infinite alternate;
+				}
+
+				@keyframes pulse {
+					0% {
+						transform: scale(1);
+					}
+
+					100% {
+						transform: scale(1.02);
+					}
+				}
+			}
+
+			.clickButton {
+				width: 400rpx;
+				line-height: 100rpx;
+				background: #0183FA;
+				border-radius: 10rpx;
+				font-size: 36rpx;
+				color: #fff;
+				text-align center;
+				margin: 140rpx auto 0;
+			}
+
+			.remind-img {
+				width: 200rpx;
+				height: 200rpx;
+				margin:200rpx auto 0;
+			}
+			.commodity-message{
+				text-align: center;
+				color:#333;
+				font-size:40rpx;
+				margin-top:60rpx;
+			}
+		}
+	}
+</style>

+ 199 - 0
pages/home.vue

@@ -0,0 +1,199 @@
+<!-- 首页 -->
+<template>
+	<view class="home">
+		<view class="user-card">
+			<view class="avatar">
+				<text>{{ userData.userName ? userData.userName.charAt(0) : '?' }}</text>
+			</view>
+			<view class="user-detail">
+				<view class="user-name">{{ userData.userName || '未登录' }}</view>
+				<view class="user-phone">{{ userData.phone || '---' }}</view>
+			</view>
+			<view class="points-section">
+				<text class="points-label">当前积分</text>
+				<text class="points-value">{{ userData.points ?? 0 }}</text>
+			</view>
+		</view>
+		<view class="flex-null-1"></view>
+		<view class="scan-btn-wrapper">
+			<view class="scanCodeButton" @click="scanCode()">
+				<text class="btn-icon"></text>
+				<text class="btn-text">积分兑换</text>
+			</view>
+		</view>
+		<view class="flex-null-2"></view>
+	</view>
+</template>
+
+<script>
+	import { getUserInfo } from '@/api/index';
+	import { browserDetection } from '@/utils/auth';
+	export default {
+		data() {
+			return {
+				userData: {
+					userName: '',
+					phone: '',
+					points: '',
+				},
+			}
+		},
+		onShow() {
+			this.getUserInfo();
+			browserDetection();
+		},
+		methods: {
+			async getUserInfo() {
+				let obj = {
+					token: uni.getStorageSync('token'),
+					phone: uni.getStorageSync('phone'),
+				}
+				const {
+					data
+				} = await getUserInfo(obj)
+				if (data.code == 200) {
+					this.$set(this, 'userData', data.data);
+					uni.setStorageSync('points',data.data.points)
+				}
+			},
+			scanCode() {
+				uni.navigateTo({
+					url: "/pages/scanCodePage",
+				});
+				// let result = 'http://192.168.166.11/api/exam/points/record/exchangeMachineService?mid=2603220061&sid=6&pid=6&pri=100.00';
+				// uni.navigateTo({
+				// 	url: '/pages/commodityInfo?q=' +
+				// 		encodeURIComponent(JSON.stringify(result))
+				// });
+			}
+		}
+	}
+</script>
+
+<style lang="stylus" scoped>
+	.home {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		overflow: hidden;
+		background: #f5f7fa;
+		padding: 60rpx 40rpx;
+		box-sizing: border-box;
+		align-items: center;
+		background: url(../static/back2.png);
+		background-size: 100% 100%;
+
+		.user-card {
+			width: 500rpx;
+			background: #ffffff;
+			border-radius: 24rpx;
+			padding: 48rpx 40rpx;
+			box-shadow: 0 12rpx 30rpx rgba(0, 0, 0, 0.06);
+			display: flex;
+			align-items: center;
+			gap: 30rpx;
+			margin-bottom: 80rpx;
+
+			.avatar {
+				width: 100rpx;
+				height: 100rpx;
+				border-radius: 50%;
+				background: linear-gradient(135deg, #0183FA, #00BFFF);
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				flex-shrink: 0;
+			}
+
+			.avatar text {
+				font-size: 44rpx;
+				color: #fff;
+				font-weight: bold;
+			}
+
+			.user-detail {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				gap: 12rpx;
+
+				.user-name {
+					font-size: 36rpx;
+					font-weight: 600;
+					color: #333;
+					line-height: 1.4;
+				}
+
+				.user-phone {
+					font-size: 28rpx;
+					color: #999;
+					line-height: 1.4;
+				}
+			}
+
+
+			.points-section {
+				display: flex;
+				flex-direction: column;
+				align-items: flex-end;
+				gap: 8rpx;
+				flex-shrink: 0;
+
+				.points-label {
+					font-size: 24rpx;
+					color: #999;
+				}
+
+				.points-value {
+					font-size: 48rpx;
+					font-weight: 700;
+					color: #ff9800;
+					line-height: 1.2;
+				}
+			}
+		}
+
+		.scan-btn-wrapper {
+			width: 100%;
+			display: flex;
+			justify-content: center;
+
+			.scanCodeButton {
+				width: 480rpx;
+				height: 100rpx;
+				background: linear-gradient(135deg, #0183FA, #00a8ff);
+				border-radius: 50rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				gap: 12rpx;
+				box-shadow: 0 10rpx 24rpx rgba(1, 131, 250, 0.35);
+				transition: all 0.2s ease;
+
+				.btn-icon {
+					font-size: 36rpx;
+				}
+
+				.btn-text {
+					font-size: 34rpx;
+					color: #fff;
+					font-weight: 600;
+					letter-spacing: 2rpx;
+				}
+			}
+
+			.scanCodeButton:active {
+				transform: scale(0.96);
+				box-shadow: 0 4rpx 12rpx rgba(1, 131, 250, 0.25);
+
+			}
+		}
+
+		.flex-null-1 {
+			flex: 8;
+		}
+		.flex-null-2 {
+			flex: 1;
+		}
+	}
+</style>

+ 225 - 0
pages/login.vue

@@ -0,0 +1,225 @@
+<!-- 登录 -->
+<template>
+	<view class="login">
+		<view class="flex-null-1"></view>
+		<img class="logo-img" src="@/static/logo.png" alt="">
+		<view class="logo-text">(积分兑换)</view>
+		<view class="input-max-box">
+			<view class="input-max-box-one">
+				<view class="input-box">
+					<img src="@/static/img_log_in_account.png">
+					<input type="text" v-model="username" @confirm="login()" placeholder="请输入手机号" maxlength="30">
+				</view>
+			</view>
+			<view class="input-max-box-two">
+				<view class="input-box">
+					<img src="@/static/img_log_in_password.png">
+					<input type="password" v-model="password" @confirm="login()" placeholder="请输入密码" maxlength="30">
+				</view>
+			</view>
+			<view class="button-box" @click="login()">登录</view>
+		</view>
+		<view class="flex-null-2"></view>
+	</view>
+</template>
+
+<script>
+	import {
+		hex_md5
+	} from '@/utils/md5.js';
+	import {
+		login
+	} from '@/api/index';
+	import {
+		browserDetection
+	} from '@/utils/auth';
+	export default {
+		data() {
+			return {
+				username: "",
+				password: "",
+			}
+		},
+		onLoad() {
+
+		},
+		onShow() {
+			browserDetection();
+		},
+		methods: {
+			//登录
+			async login() {
+				let self = this;
+				if (!this.username) {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: "请输入手机号",
+						duration: 2000
+					});
+					return
+				}
+				if (!this.password) {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: "请输入密码",
+						duration: 2000
+					});
+					return
+				}
+				let obj = {
+					account: this.username,
+					password: hex_md5(this.password),
+				}
+				const {
+					data
+				} = await login(obj)
+				if (data.code == 200) {
+					uni.setStorageSync('token', data.data.token);
+					uni.setStorageSync('phone', data.data.phone);
+					uni.redirectTo({
+						url: '/pages/home',
+					});
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="stylus" scoped>
+	.login {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		overflow: hidden;
+		background: url(../static/back.png);
+		background-size: 100% 100%;
+
+		.flex-null-1 {
+			flex: 2;
+		}
+
+		.flex-null-2 {
+			flex: 3;
+		}
+
+		.logo-img {
+			width: 448rpx;
+			height: 187rpx;
+			margin: 0 auto 0;
+		}
+
+		.logo-text {
+			margin-top:40rpx;
+			/* 1. 字体设置:必须够粗 */
+			font-family: "Microsoft YaHei", "SimHei", sans-serif;
+			font-weight: 900;
+			/* 最粗 */
+			font-size: 52rpx;
+			/* 根据实际需要调整大小 */
+			letter-spacing: 2rpx;
+			color: #ffffff;
+			text-shadow:
+				-1rpx -1rpx 0 #7cb9e8,
+				1rpx -1rpx 0 #7cb9e8,
+				-1rpx 1rpx 0 #7cb9e8,
+				1rpx 1rpx 0 #7cb9e8,
+				-2rpx 0rpx 0 #7cb9e8,
+				2rpx 0rpx 0 #7cb9e8,
+				0rpx -2rpx 0 #7cb9e8,
+				0rpx 2rpx 0 #7cb9e8,
+				0rpx 0rpx 4rpx rgba(124, 185, 232, 0.6);
+			padding: 15rpx 40rpx;
+			display: inline-block;
+			text-align: center;
+		}
+
+		.input-max-box {
+
+			.input-max-box-one {
+				overflow: hidden;
+				// margin-top: 68rpx;
+
+				.input-box {
+					display flex;
+					width: 600rpx;
+					height: 80rpx;
+					border: 1rpx solid #0183FA;
+					border-radius: 40rpx;
+					margin: 147rpx auto 0;
+
+					img {
+						width: 28rpx;
+						height: 32rpx;
+						margin: 24rpx 31rpx;
+					}
+
+					input {
+						flex: 1;
+						font-size: 24rpx;
+						height: 80rpx;
+						line-height: 80rpx;
+						margin-right: 31rpx;
+					}
+				}
+
+				.text-box {
+					height: 59rpx;
+					line-height: 59rpx;
+					color: #DC1616;
+					font-size: 24rpx;
+					margin-left: 102rpx;
+				}
+			}
+
+			.input-max-box-two {
+				margin-top: 40rpx;
+
+				.input-box {
+					display flex;
+					width: 600rpx;
+					height: 80rpx;
+					border: 1rpx solid #0183FA;
+					border-radius: 40rpx;
+					margin: 0 auto 0;
+
+					img {
+						width: 30rpx;
+						height: 32rpx;
+						margin: 24rpx 30rpx;
+					}
+
+					input {
+						flex: 1;
+						font-size: 24rpx;
+						height: 80rpx;
+						line-height: 80rpx;
+						margin-right: 31rpx;
+					}
+				}
+
+				.text-box {
+					height: 59rpx;
+					line-height: 59rpx;
+					color: #DC1616;
+					font-size: 24rpx;
+					margin-left: 102rpx;
+				}
+			}
+		}
+
+		.button-box {
+			width: 600rpx;
+			line-height: 80rpx;
+			background: #0183FA;
+			border-radius: 40rpx;
+			font-size: 36rpx;
+			color: #fff;
+			text-align center;
+			margin: 140rpx auto 0;
+		}
+	}
+</style>

+ 217 - 0
pages/scanCodePage.vue

@@ -0,0 +1,217 @@
+<!-- H5 扫码页面 -->
+<template>
+	<view class="scanCodePage">
+		<video id="video-canvas" autoplay :controls="false"></video>
+		<!-- 扫码遮罩层(中间镂空) -->
+		<view class="scan-overlay">
+			<!-- 扫码框 -->
+			<view class="scan-frame">
+				<!-- 四角标记线 -->
+				<view class="corner top-left"></view>
+				<view class="corner top-right"></view>
+				<view class="corner bottom-left"></view>
+				<view class="corner bottom-right"></view>
+				<!-- 扫描动画线 -->
+				<view class="scan-line"></view>
+			</view>
+			<!-- 提示文字 -->
+			<text class="scan-tip">将二维码放入框内,即可自动扫描</text>
+		</view>
+	</view>
+</template>
+<script>
+	import {
+		BrowserMultiFormatReader
+	} from '@zxing/library';
+	export default {
+		data() {
+			return {
+				codeReader: null,
+				deviceId: null,
+			}
+		},
+		mounted() {
+			this.initScanner();
+		},
+		methods: {
+			async initScanner() {
+				let self = this;
+				const videoDom = document.getElementById('video-canvas').getElementsByTagName('video')[0];
+				videoDom.id = 'zxing-video';
+				this.codeReader = new BrowserMultiFormatReader();
+				try {
+					const devices = await this.codeReader.listVideoInputDevices();
+					this.deviceId = devices[devices.length - 1].deviceId;
+					this.startScanning();
+				} catch (err) {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: "请启用摄像头权限",
+						duration: 2000
+					});
+					setTimeout(() => {
+						uni.navigateBack();
+					}, 2000);
+				}
+			},
+			startScanning() {
+				let self = this;
+				this.codeReader.decodeFromVideoDevice(
+					this.deviceId,
+					'zxing-video',
+					(result, err) => {
+						if (result) {
+							self.codeReader.reset();
+							self.inspectCode(result.text);
+						}
+					}
+				);
+			},
+			inspectCode(result) {
+				if (result.indexOf('mid') != -1 &&
+					result.indexOf('sid') != -1 &&
+					result.indexOf('pid') != -1 &&
+					result.indexOf('pri') != -1) {
+					this.getCommodityInfo(result);
+				} else {
+					uni.showToast({
+						mask: true,
+						icon: "none",
+						position: "center",
+						title: "请扫描正确的二维码",
+						duration: 2000
+					});
+					setTimeout(() => {
+						uni.navigateBack();
+					}, 2000);
+				}
+			},
+			getCommodityInfo(result) {
+				uni.navigateTo({
+					url: '/pages/commodityInfo?q=' +
+						encodeURIComponent(JSON.stringify(result))
+				});
+			},
+		},
+		beforeDestroy() {
+			this.codeReader?.reset();
+		}
+	}
+</script>
+<style lang="stylus" scoped>
+	.scanCodePage {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		overflow: hidden;
+
+		::v-deep #video-canvas {
+			height: 100%;
+			width: 100%;
+
+			.uni-video-cover {
+				display: none;
+			}
+		}
+		.scan-overlay {
+		  position: absolute;
+		  top: 0;
+		  left: 0;
+		  width: 100%;
+		  height: 100%;
+		  z-index: 2;
+		  display: flex;
+		  flex-direction: column;
+		  align-items: center;
+		  justify-content: center;
+		  background: rgba(0, 0, 0, 0.6);
+		  clip-path: polygon(
+		    0% 0%, 100% 0%, 100% 100%, 0% 100%,
+		    0% calc(50% - 240rpx),
+		    calc(50% - 240rpx) calc(50% - 240rpx),
+		    calc(50% - 240rpx) calc(50% + 240rpx),
+		    calc(50% + 240rpx) calc(50% + 240rpx),
+		    calc(50% + 240rpx) calc(50% - 240rpx),
+		    0% calc(50% - 240rpx)
+		  );
+		}
+		.scan-frame {
+		  position: absolute;
+		  width: 480rpx;
+		  height: 480rpx;
+		  border: 2rpx solid rgba(255, 255, 255, 0.3);
+		  box-sizing: border-box;
+		}
+		.corner {
+		  position: absolute;
+		  width: 36rpx;
+		  height: 36rpx;
+		  border-color: #0183FA;
+		  border-style: solid;
+		  border-width: 0;
+		}
+		
+		.top-left {
+		  top: -2rpx;
+		  left: -2rpx;
+		  border-top-width: 6rpx;
+		  border-left-width: 6rpx;
+		}
+		
+		.top-right {
+		  top: -2rpx;
+		  right: -2rpx;
+		  border-top-width: 6rpx;
+		  border-right-width: 6rpx;
+		}
+		
+		.bottom-left {
+		  bottom: -2rpx;
+		  left: -2rpx;
+		  border-bottom-width: 6rpx;
+		  border-left-width: 6rpx;
+		}
+		
+		.bottom-right {
+		  bottom: -2rpx;
+		  right: -2rpx;
+		  border-bottom-width: 6rpx;
+		  border-right-width: 6rpx;
+		}
+		.scan-line {
+		  position: absolute;
+		  top: 0;
+		  left: 20rpx;
+		  right: 20rpx;
+		  height: 3rpx;
+		  background: linear-gradient(90deg, transparent, #0183FA, transparent);
+		  animation: scan-move 2s linear infinite;
+		}
+		
+		@keyframes scan-move {
+		  0% {
+		    top: 0;
+		    opacity: 0;
+		  }
+		  10% {
+		    opacity: 1;
+		  }
+		  90% {
+		    opacity: 1;
+		  }
+		  100% {
+		    top: 100%;
+		    opacity: 0;
+		  }
+		}
+		.scan-tip {
+		  position: absolute;
+		  bottom: calc(50% - 300rpx);
+		  color: #fff;
+		  font-size: 28rpx;
+		  text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
+		}
+	}
+</style>

+ 49 - 0
pages/warning.vue

@@ -0,0 +1,49 @@
+<!-- 提示 -->
+<template>
+	<view class="warning">
+		<view class="flex-null-box-1"></view>
+		<view class="warning-text">
+			已禁止本次访问
+		</view>
+		<view class="warning-text">
+			您必须使用微信内置浏览器访问本页面!
+		</view>
+		<view class="flex-null-box-2"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="stylus" scoped>
+	.warning {
+		flex:1;
+		display: flex;
+		flex-direction: column;
+		overflow: hidden;
+		.warning-text{
+			font-size:36rpx;
+			line-height:60rpx;
+			text-align: center;
+		}
+		.flex-null-box-1{
+			flex:1;
+		}
+		.flex-null-box-2{
+			flex:2;
+		}
+	}
+</style>

BIN
static/back.png


BIN
static/back2.png


BIN
static/icon_dhli.png


BIN
static/icon_kcxq_cg.png


BIN
static/icon_kcxq_sb.png


BIN
static/icon_wd_dh@1x.png


BIN
static/icon_wd_xyf@1x.png


BIN
static/icon_ysry_ry.png


BIN
static/img_log_in_account.png


BIN
static/img_log_in_password.png


BIN
static/logo.png


+ 13 - 0
uni.promisify.adaptor.js

@@ -0,0 +1,13 @@
+uni.addInterceptor({
+  returnValue (res) {
+    if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
+      return res;
+    }
+    return new Promise((resolve, reject) => {
+      res.then((res) => {
+        if (!res) return resolve(res) 
+        return res[0] ? reject(res[0]) : resolve(res[1])
+      });
+    });
+  },
+});

+ 76 - 0
uni.scss

@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16px;
+
+/* 图片尺寸 */
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:20px;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:26px;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:15px;

+ 37 - 0
utils/auth.js

@@ -0,0 +1,37 @@
+function browserDetection() {
+	const ua = window.navigator.userAgent.toLowerCase()
+	// 检测是否包含 micromessenger 且不包含 miniprogram(排除小程序环境)
+	const isWeixin = /micromessenger/i.test(ua) && !/miniprogram/i.test(ua)
+	if (!isWeixin) {
+		uni.redirectTo({
+			url: '/pages/warning',
+		});
+	}
+}
+
+function safeToNumber(value, options = {}) {
+  const { defaultVal = NaN, allowFloat = true } = options;
+  if (typeof value !== 'string') {
+    return defaultVal;
+  }
+  const trimmed = value.trim();
+  if (trimmed === '') {
+    return defaultVal;
+  }
+  let result;
+  if (allowFloat) {
+    result = Number(trimmed);
+  } else {
+    if (/\.|e/i.test(trimmed)) {
+      return defaultVal;
+    }
+    result = parseInt(trimmed, 10);
+  }
+  if (!Number.isFinite(result)) {
+    return defaultVal;
+  }
+
+  return result;
+}
+
+export { browserDetection , safeToNumber }

Datei-Diff unterdrückt, da er zu groß ist
+ 1111 - 0
utils/md5.js