Procházet zdrojové kódy

完善首页、我的页面菜单路由

wangzhiqiang před 1 měsícem
rodič
revize
76b4c94b79

+ 27 - 0
api/login.js

@@ -0,0 +1,27 @@
+import request from "../request/request"; //引入request.js
+const api = request;
+
+
+// post 请求
+export const getSmsCode = (data) => {
+	return api.request(
+		"/getSmsCode",
+		"post",
+		data
+	).then((res) => {
+		return res
+	})
+};
+
+
+
+// get请求  params(可选)
+export const getXcxUserInfoByCode = (params) => {
+	return api.request(
+		"/wxMessage/getXcxUserInfoByCode",
+		"get",
+		params
+	).then((res) => {
+		return res
+	})
+};

+ 35 - 1
main.js

@@ -1,8 +1,10 @@
 import App from './App'
 import uView from '@/uni_modules/uview-ui'
+
 import '@/static/css/fui.css'
 import '@/static/css/flex.css'
 import '@/static/css/uflex.css'
+
 // #ifndef VUE3
 import Vue from 'vue'
 import './uni.promisify.adaptor'
@@ -15,12 +17,44 @@ const app = new Vue({
 app.$mount()
 // #endif
 
+// 定义全局方法
+const navBack = (delta = 1) => {
+  uni.navigateBack({
+    delta,
+  });
+}
+
+let lastNavTime = 0;
+const navTo = (url, type = '') => {
+  const now = Date.now();
+  if (now - lastNavTime < 300) return; // 0.3秒内重复点击不跳转
+  lastNavTime = now;
+
+  const pageStackLen = getCurrentPages().length;
+
+  if (type === 'tabbar') {
+    uni.switchTab({ url });
+  } else if (type === 'redirect') {
+    uni.redirectTo({ url });
+  } else {
+    console.log('页面调用栈', getCurrentPages().length)
+    if (pageStackLen >= 9) {
+      uni.reLaunch({ url });
+    } else {
+      uni.navigateTo({ url });
+    }
+  }
+};
+
 // #ifdef VUE3
 import { createSSRApp } from 'vue'
 export function createApp() {
   const app = createSSRApp(App)
+  app.config.globalProperties.navBack = navBack
+  app.config.globalProperties.navTo = navTo
   return {
     app
   }
 }
-// #endif
+// #endif
+

+ 74 - 20
pages.json

@@ -99,6 +99,48 @@
 				"navigationBarTitleText": "我的消息"
 			}
 		},
+		{
+			"path": "pages/myTakeOrder/index",
+			"style": {
+				"navigationBarTitleText": "我的接单"
+			}
+		},
+		{
+			"path": "pages/myBounty/index",
+			"style": {
+				"navigationBarTitleText": "我的悬赏"
+			}
+		},
+		{
+			"path": "pages/inviteFriends/index",
+			"style": {
+				"navigationBarTitleText": "邀请好友"
+			}
+		},
+		{
+			"path": "pages/myTools/index",
+			"style": {
+				"navigationBarTitleText": "我的工具包"
+			}
+		},
+		{
+			"path": "pages/safeguardRights/index",
+			"style": {
+				"navigationBarTitleText": "维权"
+			}
+		},
+		{
+			"path": "pages/statisticsEarnings/index",
+			"style": {
+				"navigationBarTitleText": "收入统计"
+			}
+		},
+		{
+			"path": "pages/myShop/index",
+			"style": {
+				"navigationBarTitleText": "我的店铺"
+			}
+		},
 		{
 			"path": "pages/myMessage/chat",
 			"style": {
@@ -178,6 +220,18 @@
 				"navigationBarTitleText": "热门悬赏"
 			}
 		},
+		{
+			"path": "pages/index/newestBounty",
+			"style": {
+				"navigationBarTitleText": "最新悬赏"
+			}
+		},
+		{
+			"path": "pages/index/quickCheck",
+			"style": {
+				"navigationBarTitleText": "急速快审"
+			}
+		},
 		{
 			"path": "pages/index/inviteEarnMoney",
 			"style": {
@@ -204,25 +258,25 @@
 		"backgroundColor": "#F8F8F8"
 	},
 	"tabBar": {
-	  "color": "#A0A0A0",
-	  "selectedColor": "#FFA74F",
-	  "backgroundColor": "#fff",
-	  "borderStyle": "black",
-	  "height": "60px",
-	  "list": [
-	    {
-	      "text": "首页",
-	      "pagePath": "pages/index/index",
-	      "iconPath": "/static/tabbar/home.png",
-	      "selectedIconPath": "/static/tabbar/homeCheck.png"
-	    },
-	    {
-	      "text": "我的",
-	      "pagePath": "pages/my/index",
-	      "iconPath": "/static/tabbar/my.png",
-	      "selectedIconPath": "/static/tabbar/myCheck.png"
-	    }
-	  ]
+		"color": "#A0A0A0",
+		"selectedColor": "#FFA74F",
+		"backgroundColor": "#fff",
+		"borderStyle": "black",
+		"height": "60px",
+		"list": [
+			{
+				"text": "首页",
+				"pagePath": "pages/index/index",
+				"iconPath": "/static/tabbar/home.png",
+				"selectedIconPath": "/static/tabbar/homeCheck.png"
+			},
+			{
+				"text": "我的",
+				"pagePath": "pages/my/index",
+				"iconPath": "/static/tabbar/my.png",
+				"selectedIconPath": "/static/tabbar/myCheck.png"
+			}
+		]
 	},
 	"uniIdRouter": {}
-}
+}

+ 143 - 34
pages/index/index.vue

@@ -1,53 +1,162 @@
 <template>
-	<view class="content">
-		<image class="logo" src="/static/logo.png"></image>
-		<view class="text-area">
-			<text class="title">{{title}}</text>
-			<!-- <u-button text="月落" type="primary"></u-button> -->
+	<view class="content pdx-30">
+		<view @click="toPage('/pages/login/index')">
+			登录
+		</view>
+		<view @click="toPage('/pages/login/register')">
+			注册
+		</view>
+		<view @click="toPage('/pages/login/forget')">
+			忘记密码
+		</view>
+		<view class="w h-80 mgt-100" @click="toPage('/pages/index/search')">
+			<view class="input flex ai_center jc_between">
+				<view>任务标题、用户ID</view>
+				<image class="w-40 h-40" src="/static/logo.png" mode="scaleToFill" />
+			</view>
+		</view>
+
+		<view class="w h-300 mgy-20">
+			<u-swiper :list="list6" @change="e => currentNum = e.current" :autoplay="false"
+				indicatorStyle="right: 20px">
+				<view slot="indicator" class="indicator-num">
+					<text class="indicator-num__text">{{ currentNum + 1 }}/{{ list6.length }}</text>
+				</view>
+			</u-swiper>
+		</view>
+
+		<view class="w h-80 flex jc_between ai_center" @click="toPage('/pages/index/notice')">
+			<view class="flex ai_center">
+				<image class="w-40 h-40 mgr-30" src="/static/logo.png" mode="scaleToFill" />
+				<view>我是公告</view>
+			</view>
+			<view>2025.1.1</view>
+		</view>
+
+		<view class="w flex mgt-20 jc_between text-24">
+			<view class="flex fd_c ai_center" v-for="item in menu" :key="item.name" @click="toPage(item.pagePath)">
+				<image class="w-60 h-60" :src="item.icon" mode="scaleToFill" />
+				<view class="mgt-10">{{ item.name }}</view>
+			</view>
+		</view>
+
+		<view class="w h-200 bg-444 text-white mgy-20" @click="toPage('/pages/index/newcomerTasks')">新人任务</view>
+
+		<view class="w">
+			<view>推荐悬赏</view>
+			<view class="w mgt-20">
+				<scroll-view scroll-y>
+					<view class="flex jc_between pdy-10" v-for="item in 5">
+						<image class="w-60 h-60" src="/static/logo.png" mode="scaleToFill" />
+						<view class="flex1 mgl-10">
+							<view class="flex jc_between mgb-10">
+								<view class="flex">
+									<view>这是一条悬赏任务</view>
+									<view class="flex">
+										<view>顶</view>
+										<view>快审</view>
+										<view>热</view>
+										<view>新</view>
+									</view>
+								</view>
+								<view>+3.02元</view>
+							</view>
+							<view class="flex jc_between">
+								<view class="flex">
+									<view>671已赚</view>
+									<view></view>
+									<view>剩余21个</view>
+								</view>
+								<view>支持设备:苹果</view>
+							</view>
+						</view>
+					</view>
+				</scroll-view>
+			</view>
 		</view>
 	</view>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				title: '首页'
-			}
-		},
-		onLoad() {
+export default {
+	data() {
+		return {
+			title: '首页',
+			menu: [
+				{ icon: '/static/logo.png', name: '新手入门', pagePath: '/pages/index/gettingStarted' },
+				{ icon: '/static/logo.png', name: '热门悬赏', pagePath: '/pages/index/popularBounty' },
+				{ icon: '/static/logo.png', name: '最新悬赏', pagePath: '/pages/index/newestBounty' },
+				{ icon: '/static/logo.png', name: '急速快审', pagePath: '/pages/index/quickCheck' },
+				{ icon: '/static/logo.png', name: '邀请赚钱', pagePath: '/pages/index/inviteEarnMoney' },
+			],
+			currentNum: 0,
+			list6: [
+				"https://uviewui.com/swiper/swiper2.png",
+				"https://uviewui.com/swiper/swiper3.png",
+				"https://uviewui.com/swiper/swiper1.png",
+			],
 
-		},
-		methods: {
+		}
+	},
+	onLoad() {
 
+	},
+	methods: {
+		toPage(url) {
+			uni.navigateTo({ url });
 		}
-	}
+	},
+
+}
 </script>
 
 <style>
-	.content {
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		justify-content: center;
-	}
+.content {
+	height: calc(100vh - 120rpx);
+	/* background-color: red; */
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	/* justify-content: center; */
 
-	.logo {
-		height: 200rpx;
-		width: 200rpx;
-		margin-top: 200rpx;
-		margin-left: auto;
-		margin-right: auto;
-		margin-bottom: 50rpx;
+	.input {
+		width: 100%;
+		height: 80rpx;
+		background-color: rgb(233, 233, 233);
+		padding: 10rpx 30rpx;
+		border-radius: 40rpx;
 	}
+}
+
+.indicator {
+	@include flex(row);
+	justify-content: center;
+
+	&__dot {
+		height: 6px;
+		width: 6px;
+		border-radius: 100px;
+		background-color: rgba(255, 255, 255, 0.35);
+		margin: 0 5px;
+		transition: background-color 0.3s;
 
-	.text-area {
-		display: flex;
-		justify-content: center;
+		&--active {
+			background-color: #ffffff;
+		}
 	}
+}
+
+.indicator-num {
+	padding: 2px 0;
+	background-color: rgba(0, 0, 0, 0.35);
+	border-radius: 100px;
+	width: 35px;
+	display: flex;
+	justify-content: center;
 
-	.title {
-		font-size: 36rpx;
-		color: #8f8f94;
+	&__text {
+		color: #ffffff;
+		font-size: 12px;
 	}
+}
 </style>

+ 25 - 0
pages/index/newestBounty.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		最新悬赏
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/index/quickCheck.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		急速快审
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/inviteFriends/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		邀请好友
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 88 - 40
pages/my/index.vue

@@ -1,53 +1,101 @@
 <template>
-	<view class="content">
-		<image class="logo" src="/static/logo.png"></image>
-		<view class="text-area">
-			<text class="title">{{title}}</text>
-			<!-- <u-button text="月落" type="primary"></u-button> -->
+	<view class="content pdx-30">
+		<view class="w flex ai_center mgt-100">
+			<image class="w-100 h-100" src="/static/logo.png"></image>
+			<view class="text-32">用户名称用户名称</view>
+			<view>V年</view>
 		</view>
+
+		<view class="w flex jc_between mgy-20">
+			<view class="flex">
+				<view>v1</view>
+				<view class="mgl-10">新手上路</view>
+			</view>
+			<view class="flex">
+				<view>等级越高赚钱越多</view>
+				<view class="mgl-10">查看攻略</view>
+			</view>
+		</view>
+		<view></view>
+
+		<view class="w flex jc_center">
+			<view>
+				<view>999.99</view>
+				<view>去提现</view>
+				<view>累计收益</view>
+			</view>
+			<view>
+				<view>999.99</view>
+				<view>悬赏金额</view>
+			</view>
+		</view>
+
+		<view class="w flex jc_between mgy-20">
+			<view v-for="item in tagList" :key="item.name" @click="navTo(item.pagePath)">
+				<image class="w-100 h-100" :src="item.icon" mode="scaleToFill" />
+				<view>{{ item.name }}</view>
+			</view>
+		</view>
+
+		<view class="w flex ai_center">
+			<image src="/static/logo.png" mode="scaleToFill" />
+			<view class="mgl-10">
+				<view>发布悬赏</view>
+				<view>任务要急做?点这里快速发</view>
+			</view>
+		</view>
+
+		<view class="w mgt-20">
+			<view class="flex jc_between ai_center w pdy-10" v-for="item in menuList" :key="item.name"
+				@click="navTo(item.pagePath)">
+				<view class="flex ai_center">
+					<image class="w-40 h-40" :src="item.icon" mode="scaleToFill" />
+					<view class="mgl-10">{{ item.name }}</view>
+				</view>
+				<image class="w-40 h-40" src="/static/logo.png" mode="scaleToFill" />
+			</view>
+		</view>
+
 	</view>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				title: '我的'
-			}
-		},
-		onLoad() {
-
-		},
-		methods: {
+export default {
+	data() {
+		return {
+			title: '我的',
+			tagList: [
+				{ icon: '/static/logo.png', name: '我的接单', pagePath: '/pages/myTakeOrder/index' },
+				{ icon: '/static/logo.png', name: '我的悬赏', pagePath: '/pages/myBounty/index' },
+				{ icon: '/static/logo.png', name: '开通会员', pagePath: '/pages/activateVIP/index' },
+				{ icon: '/static/logo.png', name: '邀请好友', pagePath: '/pages/inviteFriends/index' },
+			],
+			menuList: [
+				{ icon: '/static/logo.png', name: '我的工具包', pagePath: '/pages/myTools/index' },
+				{ icon: '/static/logo.png', name: '我的消息', pagePath: '/pages/myMessage/index' },
+				{ icon: '/static/logo.png', name: '维权', pagePath: '/pages/safeguardRights/index' },
+				{ icon: '/static/logo.png', name: '收益统计', pagePath: '/pages/statisticsEarnings/index' },
+				{ icon: '/static/logo.png', name: '我的店铺', pagePath: '/pages/myShop/index' },
+				{ icon: '/static/logo.png', name: '系统设置', pagePath: '/pages/setting/index' },
+			]
+		}
+	},
+	onLoad() {
 
+	},
+	methods: {
+		navTo(url) {
+			uni.navigateTo({ url });
 		}
 	}
+}
 </script>
 
 <style>
-	.content {
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		justify-content: center;
-	}
-
-	.logo {
-		height: 200rpx;
-		width: 200rpx;
-		margin-top: 200rpx;
-		margin-left: auto;
-		margin-right: auto;
-		margin-bottom: 50rpx;
-	}
-
-	.text-area {
-		display: flex;
-		justify-content: center;
-	}
-
-	.title {
-		font-size: 36rpx;
-		color: #8f8f94;
-	}
+.content {
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: center;
+}
 </style>

+ 25 - 0
pages/myBounty/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		我的悬赏
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/myShop/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		我的店铺
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return { 
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/myTakeOrder/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		我的接单
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/myTools/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		我的工具包
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/safeguardRights/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		维权
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 25 - 0
pages/statisticsEarnings/index.vue

@@ -0,0 +1,25 @@
+<template>
+	<view class="content">
+		收入统计
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	
+</style>

+ 120 - 0
request/request.js

@@ -0,0 +1,120 @@
+/* 
+		@params url 接口地址
+		@params method 请求方式
+		@params data 参数
+ */
+let BASE_URL = ''
+// #ifdef MP-WEIXIN
+// 仅在微信小程序可用
+BASE_URL = 
+// 'https://novel.ytpm.net/pro-api'
+uni.getAccountInfoSync().miniProgram.envVersion == 'release' ? 'https://novel.ytpm.net/pro-api'
+: "https://novel.test.ytpm.net/pro-api"; // 区分正式与体验版
+// #endif
+
+// #ifdef H5
+BASE_URL = "https://novel.test.ytpm.net/pro-api"
+// BASE_URL = "http://192.168.1.89:8685"
+// #endif
+
+const WebUrl = BASE_URL.split('/pro-api')[0]
+const imgApi = BASE_URL+"/file/uploadFile"; // 上传接口
+const imgBaseApi = BASE_URL+ "/file/uploadBaseFile"
+const request = (url, method, data) => {
+  let token = uni.getStorageSync("token"); //openId
+  let header = {
+    "Content-Type": "application/json",
+	'Accept':"application/json"
+  };
+
+  if (token) {
+    header.Authorization = token;
+  }
+  return new Promise((resolve, reject) => {
+    uni.request({
+      url: BASE_URL + url, // 开发者服务器接口地址
+      method: method, //请求方式
+      timeout: 60000, //请求超时时间
+      data: data, //请求的参数
+      header: header,
+
+      success(res) {
+		  if(res.statusCode == 401){
+			  uni.showToast({
+				title: "身份验证过期,请重新登录",
+				icon: "none",
+			  });
+			  let firstView = uni.getStorageSync('firstView')
+			  uni.clearStorageSync()
+			  var pages = getCurrentPages();
+			  var page = pages[pages.length - 1];
+			  var fullpath = page.$page.fullPath
+			  uni.setStorageSync('firstView',firstView)
+			  uni.setStorageSync('tempUrl',fullpath)
+			  uni.setStorageSync('401Flag',true) // 401时用户手动点击登录
+			  setTimeout(() => {
+				uni.navigateTo({
+				  url: "/pages/login/index",
+				});
+			  }, 500);
+			  return
+		  }
+        //对请求请求到的信息进行处理
+        if (res.data.status == 200 || res.data.status == 500 || res.data.status == 0) {
+          if (res.data.description) {
+            if (res.data.data) {
+              res.data.data = res.data.data;
+            } else {
+              res.data.data = { description: "" };
+            }
+            // res.data.data.description = res.data.description;
+          }
+          resolve(res.data.data);
+          if (res.data.Authorization) {
+            // 更新 token
+            uni.setStorageSync("token", res.data.Authorization);
+          }
+        } else if (res.data.status == 403) {
+          uni.showToast({
+            title: "身份验证过期,请重新登录",
+            icon: "none",
+          });
+          setTimeout(() => {
+            uni.navigateTo({
+              url: "/pages/login/index",
+            });
+          }, 1000);
+        } else if (res.data.status == 40305) {
+          uni.showToast({
+            title: "该账号已被冻结,请联系客服",
+            icon: "none",
+          });
+          // uni.navigateTo({
+          //   url: "/pages/login/index",
+          // });
+        } else if (res.data.status == 100) {
+          uni.showToast({
+            title: res.data.description,
+            icon: "none",
+          });
+        } else {
+          uni.showToast({
+            title: "请求失败,请重新获取数据",
+            icon: "none",
+          });
+        }
+      },
+      fail(err) {
+        reject(err);
+      },
+    });
+  });
+};
+
+export default {
+  request, //向外暴露request
+  imgApi, 
+  imgBaseApi,
+  BASE_URL,
+  WebUrl
+};

+ 21 - 0
static/css/fui.css

@@ -199,6 +199,12 @@ image {
 .text-856404{
 	color: #856404;
 }
+.text-303030{
+	color: #303030;
+}
+.text-7E7E7E{
+	color: #7E7E7E;
+}
 /* #ifndef APP-PLUS-NVUE */
 .text-color-initial {
 	color: initial;
@@ -1212,6 +1218,9 @@ image {
 .mgt-30 {
 	margin-top: 30rpx;
 }
+.mgt-32 {
+	margin-top: 32rpx;
+}
 .mgt-35 {
 	margin-top: 35rpx;
 }
@@ -1224,6 +1233,9 @@ image {
 .mgt-40 {
 	margin-top: 40rpx;
 }
+.mgt-48 {
+	margin-top: 48rpx;
+}
 .mgt-50 {
 	margin-top: 50rpx;
 }
@@ -1233,6 +1245,9 @@ image {
 .mgt-70 {
 	margin-top: 70rpx;
 }
+.mgt-72 {
+	margin-top: 72rpx;
+}
 .mgt-80 {
 	margin-top: 80rpx;
 }
@@ -1251,6 +1266,9 @@ image {
 .mgt-130 {
 	margin-top: 130rpx;
 }
+.mgt-132 {
+	margin-top: 132rpx;
+}
 .mgt-140 {
 	margin-top: 140rpx;
 }
@@ -2103,6 +2121,9 @@ image {
 .h-110 {
 	height: 110rpx;
 }
+.h-112 {
+	height: 112rpx;
+}
 .h-120 {
 	height: 120rpx;
 }

binární
static/image/login/close_icon.png


+ 30 - 0
utils/index.js

@@ -0,0 +1,30 @@
+// 防抖 只有在用户停止触发事件一段时间后才执行事件处理函数
+export function debounce(fn, delay) {
+	let timer = null;
+	return function (...args) {
+		if (timer) clearTimeout(timer);
+		timer = setTimeout(() => {
+			fn.apply(this, args);
+		}, delay);
+	};
+}
+
+// 节流 确保在一段时间内只执行一次事件处理函数
+export function throttle(fn, delay) {
+	let lastTime = 0; // 记录上一次执行的时间
+	return function (...args) {
+		const now = Date.now();
+		if (now - lastTime >= delay) {
+			lastTime = now;
+			fn.apply(this, args);
+		}
+	};
+}
+
+/**验证手机号格式
+ * @param {Number} phone 手机号码
+ */
+export function isValidPhone(phone) {
+	const regex = /^1[3-9]\d{9}$/;
+	return regex.test(phone.trim());
+}