login.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <template xmlns="">
  2. <div class="container">
  3. <div class="logo"></div>
  4. <!-- 登录区域 -->
  5. <div class="content">
  6. <!-- 配图 -->
  7. <div class="pic"></div>
  8. <!-- 表单 -->
  9. <div class="field">
  10. <!-- [移动端]标题 -->
  11. <h2 class="mobile-title">
  12. <h3 class="title">芋道后台管理系统</h3>
  13. </h2>
  14. <!-- 表单 -->
  15. <div class="form-cont">
  16. <el-tabs class="form" v-model="loginForm.loginType" style=" float:none;">
  17. <el-tab-pane label="账号密码登录" name="uname">
  18. </el-tab-pane>
  19. <el-tab-pane label="短信验证码登录" name="sms">
  20. </el-tab-pane>
  21. </el-tabs>
  22. <div>
  23. <el-form ref="loginForm" :model="loginForm" :rules="LoginRules" class="login-form">
  24. <el-form-item prop="tenantName" v-if="tenantEnable">
  25. <el-input v-model="loginForm.tenantName" type="text" auto-complete="off" placeholder='租户'>
  26. <svg-icon slot="prefix" icon-class="tree" class="el-input__icon input-icon"/>
  27. </el-input>
  28. </el-form-item>
  29. <!-- 账号密码登录 -->
  30. <div v-if="loginForm.loginType === 'uname'">
  31. <el-form-item prop="username">
  32. <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
  33. <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon"/>
  34. </el-input>
  35. </el-form-item>
  36. <el-form-item prop="password">
  37. <el-input v-model="loginForm.password" type="password" auto-complete="off" placeholder="密码"
  38. @keyup.enter.native="getCode">
  39. <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
  40. </el-input>
  41. </el-form-item>
  42. <el-checkbox v-model="loginForm.rememberMe" style="margin:0 0 25px 0;">记住密码</el-checkbox>
  43. </div>
  44. <!-- 短信验证码登录 -->
  45. <div v-if="loginForm.loginType === 'sms'">
  46. <el-form-item prop="mobile">
  47. <el-input v-model="loginForm.mobile" type="text" auto-complete="off" placeholder="请输入手机号">
  48. <svg-icon slot="prefix" icon-class="phone" class="el-input__icon input-icon"/>
  49. </el-input>
  50. </el-form-item>
  51. <el-form-item prop="mobileCode">
  52. <el-input v-model="loginForm.mobileCode" type="text" auto-complete="off" placeholder="短信验证码"
  53. @keyup.enter.native="handleLogin">
  54. <template v-slot="icon">
  55. <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon"/>
  56. </template>
  57. <template v-slot="append">
  58. <span v-if="mobileCodeTimer <= 0" class="getMobileCode" @click="getSmsCode" style="cursor: pointer;">获取验证码</span>
  59. <span v-if="mobileCodeTimer > 0" class="getMobileCode">{{ mobileCodeTimer }}秒后可重新获取</span>
  60. </template>
  61. </el-input>
  62. </el-form-item>
  63. </div>
  64. <!-- 下方的登录按钮 -->
  65. <el-form-item style="width:100%;">
  66. <el-button :loading="loading" size="medium" type="primary" style="width:100%;"
  67. @click.native.prevent="getCode">
  68. <span v-if="!loading">登 录</span>
  69. <span v-else>登 录 中...</span>
  70. </el-button>
  71. </el-form-item>
  72. <!-- 社交登录 -->
  73. <el-form-item style="width:100%;">
  74. <div class="oauth-login" style="display:flex">
  75. <div class="oauth-login-item" v-for="item in SysUserSocialTypeEnum" :key="item.type" @click="doSocialLogin(item)">
  76. <img :src="item.img" height="25px" width="25px" alt="登录" >
  77. <span>{{item.title}}</span>
  78. </div>
  79. </div>
  80. </el-form-item>
  81. </el-form>
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. <!-- 图形验证码 -->
  87. <Verify ref="verify" :captcha-type="'blockPuzzle'" :img-size="{width:'400px',height:'200px'}"
  88. @success="handleLogin" />
  89. <!-- footer -->
  90. <div class="footer">
  91. Copyright © 2020-2022 iocoder.cn All Rights Reserved.
  92. </div>
  93. </div>
  94. </template>
  95. <script>
  96. import {sendSmsCode, socialAuthRedirect} from "@/api/login";
  97. import {getTenantIdByName} from "@/api/system/tenant";
  98. import {SystemUserSocialTypeEnum} from "@/utils/constants";
  99. import {getCaptchaEnable, getTenantEnable} from "@/utils/ruoyi";
  100. import {
  101. getPassword,
  102. getRememberMe, getTenantName,
  103. getUsername,
  104. removePassword, removeRememberMe, removeTenantName,
  105. removeUsername,
  106. setPassword, setRememberMe, setTenantId, setTenantName,
  107. setUsername
  108. } from "@/utils/auth";
  109. import Verify from '@/components/Verifition/Verify';
  110. import {resetUserPwd} from "@/api/system/user";
  111. export default {
  112. name: "Login",
  113. components: {
  114. Verify
  115. },
  116. data() {
  117. return {
  118. codeUrl: "",
  119. captchaEnable: true,
  120. tenantEnable: true,
  121. mobileCodeTimer: 0,
  122. loginForm: {
  123. loginType: "uname",
  124. username: "admin",
  125. password: "admin123",
  126. captchaVerification: "",
  127. mobile: "",
  128. mobileCode: "",
  129. rememberMe: false,
  130. tenantName: "芋道源码",
  131. },
  132. scene: 21,
  133. LoginRules: {
  134. username: [
  135. {required: true, trigger: "blur", message: "用户名不能为空"}
  136. ],
  137. password: [
  138. {required: true, trigger: "blur", message: "密码不能为空"}
  139. ],
  140. mobile: [
  141. {required: true, trigger: "blur", message: "手机号不能为空"},
  142. {
  143. validator: function (rule, value, callback) {
  144. if (/^(?:(?:\+|00)86)?1(?:3[\d]|4[5-79]|5[0-35-9]|6[5-7]|7[0-8]|8[\d]|9[189])\d{8}$/.test(value) === false) {
  145. callback(new Error("手机号格式错误"));
  146. } else {
  147. callback();
  148. }
  149. }, trigger: "blur"
  150. }
  151. ],
  152. tenantName: [
  153. {required: true, trigger: "blur", message: "租户不能为空"},
  154. {
  155. validator: (rule, value, callback) => {
  156. // debugger
  157. getTenantIdByName(value).then(res => {
  158. const tenantId = res.data;
  159. if (tenantId && tenantId >= 0) {
  160. // 设置租户
  161. setTenantId(tenantId)
  162. callback();
  163. } else {
  164. callback('租户不存在');
  165. }
  166. });
  167. },
  168. trigger: 'blur'
  169. }
  170. ]
  171. },
  172. loading: false,
  173. redirect: undefined,
  174. // 枚举
  175. SysUserSocialTypeEnum: SystemUserSocialTypeEnum,
  176. };
  177. },
  178. created() {
  179. // 租户开关
  180. this.tenantEnable = getTenantEnable();
  181. if (this.tenantEnable) {
  182. getTenantIdByName(this.loginForm.tenantName).then(res => { // 设置租户
  183. const tenantId = res.data;
  184. if (tenantId && tenantId >= 0) {
  185. setTenantId(tenantId)
  186. }
  187. });
  188. }
  189. // 验证码开关
  190. this.captchaEnable = getCaptchaEnable();
  191. // 重定向地址
  192. this.redirect = this.$route.query.redirect ? decodeURIComponent(this.$route.query.redirect) : undefined;
  193. this.getCookie();
  194. },
  195. methods: {
  196. getCode() {
  197. // 情况一,未开启:则直接登录
  198. if (!this.captchaEnable) {
  199. this.handleLogin({})
  200. return;
  201. }
  202. // 情况二,已开启:则展示验证码;只有完成验证码的情况,才进行登录
  203. // 弹出验证码
  204. this.$refs.verify.show()
  205. },
  206. getCookie() {
  207. const username = getUsername();
  208. const password = getPassword();
  209. const rememberMe = getRememberMe();
  210. const tenantName = getTenantName();
  211. this.loginForm = {
  212. ...this.loginForm,
  213. username: username ? username : this.loginForm.username,
  214. password: password ? password : this.loginForm.password,
  215. rememberMe: rememberMe ? getRememberMe() : false,
  216. tenantName: tenantName ? tenantName : this.loginForm.tenantName,
  217. };
  218. },
  219. handleLogin(captchaParams) {
  220. this.$refs.loginForm.validate(valid => {
  221. if (valid) {
  222. this.loading = true;
  223. // 设置 Cookie
  224. if (this.loginForm.rememberMe) {
  225. setUsername(this.loginForm.username)
  226. setPassword(this.loginForm.password)
  227. setRememberMe(this.loginForm.rememberMe)
  228. setTenantName(this.loginForm.tenantName)
  229. } else {
  230. removeUsername()
  231. removePassword()
  232. removeRememberMe()
  233. removeTenantName()
  234. }
  235. this.loginForm.captchaVerification = captchaParams.captchaVerification
  236. // 发起登陆
  237. // console.log("发起登录", this.loginForm);
  238. this.$store.dispatch(this.loginForm.loginType === "sms" ? "SmsLogin" : "Login", this.loginForm).then(() => {
  239. this.$router.push({path: this.redirect || "/"}).catch(() => {
  240. });
  241. }).catch(() => {
  242. this.loading = false;
  243. });
  244. }
  245. });
  246. },
  247. async doSocialLogin(socialTypeEnum) {
  248. // 设置登录中
  249. this.loading = true;
  250. let tenant = false;
  251. if (this.tenantEnable) {
  252. await this.$prompt('请输入租户名称', "提示", {
  253. confirmButtonText: "确定",
  254. cancelButtonText: "取消"
  255. }).then(async ({value}) => {
  256. await getTenantIdByName(value).then(res => {
  257. const tenantId = res.data;
  258. tenant = true
  259. if (tenantId && tenantId >= 0) {
  260. setTenantId(tenantId)
  261. }
  262. });
  263. }).catch(() => {
  264. // 取消登录按钮 loading状态
  265. this.loading = false;
  266. return false
  267. });
  268. } else {
  269. tenant = true
  270. }
  271. if(tenant){
  272. // 计算 redirectUri
  273. const redirectUri = location.origin + '/social-login?'
  274. + encodeURIComponent('type=' + socialTypeEnum.type + '&redirect=' + (this.redirect || "/")); // 重定向不能丢
  275. // const redirectUri = 'http://127.0.0.1:48080/api/gitee/callback';
  276. // const redirectUri = 'http://127.0.0.1:48080/api/dingtalk/callback';
  277. // 进行跳转
  278. socialAuthRedirect(socialTypeEnum.type, encodeURIComponent(redirectUri)).then((res) => {
  279. // console.log(res.url);
  280. window.location.href = res.data;
  281. });
  282. }
  283. },
  284. /** ========== 以下为升级短信登录 ========== */
  285. getSmsCode() {
  286. if (this.mobileCodeTimer > 0) return;
  287. this.$refs.loginForm.validate(valid => {
  288. if (!valid) return;
  289. sendSmsCode(this.loginForm.mobile, this.scene, this.loginForm.uuid, this.loginForm.code).then(res => {
  290. this.$modal.msgSuccess("获取验证码成功")
  291. this.mobileCodeTimer = 60;
  292. let msgTimer = setInterval(() => {
  293. this.mobileCodeTimer = this.mobileCodeTimer - 1;
  294. if (this.mobileCodeTimer <= 0) {
  295. clearInterval(msgTimer);
  296. }
  297. }, 1000);
  298. });
  299. });
  300. }
  301. }
  302. };
  303. </script>
  304. <style lang="scss" scoped>
  305. @import "~@/assets/styles/login.scss";
  306. .oauth-login {
  307. display: flex;
  308. align-items: center;
  309. cursor:pointer;
  310. }
  311. .oauth-login-item {
  312. display: flex;
  313. align-items: center;
  314. margin-right: 10px;
  315. }
  316. .oauth-login-item img {
  317. height: 25px;
  318. width: 25px;
  319. }
  320. .oauth-login-item span:hover {
  321. text-decoration: underline red;
  322. color: red;
  323. }
  324. </style>