LoginForm.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <script setup lang="ts">
  2. import { reactive, ref, unref, watch } from 'vue'
  3. import { Form } from '@/components/Form'
  4. import { useI18n } from '@/hooks/web/useI18n'
  5. import { ElButton, ElCheckbox, ElLink } from 'element-plus'
  6. import { required } from '@/utils/formRules'
  7. import { useForm } from '@/hooks/web/useForm'
  8. import { loginApi, getTestRoleApi, getAdminRoleApi } from '@/api/login'
  9. import type { UserLoginType } from '@/api/login/types'
  10. import { useCache } from '@/hooks/web/useCache'
  11. import { useAppStore } from '@/store/modules/app'
  12. import { usePermissionStore } from '@/store/modules/permission'
  13. import { useRouter } from 'vue-router'
  14. import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
  15. const appStore = useAppStore()
  16. const permissionStore = usePermissionStore()
  17. const { currentRoute, addRoute, push } = useRouter()
  18. const { t } = useI18n()
  19. const rules = {
  20. username: [required],
  21. password: [required]
  22. }
  23. const schema = reactive<FormSchema[]>([
  24. {
  25. field: 'title',
  26. colProps: {
  27. span: 24
  28. }
  29. },
  30. {
  31. field: 'username',
  32. label: t('login.username'),
  33. value: 'admin',
  34. component: 'Input',
  35. colProps: {
  36. span: 24
  37. },
  38. componentProps: {
  39. placeholder: t('login.usernamePlaceholder')
  40. }
  41. },
  42. {
  43. field: 'password',
  44. label: t('login.password'),
  45. value: 'admin',
  46. component: 'InputPassword',
  47. colProps: {
  48. span: 24
  49. },
  50. componentProps: {
  51. style: {
  52. width: '100%'
  53. },
  54. placeholder: t('login.passwordPlaceholder')
  55. }
  56. },
  57. {
  58. field: 'tool',
  59. colProps: {
  60. span: 24
  61. }
  62. },
  63. {
  64. field: 'login',
  65. colProps: {
  66. span: 24
  67. }
  68. },
  69. {
  70. field: 'other',
  71. component: 'Divider',
  72. label: t('login.otherLogin'),
  73. componentProps: {
  74. contentPosition: 'center'
  75. }
  76. },
  77. {
  78. field: 'otherIcon',
  79. colProps: {
  80. span: 24
  81. }
  82. }
  83. ])
  84. const iconSize = 30
  85. const remember = ref(false)
  86. const { register, elFormRef, methods } = useForm()
  87. const loading = ref(false)
  88. const iconColor = '#999'
  89. const redirect = ref<string>('')
  90. watch(
  91. () => currentRoute.value,
  92. (route: RouteLocationNormalizedLoaded) => {
  93. redirect.value = route?.query?.redirect as string
  94. },
  95. {
  96. immediate: true
  97. }
  98. )
  99. // 登录
  100. const signIn = async () => {
  101. const formRef = unref(elFormRef)
  102. await formRef?.validate(async (isValid) => {
  103. if (isValid) {
  104. loading.value = true
  105. const { getFormData } = methods
  106. const formData = await getFormData<UserLoginType>()
  107. const res = await loginApi(formData)
  108. .catch(() => {})
  109. .finally(() => (loading.value = false))
  110. if (res) {
  111. const { wsCache } = useCache()
  112. wsCache.set(appStore.getUserInfo, res.data)
  113. getRole()
  114. }
  115. }
  116. })
  117. }
  118. // 获取角色信息
  119. const getRole = async () => {
  120. const { getFormData } = methods
  121. const formData = await getFormData<UserLoginType>()
  122. const params = {
  123. roleName: formData.username
  124. }
  125. // admin - 模拟后端过滤菜单
  126. // test - 模拟前端过滤菜单
  127. const res =
  128. formData.username === 'admin'
  129. ? await getAdminRoleApi({ params })
  130. : await getTestRoleApi({ params })
  131. if (res) {
  132. const { wsCache } = useCache()
  133. const routers = res.data.list || []
  134. wsCache.set('roleRouters', routers)
  135. formData.username === 'admin'
  136. ? await permissionStore.generateRoutes('admin', routers).catch(() => {})
  137. : await permissionStore.generateRoutes('test', routers).catch(() => {})
  138. permissionStore.getAddRouters.forEach((route) => {
  139. addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
  140. })
  141. permissionStore.setIsAddRouters(true)
  142. push({ path: redirect.value || permissionStore.addRouters[0].path })
  143. }
  144. }
  145. </script>
  146. <template>
  147. <Form
  148. :schema="schema"
  149. :rules="rules"
  150. label-position="top"
  151. hide-required-asterisk
  152. size="large"
  153. @register="register"
  154. >
  155. <template #title>
  156. <h2 class="text-2xl font-bold text-center w-[100%]">{{ t('login.login') }}</h2>
  157. </template>
  158. <template #tool>
  159. <div class="flex justify-between items-center w-[100%]">
  160. <ElCheckbox v-model="remember" :label="t('login.remember')" size="small" />
  161. <ElLink type="primary" :underline="false">{{ t('login.forgetPassword') }}</ElLink>
  162. </div>
  163. </template>
  164. <template #login>
  165. <ElButton :loading="loading" type="primary" class="w-[100%]" @click="signIn">
  166. {{ t('login.login') }}
  167. </ElButton>
  168. </template>
  169. <template #otherIcon>
  170. <div class="flex justify-between w-[100%]">
  171. <Icon
  172. icon="ant-design:github-filled"
  173. :size="iconSize"
  174. class="cursor-pointer anticon"
  175. :color="iconColor"
  176. />
  177. <Icon
  178. icon="ant-design:wechat-filled"
  179. :size="iconSize"
  180. class="cursor-pointer anticon"
  181. :color="iconColor"
  182. />
  183. <Icon
  184. icon="ant-design:alipay-circle-filled"
  185. :size="iconSize"
  186. :color="iconColor"
  187. class="cursor-pointer anticon"
  188. />
  189. <Icon
  190. icon="ant-design:weibo-circle-filled"
  191. :size="iconSize"
  192. :color="iconColor"
  193. class="cursor-pointer anticon"
  194. />
  195. </div>
  196. </template>
  197. </Form>
  198. </template>
  199. <style lang="less" scoped>
  200. :deep(.anticon) {
  201. &:hover {
  202. color: var(--el-color-primary) !important;
  203. }
  204. }
  205. </style>