From 75e6912a8d93725e1038d1ecd9c1438ec223f2ca Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期四, 14 十一月 2024 14:38:10 +0800 Subject: [PATCH] refactor(layout): 重构布局组件并优化登录功能 --- vite.config.ts | 2 src/stores/chatRoom.ts | 2 src/layout/component/main.vue | 13 + src/layout/component/sidebar/components/MenuList.vue | 148 -------------------- src/layout/component/login/Login.vue | 253 ++++++++++++++++++++++++++++++++++++ 5 files changed, 267 insertions(+), 151 deletions(-) diff --git a/src/layout/component/login/Login.vue b/src/layout/component/login/Login.vue new file mode 100644 index 0000000..89733e9 --- /dev/null +++ b/src/layout/component/login/Login.vue @@ -0,0 +1,253 @@ +<template> + <div class="pc-login items-center justify-center" style="display: flex" v-show="isShowLogin"> + <div class="login_box"> + <div class="sign_in"> + <i class="ywifont ywicon-guanbi closes" @click="handleClose"></i> + <h1><span>鐧诲綍 WI 姘村姟鏅鸿兘</span></h1> + <el-tabs v-model="state.activeLoginName" class="mt-[24px]" @tab-change="handleUserClick"> + <el-tab-pane label="璐︽埛瀵嗙爜鐧诲綍" name="accountUser"> + <el-form + ref="loginFormRef" + :model="state.loginForm" + :rules="loginRules" + class="demo-ruleForm mt-[24px] min-h-[140px]" + size="large" + > + <el-form-item label="璐﹀彿" prop="account"> + <el-input v-model="state.loginForm.account" clearable /> + </el-form-item> + <el-form-item label="瀵嗙爜" prop="pwd"> + <el-input v-model="state.loginForm.pwd" type="password" autocomplete="off" clearable /> + </el-form-item> + </el-form> + </el-tab-pane> + <el-tab-pane label="鎵嬫満鍙风櫥褰�" name="phoneUser"> + <el-form + ref="formPhoneRef" + :rules="loginPhoneRules" + :model="state.loginPhoneForm" + size="large" + class="mt-[24px] min-h-[140px]" + > + <el-form-item label="鎵嬫満鍙�" prop="phoneUser"> + <el-input v-model="state.loginPhoneForm.phoneUser" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" clearable> + <template #prepend>+86</template> + </el-input> + </el-form-item> + <el-form-item prop="verifyCode" label="楠岃瘉鐮�"> + <el-input v-model="state.loginPhoneForm.verifyCode" placeholder="璇疯緭鍏ュ洓浣嶉獙璇佺爜" maxlength="6" clearable> + <template #append> + <el-button type="primary" @click="handleSendVerifyCode" :disabled="hasSended">{{ sendCodeMsg }}</el-button> + </template> + </el-input> + </el-form-item> + </el-form> + </el-tab-pane> + </el-tabs> + + <div class="mt-[24px]"> + <el-button type="primary" @click="onSubmit" class="set-login_btn">鐧诲綍</el-button> + </div> + </div> + </div> + </div> +</template> +<script setup lang="ts"> +import { ElMessage, type FormInstance } from 'element-plus'; +import { computed, reactive, ref } from 'vue'; +import { PostLogin, loginMessageUser, loginVerifyMessage } from '/@/api/ai/user'; +import { isLoginStatus, isShowLogin } from '/@/stores/chatRoom'; + +import { LoginInfo } from '/@/utils/storage'; + +const handleClose = () => { + isShowLogin.value = false; +}; + +//鍒囨崲鐢ㄦ埛鐧诲綍椤甸潰 +const handleUserClick = (item) => { + state.activeLoginName = item; + // formPhoneRef?.value?.resetFields(); + // loginFormRef.value.resetFields(); +}; +const state = reactive({ + activeLoginName: 'accountUser', + loginForm: { + account: '', + pwd: '', + }, + loginPhoneForm: { + phoneUser: '', + verifyCode: '', + }, +}); +const loginRules = reactive({ + account: [{ required: true, message: '璇疯緭鍏ヨ处鍙�', trigger: 'blur' }], + pwd: [{ required: true, message: '璇疯緭鍏ュ瘑鐮�', trigger: 'blur' }], +}); +const loginPhoneRules = { + phoneUser: [ + { required: true, message: '璇疯緭鍏ユ墜鏈哄彿鐮�', trigger: 'blur' }, + { pattern: /^1\d{10}$/, message: '璇疯緭鍏ユ纭殑鎵嬫満鍙风爜', trigger: 'blur' }, + ], + verifyCode: [{ required: true, message: '璇疯緭鍏ラ獙璇佺爜', trigger: 'blur' }], +}; +const LOGIN_CLIENT = 'Web绔�'; +const loginFormRef = ref<FormInstance>(null); //璐︽埛瀵嗙爜鐧诲綍 +const formPhoneRef = ref(); //鎵嬫満鍙风櫥褰� +const hasSended = computed(() => { + return countdown.value !== null; +}); +const sendCodeMsg = computed(() => { + return !hasSended.value ? '鑾峰彇楠岃瘉鐮�' : `${countdown.value} 绉掑悗閲嶈瘯`; +}); +//鐧诲綍 +const onSubmit = async () => { + if (state.activeLoginName === 'accountUser') { + //璐︽埛瀵嗙爜鐧诲綍 + const isValid = await loginFormRef.value.validate().catch(() => {}); + if (!isValid) return; + const res = await PostLogin({ + user: state.loginForm.account, + pass: state.loginForm.pwd, + client: LOGIN_CLIENT, + }); + if (!res.json_ok) { + return ElMessage.error(res.json_msg); + } + + LoginInfo.set(res.hswatersession, state.loginForm.account); + } else if (state.activeLoginName === 'phoneUser') { + //鎵嬫満鐧诲綍 + const isValid = await formPhoneRef.value.validate().catch(() => {}); + if (!isValid) return; + const res = await loginMessageUser({ + phone: state.loginPhoneForm.phoneUser, + code: state.loginPhoneForm.verifyCode, + client: LOGIN_CLIENT, + }); + if (!res.json_ok) { + return ElMessage.error(res.json_msg); + } + LoginInfo.set(res.hswatersession, state.loginPhoneForm.phoneUser); + } + + isShowLogin.value = false; + isLoginStatus.value = true; + window.location.reload(); +}; +const countdown = ref(null); + +//鑾峰彇楠岃瘉鐮� +const handleSendVerifyCode = async () => { + formPhoneRef.value.validateField('phoneUser', async (valid: boolean) => { + if (valid) { + const res = await loginVerifyMessage({ + phone: state.loginPhoneForm.phoneUser, + }); + if (res.json_ok) { + countdown.value = 60; //寮�鍚�掕鏃� + // 鍊掕鏃堕�昏緫 + const intervalId = setInterval(() => { + if (countdown.value > 0) { + countdown.value--; + } else { + clearInterval(intervalId); + } + }, 1000); + } + } + }); +}; +</script> + +<style lang="scss" scoped> +.pc-login { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: 2000; + background-color: rgba(0, 0, 0, 0.6); + .login_box { + position: relative; + width: 450px; + margin: 15vh auto; + .sign_in { + padding: 39px; + position: relative; + width: 100%; + height: 100%; + border-radius: 12px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #fff; + -webkit-box-shadow: 0 0 16px 0 rgba(20, 29, 53, 0.21); + box-shadow: 0 0 16px 0 rgba(20, 29, 53, 0.21); + .closes { + position: absolute; + top: -28px; + right: -38px; + font-size: 30px; + cursor: pointer; + color: #eee; + -o-transition: color 0.1s; + transition: color 0.1s; + } + h1 { + box-sizing: content-box; + width: 100%; + font-size: 30px; + font-weight: 500; + color: #1c153a; + text-align: left !important; + } + .demo-ruleForm { + :deep(.el-input__wrapper) { + position: relative; + margin-bottom: 12px; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 346px; + // height: 44px; + background-color: #fff; + border-radius: 5px; + } + :deep(.el-form-item--large .el-form-item__error) { + padding: unset !important; + } + } + .set-pwd { + text-align: right; + font-size: 14px; + font-weight: 300; + color: #999; + width: 100%; + padding: 0px 32px; + } + .set-login_btn { + width: 366px; + height: 44px; + font-size: 16px; + font-weight: 500; + color: #fff; + background: #0a58ed; + border-radius: 12px; + -webkit-box-shadow: 4px 6px 15px rgba(10, 88, 237, 0.2); + box-shadow: 4px 6px 15px rgba(10, 88, 237, 0.2); + } + } + } +} +</style> diff --git a/src/layout/component/main.vue b/src/layout/component/main.vue index ae57df5..c497846 100644 --- a/src/layout/component/main.vue +++ b/src/layout/component/main.vue @@ -9,7 +9,7 @@ wrap-class="layout-main-scroll flex" view-class="layout-main-scroll bg-[#1c1e1d] flex h100 w-full" > - <SideBar v-if="!isSharePage && sidebarIsShow" :isShow="sidebarIsShow" @toggleSidebar="toggleSidebar"/> + <SideBar v-if="!isSharePage && sidebarIsShow" :isShow="sidebarIsShow" @toggleSidebar="toggleSidebar" /> <div class="flex-auto flex-col flex right-container" :class="{ @@ -19,10 +19,11 @@ 'bg-[#f7f8fa]': isSharePage, }" > - <Header v-if="!isSharePage" class="flex-0" @toggleSidebar="toggleSidebar" :sidebarIsShow="sidebarIsShow"/> + <Header v-if="!isSharePage" class="flex-0" @toggleSidebar="toggleSidebar" :sidebarIsShow="sidebarIsShow" /> <ShareHeader v-else class="flex-0"></ShareHeader> <LayoutParentView class="flex-auto" /> </div> + <Login v-show="isShowLogin" /> </el-scrollbar> <el-backtop :target="setBacktopClass" /> </el-main> @@ -36,12 +37,12 @@ import ShareHeader from './header/ShareHeader.vue'; import SideBar from './sidebar/Sidebar.vue'; +import { isSharePage, isShowLogin } from '/@/stores/chatRoom'; import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes'; import { useThemeConfig } from '/@/stores/themeConfig'; import { NextLoading } from '/@/utils/loading'; -import { isSharePage } from '/@/stores/chatRoom'; import { Local } from '/@/utils/storage'; - +import Login from './login/Login.vue'; // 寮曞叆缁勪欢 const LayoutParentView = defineAsyncComponent(() => import('/@/layout/routerView/parent.vue')); const LayoutFooter = defineAsyncComponent(() => import('/@/layout/footer/index.vue')); @@ -52,7 +53,7 @@ const storesThemeConfig = useThemeConfig(); const { themeConfig } = storeToRefs(storesThemeConfig); const { isTagsViewCurrenFull } = storeToRefs(storesTagsViewRoutes); - +; // 璁剧疆 footer 鏄剧ず/闅愯棌 const isFooter = computed(() => { return themeConfig.value.isFooter && !route.meta.isIframe; @@ -87,7 +88,7 @@ const sidebarIsShow = ref(!!Local.get('sidebarIsShow')); const toggleSidebar = (val) => { sidebarIsShow.value = val; - Local.set('sidebarIsShow',val) + Local.set('sidebarIsShow', val); }; //#endregion </script> diff --git a/src/layout/component/sidebar/components/MenuList.vue b/src/layout/component/sidebar/components/MenuList.vue index 579cdb5..2bbf11c 100644 --- a/src/layout/component/sidebar/components/MenuList.vue +++ b/src/layout/component/sidebar/components/MenuList.vue @@ -37,76 +37,19 @@ </div> </div> </div> - <div class="pc-login items-center justify-center" style="display: flex" v-show="isShowLogin"> - <div class="login_box"> - <div class="sign_in"> - <i class="ywifont ywicon-guanbi closes" @click="handleClose"></i> - <h1><span>鐧诲綍 WI 姘村姟鏅鸿兘</span></h1> - <el-tabs v-model="state.activeLoginName" class="mt-[24px]" @tab-change="handleUserClick"> - <el-tab-pane label="璐︽埛瀵嗙爜鐧诲綍" name="accountUser"> - <el-form - ref="loginFormRef" - :model="state.loginForm" - :rules="loginRules" - class="demo-ruleForm mt-[24px] min-h-[140px]" - size="large" - > - <el-form-item label="璐﹀彿" prop="account"> - <el-input v-model="state.loginForm.account" clearable /> - </el-form-item> - <el-form-item label="瀵嗙爜" prop="pwd"> - <el-input v-model="state.loginForm.pwd" type="password" autocomplete="off" clearable /> - </el-form-item> - </el-form> - </el-tab-pane> - <el-tab-pane label="鎵嬫満鍙风櫥褰�" name="phoneUser"> - <el-form - ref="formPhoneRef" - :rules="loginPhoneRules" - :model="state.loginPhoneForm" - size="large" - class="mt-[24px] min-h-[140px]" - > - <el-form-item label="鎵嬫満鍙�" prop="phoneUser"> - <el-input v-model="state.loginPhoneForm.phoneUser" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" clearable> - <template #prepend>+86</template> - </el-input> - </el-form-item> - <el-form-item prop="verifyCode" label="楠岃瘉鐮�"> - <el-input v-model="state.loginPhoneForm.verifyCode" placeholder="璇疯緭鍏ュ洓浣嶉獙璇佺爜" maxlength="6" clearable> - <template #append> - <el-button type="primary" @click="handleSendVerifyCode" :disabled="hasSended">{{ sendCodeMsg }}</el-button> - </template> - </el-input> - </el-form-item> - </el-form> - </el-tab-pane> - </el-tabs> - - <div class="mt-[24px]"> - <el-button type="primary" @click="onSubmit" class="set-login_btn">鐧诲綍</el-button> - </div> - </div> - </div> - </div> </template> <script setup lang="ts"> -import { ElMessage, type FormInstance } from 'element-plus'; import { computed, onMounted, reactive, ref, watchEffect } from 'vue'; -import { PostLogin, loginMessageUser, loginVerifyMessage } from '/@/api/ai/user'; import router from '/@/router'; -import { isSharePage, isShowLogin } from '/@/stores/chatRoom'; -import emitter from '/@/utils/mitt'; +import { isLoginStatus, isSharePage, isShowLogin } from '/@/stores/chatRoom'; import { accessSessionKey, userNameKey } from '/@/utils/request'; import { gotoRoute } from '/@/utils/route'; import { Local, LoginInfo } from '/@/utils/storage'; -const loginFormRef = ref<FormInstance>(null); //璐︽埛瀵嗙爜鐧诲綍 -const formPhoneRef = ref(); //鎵嬫満鍙风櫥褰� -const isLoginStatus = ref(!!Local.get(accessSessionKey)); +import emitter from '/@/utils/mitt'; const userName = ref(''); -const countdown = ref(null); const firstUserCharacter = computed(() => userName.value?.[0]?.toUpperCase()); +isLoginStatus.value = !!Local.get(accessSessionKey); watchEffect(() => { if (!isLoginStatus.value) return; userName.value = Local.get(userNameKey); @@ -148,72 +91,16 @@ }, activeLoginName: 'accountUser', }); -const loginRules = reactive({ - account: [{ required: true, message: '璇疯緭鍏ヨ处鍙�', trigger: 'blur' }], - pwd: [{ required: true, message: '璇疯緭鍏ュ瘑鐮�', trigger: 'blur' }], -}); -const loginPhoneRules = { - phoneUser: [ - { required: true, message: '璇疯緭鍏ユ墜鏈哄彿鐮�', trigger: 'blur' }, - { pattern: /^1\d{10}$/, message: '璇疯緭鍏ユ纭殑鎵嬫満鍙风爜', trigger: 'blur' }, - ], - verifyCode: [{ required: true, message: '璇疯緭鍏ラ獙璇佺爜', trigger: 'blur' }], -}; const handleClick = (item) => { if (!item.routerName) return; gotoRoute({ name: item.routerName }); }; -const LOGIN_CLIENT = 'Web绔�'; //鐧诲綍 const openLoginDlg = async () => { // 鍒嗕韩椤典笉闇�瑕� if (isSharePage.value) return; isShowLogin.value = true; -}; -const handleClose = () => { - isShowLogin.value = false; -}; -const hasSended = computed(() => { - return countdown.value !== null; -}); -const sendCodeMsg = computed(() => { - return !hasSended.value ? '鑾峰彇楠岃瘉鐮�' : `${countdown.value} 绉掑悗閲嶈瘯`; -}); -//鐧诲綍 -const onSubmit = async () => { - if (state.activeLoginName === 'accountUser') { - //璐︽埛瀵嗙爜鐧诲綍 - const isValid = await loginFormRef.value.validate().catch(() => {}); - if (!isValid) return; - const res = await PostLogin({ - user: state.loginForm.account, - pass: state.loginForm.pwd, - client: LOGIN_CLIENT, - }); - if (!res.json_ok) { - return ElMessage.error(res.json_msg); - } - - LoginInfo.set(res.hswatersession, state.loginForm.account); - } else if (state.activeLoginName === 'phoneUser') { - //鎵嬫満鐧诲綍 - const isValid = await formPhoneRef.value.validate().catch(() => {}); - if (!isValid) return; - const res = await loginMessageUser({ - phone: state.loginPhoneForm.phoneUser, - code: state.loginPhoneForm.verifyCode, - client: LOGIN_CLIENT, - }); - if (!res.json_ok) { - return ElMessage.error(res.json_msg); - } - LoginInfo.set(res.hswatersession, state.loginPhoneForm.phoneUser); - } - - isShowLogin.value = false; - isLoginStatus.value = true; - window.location.reload(); }; const currentRoute = router.currentRoute; @@ -235,33 +122,7 @@ state.isShowExitLogin = false; } }; -//鍒囨崲鐢ㄦ埛鐧诲綍椤甸潰 -const handleUserClick = (item) => { - state.activeLoginName = item; - // formPhoneRef?.value?.resetFields(); - // loginFormRef.value.resetFields(); -}; -//鑾峰彇楠岃瘉鐮� -const handleSendVerifyCode = async () => { - formPhoneRef.value.validateField('phoneUser', async (valid: boolean) => { - if (valid) { - const res = await loginVerifyMessage({ - phone: state.loginPhoneForm.phoneUser, - }); - if (res.json_ok) { - countdown.value = 60; //寮�鍚�掕鏃� - // 鍊掕鏃堕�昏緫 - const intervalId = setInterval(() => { - if (countdown.value > 0) { - countdown.value--; - } else { - clearInterval(intervalId); - } - }, 1000); - } - } - }); -}; + onMounted(() => { emitter.on('openLoginDlg', () => { if (isShowLogin.value || isLoginStatus.value) return; @@ -271,7 +132,6 @@ emitter.on('logout', () => { logoutClick(); }); - document.addEventListener('click', listenClickOtherExit); }); </script> diff --git a/src/stores/chatRoom.ts b/src/stores/chatRoom.ts index 2246114..f3040be 100644 --- a/src/stores/chatRoom.ts +++ b/src/stores/chatRoom.ts @@ -70,6 +70,8 @@ */ export const sectionAList = ref([]); export const isShowLogin = ref(false); +export const isLoginStatus = ref(false); + //#region ====================== 鍏ㄥ眬浣跨敤鏁版嵁 ====================== // group 鍒楄〃 export const sceneGroupList = ref([]); diff --git a/vite.config.ts b/vite.config.ts index 0b2943c..8721d31 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -41,7 +41,7 @@ host: '0.0.0.0', port: env.VITE_PORT as unknown as number, open: JSON.parse(env.VITE_OPEN), - hmr: true, + hmr: false, }, build: { // outDir: 'dist/' + mode.mode, -- Gitblit v1.9.3