diff --git a/admin/src/api/setting/system.ts b/admin/src/api/setting/system.ts index 60b2b9b191ddf1259859479e67a9c72aedd3b46b..c4b0aac60865559adf92059c2e64ea298901d857 100644 --- a/admin/src/api/setting/system.ts +++ b/admin/src/api/setting/system.ts @@ -39,3 +39,8 @@ export function crontabEdit(params: any) { export function crontabDel(params: any) { return request.post({ url: '/crontab/del', params }) } + +// 获取登录日志列表 +export function loginLogLists(params: any) { + return request.get({ url: '/system/log/login', params }) +} diff --git a/admin/src/api/user.ts b/admin/src/api/user.ts index ce54b585f001b87ce58c474e70389dda421e59df..19babf06e5c12ebed12747ab07be40a7b873deac 100644 --- a/admin/src/api/user.ts +++ b/admin/src/api/user.ts @@ -6,6 +6,11 @@ export function login(params: Record) { return request.post({ url: '/system/login', params: { ...params, terminal: config.terminal } }) } +// 登录 +export function loginCaptcha() { + return request.get({ url: '/system/captcha' }) +} + // 退出登录 export function logout() { return request.post({ url: '/system/logout' }) diff --git a/admin/src/enums/requestEnums.ts b/admin/src/enums/requestEnums.ts index 67d30b210c457340f7f6cd6c8e6c563d71a01af4..8ed7d3da37fcf58caffa1b062defddd5e89a3601 100644 --- a/admin/src/enums/requestEnums.ts +++ b/admin/src/enums/requestEnums.ts @@ -22,6 +22,7 @@ export enum RequestCodeEnum { LOGIN_DISABLE_ERROR = 331, //登陆账号已被禁用 TOKEN_EMPTY = 332, // TOKEN参数为空 TOKEN_INVALID = 333, // TOKEN参数无效 + VERIFICATION_CODE_ERROR = 334, // 验证码错误 NO_PERMISSTION = 403, //无相关权限 REQUEST_404_ERROR = 404, //请求接口不存在 SYSTEM_ERROR = 500 //系统错误 diff --git a/admin/src/stores/modules/user.ts b/admin/src/stores/modules/user.ts index d5248d6bc7255f5cc011a8ff0a86f0005aaa487d..16872857c15e7eeb82a4039bf8f98452c83c6a53 100644 --- a/admin/src/stores/modules/user.ts +++ b/admin/src/stores/modules/user.ts @@ -34,11 +34,13 @@ const useUserStore = defineStore({ this.perms = [] }, login(playload: any) { - const { account, password } = playload + const { account, password, code, uuid } = playload return new Promise((resolve, reject) => { login({ username: account, - password: password + password, + code, + uuid }) .then((data) => { this.token = data.token diff --git a/admin/src/utils/request/index.ts b/admin/src/utils/request/index.ts index 7fa37b3fd343f8d3d5884b8ebac39fff9d55ea68..48a8120f16428a3a8ead25c561b42a9c17f3127c 100644 --- a/admin/src/utils/request/index.ts +++ b/admin/src/utils/request/index.ts @@ -69,6 +69,7 @@ const axiosHooks: AxiosHooks = { case RequestCodeEnum.NO_PERMISSTION: case RequestCodeEnum.FAILED: case RequestCodeEnum.SYSTEM_ERROR: + case RequestCodeEnum.VERIFICATION_CODE_ERROR: msg && feedback.msgError(msg) return Promise.reject(data) diff --git a/admin/src/views/account/login.vue b/admin/src/views/account/login.vue index 8f813be8be8e495e694c36ac532817d6c97b3b84..2ca5d9bfe8e87c84424126948d6653a9612634bc 100644 --- a/admin/src/views/account/login.vue +++ b/admin/src/views/account/login.vue @@ -34,6 +34,25 @@ + +
+ + + +
+ +
+
+
@@ -58,6 +77,7 @@ import cache from '@/utils/cache' import { ACCOUNT_KEY } from '@/enums/cacheEnums' import { PageEnum } from '@/enums/pageEnum' import { useLockFn } from '@/hooks/useLockFn' +import { loginCaptcha } from '@/api/user' const passwordRef = shallowRef() const formRef = shallowRef() const appStore = useAppStore() @@ -66,9 +86,12 @@ const route = useRoute() const router = useRouter() const remAccount = ref(false) const config = computed(() => appStore.config) +const codeImg = ref() const formData = reactive({ account: '', - password: '' + password: '', + code: '', + uuid: '' }) const rules = { account: [ @@ -84,8 +107,21 @@ const rules = { message: '请输入密码', trigger: ['blur'] } + ], + code: [ + { + required: true, + message: '请输入验证码', + trigger: ['blur'] + } ] } + +const getLoginCaptcha = async () => { + const data = await loginCaptcha() + formData.uuid = data.uuid + codeImg.value = data.img +} // 回车按键监听 const handleEnter = () => { if (!formData.password) { @@ -101,7 +137,11 @@ const handleLogin = async () => { remember: remAccount.value, account: remAccount.value ? formData.account : '' }) - await userStore.login(formData) + try { + await userStore.login(formData) + } catch (error) { + getLoginCaptcha() + } const { query: { redirect } } = route @@ -112,6 +152,7 @@ const { isLock, lockFn: lockLogin } = useLockFn(handleLogin) onMounted(() => { const value = cache.get(ACCOUNT_KEY) + getLoginCaptcha() if (value?.remember) { remAccount.value = value.remember formData.account = value.account @@ -125,6 +166,9 @@ onMounted(() => { @apply min-h-screen bg-no-repeat bg-center bg-cover; .login-card { height: 400px; + :deep(.el-input-group__prepend) { + padding: 0 15px; + } } } diff --git a/admin/src/views/channel/wx_oa/menu_com/useMenuOa.ts b/admin/src/views/channel/wx_oa/menu_com/useMenuOa.ts index f86ba91b169ed186e8218379cd516373ab2ed38a..dcdfd637532bbe0feecded206d42e48954e0de80 100644 --- a/admin/src/views/channel/wx_oa/menu_com/useMenuOa.ts +++ b/admin/src/views/channel/wx_oa/menu_com/useMenuOa.ts @@ -47,7 +47,7 @@ export const rules = reactive({ }, { pattern: - /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(([A-Za-z0-9-~]+)\.)+([A-Za-z0-9-~\/])+$/, + /(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/, message: '请输入合法的网址链接', trigger: ['blur', 'change'] } diff --git a/admin/src/views/permission/menu/index.vue b/admin/src/views/permission/menu/index.vue index d4ec4ff53271342234db4a0afa412e8d81ac9459..76da60cee75f016c0cdfd1e681d0a1d98602ca9c 100644 --- a/admin/src/views/permission/menu/index.vue +++ b/admin/src/views/permission/menu/index.vue @@ -60,6 +60,7 @@