巴青农资商城

index.vue 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <template>
  2. <view class="auth-page">
  3. <view class="auth-hero">
  4. <view class="auth-hero__brand">
  5. <text class="auth-hero__app">巴青农资商城</text>
  6. <text class="auth-hero__welcome">欢迎登录农资商城</text>
  7. </view>
  8. </view>
  9. <view class="auth-body">
  10. <view class="auth-card">
  11. <text class="auth-card__title">会员登录</text>
  12. <text class="auth-card__sub">可使用手机号登录</text>
  13. <view class="auth-field">
  14. <view class="auth-field__box">
  15. <u-icon name="account" color="#6b7f72" size="22" />
  16. <input
  17. v-model="form.account"
  18. class="auth-field__input"
  19. type="text"
  20. placeholder="手机号"
  21. placeholder-class="auth-field__placeholder"
  22. confirm-type="next"
  23. />
  24. </view>
  25. </view>
  26. <view class="auth-field">
  27. <view class="auth-field__box">
  28. <u-icon name="lock" color="#6b7f72" size="22" />
  29. <input
  30. v-model="form.password"
  31. class="auth-field__input"
  32. type="password"
  33. placeholder="请输入密码"
  34. placeholder-class="auth-field__placeholder"
  35. confirm-type="done"
  36. @confirm="handleLogin"
  37. />
  38. </view>
  39. </view>
  40. <view class="auth-remember" @click="form.rememberMe = !form.rememberMe">
  41. <view :class="['auth-remember__check', { 'auth-remember__check--on': form.rememberMe }]">
  42. <u-icon v-if="form.rememberMe" name="checkmark" color="#ffffff" size="14" />
  43. </view>
  44. <text class="auth-remember__txt">记住账号</text>
  45. </view>
  46. <agreement-block
  47. v-model="form.agreementAccepted"
  48. :enabled="needAgreement"
  49. :checkbox-label="agreement.checkboxLabel"
  50. :agreement-title="agreement.agreementTitle"
  51. :version-label="agreement.versionLabel"
  52. :content="agreement.content"
  53. />
  54. <view
  55. :class="['auth-btn', { 'auth-btn--loading': loading }]"
  56. :disabled="loading"
  57. @click="handleLogin"
  58. >
  59. <text class="auth-btn__txt">{{ loading ? '登录中…' : '登 录' }}</text>
  60. </view>
  61. <view class="auth-switch">
  62. <text>还没有账号?</text>
  63. <text class="auth-switch__link" @click="goRegister">立即注册</text>
  64. </view>
  65. </view>
  66. <text class="auth-footer">农资商城</text>
  67. </view>
  68. </view>
  69. </template>
  70. <script setup>
  71. import { ref, reactive, computed } from 'vue'
  72. import { onLoad } from '@dcloudio/uni-app'
  73. import { getToken } from '@/utils/auth'
  74. import { REMEMBER_ACCOUNT_KEY } from '@/config'
  75. import { useUserStore } from '@/store/user'
  76. import { loadServiceAgreement } from '@/utils/memberAgreement'
  77. import { PAGE_HOME, PAGE_REGISTER } from '@/utils/pageRoute'
  78. import AgreementBlock from '@/components/account/AgreementBlock.vue'
  79. import { useActionGuard } from '@/utils/actionGuard'
  80. const loginGuard = useActionGuard()
  81. const loading = loginGuard.locked
  82. const agreement = reactive({
  83. enabled: false,
  84. requireAgreementOnLogin: false,
  85. agreementTitle: '',
  86. versionLabel: '',
  87. content: '',
  88. checkboxLabel: ''
  89. })
  90. const form = reactive({
  91. account: '',
  92. password: '',
  93. rememberMe: false,
  94. agreementAccepted: false
  95. })
  96. const needAgreement = computed(
  97. () => agreement.enabled && agreement.requireAgreementOnLogin
  98. )
  99. onLoad(async (options) => {
  100. if (getToken()) {
  101. goHome()
  102. return
  103. }
  104. const cfg = await loadServiceAgreement()
  105. Object.assign(agreement, cfg)
  106. if (options && options.account) {
  107. form.account = decodeURIComponent(options.account)
  108. }
  109. loadRememberedAccount()
  110. })
  111. function loadRememberedAccount() {
  112. const saved =
  113. uni.getStorageSync(REMEMBER_ACCOUNT_KEY) || uni.getStorageSync('shop_login_username')
  114. if (saved) {
  115. form.account = saved
  116. form.rememberMe = true
  117. }
  118. }
  119. function goHome() {
  120. uni.switchTab({ url: PAGE_HOME })
  121. }
  122. function goRegister() {
  123. const q = form.account ? `?mobile=${encodeURIComponent(form.account.trim())}` : ''
  124. uni.navigateTo({ url: `${PAGE_REGISTER}${q}` })
  125. }
  126. function validateForm() {
  127. if (!(form.account || '').trim()) {
  128. uni.showToast({ title: '请输入账号', icon: 'none' })
  129. return false
  130. }
  131. if (!form.password) {
  132. uni.showToast({ title: '请输入密码', icon: 'none' })
  133. return false
  134. }
  135. if (needAgreement.value && !form.agreementAccepted) {
  136. uni.showToast({ title: '请先阅读并同意服务协议', icon: 'none' })
  137. return false
  138. }
  139. return true
  140. }
  141. function handleLogin() {
  142. loginGuard.run(async () => {
  143. if (!validateForm()) return
  144. const account = form.account.trim()
  145. if (form.rememberMe) {
  146. uni.setStorageSync(REMEMBER_ACCOUNT_KEY, account)
  147. } else {
  148. uni.removeStorageSync(REMEMBER_ACCOUNT_KEY)
  149. }
  150. const userStore = useUserStore()
  151. userStore.fedLogOut()
  152. await userStore.login({
  153. account,
  154. password: form.password,
  155. agreementAccepted: needAgreement.value ? form.agreementAccepted : true
  156. })
  157. await userStore.fetchUserInfo()
  158. goHome()
  159. })
  160. }
  161. </script>
  162. <style lang="scss" scoped>
  163. @import '@/styles/auth.scss';
  164. .auth-remember {
  165. display: flex;
  166. align-items: center;
  167. margin-top: 8rpx;
  168. }
  169. .auth-remember__check {
  170. width: 32rpx;
  171. height: 32rpx;
  172. margin-right: 12rpx;
  173. border: 2rpx solid #c8e6c9;
  174. border-radius: 6rpx;
  175. display: flex;
  176. align-items: center;
  177. justify-content: center;
  178. background: #fff;
  179. }
  180. .auth-remember__check--on {
  181. background: #2e7d32;
  182. border-color: #2e7d32;
  183. }
  184. .auth-remember__txt {
  185. font-size: 26rpx;
  186. color: #666;
  187. }
  188. .auth-footer {
  189. display: block;
  190. margin-top: 48rpx;
  191. text-align: center;
  192. font-size: 24rpx;
  193. color: #aaa;
  194. }
  195. </style>