register.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <template>
  2. <view class="register-container">
  3. <!-- 标题和进度 -->
  4. <navBar title="注册1/2" color="#000" />
  5. <view class="progress-box">
  6. <view class="progress-item"></view>
  7. <view class="progress-item" style="background: #99C4FA;"></view>
  8. </view>
  9. <!-- 表单区域 -->
  10. <view class="register-form">
  11. <!-- 手机号码输入 -->
  12. <view class="form-item">
  13. <view class="item-label"> 手机号码 </view>
  14. <u-input
  15. placeholder="请输入登录的手机号码"
  16. v-model="phoneNumber"
  17. clearable
  18. type="number"
  19. maxlength="11"
  20. @input="onPhoneInput"
  21. class="custom-input"
  22. >
  23. </u-input>
  24. </view>
  25. <!-- 验证码输入 -->
  26. <view class="form-item">
  27. <text class="item-label">验证码</text>
  28. <view class="input-container">
  29. <view class="input-box">
  30. <u-input
  31. class="custom-input"
  32. placeholder="输入验证码"
  33. v-model="verificationCode"
  34. type="number"
  35. maxlength="6"
  36. :clearable="false"
  37. />
  38. <view
  39. class="verification-btn"
  40. :class="{ 'verification-btn-disabled': isCounting || !canGetCode }"
  41. @click="getVerificationCode"
  42. >{{ countdownText }}</view
  43. >
  44. </view>
  45. </view>
  46. </view>
  47. <!-- 下一步按钮 -->
  48. <u-button
  49. type="primary"
  50. :disabled="!canNext"
  51. @click="handleNext"
  52. :customStyle="{
  53. marginTop: '32rpx',
  54. height: '90rpx',
  55. fontSize: '32rpx',
  56. borderRadius: '100rpx',
  57. }"
  58. >
  59. 下一步
  60. </u-button>
  61. </view>
  62. </view>
  63. </template>
  64. <script>
  65. import navBar from "@/components/nav-bar/index.vue";
  66. export default {
  67. data() {
  68. return {
  69. phoneNumber: "", // 手机号码
  70. verificationCode: "", // 验证码
  71. isCounting: false, // 是否在倒计时中
  72. countdown: 60, // 倒计时秒数
  73. countdownTimer: null, // 倒计时定时器
  74. };
  75. },
  76. components: {
  77. navBar,
  78. },
  79. computed: {
  80. // 是否可以获取验证码
  81. canGetCode() {
  82. return /^1[3-9]\d{9}$/.test(this.phoneNumber);
  83. },
  84. // 是否可以下一步
  85. canNext() {
  86. return (
  87. this.canGetCode &&
  88. this.verificationCode.length === 6 &&
  89. /^\d{6}$/.test(this.verificationCode)
  90. );
  91. },
  92. // 倒计时显示文本
  93. countdownText() {
  94. return this.isCounting ? `${this.countdown}s后重新获取` : "获取验证码";
  95. },
  96. },
  97. methods: {
  98. // 手机号输入处理
  99. onPhoneInput(e) {
  100. // 限制只能输入数字
  101. this.phoneNumber = e.replace(/[^\d]/g, "");
  102. },
  103. // 获取验证码
  104. async getVerificationCode() {
  105. if (!this.canGetCode) {
  106. uni.showToast({
  107. title: "请输入正确的手机号码",
  108. icon: "none",
  109. });
  110. return;
  111. }
  112. if (this.isCounting) {
  113. return;
  114. }
  115. // 显示加载中
  116. uni.showLoading({
  117. title: "发送中...",
  118. mask: true,
  119. });
  120. try {
  121. // 模拟API请求
  122. await this.mockSendVerificationCode();
  123. uni.showToast({
  124. title: "验证码已发送",
  125. icon: "success",
  126. });
  127. // 开始倒计时
  128. this.startCountdown();
  129. } catch (error) {
  130. uni.showToast({
  131. title: "发送失败,请重试",
  132. icon: "none",
  133. });
  134. } finally {
  135. uni.hideLoading();
  136. }
  137. },
  138. // 模拟发送验证码API
  139. mockSendVerificationCode() {
  140. return new Promise((resolve, reject) => {
  141. setTimeout(() => {
  142. // 模拟90%成功率
  143. if (Math.random() > 0.1) {
  144. resolve({
  145. code: 200,
  146. message: "发送成功",
  147. });
  148. } else {
  149. reject({
  150. code: 500,
  151. message: "发送失败",
  152. });
  153. }
  154. }, 1000);
  155. });
  156. },
  157. // 开始倒计时
  158. startCountdown() {
  159. this.isCounting = true;
  160. this.countdown = 60;
  161. this.countdownTimer = setInterval(() => {
  162. this.countdown--;
  163. if (this.countdown <= 0) {
  164. this.stopCountdown();
  165. }
  166. }, 1000);
  167. },
  168. // 停止倒计时
  169. stopCountdown() {
  170. this.isCounting = false;
  171. this.countdown = 60;
  172. if (this.countdownTimer) {
  173. clearInterval(this.countdownTimer);
  174. this.countdownTimer = null;
  175. }
  176. },
  177. // 下一步
  178. handleNext() {
  179. if (!this.validateForm()) {
  180. return;
  181. }
  182. uni.showLoading({
  183. title: "验证中...",
  184. mask: true,
  185. });
  186. // 模拟验证码验证
  187. setTimeout(() => {
  188. uni.hideLoading();
  189. // 这里应该是验证码验证逻辑
  190. if (this.verificationCode === "123456") {
  191. // 模拟固定验证码
  192. uni.showToast({
  193. title: "验证成功",
  194. icon: "success",
  195. });
  196. // 跳转到下一步(注册2/2)
  197. setTimeout(() => {
  198. uni.navigateTo({
  199. url: `/pages/register-step2/register-step2?phone=${this.phoneNumber}`,
  200. });
  201. }, 1000);
  202. } else {
  203. uni.showToast({
  204. title: "验证码错误",
  205. icon: "none",
  206. });
  207. }
  208. }, 1500);
  209. },
  210. // 表单验证
  211. validateForm() {
  212. if (!this.phoneNumber) {
  213. uni.showToast({
  214. title: "请输入手机号码",
  215. icon: "none",
  216. });
  217. return false;
  218. }
  219. if (!this.canGetCode) {
  220. uni.showToast({
  221. title: "请输入正确的手机号码",
  222. icon: "none",
  223. });
  224. return false;
  225. }
  226. if (!this.verificationCode) {
  227. uni.showToast({
  228. title: "请输入验证码",
  229. icon: "none",
  230. });
  231. return false;
  232. }
  233. if (!/^\d{6}$/.test(this.verificationCode)) {
  234. uni.showToast({
  235. title: "请输入6位数字验证码",
  236. icon: "none",
  237. });
  238. return false;
  239. }
  240. return true;
  241. },
  242. },
  243. // 页面卸载时清除定时器
  244. beforeUnmount() {
  245. this.stopCountdown();
  246. },
  247. };
  248. </script>
  249. <style scoped lang="scss">
  250. .register-container {
  251. background: #fff;
  252. position: absolute;
  253. left: 0;
  254. right: 0;
  255. top: 0;
  256. bottom: 0;
  257. }
  258. .register-form {
  259. padding: 32rpx;
  260. box-sizing: border-box;
  261. }
  262. .form-item {
  263. margin-bottom: 32rpx;
  264. }
  265. .item-label {
  266. color: rgba(18, 26, 44, 1);
  267. font-family: Roboto;
  268. font-size: 32rpx;
  269. font-weight: 400;
  270. line-height: 51.2rpx;
  271. letter-spacing: 0px;
  272. text-align: left;
  273. padding-bottom: 6rpx;
  274. }
  275. .custom-input {
  276. box-sizing: border-box;
  277. border: 2rpx solid rgba(158, 161, 168, 1);
  278. border-radius: 24rpx;
  279. background: rgba(255, 255, 255, 1);
  280. padding: 8rpx 24rpx !important;
  281. }
  282. .input-box {
  283. position: relative;
  284. }
  285. .verification-btn {
  286. color: #2979ff;
  287. font-size: 28rpx;
  288. padding: 8rpx 16rpx;
  289. white-space: nowrap;
  290. position: absolute;
  291. right: 24rpx;
  292. top: 0;
  293. bottom: 0;
  294. display: flex;
  295. justify-content: center;
  296. align-items: center;
  297. }
  298. .verification-btn-disabled {
  299. color: #c0c4cc !important;
  300. }
  301. .next-btn-active {
  302. background: #2979ff;
  303. }
  304. ::v-deep .u-input {
  305. text-align: left !important;
  306. }
  307. .progress-box {
  308. display: flex;
  309. justify-content: center;
  310. align-items: center;
  311. gap: 24rpx;
  312. padding-top: 40rpx;
  313. box-sizing: border-box;
  314. .progress-item {
  315. width: 40rpx;
  316. height: 8rpx;
  317. background-color: #016bf6;
  318. border-radius: 40rpx;
  319. }
  320. }
  321. </style>