login.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. <template>
  2. <view class="login-bg">
  3. <view class="login-box">
  4. <view class="login-title">欢迎登录</view>
  5. <view class="login-tabs">
  6. <view :class="['tab', loginType === 'phone' ? 'active' : '']" @click="loginType = 'phone'">手机号登录</view>
  7. <view :class="['tab', loginType === 'account' ? 'active' : '']" @click="loginType = 'account'">账号密码登录</view>
  8. </view>
  9. <view v-if="loginType === 'phone'" class="login-form">
  10. <input class="login-input" type="text" placeholder="请输入手机号" v-model="phone" />
  11. <view class="code-row">
  12. <input class="login-input code-input" type="text" placeholder="请输入验证码" v-model="code" />
  13. <button class="code-btn" @click="sendCode" :disabled="loginCodeTimer > 0 || isSendingLoginCode">
  14. {{ loginCodeTimer > 0 ? loginCodeTimer + 's' : '获取验证码' }}
  15. </button>
  16. </view>
  17. </view>
  18. <view v-else class="login-form">
  19. <input class="login-input" type="text" placeholder="请输入账号" v-model="username" />
  20. <input class="login-input" type="password" password placeholder="请输入密码" v-model="password" />
  21. <view class="form-actions">
  22. <text class="login-link" @click="toRegister">去注册</text>
  23. <text class="forgot-password-link" @click="toForgot">忘记密码?</text>
  24. </view>
  25. </view>
  26. <button class="login-btn" :disabled="!agreed" @click="doLogin">登录</button>
  27. <view class="login-agree">
  28. <checkbox :checked="agreed" @click="agreed = !agreed" />
  29. <text>我已阅读并同意</text>
  30. <text class="link" @click="openAgreement">《服务协议》</text>
  31. <text>和</text>
  32. <text class="link" @click="openPrivacy">《隐私政策》</text>
  33. </view>
  34. <view class="login-divider">第三方账号登录</view>
  35. <button class="wechat-btn" @click="oneClickLogin">
  36. <image src="/static/wechat.png" class="icon" /> 一键登录
  37. </button>
  38. </view>
  39. </view>
  40. <!-- 注册弹窗 -->
  41. <view v-if="showRegisterPopup" class="popup-overlay">
  42. <view class="register-popup-content">
  43. <view class="popup-title">注册账号</view>
  44. <view class="register-form">
  45. <input class="login-input" type="text" placeholder="请输入手机号" v-model="regPhone" />
  46. <view class="code-row">
  47. <input class="login-input code-input" type="text" placeholder="请输入验证码" v-model="regCode" />
  48. <button class="code-btn" @click="sendRegCode" :disabled="regCodeTimer > 0 || isSendingRegCode">
  49. {{ regCodeTimer > 0 ? regCodeTimer + 's' : '获取验证码' }}
  50. </button>
  51. </view>
  52. <input class="login-input" type="text" placeholder="请输入账号" v-model="regUsername" />
  53. <input class="login-input" type="password" password placeholder="请输入密码" v-model="regPassword" />
  54. </view>
  55. <button class="login-btn" @click="doRegister">注册</button>
  56. <view class="close-btn" @click="showRegisterPopup = false">
  57. <image src="/static/cw.png" class="icon"></image>
  58. </view>
  59. </view>
  60. </view>
  61. <!-- 忘记密码弹窗 -->
  62. <view v-if="showForgotPopup" class="popup-overlay">
  63. <view class="forgot-popup-content">
  64. <view class="popup-title">找回密码</view>
  65. <view class="forgot-form">
  66. <input class="login-input" type="text" placeholder="请输入手机号" v-model="forgotPhone" />
  67. <view class="code-row">
  68. <input class="login-input code-input" type="text" placeholder="请输入验证码" v-model="forgotCode" />
  69. <button class="code-btn" @click="sendForgotCode" :disabled="forgotCodeTimer > 0 || isSendingForgotCode">
  70. {{ forgotCodeTimer > 0 ? forgotCodeTimer + 's' : '获取验证码' }}
  71. </button>
  72. </view>
  73. <input class="login-input" type="password" password placeholder="请输入新密码" v-model="newPassword" />
  74. <input class="login-input" type="password" password placeholder="请确认新密码" v-model="confirmPassword" />
  75. </view>
  76. <button class="login-btn" @click="doResetPassword">确认修改</button>
  77. <view class="close-btn" @click="showForgotPopup = false">
  78. <image src="/static/cw.png" class="icon"></image>
  79. </view>
  80. </view>
  81. </view>
  82. </template>
  83. <script>
  84. export default {
  85. data() {
  86. return {
  87. loginType: 'phone', // 'phone' or 'account'
  88. phone: '',
  89. code: '',
  90. username: '',
  91. password: '',
  92. agreed: false,
  93. showRegisterPopup: false,
  94. regPhone: '',
  95. regCode: '',
  96. regUsername: '',
  97. regPassword: '',
  98. regCodeTimer: 0, // Countdown timer for registration code
  99. isSendingRegCode: false, // Flag to prevent multiple requests
  100. loginCodeTimer: 0, // Countdown timer for login code
  101. isSendingLoginCode: false, // Flag to prevent multiple requests
  102. showForgotPopup: false,
  103. forgotPhone: '',
  104. forgotCode: '',
  105. newPassword: '',
  106. confirmPassword: '',
  107. forgotCodeTimer: 0,
  108. isSendingForgotCode: false,
  109. }
  110. },
  111. methods: {
  112. // 处理微信登录
  113. async oneClickLogin() {
  114. console.log('WeChat login button clicked');
  115. // 1. 先获取用户信息
  116. uni.getUserProfile({
  117. desc: '用于完善用户资料',
  118. lang: 'zh_CN',
  119. success: (userRes) => {
  120. console.log(userRes)
  121. // 2. 获取微信登录凭证
  122. uni.showLoading({ title: '登录中...', mask: true })
  123. uni.login({
  124. provider: 'weixin',
  125. success: wx_res => {
  126. // 3. 发送登录请求,参数按后端WeLogin类
  127. console.log('uni.getUserProfile success:', userRes);
  128. console.log('uni.login success, got code:', wx_res.code);
  129. uni.request({
  130. url: 'http://localhost:3333/WeChart/login',
  131. method: 'POST',
  132. data: {
  133. code: wx_res.code,
  134. weChatLoginDto: userRes.userInfo,
  135. },
  136. header: { 'content-type': 'application/json' },
  137. success: (res) => {
  138. uni.hideLoading()
  139. if (res.statusCode === 200 && res.data) {
  140. console.log('Backend login success:', res.data);
  141. uni.showToast({ title: '登录成功', icon: 'success' })
  142. setTimeout(() => {
  143. uni.switchTab({ url: '/pages/home/index' })
  144. }, 1500)
  145. } else {
  146. console.error('Backend login failed:', res);
  147. uni.showToast({ title: res.data?.message || '登录失败', icon: 'none' })
  148. }
  149. },
  150. fail: (err) => {
  151. uni.hideLoading()
  152. console.error('Backend request failed:', err);
  153. uni.showToast({ title: '微信登录失败', icon: 'none' })
  154. }
  155. })
  156. },
  157. fail: (err) => {
  158. uni.hideLoading()
  159. console.error('uni.login failed:', err);
  160. uni.showToast({ title: '微信登录失败', icon: 'none' })
  161. }
  162. })
  163. },
  164. fail: (err) => {
  165. console.error('uni.getUserProfile failed:', err);
  166. uni.showToast({ title: '获取用户信息失败', icon: 'none' })
  167. }
  168. })
  169. },
  170. async sendCode() {
  171. if (this.isSendingLoginCode || this.loginCodeTimer > 0) {
  172. return;
  173. }
  174. if (!this.phone) {
  175. uni.showToast({ title: '请输入手机号', icon: 'none' });
  176. return;
  177. }
  178. this.isSendingLoginCode = true;
  179. uni.showLoading({ title: '发送中...', mask: true });
  180. try {
  181. const res = await uni.request({
  182. url: 'http://localhost:3333/user/code',
  183. method: 'POST',
  184. data: {
  185. phone: this.phone
  186. },
  187. header: { 'content-type': 'application/json' }
  188. });
  189. uni.hideLoading();
  190. this.isSendingLoginCode = false;
  191. if (res.statusCode === 200 && res.data) {
  192. console.log('Send login code success:', res.data);
  193. uni.showToast({ title: '验证码已发送', icon: 'success' });
  194. // Start countdown
  195. this.loginCodeTimer = 60;
  196. const timerInterval = setInterval(() => {
  197. this.loginCodeTimer--;
  198. if (this.loginCodeTimer <= 0) {
  199. clearInterval(timerInterval);
  200. this.loginCodeTimer = 0;
  201. }
  202. }, 1000);
  203. } else {
  204. console.error('Send login code failed:', res);
  205. uni.showToast({ title: res.data?.message || '发送失败', icon: 'none' });
  206. }
  207. } catch (err) {
  208. uni.hideLoading();
  209. this.isSendingLoginCode = false;
  210. console.error('Send login code request failed:', err);
  211. uni.showToast({ title: '发送失败', icon: 'none' });
  212. }
  213. },
  214. async doLogin() {
  215. if (!this.agreed) {
  216. uni.showToast({ title: '请先同意协议', icon: 'none' });
  217. return;
  218. }
  219. if (this.loginType === 'phone') {
  220. // 手机号+验证码登录
  221. if (!this.phone || !this.code) {
  222. uni.showToast({ title: '请填写手机号和验证码', icon: 'none' });
  223. return;
  224. }
  225. uni.showLoading({ title: '登录中...', mask: true });
  226. try {
  227. const res = await uni.request({
  228. url: 'http://localhost:3333/user/login',
  229. method: 'POST',
  230. data: {
  231. phone: this.phone,
  232. code: this.code
  233. },
  234. header: { 'content-type': 'application/json' }
  235. });
  236. uni.hideLoading();
  237. if (res.statusCode === 200 && res.data) {
  238. uni.showToast({ title: '登录成功', icon: 'success' });
  239. setTimeout(() => {
  240. uni.switchTab({ url: '/pages/home/index' });
  241. }, 1500);
  242. } else {
  243. uni.showToast({ title: res.data?.message || '登录失败', icon: 'error' });
  244. }
  245. } catch (err) {
  246. uni.hideLoading();
  247. uni.showToast({ title: '登录失败', icon: 'none' });
  248. }
  249. } else if (this.loginType === 'account') {
  250. // 账号+密码登录
  251. if (!this.username || !this.password) {
  252. uni.showToast({ title: '请填写账号和密码', icon: 'none' });
  253. return;
  254. }
  255. uni.showLoading({ title: '登录中...', mask: true });
  256. try {
  257. const res = await uni.request({
  258. url: 'http://localhost:3333/user/UserPassLogin',
  259. method: 'POST',
  260. data: {
  261. username: this.username,
  262. password: this.password
  263. },
  264. header: { 'content-type': 'application/json' }
  265. });
  266. uni.hideLoading();
  267. if (res.statusCode === 200 && res.data && res.data.code === 200) {
  268. uni.showToast({ title: '登录成功', icon: 'success' });
  269. setTimeout(() => {
  270. uni.switchTab({ url: '/pages/home/index' });
  271. }, 1500);
  272. } else {
  273. uni.showToast({ title: res.data?.msg || '登录失败', icon: 'error' });
  274. }
  275. } catch (err) {
  276. uni.hideLoading();
  277. uni.showToast({ title: '登录失败', icon: 'none' });
  278. }
  279. }
  280. },
  281. toRegister() {
  282. this.showRegisterPopup = true;
  283. },
  284. toForgot() {
  285. this.showForgotPopup = true;
  286. },
  287. openAgreement() {
  288. uni.navigateTo({ url: '/pages/agreement/agreement' });
  289. },
  290. openPrivacy() {
  291. uni.navigateTo({ url: '/pages/privacy/privacy' });
  292. },
  293. qqLogin() {
  294. uni.showToast({ title: 'QQ登录', icon: 'none' });
  295. },
  296. async sendRegCode() {
  297. // 如果正在发送或倒计时中,则不执行任何操作
  298. if (this.isSendingRegCode || this.regCodeTimer > 0) {
  299. return;
  300. }
  301. // 检查手机号是否已填写
  302. if (!this.regPhone) {
  303. uni.showToast({ title: '请输入手机号', icon: 'none' });
  304. return;
  305. }
  306. // 设置状态,显示加载提示
  307. this.isSendingRegCode = true;
  308. uni.showLoading({ title: '发送中...', mask: true });
  309. try {
  310. // 发起POST请求到后端接口
  311. const res = await uni.request({
  312. url: 'http://localhost:3333/user/code',
  313. method: 'POST',
  314. data: {
  315. phone: this.regPhone // 发送手机号参数
  316. },
  317. header: { 'content-type': 'application/json' }
  318. });
  319. // 隐藏加载提示,重置发送状态
  320. uni.hideLoading();
  321. this.isSendingRegCode = false;
  322. // 根据后端响应处理结果
  323. if (res.statusCode === 200 && res.data) {
  324. console.log('Send registration code success:', res.data);
  325. uni.showToast({ title: '验证码已发送', icon: 'success' });
  326. // 开始60秒倒计时
  327. this.regCodeTimer = 60;
  328. const timerInterval = setInterval(() => {
  329. this.regCodeTimer--;
  330. if (this.regCodeTimer <= 0) {
  331. clearInterval(timerInterval); // 倒计时结束时清除定时器
  332. this.regCodeTimer = 0;
  333. }
  334. }, 1000); // 每秒更新
  335. } else {
  336. // 处理发送失败的情况
  337. console.error('Send registration code failed:', res);
  338. uni.showToast({ title: res.data?.message || '发送失败', icon: 'none' });
  339. }
  340. } catch (err) {
  341. // 处理请求异常
  342. uni.hideLoading();
  343. this.isSendingRegCode = false;
  344. console.error('Send registration code request failed:', err);
  345. uni.showToast({ title: '发送失败', icon: 'none' });
  346. }
  347. },
  348. async doRegister() {
  349. if (!this.regPhone || !this.regCode || !this.regUsername || !this.regPassword) {
  350. uni.showToast({ title: '请填写所有注册信息', icon: 'none' });
  351. return;
  352. }
  353. uni.showLoading({ title: '注册中...', mask: true });
  354. try {
  355. const res = await uni.request({
  356. url: 'http://localhost:3333/user/register',
  357. method: 'POST',
  358. data: {
  359. phone: this.regPhone,
  360. code: this.regCode,
  361. username: this.regUsername,
  362. password: this.regPassword
  363. },
  364. header: { 'content-type': 'application/json' }
  365. });
  366. uni.hideLoading();
  367. if (res.statusCode === 200 && res.data) {
  368. console.log('Registration success:', res.data);
  369. uni.showToast({ title: '注册成功', icon: 'success' });
  370. // Optionally, clear the form fields
  371. this.regPhone = '';
  372. this.regCode = '';
  373. this.regUsername = '';
  374. this.regPassword = '';
  375. // Close the popup after successful registration
  376. setTimeout(() => {
  377. this.showRegisterPopup = false;
  378. }, 1500); // Delay closing slightly to show toast
  379. } else {
  380. console.error('Registration failed:', res);
  381. uni.showToast({ title: res.data?.message || '注册失败', icon: 'none' });
  382. }
  383. } catch (err) {
  384. uni.hideLoading();
  385. console.error('Registration request failed:', err);
  386. uni.showToast({ title: '注册失败', icon: 'none' });
  387. }
  388. },
  389. async sendForgotCode() {
  390. if (this.isSendingForgotCode || this.forgotCodeTimer > 0) {
  391. return;
  392. }
  393. if (!this.forgotPhone) {
  394. uni.showToast({ title: '请输入手机号', icon: 'none' });
  395. return;
  396. }
  397. this.isSendingForgotCode = true;
  398. uni.showLoading({ title: '发送中...', mask: true });
  399. try {
  400. const res = await uni.request({
  401. url: 'http://localhost:3333/user/code',
  402. method: 'POST',
  403. data: {
  404. phone: this.forgotPhone
  405. },
  406. header: { 'content-type': 'application/json' }
  407. });
  408. uni.hideLoading();
  409. this.isSendingForgotCode = false;
  410. if (res.statusCode === 200 && res.data) {
  411. console.log('Send forgot code success:', res.data);
  412. uni.showToast({ title: '验证码已发送', icon: 'success' });
  413. this.forgotCodeTimer = 60;
  414. const timerInterval = setInterval(() => {
  415. this.forgotCodeTimer--;
  416. if (this.forgotCodeTimer <= 0) {
  417. clearInterval(timerInterval);
  418. this.forgotCodeTimer = 0;
  419. }
  420. }, 1000);
  421. } else {
  422. console.error('Send forgot code failed:', res);
  423. uni.showToast({ title: res.data?.message || '发送失败', icon: 'none' });
  424. }
  425. } catch (err) {
  426. uni.hideLoading();
  427. this.isSendingForgotCode = false;
  428. console.error('Send forgot code request failed:', err);
  429. uni.showToast({ title: '发送失败', icon: 'none' });
  430. }
  431. },
  432. async doResetPassword() {
  433. if (!this.forgotPhone || !this.forgotCode || !this.newPassword || !this.confirmPassword) {
  434. uni.showToast({ title: '请填写所有信息', icon: 'none' });
  435. return;
  436. }
  437. if (this.newPassword !== this.confirmPassword) {
  438. uni.showToast({ title: '两次密码输入不一致', icon: 'none' });
  439. return;
  440. }
  441. uni.showLoading({ title: '修改中...', mask: true });
  442. try {
  443. const res = await uni.request({
  444. url: 'http://localhost:3333/user/ForgetPass',
  445. method: 'POST',
  446. data: {
  447. phone: this.forgotPhone,
  448. code: this.forgotCode,
  449. newPassword: this.newPassword
  450. },
  451. header: { 'content-type': 'application/json' }
  452. });
  453. uni.hideLoading();
  454. if (res.statusCode === 200 && res.data) {
  455. console.log('Reset password success:', res.data);
  456. uni.showToast({ title: '密码修改成功', icon: 'success' });
  457. // 清空表单
  458. this.forgotPhone = '';
  459. this.forgotCode = '';
  460. this.newPassword = '';
  461. this.confirmPassword = '';
  462. // 关闭弹窗并返回登录界面
  463. setTimeout(() => {
  464. this.showForgotPopup = false;
  465. // 切换到账号密码登录
  466. this.loginType = 'account';
  467. }, 1500);
  468. } else {
  469. console.error('Reset password failed:', res);
  470. uni.showToast({ title: res.data?.message || '修改失败', icon: 'none' });
  471. }
  472. } catch (err) {
  473. uni.hideLoading();
  474. console.error('Reset password request failed:', err);
  475. uni.showToast({ title: '修改失败', icon: 'none' });
  476. }
  477. },
  478. }
  479. }
  480. </script>
  481. <style>
  482. .login-bg {
  483. min-height: 100vh;
  484. background: #f7f8fa;
  485. display: flex;
  486. align-items: center;
  487. justify-content: center;
  488. }
  489. .login-box {
  490. width: 90vw;
  491. max-width: 600rpx;
  492. background: #fff;
  493. border-radius: 24rpx;
  494. box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.08);
  495. padding: 60rpx 40rpx 40rpx 40rpx;
  496. display: flex;
  497. flex-direction: column;
  498. align-items: center;
  499. }
  500. .login-title {
  501. font-size: 40rpx;
  502. font-weight: bold;
  503. margin-bottom: 40rpx;
  504. }
  505. .login-tabs {
  506. display: flex;
  507. width: 100%;
  508. margin-bottom: 30rpx;
  509. }
  510. .tab {
  511. flex: 1;
  512. text-align: center;
  513. font-size: 28rpx;
  514. padding: 16rpx 0;
  515. color: #888;
  516. border-bottom: 4rpx solid transparent;
  517. }
  518. .tab.active {
  519. color: #7ac81e;
  520. border-bottom: 4rpx solid #7ac81e;
  521. font-weight: bold;
  522. }
  523. .login-form {
  524. width: 100%;
  525. margin-bottom: 20rpx;
  526. }
  527. .login-input {
  528. width: 90%;
  529. height: 80rpx;
  530. border: 1rpx solid #eee;
  531. border-radius: 12rpx;
  532. margin-bottom: 20rpx;
  533. padding: 0 24rpx;
  534. font-size: 28rpx;
  535. background: #f7f8fa;
  536. }
  537. .code-row {
  538. display: flex;
  539. align-items: center;
  540. }
  541. .code-input {
  542. flex: 1;
  543. margin-right: 16rpx;
  544. }
  545. .code-btn {
  546. height: 80rpx;
  547. background: #7ac81e;
  548. color: #fff;
  549. border-radius: 12rpx;
  550. padding: 0 24rpx;
  551. font-size: 28rpx;
  552. }
  553. .login-btn {
  554. width: 100%;
  555. height: 80rpx;
  556. background: #7ac81e;
  557. color: #fff;
  558. font-size: 32rpx;
  559. border-radius: 40rpx;
  560. margin-bottom: 20rpx;
  561. }
  562. .login-btn:disabled {
  563. background: #b2e59e;
  564. }
  565. .login-agree {
  566. display: flex;
  567. align-items: center;
  568. font-size: 24rpx;
  569. color: #888;
  570. margin-bottom: 30rpx;
  571. }
  572. .login-agree .link {
  573. color: #7ac81e;
  574. margin: 0 4rpx;
  575. }
  576. .login-divider {
  577. width: 100%;
  578. text-align: center;
  579. color: #bbb;
  580. font-size: 24rpx;
  581. margin: 30rpx 0 20rpx 0;
  582. }
  583. .wechat-btn, .qq-btn {
  584. width: 100%;
  585. height: 70rpx;
  586. border-radius: 35rpx;
  587. font-size: 28rpx;
  588. display: flex;
  589. align-items: center;
  590. justify-content: center;
  591. margin-bottom: 16rpx;
  592. border: 1rpx solid #eee;
  593. background: #f7f8fa;
  594. }
  595. .wechat-btn {
  596. color: #09bb07;
  597. border: 1rpx solid #09bb07;
  598. }
  599. .qq-btn {
  600. color: #498ff6;
  601. border: 1rpx solid #498ff6;
  602. }
  603. .icon {
  604. width: 40rpx;
  605. height: 40rpx;
  606. margin-right: 16rpx;
  607. }
  608. .popup-overlay {
  609. position: fixed;
  610. top: 0;
  611. left: 0;
  612. right: 0;
  613. bottom: 0;
  614. background-color: rgba(0, 0, 0, 0.6); /* 半透明背景 */
  615. display: flex;
  616. align-items: center;
  617. justify-content: center;
  618. z-index: 999; /* 确保在最上层 */
  619. }
  620. .register-popup-content {
  621. background-color: #fff;
  622. border-radius: 24rpx;
  623. width: 85vw; /* 弹窗宽度 */
  624. max-width: 600rpx;
  625. padding: 60rpx 40rpx;
  626. position: relative; /* 用于定位关闭按钮 */
  627. display: flex;
  628. flex-direction: column;
  629. align-items: center;
  630. }
  631. .register-popup-content .popup-title {
  632. font-size: 40rpx;
  633. font-weight: bold;
  634. margin-bottom: 40rpx;
  635. color: #333;
  636. }
  637. .register-form {
  638. width: 100%;
  639. margin-bottom: 30rpx;
  640. }
  641. /* 注册表单的输入框样式,可以复用登录的 login-input */
  642. .register-form .login-input {
  643. width: 90%; /* 输入框宽度调整为100% */
  644. height: 80rpx;
  645. border: 1rpx solid #eee;
  646. border-radius: 12rpx;
  647. margin-bottom: 20rpx;
  648. padding: 0 24rpx;
  649. font-size: 28rpx;
  650. background: #f7f8fa;
  651. }
  652. /* 注册表单的获取验证码行样式,可以复用登录的 code-row */
  653. .register-form .code-row {
  654. display: flex;
  655. align-items: center;
  656. margin-bottom: 20rpx; /* 增加底部间距 */
  657. }
  658. /* 注册表单的验证码输入框样式,可以复用登录的 code-input */
  659. .register-form .code-input {
  660. flex: 1;
  661. margin-right: 16rpx;
  662. width: auto; /* 验证码输入框宽度自适应 */
  663. }
  664. /* 注册表单的获取验证码按钮样式,可以复用登录的 code-btn */
  665. .register-form .code-btn {
  666. height: 80rpx;
  667. background: #7ac81e;
  668. color: #fff;
  669. border-radius: 12rpx;
  670. padding: 0 24rpx;
  671. font-size: 28rpx;
  672. }
  673. /* 注册按钮样式,可以复用登录的 login-btn */
  674. .register-popup-content .login-btn {
  675. width: 100%;
  676. height: 80rpx;
  677. background: #7ac81e;
  678. color: #fff;
  679. font-size: 32rpx;
  680. border-radius: 40rpx;
  681. margin-bottom: 0; /* 移除底部间距 */
  682. }
  683. .close-btn {
  684. position: absolute;
  685. top: 20rpx;
  686. right: 20rpx;
  687. font-size: 36rpx; /* 调整文本大小 */
  688. color: #999;
  689. padding: 10rpx;
  690. /* 可以加个边框或者背景 */
  691. /* border: 1rpx solid #999; */
  692. /* border-radius: 50%; */
  693. /* background-color: #eee; */
  694. }
  695. /* 如果你没有引入uni-ui,可以使用文本X并给样式 */
  696. /* .close-btn text { font-size: 36rpx; } */
  697. .form-actions {
  698. width: 100%;
  699. display: flex;
  700. justify-content: space-between;
  701. align-items: center;
  702. margin-top: -10rpx;
  703. margin-bottom: 20rpx;
  704. padding: 0 10rpx;
  705. }
  706. .login-link {
  707. color: #7ac81e;
  708. font-size: 26rpx;
  709. }
  710. .forgot-password-link {
  711. color: #7ac81e;
  712. font-size: 26rpx;
  713. }
  714. .forgot-popup-content {
  715. background-color: #fff;
  716. border-radius: 24rpx;
  717. width: 85vw;
  718. max-width: 600rpx;
  719. padding: 60rpx 40rpx;
  720. position: relative;
  721. display: flex;
  722. flex-direction: column;
  723. align-items: center;
  724. }
  725. .forgot-form {
  726. width: 100%;
  727. margin-bottom: 30rpx;
  728. }
  729. .forgot-form .login-input {
  730. width: 90%;
  731. height: 80rpx;
  732. border: 1rpx solid #eee;
  733. border-radius: 12rpx;
  734. margin-bottom: 20rpx;
  735. padding: 0 24rpx;
  736. font-size: 28rpx;
  737. background: #f7f8fa;
  738. }
  739. .forgot-form .code-row {
  740. display: flex;
  741. align-items: center;
  742. margin-bottom: 20rpx;
  743. }
  744. .forgot-form .code-input {
  745. flex: 1;
  746. margin-right: 16rpx;
  747. width: auto;
  748. }
  749. .forgot-form .code-btn {
  750. height: 80rpx;
  751. background: #7ac81e;
  752. color: #fff;
  753. border-radius: 12rpx;
  754. padding: 0 24rpx;
  755. font-size: 28rpx;
  756. }
  757. </style>