diff --git a/yudao-ui-admin-vue3/package.json b/yudao-ui-admin-vue3/package.json index c221f0d68..c0669aab5 100644 --- a/yudao-ui-admin-vue3/package.json +++ b/yudao-ui-admin-vue3/package.json @@ -38,6 +38,7 @@ "element-plus": "2.2.12", "intro.js": "^6.0.0", "jsencrypt": "^3.2.1", + "crypto-js": "^4.1.1", "lodash-es": "^4.17.21", "mitt": "^3.0.0", "nprogress": "^0.2.0", diff --git a/yudao-ui-admin-vue3/src/api/login/index.ts b/yudao-ui-admin-vue3/src/api/login/index.ts index 485d273c9..6b53f84e5 100644 --- a/yudao-ui-admin-vue3/src/api/login/index.ts +++ b/yudao-ui-admin-vue3/src/api/login/index.ts @@ -18,11 +18,6 @@ export interface SmsLoginVO { code: string } -// 获取验证码 -export const getCodeImgApi = () => { - return request.get({ url: '/system/captcha/get-image' }) -} - // 登录 export const loginApi = (data: UserLoginVO) => { return request.post({ url: '/system/auth/login', data }) diff --git a/yudao-ui-admin-vue3/src/api/login/types.ts b/yudao-ui-admin-vue3/src/api/login/types.ts index 75abe28ce..29bc80642 100644 --- a/yudao-ui-admin-vue3/src/api/login/types.ts +++ b/yudao-ui-admin-vue3/src/api/login/types.ts @@ -1,8 +1,6 @@ export type UserLoginVO = { username: string password: string - code: string - uuid: string } export type TokenType = { diff --git a/yudao-ui-admin-vue3/src/components/Verifition/index.ts b/yudao-ui-admin-vue3/src/components/Verifition/index.ts new file mode 100644 index 000000000..bcfe6d940 --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/index.ts @@ -0,0 +1,3 @@ +import Verify from './src/Verify.vue' + +export { Verify } diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/Verify.vue b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify.vue new file mode 100644 index 000000000..9fe0c5475 --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify.vue @@ -0,0 +1,438 @@ + + + diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/VerifyPoints.vue b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/VerifyPoints.vue new file mode 100644 index 000000000..36fdae889 --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/VerifyPoints.vue @@ -0,0 +1,279 @@ + + diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/VerifySlide.vue b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/VerifySlide.vue new file mode 100644 index 000000000..a31f4587f --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/VerifySlide.vue @@ -0,0 +1,422 @@ + + diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/index.ts b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/index.ts new file mode 100644 index 000000000..0daa63a56 --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/Verify/index.ts @@ -0,0 +1,4 @@ +import VerifySlide from './VerifySlide.vue' +import VerifyPoints from './VerifyPoints.vue' + +export { VerifySlide, VerifyPoints } diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/api/index.ts b/yudao-ui-admin-vue3/src/components/Verifition/src/api/index.ts new file mode 100644 index 000000000..6a67b7119 --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/api/index.ts @@ -0,0 +1,24 @@ +/** + * 此处可直接引用自己项目封装好的 axios 配合后端联调 + */ + +import request from './../utils/axios' //组件内部封装的axios +// import request from "@/api/axios.js" //调用项目封装的axios + +//获取验证图片 以及token +export function reqGet(data) { + return request({ + url: '/captcha/get', + method: 'post', + data + }) +} + +//滑动或者点选验证 +export function reqCheck(data) { + return request({ + url: '/captcha/check', + method: 'post', + data + }) +} diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/utils/ase.ts b/yudao-ui-admin-vue3/src/components/Verifition/src/utils/ase.ts new file mode 100644 index 000000000..d2e6b988f --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/utils/ase.ts @@ -0,0 +1,14 @@ +import CryptoJS from 'crypto-js' +/** + * @word 要加密的内容 + * @keyWord String 服务器随机返回的关键字 + * */ +export function aesEncrypt(word, keyWord = 'XwKsGlMcdPMEhR1B') { + const key = CryptoJS.enc.Utf8.parse(keyWord) + const srcs = CryptoJS.enc.Utf8.parse(word) + const encrypted = CryptoJS.AES.encrypt(srcs, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7 + }) + return encrypted.toString() +} diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/utils/axios.ts b/yudao-ui-admin-vue3/src/components/Verifition/src/utils/axios.ts new file mode 100644 index 000000000..ca68097e7 --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/utils/axios.ts @@ -0,0 +1,26 @@ +import axios from 'axios' + +axios.defaults.baseURL = import.meta.env.VITE_BASE_URL + +const service = axios.create({ + timeout: 40000, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/json; charset=UTF-8' + } +}) +service.interceptors.request.use( + (config) => { + return config + }, + (error) => { + Promise.reject(error) + } +) + +// response interceptor +service.interceptors.response.use((response) => { + const res = response.data + return res +}) +export default service diff --git a/yudao-ui-admin-vue3/src/components/Verifition/src/utils/util.ts b/yudao-ui-admin-vue3/src/components/Verifition/src/utils/util.ts new file mode 100644 index 000000000..15c16270d --- /dev/null +++ b/yudao-ui-admin-vue3/src/components/Verifition/src/utils/util.ts @@ -0,0 +1,97 @@ +export function resetSize(vm) { + let img_width, img_height, bar_width, bar_height //图片的宽度、高度,移动条的宽度、高度 + const EmployeeWindow = window as any + const parentWidth = vm.$el.parentNode.offsetWidth || EmployeeWindow.offsetWidth + const parentHeight = vm.$el.parentNode.offsetHeight || EmployeeWindow.offsetHeight + if (vm.imgSize.width.indexOf('%') != -1) { + img_width = (parseInt(vm.imgSize.width) / 100) * parentWidth + 'px' + } else { + img_width = vm.imgSize.width + } + + if (vm.imgSize.height.indexOf('%') != -1) { + img_height = (parseInt(vm.imgSize.height) / 100) * parentHeight + 'px' + } else { + img_height = vm.imgSize.height + } + + if (vm.barSize.width.indexOf('%') != -1) { + bar_width = (parseInt(vm.barSize.width) / 100) * parentWidth + 'px' + } else { + bar_width = vm.barSize.width + } + + if (vm.barSize.height.indexOf('%') != -1) { + bar_height = (parseInt(vm.barSize.height) / 100) * parentHeight + 'px' + } else { + bar_height = vm.barSize.height + } + + return { imgWidth: img_width, imgHeight: img_height, barWidth: bar_width, barHeight: bar_height } +} + +export const _code_chars = [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z' +] +export const _code_color1 = ['#fffff0', '#f0ffff', '#f0fff0', '#fff0f0'] +export const _code_color2 = ['#FF0033', '#006699', '#993366', '#FF9900', '#66CC66', '#FF33CC'] diff --git a/yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue b/yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue index bb876e0a3..0a43fa675 100644 --- a/yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue +++ b/yudao-ui-admin-vue3/src/views/Login/components/LoginForm.vue @@ -30,6 +30,7 @@ import { required } from '@/utils/formRules' import { Icon } from '@/components/Icon' import { LoginStateEnum, useLoginState, useFormValid } from './useLogin' import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router' +import { Verify } from '@/components/Verifition' const { currentRoute, addRoute, push } = useRouter() const permissionStore = usePermissionStore() @@ -46,12 +47,10 @@ const { t } = useI18n() const iconHouse = useIcon({ icon: 'ep:house' }) const iconAvatar = useIcon({ icon: 'ep:avatar' }) const iconLock = useIcon({ icon: 'ep:lock' }) -const iconCircleCheck = useIcon({ icon: 'ep:circle-check' }) const LoginCaptchaRules = { tenantName: [required], username: [required], - password: [required], - code: [required] + password: [required] } const LoginRules = { tenantName: [required], @@ -60,7 +59,6 @@ const LoginRules = { } const loginLoading = ref(false) const loginData = reactive({ - codeImg: '', isShowPassword: false, captchaEnable: true, tenantEnable: true, @@ -72,20 +70,16 @@ const loginData = reactive({ tenantName: '芋道源码', username: 'admin', password: 'admin123', - rememberMe: false, - code: '', - uuid: '' + rememberMe: false } }) +// blockPuzzle 滑块 clickWord 点击文字 +const verify = ref() +const captchaType = ref('blockPuzzle') // 获取验证码 const getCode = async () => { - const res = await LoginApi.getCodeImgApi() - loginData.captchaEnable = res.enable - if (res.enable) { - loginData.codeImg = 'data:image/gif;base64,' + res.img - loginData.loginForm.uuid = res.uuid - } + verify.value.show() } //获取租户ID const getTenantId = async () => { @@ -112,19 +106,12 @@ const handleLogin = async () => { const data = await validForm() if (!data) return loginLoading.value = true - await LoginApi.loginApi(loginData.loginForm) - .then(async (res) => { - setToken(res) - const userInfo = await LoginApi.getInfoApi() - await userStore.getUserInfoAction(userInfo) - await getRoutes() - }) - .catch(() => { - getCode() - }) - .finally(() => { - loginLoading.value = false - }) + const res = await LoginApi.loginApi(loginData.loginForm) + setToken(res) + const userInfo = await LoginApi.getInfoApi() + await userStore.getUserInfoAction(userInfo) + await getRoutes() + loginLoading.value = false } // 获取路由 @@ -159,8 +146,7 @@ watch( immediate: true } ) -onMounted(async () => { - await getCode() +onMounted(() => { getCookie() }) @@ -207,31 +193,11 @@ onMounted(async () => { type="password" :placeholder="t('login.passwordPlaceholder')" show-password - @keyup.enter="handleLogin" + @keyup.enter="getCode()" :prefix-icon="iconLock" /> - - - - - - - - - - - - { - + {{ t('login.login') }} +