gerson
2024-07-04 806020211c46dbea8a2ef321e78d54fb001057a0
路由和请求均可唤起登录弹窗
已删除2个文件
已修改13个文件
898 ■■■■ 文件已修改
src/api/menu/menuData.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/component/sidebar/waterLeftAside/asideTitle.vue 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/main/classic.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/navBars/breadcrumb/user.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/upgrade/index.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.ts 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/backEnd.ts 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/route.ts 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/stores/userInfo.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/types/mitt.d.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.ts 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/error/404.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/component/account.vue 358 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index_ch.vue 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/menu/menuData.ts
@@ -1,4 +1,4 @@
export const MenuData = [
export const menuData = [
    {
        Children: [],
        ID: '1805430930840621056',
src/layout/component/sidebar/waterLeftAside/asideTitle.vue
@@ -12,32 +12,29 @@
                <span class="font-medium text-sm text-white tracking-wide">{{ item.title }}</span>
            </div>
        </div>
        <div class="user_text">
        <div class="user_text" v-if="isLoginStatus">
            <div class="user_head">
                <span
                    ><span
                        ><span class="user-head">T</span><span class="identifying"><!----></span></span
                    ><span class="user_name"> tc </span></span
                        ><span class="user-head">{{ firstUserCharacter }}</span><span class="identifying"><!----></span></span
                    ><span class="user_name"> {{ userName }} </span></span
                ><span ref="toggleExitLoginBtnRef"
                ><span
                    ><span><i class="ywicon icon-fold text-white" @click="showExitLogin"></i></span
                        class="ywicon text-white"
                        :class="{ 'icon-fold': !state.isShowExitLogin, 'icon-unfold': state.isShowExitLogin }"
                        @click="toggleShowExitLogin"
                    ></span
                ></span>
            </div>
            <!-- <div class="pop_up actived" v-show="state.isShowExitLogin">
                <div class="exit" @click="handleExitClose"><i class="ywicon icon-tuichu"></i> é€€å‡ºç™»å½•</div>
            </div> -->
        </div>
        <!-- <div class="user_login">
            <p class="text-white font-medium text-sm text-center">您更好的AI助手!</p>
            <div class="set-login" @click="login">
                <span class="text-stone-100 font-medium text-sm text-center">{{ state.isShowLogin ? '登录 / æ³¨å†Œ' : '会员登录' }}</span>
            <div class="pop_up actived" v-show="state.isShowExitLogin">
                <div class="exit" @click="logoutClick"><i class="ywicon icon-tuichu"></i> é€€å‡ºç™»å½•</div>
            </div>
        </div>
        <div class="offices">
            <div class="officeText">
                <img :src="'/static/images/wave/Waveform.png'" alt="" class="pl-2.5 pr-2.5 w-4 h-4" style="box-sizing: content-box" />
                <span class="font-medium text-sm text-white tracking-wide">Office æ™ºèƒ½åŠ©æ‰‹</span>
        <div v-else class="user_login">
            <div class="set-login" @click="openLoginDlg">
                <span class="text-stone-100 font-medium text-sm text-center">登录 / æ³¨å†Œ</span>
            </div>
        </div> -->
        </div>
    </div>
    <div class="pc-login" v-show="state.isShowLogin">
        <div class="login_box">
@@ -52,7 +49,6 @@
                        <el-input v-model="state.loginForm.pwd" type="password" autocomplete="off" clearable />
                    </el-form-item>
                </el-form>
                <div class="set-pwd">忘记密码 ?</div>
                <div class="mt-[115px]">
                    <el-button type="primary" @click="onSubmit" class="set-login_btn">登录</el-button>
                </div>
@@ -62,9 +58,24 @@
</template>
<script setup lang="ts">
import { reactive } from 'vue';
import type { FormInstance } from 'element-plus';
import { computed, onMounted, reactive, ref, watchEffect } from 'vue';
import { PostLogin } from '/@/api/ai/user';
import router from '/@/router';
import { accessSessionKey, userNameKey } from '/@/utils/request';
import { gotoRoute } from '/@/utils/route';
import { Local } from '/@/utils/storage';
import emitter from '/@/utils/mitt';
const loginFormRef = ref<FormInstance>(null);
const isLoginStatus = ref(!!Local.get(accessSessionKey));
const userName = ref('');
const firstUserCharacter =computed(()=>userName.value?.[0]?.toUpperCase());
watchEffect(()=>{
    if(!isLoginStatus.value)return;
    userName.value = Local.get(userNameKey)
})
let state = reactive({
    asideTitleList: [
        {
@@ -99,31 +110,65 @@
    },
});
const loginRules = reactive({
    account: [{ required: true, message: '必填项', trigger: 'blur' }],
    pwd: [{ required: true, message: '必填项', trigger: 'blur' }],
    account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
    pwd: [{ required: true, message: '请输入密码', trigger: 'blur' }],
});
const handleClick = (item) => {
    gotoRoute({ name: item.routerName });
};
//登录
const login = () => {
const openLoginDlg = async () => {
    state.isShowLogin = true;
};
const handleClose = () => {
    state.isShowLogin = false;
};
//登录
const onSubmit = () => {};
const currentRoute = router.currentRoute;
//是否显示退出登录弹窗
const showExitLogin = () => {
    state.isShowExitLogin = true;
};
//关闭退出登录弹窗
const handleExitClose = () => {
    state.isShowExitLogin = false;
const onSubmit = async () => {
    const isValid = await loginFormRef.value.validate().catch(() => {});
    if (!isValid) return;
    const res = await PostLogin({
        user: state.loginForm.account,
        pass: state.loginForm.pwd,
    });
    Local.set(accessSessionKey, res.hswatersession);
    Local.set(userNameKey,state.loginForm.account);
    state.isShowLogin = false;
    isLoginStatus.value = true;
    window.location.reload();
};
const currentRoute = router.currentRoute;
//是否显示退出登录弹窗cpolar.top/login
const toggleShowExitLogin = () => {
    state.isShowExitLogin = !state.isShowExitLogin;
};
//退出登录
const logoutClick = () => {
    state.isShowExitLogin = false;
    isLoginStatus.value = false;
    Local.remove(accessSessionKey);
};
const toggleExitLoginBtnRef = ref<HTMLDivElement>(null);
const listenClickOtherExit = (e) => {
    if (toggleExitLoginBtnRef.value !== e.target && !toggleExitLoginBtnRef.value?.contains(e.target)) {
        state.isShowExitLogin = false;
    }
};
onMounted(() => {
    emitter.on('openLoginDlg', () => {
        if(state.isShowLogin || isLoginStatus.value)return;
        openLoginDlg();
    });
    emitter.on('logout', () => {});
    document.addEventListener('click', listenClickOtherExit);
});
</script>
<style scoped lang="scss">
.aisde-title {
src/layout/main/classic.vue
@@ -8,29 +8,12 @@
import { storeToRefs } from 'pinia';
import { computed, defineAsyncComponent, nextTick, onMounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { PostLogin } from '/@/api/ai/user';
import { useThemeConfig } from '/@/stores/themeConfig';
import { Local } from '/@/utils/storage';
const login = () => {
    return PostLogin({
        user: 'tc',
        pass: 'a',
    }).then((res)=>{
        const hswatersession = res.hswatersession;
        Local.set('hswatersession',hswatersession);
    });
};
// å¼•入组件
const LayoutMain = defineAsyncComponent(async () => {
    try {
        await login();
    } finally {
        // eslint-disable-next-line no-unsafe-finally
        return import('/@/layout/component/main.vue');
    }
});
// å®šä¹‰å˜é‡å†…容
src/layout/navBars/breadcrumb/user.vue
@@ -173,7 +173,6 @@
            },
        })
            .then(async () => {
                console.log('🚀 ~ reload',);
                // æ¸…除缓存/token等
                clearAccessTokens();
                // ä½¿ç”¨ reload æ—¶ï¼Œä¸éœ€è¦è°ƒç”¨ resetRoute() é‡ç½®è·¯ç”±
@@ -196,8 +195,6 @@
    themeConfig.value.globalComponentSize = size;
    Local.set('themeConfig', themeConfig.value);
    initI18nOrSize('globalComponentSize', 'disabledSize');
    console.log('🚀 ~ reload',);
    window.location.reload();
};
//通知中心
src/layout/upgrade/index.vue
@@ -64,8 +64,6 @@
    state.btnTxt = t('message.upgrade.btnTwoLoading');
    setTimeout(() => {
        Local.clear();
        console.log('🚀 ~ reload',);
        window.location.reload();
        Local.set('version', state.version);
    }, 2000);
src/main.ts
@@ -1,16 +1,16 @@
import { createApp } from 'vue';
import pinia from '/@/stores/index';
import App from '/@/App.vue';
import router from '/@/router/index';
import { directive } from '/@/directive/index';
import { i18n } from '/@/i18n/index';
import router from '/@/router/index';
import pinia from '/@/stores/index';
import other from '/@/utils/other';
import ElementPlus from 'element-plus';
import '/@/theme/index.scss';
import VueGridLayout from 'vue-grid-layout';
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import ElementPlus from 'element-plus';
import VueGridLayout from 'vue-grid-layout';
import { initBackEndControlRoutes } from './router/backEnd';
import '/@/theme/index.scss';
const app = createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
@@ -18,7 +18,8 @@
}
directive(app);
other.elSvg(app);
app.use(pinia).use(router).use(ElementPlus).use(i18n).use(VueGridLayout).mount('#app');
initBackEndControlRoutes()
console.log('🚀 ~nihao ',);
(async function () {
    await initBackEndControlRoutes();
    app.use(pinia).use(router).use(ElementPlus).use(i18n).use(VueGridLayout).mount('#app');
})();
src/router/backEnd.ts
@@ -1,6 +1,4 @@
import { ElMessage } from 'element-plus';
import type { RouteRecordRaw } from 'vue-router';
import { MenuData } from '../api/menu/menuData';
import { parseMenuTree, useMenuApi } from '/@/api/menu/index';
import { formatFlatteningRoutes, formatTwoStageRoutes, router } from '/@/router/index';
import { pathMap } from '/@/router/pathMap';
@@ -9,10 +7,8 @@
import { useRequestOldRoutes } from '/@/stores/requestOldRoutes';
import { useRoutesList } from '/@/stores/routesList';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useUserInfo } from '/@/stores/userInfo';
import { NextLoading } from '/@/utils/loading';
import { accessSessionKey, clearAccessTokens } from '/@/utils/request';
import { Local } from '/@/utils/storage';
import { menuData } from '../api/menu/menuData';
// åŽç«¯æŽ§åˆ¶è·¯ç”±
@@ -38,15 +34,14 @@
 */
export async function initBackEndControlRoutes() {
    // ç•Œé¢ loading åŠ¨ç”»å¼€å§‹æ‰§è¡Œ
    if (window.nextLoading === undefined) NextLoading.start();
    // if (window.nextLoading === undefined) NextLoading.start();
    // æ—  token åœæ­¢æ‰§è¡Œä¸‹ä¸€æ­¥
    // if (!Local.get(accessSessionKey)) return false;
    // è§¦å‘初始化用户信息 pinia
    // https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
    // await useUserInfo().setUserInfos();
    // èŽ·å–è·¯ç”±èœå•æ•°æ®
    const menuData = (await getBackEndControlRoutes()) as any;
    const formattedTreeMenu = parseMenuTree(menuData, pathMap);
    const formattedTreeMenu = parseMenuTree(menuData as any, pathMap);
    // æ— ç™»å½•权限时,添加判断
    // https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
    // if (res.data.length <= 0) return Promise.resolve(true);
@@ -105,31 +100,6 @@
        router.addRoute(route);
    });
}
/**
 * è¯·æ±‚后端路由菜单接口
 * @description isRequestRoutes ä¸º true,则开启后端控制路由
 * @returns è¿”回后端路由菜单数据
 */
export async function getBackEndControlRoutes() {
    // æ¨¡æ‹Ÿ admin ä¸Ž test
    return MenuData;
    // const auth = userInfos.value.roles[0];
    // ç®¡ç†å‘˜ admin
    // if (auth === 'admin') return menuApi.getAdminMenu();
    // å…¶å®ƒç”¨æˆ· test
    // else return menuApi.getTestMenu();
}
/**
 * é‡æ–°è¯·æ±‚后端路由菜单接口
 * @description ç”¨äºŽèœå•管理界面刷新菜单(未进行测试)
 * @description è·¯å¾„:/src/views/system/menu/component/addMenu.vue
 */
// export async function setBackEndControlRefreshRoutes() {
//     await getBackEndControlRoutes();
// }
/**
 * åŽç«¯è·¯ç”± component è½¬æ¢
src/router/index.ts
@@ -1,17 +1,14 @@
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import { storeToRefs } from 'pinia';
import { createRouter, createWebHashHistory } from 'vue-router';
import { MenuTypeEnum } from '/@/api/menu/type';
import { initBackEndControlRoutes } from '/@/router/backEnd';
import { initFrontEndControlRoutes } from '/@/router/frontEnd';
import { notFoundAndNoPower, staticRoutes } from '/@/router/route';
import pinia from '/@/stores/index';
import { useKeepALiveNames } from '/@/stores/keepAliveNames';
import { useRoutesList } from '/@/stores/routesList';
import { useThemeConfig } from '/@/stores/themeConfig';
import { accessSessionKey, clearAccessTokens } from '/@/utils/request';
import { Local } from '/@/utils/storage';
import { Local } from '../utils/storage';
import { accessSessionKey } from '../utils/request';
import emitter from '../utils/mitt';
/**
 * 1、前端控制路由时:isRequestRoutes ä¸º false,需要写 roles,需要走 setFilterRoute æ–¹æ³•。
@@ -95,8 +92,21 @@
}
// è·¯ç”±åŠ è½½å‰
router.beforeEach((to, from, next) => {
    const accessSession = Local.get(accessSessionKey);
    if (!accessSession) {
        emitter.emit('openLoginDlg');
        if(to.name==='Home'){
            next();
        }else{
            next({
                name: 'Home',
            });
        }
    }
    next();
});
// è·¯ç”±åŠ è½½åŽ
// å¯¼å‡ºè·¯ç”±
src/router/route.ts
@@ -82,22 +82,4 @@
 * @description å‰ç«¯æŽ§åˆ¶ç›´æŽ¥æ”¹ dynamicRoutes ä¸­çš„路由,后端控制不需要修改,请求接口路由数据时,会覆盖 dynamicRoutes ç¬¬ä¸€ä¸ªé¡¶çº§ children çš„内容(全屏,不包含 layout ä¸­çš„路由出口)
 * @returns è¿”回路由菜单数据
 */
export const staticRoutes: Array<RouteRecordRaw> = [
    {
        path: '/login',
        name: 'login',
        // ä¸åŒè½¯ä»¶ç¼–码使用不同的登录页
        component: () => {
            switch (window.globalConfig.Auth.SoftWareCode) {
                case 'CH_web':
                    return import('/@/views/login/index_ch.vue');
                default:
                    return import('/@/views/login/index_ch.vue');
            }
        },
        meta: {
            title: '登录',
        },
    },
];
export const staticRoutes: Array<RouteRecordRaw> = [];
src/stores/userInfo.ts
@@ -39,8 +39,6 @@
                    } else {
                        clearAccessTokens();
                        window.location.reload();
                        console.log('🚀 ~ reload',);
                        return;
                    }
                }, 0);
src/types/mitt.d.ts
@@ -23,18 +23,14 @@
    openShareTagsView?: string;
    onTagsViewRefreshRouterView?: T;
    onCurrentContextmenuClick?: T;
    refreshTestStandard?: T;
    refreshTestGrade?: T;
    x6CellPropertyChange?: T;
    x6ViewPropertyChange?: T;
    refreshFaultGroup?: T;
    refreshFault?: T;
    refreshMethodDefinition?: T;
    // æ›´æ–°æ•…障事件 contentName
    updateFaultContentName: T;
    //#region ====================== ai ======================
    updateChatInput: T;
    /** @description å¼¹å‡ºç™»å½•对话框 */
    openLoginDlg:T;
    /** @description é€€å‡ºç™»å½• */
    logout:T;
    //#endregion
};
src/utils/request.ts
@@ -1,6 +1,8 @@
import type { AxiosInstance, AxiosRequestConfig } from 'axios';
import axios from 'axios';
import { ElMessage } from 'element-plus';
import emitter from './mitt';
import { debounce } from './util';
import { AUTH_URL, MAIN_URL, SECONDARY_URL } from '/@/constants';
import { Local, Session } from '/@/utils/storage';
// import JSONbig from 'json-bigint';
@@ -12,6 +14,10 @@
}
//#endregion
const openLoginDlg = debounce(() => {
    emitter.emit('openLoginDlg');
});
const initRequestInterceptor = (request: AxiosInstance) => {
    // æ·»åŠ è¯·æ±‚æ‹¦æˆªå™¨
    request.interceptors.request.use(
@@ -21,6 +27,8 @@
            if (accessSession) {
                // å°† token æ·»åŠ åˆ°è¯·æ±‚æŠ¥æ–‡å¤´ä¸­
                config.headers['hswatersession'] = accessSession;
            } else {
                openLoginDlg();
            }
            return config;
        },
@@ -55,9 +63,8 @@
            if (!serveData.json_ok) {
                switch (serveData?.err_code) {
                    case ErrorCode.Auth:
                        // clearAccessTokens();
                        // window.location.reload();
                        break;
                        openLoginDlg();
                        throw '权限验证失败';
                }
                const msg = serveData.json_msg ?? '';
@@ -132,6 +139,8 @@
const domainPrefix = subDomainName ? `${subDomainName}-` : '';
// token é”®å®šä¹‰
export const accessSessionKey = domainPrefix + 'access-session';
export const userNameKey = domainPrefix + 'userName';
export const refreshAccessTokenKey = `x-${accessSessionKey}`;
// userInfo键定义
src/views/error/404.vue
@@ -23,6 +23,7 @@
</template>
<script setup lang="ts" name="notFound">
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
// å®šä¹‰å˜é‡å†…容
@@ -32,6 +33,10 @@
const onGoHome = () => {
    router.push('/');
};
onMounted(()=>{
})
const currentRoute = router.currentRoute.value
</script>
<style scoped lang="scss">
src/views/login/component/account.vue
ÎļþÒÑɾ³ý
src/views/login/index_ch.vue
ÎļþÒÑɾ³ý