LoginForm.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <script setup lang="tsx">
  2. import { reactive, ref, watch } from 'vue'
  3. import { Form, FormSchema } from '@/components/Form'
  4. import { useI18n } from '@/hooks/web/useI18n'
  5. import { ElButton, ElCheckbox, ElLink } from 'element-plus'
  6. import { useForm } from '@/hooks/web/useForm'
  7. import { loginApi, getTestRoleApi, getAdminRoleApi } from '@/api/login'
  8. import { useStorage } from '@/hooks/web/useStorage'
  9. import { useAppStore } from '@/store/modules/app'
  10. import { usePermissionStore } from '@/store/modules/permission'
  11. import { useRouter } from 'vue-router'
  12. import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
  13. import { UserType } from '@/api/login/types'
  14. import { useValidator } from '@/hooks/web/useValidator'
  15. import { Icon } from '@/components/Icon'
  16. const { required } = useValidator()
  17. const emit = defineEmits(['to-register'])
  18. const appStore = useAppStore()
  19. const permissionStore = usePermissionStore()
  20. const { currentRoute, addRoute, push } = useRouter()
  21. const { setStorage } = useStorage()
  22. const { t } = useI18n()
  23. const rules = {
  24. username: [required()],
  25. password: [required()]
  26. }
  27. const schema = reactive<FormSchema[]>([
  28. {
  29. field: 'title',
  30. colProps: {
  31. span: 24
  32. },
  33. formItemProps: {
  34. slots: {
  35. default: () => {
  36. return <h2 class="text-2xl font-bold text-center w-[100%]">{t('login.login')}</h2>
  37. }
  38. }
  39. }
  40. },
  41. {
  42. field: 'account',
  43. label: t('login.username'),
  44. value: 'admin',
  45. component: 'Input',
  46. colProps: {
  47. span: 24
  48. },
  49. componentProps: {
  50. placeholder: t('login.usernamePlaceholder')
  51. }
  52. },
  53. {
  54. field: 'password',
  55. label: t('login.password'),
  56. value: '123456',
  57. component: 'InputPassword',
  58. colProps: {
  59. span: 24
  60. },
  61. componentProps: {
  62. style: {
  63. width: '100%'
  64. },
  65. placeholder: t('login.passwordPlaceholder')
  66. }
  67. },
  68. {
  69. field: 'tool',
  70. colProps: {
  71. span: 24
  72. },
  73. formItemProps: {
  74. slots: {
  75. default: () => {
  76. return (
  77. <>
  78. <div class="flex justify-between items-center w-[100%]">
  79. <ElCheckbox v-model={remember.value} label={t('login.remember')} size="small" />
  80. <ElLink type="primary" underline={false}>
  81. {t('login.forgetPassword')}
  82. </ElLink>
  83. </div>
  84. </>
  85. )
  86. }
  87. }
  88. }
  89. },
  90. {
  91. field: 'login',
  92. colProps: {
  93. span: 24
  94. },
  95. formItemProps: {
  96. slots: {
  97. default: () => {
  98. return (
  99. <>
  100. <div class="w-[100%]">
  101. <ElButton loading={loading.value} type="primary" class="w-[100%]" onClick={signIn}>
  102. {t('login.login')}
  103. </ElButton>
  104. </div>
  105. </>
  106. )
  107. }
  108. }
  109. }
  110. }
  111. // {
  112. // field: 'other',
  113. // component: 'Divider',
  114. // label: t('login.otherLogin'),
  115. // componentProps: {
  116. // contentPosition: 'center'
  117. // }
  118. // },
  119. // {
  120. // field: 'otherIcon',
  121. // colProps: {
  122. // span: 24
  123. // },
  124. // formItemProps: {
  125. // slots: {
  126. // default: () => {
  127. // return (
  128. // <>
  129. // <div class="flex justify-between w-[100%]">
  130. // <Icon
  131. // icon="ant-design:github-filled"
  132. // size={iconSize}
  133. // class="cursor-pointer ant-icon"
  134. // color={iconColor}
  135. // hoverColor={hoverColor}
  136. // />
  137. // <Icon
  138. // icon="ant-design:wechat-filled"
  139. // size={iconSize}
  140. // class="cursor-pointer ant-icon"
  141. // color={iconColor}
  142. // hoverColor={hoverColor}
  143. // />
  144. // <Icon
  145. // icon="ant-design:alipay-circle-filled"
  146. // size={iconSize}
  147. // color={iconColor}
  148. // hoverColor={hoverColor}
  149. // class="cursor-pointer ant-icon"
  150. // />
  151. // <Icon
  152. // icon="ant-design:weibo-circle-filled"
  153. // size={iconSize}
  154. // color={iconColor}
  155. // hoverColor={hoverColor}
  156. // class="cursor-pointer ant-icon"
  157. // />
  158. // </div>
  159. // </>
  160. // )
  161. // }
  162. // }
  163. // }
  164. // }
  165. ])
  166. const iconSize = 30
  167. const remember = ref(false)
  168. const { formRegister, formMethods } = useForm()
  169. const { getFormData, getElFormExpose } = formMethods
  170. const loading = ref(false)
  171. const iconColor = '#999'
  172. const hoverColor = 'var(--el-color-primary)'
  173. const redirect = ref<string>('')
  174. watch(
  175. () => currentRoute.value,
  176. (route: RouteLocationNormalizedLoaded) => {
  177. redirect.value = route?.query?.redirect as string
  178. },
  179. {
  180. immediate: true
  181. }
  182. )
  183. // 登录
  184. const signIn = async () => {
  185. await permissionStore.generateRoutes('none').catch(() => {})
  186. permissionStore.getAddRouters.forEach((route) => {
  187. addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
  188. })
  189. permissionStore.setIsAddRouters(true)
  190. push({ path: redirect.value || permissionStore.addRouters[0].path })
  191. const formRef = await getElFormExpose()
  192. await formRef?.validate(async (isValid) => {
  193. if (isValid) {
  194. loading.value = true
  195. const formData = await getFormData<UserType>()
  196. try {
  197. const res = await loginApi(formData)
  198. if (res) {
  199. setStorage(appStore.getUserInfo, res.data)
  200. setStorage('token', res.token)
  201. // 是否使用动态路由
  202. if (appStore.getDynamicRouter) {
  203. getRole()
  204. } else {
  205. await permissionStore.generateRoutes('none').catch(() => {})
  206. permissionStore.getAddRouters.forEach((route) => {
  207. addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
  208. })
  209. permissionStore.setIsAddRouters(true)
  210. push({ path: redirect.value || permissionStore.addRouters[0].path })
  211. }
  212. }
  213. } finally {
  214. loading.value = false
  215. }
  216. }
  217. })
  218. }
  219. // 获取角色信息
  220. const getRole = async () => {
  221. const formData = await getFormData<UserType>()
  222. const params = {
  223. roleName: formData.account
  224. }
  225. // admin - 模拟后端过滤菜单
  226. // test - 模拟前端过滤菜单
  227. const res =
  228. formData.account === 'admin' ? await getAdminRoleApi(params) : await getTestRoleApi(params)
  229. if (res) {
  230. const routers = res.data || []
  231. setStorage('roleRouters', routers)
  232. formData.account === 'admin'
  233. ? await permissionStore.generateRoutes('admin', routers).catch(() => {})
  234. : await permissionStore.generateRoutes('test', routers).catch(() => {})
  235. permissionStore.getAddRouters.forEach((route) => {
  236. addRoute(route as RouteRecordRaw) // 动态添加可访问路由表
  237. })
  238. permissionStore.setIsAddRouters(true)
  239. push({ path: redirect.value || permissionStore.addRouters[0].path })
  240. }
  241. }
  242. // 去注册页面
  243. const toRegister = () => {
  244. emit('to-register')
  245. }
  246. </script>
  247. <template>
  248. <Form
  249. :schema="schema"
  250. :rules="rules"
  251. label-position="top"
  252. hide-required-asterisk
  253. size="large"
  254. class="dark:(border-1 border-[var(--el-border-color)] border-solid)"
  255. @register="formRegister"
  256. />
  257. </template>