login.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <route lang="json5" type="page">
  2. {
  3. layout: 'default',
  4. style: {
  5. navigationStyle: 'custom',
  6. },
  7. }
  8. </route>
  9. <script lang="ts" setup>
  10. import { t } from '@/locale'
  11. import { useUserStore } from '@/store/user'
  12. import { goBack, toPage } from '@/utils/page'
  13. import { toast } from '@/utils/toast'
  14. defineOptions({
  15. name: 'Login', // 登录
  16. })
  17. // 获取屏幕边界到安全区域距离
  18. const systemInfo = uni.getSystemInfoSync()
  19. const safeAreaInsets = systemInfo.safeAreaInsets
  20. // 用户状态管理
  21. const userStore = useUserStore()
  22. const redirectUrl = ref<string | null>(null)
  23. // 表单数据
  24. const formData = ref({
  25. username: '',
  26. password: '',
  27. })
  28. // 表单验证
  29. function validateForm() {
  30. return new Promise((resolve) => {
  31. // 验证用户名
  32. if (!formData.value.username.trim()) {
  33. toast.error(t('auth.login.error.emptyUsername'))
  34. resolve(false)
  35. return
  36. }
  37. // 验证密码
  38. if (!formData.value.password.trim()) {
  39. toast.error(t('auth.login.error.emptyPassword'))
  40. resolve(false)
  41. return
  42. }
  43. // 验证密码长度
  44. if (formData.value.password.length < 6 || formData.value.password.length > 20) {
  45. toast.error(t('auth.login.error.passwordLength'))
  46. resolve(false)
  47. return
  48. }
  49. resolve(true)
  50. })
  51. }
  52. // 登录处理
  53. async function handleLogin() {
  54. try {
  55. // 表单验证
  56. const isValid = await validateForm()
  57. if (!isValid)
  58. return
  59. // 准备登录数据
  60. const loginData = {
  61. account: formData.value.username,
  62. pwd: formData.value.password,
  63. }
  64. // 调用 userStore 中的登录方法,传入跳转地址
  65. await userStore.login(loginData, redirectUrl.value)
  66. }
  67. catch (error) {
  68. // 错误处理已在 userStore.login 中处理
  69. console.error('Login error:', error)
  70. }
  71. }
  72. const isReLaunch = ref<any>(null)
  73. onLoad((options) => {
  74. isReLaunch.value = options.isReLaunch
  75. redirectUrl.value = options.redirect || null
  76. })
  77. </script>
  78. <template>
  79. <view class="login-page min-h-screen bg-white">
  80. <!-- 背景图片区域 -->
  81. <view class="auth-bg-section relative">
  82. <!-- 自定义导航栏 -->
  83. <view :style="{ paddingTop: `${safeAreaInsets?.top}px` }">
  84. <view class="h-88rpx flex items-center px-24rpx">
  85. <wd-icon v-if="!isReLaunch" name="thin-arrow-left" size="32rpx" @click="() => goBack()" />
  86. </view>
  87. </view>
  88. <!-- Logo和标语 -->
  89. <view class="pb-40rpx pt-134rpx text-center">
  90. <view class="mb-20rpx flex flex-col items-center justify-center">
  91. <image src="/static/login-logo.png" class="mb-18rpx h-56rpx w-350.48rpx" />
  92. <view>{{ $t('login.slogan') }}</view>
  93. </view>
  94. </view>
  95. </view>
  96. <!-- 表单内容区域 -->
  97. <view class="flex flex-col px-20rpx">
  98. <view class="mb-40rpx" />
  99. <!-- 登录表单 -->
  100. <wd-form ref="form" :model="formData">
  101. <view class="mb-40rpx space-y-32rpx">
  102. <wd-input
  103. v-model="formData.username"
  104. prop="username"
  105. :placeholder="t('auth.login.username.placeholder')"
  106. no-border
  107. custom-class="bandhu-auth-input-field"
  108. />
  109. <wd-input
  110. v-model="formData.password"
  111. prop="password"
  112. :placeholder="t('auth.login.password.placeholder')"
  113. no-border show-password
  114. custom-class="bandhu-auth-input-field"
  115. />
  116. </view>
  117. <!-- 登录按钮 -->
  118. <wd-button
  119. size="large"
  120. block
  121. custom-class="mb-40rpx"
  122. @click="handleLogin"
  123. >
  124. {{ $t('auth.login.button') }}
  125. </wd-button>
  126. </wd-form>
  127. <!-- 注册提示 -->
  128. <view class="mb-200rpx text-center">
  129. <text class="text-28rpx text-#5C5C5C">
  130. {{ $t('auth.login.noAccount') }}
  131. </text>
  132. <view class="mt-40rpx">
  133. <wd-button
  134. plain
  135. @click="toPage({ url: '/pages/register/register' })"
  136. >
  137. {{ $t('auth.login.register') }}
  138. </wd-button>
  139. </view>
  140. </view>
  141. <!-- 忘记密码 -->
  142. <view class="fixed bottom-20rpx left-0 w-full text-center" :style="{ paddingBottom: `${safeAreaInsets?.bottom + 40}px` }">
  143. <text class="text-28rpx text-#5C5C5C" @click="toPage({ url: '/pages/forgotPassword/forgotPassword' })">
  144. {{ $t('auth.login.forgotPassword') }}
  145. </text>
  146. </view>
  147. </view>
  148. </view>
  149. </template>
  150. <style lang="scss" scoped>
  151. // 登录页面特有样式(如果有的话)
  152. </style>