login.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <template>
  2. <div class="login-wrapper">
  3. <div class="login-title">{{ sysBaseConfig.SNOWY_SYS_NAME }}</div>
  4. <div class="login_form">
  5. <div class="form_head">登 录</div>
  6. <div class="form_body">
  7. <a-form ref="loginForm" :model="ruleForm" :rules="rules">
  8. <!-- 用户名 -->
  9. <a-form-item name="account">
  10. <a-input v-model:value="ruleForm.account" placeholder="用户名" size="large" @keyup.enter="login"> </a-input>
  11. </a-form-item>
  12. <!-- 密码 -->
  13. <a-form-item name="password">
  14. <a-input-password
  15. v-model:value="ruleForm.password"
  16. placeholder="密码"
  17. size="large"
  18. autocomplete="off"
  19. @keyup.enter="login"
  20. >
  21. </a-input-password>
  22. </a-form-item>
  23. <!-- 验证码 -->
  24. <a-form-item name="validCode" v-if="captchaOpen === 'true'">
  25. <a-row :gutter="8">
  26. <a-col :span="17">
  27. <a-input v-model:value="ruleForm.validCode" placeholder="验证码" size="large" @keyup.enter="login">
  28. </a-input>
  29. </a-col>
  30. <a-col :span="7">
  31. <img :src="validCodeBase64" class="login-validCode-img" @click="loginCaptcha" />
  32. </a-col>
  33. </a-row>
  34. </a-form-item>
  35. <!-- 记住登录状态 -->
  36. <a-form-item>
  37. <a-checkbox v-model:checked="ruleForm.autologin">记住登录状态</a-checkbox>
  38. </a-form-item>
  39. <!-- 登录按钮 -->
  40. <a-form-item>
  41. <a-button type="primary" class="w-full" :loading="loading" round size="large" @click="login"
  42. >{{ $t('login.signIn') }}
  43. </a-button>
  44. </a-form-item>
  45. </a-form>
  46. </div>
  47. <!-- <div class="form_foot">没有账号?点击<router-link to="/findpwd" class="nav-link">注册</router-link></div> -->
  48. </div>
  49. <div class="version">
  50. {{ sysBaseConfig.SNOWY_SYS_COPYRIGHT }}
  51. </div>
  52. </div>
  53. </template>
  54. <script setup>
  55. import loginApi from '@/api/auth/loginApi'
  56. const PhoneLoginForm = defineAsyncComponent(() => import('./phoneLoginForm.vue'))
  57. import ThreeLogin from './threeLogin.vue'
  58. import smCrypto from '@/utils/smCrypto'
  59. import { required } from '@/utils/formRules'
  60. import { afterLogin } from './util'
  61. import configData from '@/config'
  62. import configApi from '@/api/dev/configApi'
  63. import tool from '@/utils/tool'
  64. import { globalStore, iframeStore, keepAliveStore, viewTagsStore } from '@/store'
  65. const { proxy } = getCurrentInstance()
  66. const activeKey = ref('userAccount')
  67. const captchaOpen = ref(configData.SYS_BASE_CONFIG.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN)
  68. const validCodeBase64 = ref('')
  69. const loading = ref(false)
  70. const ruleForm = reactive({
  71. account: 'superAdmin',
  72. password: '123456',
  73. validCode: '',
  74. validCodeReqNo: '',
  75. autologin: false
  76. })
  77. const rules = reactive({
  78. account: [required('请输入用户名', 'blur')],
  79. password: [required(proxy.$t('login.PWError'), 'blur')]
  80. })
  81. const lang = ref([
  82. {
  83. name: '简体中文',
  84. value: 'zh-cn'
  85. },
  86. {
  87. name: 'English',
  88. value: 'en'
  89. }
  90. ])
  91. const config = ref({
  92. lang: tool.data.get('APP_LANG') || proxy.$CONFIG.LANG,
  93. theme: tool.data.get('APP_THEME') || 'default'
  94. })
  95. const store = globalStore()
  96. const kStore = keepAliveStore()
  97. const iStore = iframeStore()
  98. const vStore = viewTagsStore()
  99. const setSysBaseConfig = store.setSysBaseConfig
  100. const clearKeepLive = kStore.clearKeepLive
  101. const clearIframeList = iStore.clearIframeList
  102. const clearViewTags = vStore.clearViewTags
  103. const sysBaseConfig = computed(() => {
  104. return store.sysBaseConfig
  105. })
  106. onMounted(() => {
  107. let formData = ref(configData.SYS_BASE_CONFIG)
  108. getAutologin() //记住登录状态
  109. configApi
  110. .configSysBaseList()
  111. .then((data) => {
  112. if (data) {
  113. data.forEach((item) => {
  114. formData.value[item.configKey] = item.configValue
  115. })
  116. captchaOpen.value = formData.value.SNOWY_SYS_DEFAULT_CAPTCHA_OPEN
  117. tool.data.set('SNOWY_SYS_BASE_CONFIG', formData.value)
  118. setSysBaseConfig(formData.value)
  119. refreshSwitch()
  120. }
  121. })
  122. .catch(() => {})
  123. })
  124. onBeforeMount(() => {
  125. clearViewTags()
  126. clearKeepLive()
  127. clearIframeList()
  128. })
  129. // 监听语言
  130. watch(
  131. () => config.value.lang,
  132. (newValue) => {
  133. proxy.$i18n.locale = newValue
  134. tool.data.set('APP_LANG', newValue)
  135. }
  136. )
  137. // 主题
  138. watch(
  139. () => config.value.theme,
  140. (newValue) => {
  141. document.body.setAttribute('data-theme', newValue)
  142. }
  143. )
  144. //记住状态
  145. const getAutologin = () => {
  146. let account = tool.data.get('account')
  147. let password = tool.data.get('password')
  148. let autologin = tool.data.get('autologin')
  149. ruleForm.account = account === undefined ? ruleForm.account : account
  150. ruleForm.password = password === undefined ? ruleForm.password : password
  151. ruleForm.autologin = autologin === undefined ? ruleForm.account : autologin
  152. }
  153. // 通过开关加载内容
  154. const refreshSwitch = () => {
  155. // 判断是否开启验证码
  156. if (captchaOpen.value === 'true') {
  157. // 加载验证码
  158. loginCaptcha()
  159. // 加入校验
  160. rules.validCode = [required(proxy.$t('login.validError'), 'blur')]
  161. }
  162. }
  163. // 获取验证码
  164. const loginCaptcha = () => {
  165. loginApi.getPicCaptcha().then((data) => {
  166. validCodeBase64.value = data.validCodeBase64
  167. ruleForm.validCodeReqNo = data.validCodeReqNo
  168. })
  169. }
  170. //登陆
  171. const loginForm = ref()
  172. const login = async () => {
  173. loginForm.value
  174. .validate()
  175. .then(async () => {
  176. loading.value = true
  177. const loginData = {
  178. account: ruleForm.account,
  179. // 密码进行SM2加密,传输过程中看到的只有密文,后端存储使用hash
  180. password: smCrypto.doSm2Encrypt(ruleForm.password),
  181. validCode: ruleForm.validCode,
  182. validCodeReqNo: ruleForm.validCodeReqNo
  183. }
  184. //是否记住登录状态
  185. if (ruleForm.autologin) {
  186. tool.data.set('loginForm', ruleForm.account)
  187. tool.data.set('password', ruleForm.password)
  188. tool.data.set('autologin', ruleForm.autologin)
  189. } else {
  190. tool.data.remove('account')
  191. tool.data.remove('password')
  192. tool.data.remove('autologin')
  193. }
  194. // 获取token
  195. try {
  196. const loginToken = await loginApi.login(loginData)
  197. await afterLogin(loginToken)
  198. } catch (err) {
  199. loading.value = false
  200. if (captchaOpen.value === 'true') {
  201. loginCaptcha()
  202. }
  203. }
  204. })
  205. .catch(() => {})
  206. }
  207. const configLang = (key) => {
  208. config.value.lang = key
  209. }
  210. // logo链接
  211. const handleLink = (e) => {
  212. if (!sysBaseConfig.value.SNOWY_SYS_COPYRIGHT_URL) {
  213. e?.stopPropagation()
  214. e?.preventDefault()
  215. }
  216. }
  217. </script>
  218. <style lang="less" scoped>
  219. .login-wrapper {
  220. width: 100%;
  221. min-height: 800px;
  222. height: 100vh;
  223. display: flex;
  224. flex-direction: column;
  225. align-items: center;
  226. justify-content: flex-start;
  227. padding-top: 10%;
  228. background-image: url('/src/assets/images/login/logo_background.png');
  229. background-size: cover;
  230. background-position: center;
  231. position: relative;
  232. .login-title {
  233. font-size: 30px;
  234. margin-bottom: 30px;
  235. letter-spacing: 5px;
  236. font-weight: bold;
  237. color: #1f3253;
  238. }
  239. // 登录
  240. .login_form {
  241. width: 400px;
  242. padding: 0 0 30px;
  243. display: flex;
  244. flex-direction: column;
  245. align-items: center;
  246. border-radius: 5px;
  247. background-color: #fbfcfd;
  248. .form_head {
  249. font-size: 20px;
  250. height: 70px;
  251. line-height: 70px;
  252. }
  253. // 表单
  254. .form_body {
  255. width: 100%;
  256. padding: 0 30px;
  257. .w-full {
  258. background-color: #0052cc;
  259. }
  260. }
  261. // 注册
  262. .form_foot {
  263. font-size: 14px;
  264. .nav-link {
  265. text-decoration: none;
  266. color: #0052cc;
  267. }
  268. .nav-link:hover {
  269. text-decoration: underline;
  270. }
  271. }
  272. }
  273. .version {
  274. position: absolute;
  275. bottom: 10px;
  276. font-size: 13px;
  277. }
  278. }
  279. </style>