(一), 概述
本文总结vben,jeecgboot的页面登录前后的文件执行顺序,注释功能,帮助学习了解系统结构体系,或遇到问题时快速定位,或者扩展额外功能。
(二)index.html导入main.ts
index.html入口页文件
<div class="app-loading">
<div class="app-loading-wrap">
<img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
<div class="app-loading-dots">
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
</div>
<div class="app-loading-title"><%= title %></div>
</div>
</div>
</div>
<script type="module" src="/src/main.ts"></script> //导入main.ts
</body>
</html>
(三) main.ts入口主文件
import '/@/design/index.less';
// 注册 windi(css 组件化)
import 'virtual:windi-base.css';
import 'virtual:windi-components.css';
import 'virtual:windi-utilities.css';
import 'virtual:windi-devtools';
// 注册图标
import 'virtual:svg-icons-register';
import App from './App.vue'; //导入App
async function bootstrap() { //开始初始化数据
// 应用挂载点
app.mount('#app', true);
(四)App.vue注解
<template>
<ConfigProvider :locale="getAntdLocale">
<AppProvider> //读取app应用组件配置参数
<RouterView /> //路由器显示区域占位,将被路由的组件components替换(功能页面在这里显示)
</AppProvider>
</ConfigProvider>
</template>
<script lang="ts" setup>
import { ConfigProvider } from 'ant-design-vue';
import { AppProvider } from '/@/components/Application';
import { useTitle } from '/@/hooks/web/useTitle';
import { useLocale } from '/@/locales/useLocale';
// support Multi-language
const { getAntdLocale } = useLocale();
useTitle(); //src\hooks\web\useTitle.ts //src\hooks\setting\index.ts
//src\utils\env.ts
//读取env中配置数据
//.env,.env. .env.development, .env. //D:\idea-down\jeecgboot-vue3-master\jeecgboot-vue3-//master\.env.production
</script>
(五)、 登录路由
src\router\routes\index.ts //App初始化构造路由路径
src\router\index.ts //生成路由器
根目录:有权限的初始访问路径,登录后可进入
export const RootRoute: AppRouteRecordRaw = {
path: '/',
name: 'Root',
redirect: PageEnum.BASE_HOME,
meta: {
title: 'Root',
},
};
无权限:访问登录页
export const LoginRoute: AppRouteRecordRaw = {
path: '/login',
name: 'Login',
component: () => import('/@/views/sys/login/Login.vue'),
meta: {
title: t('routes.basic.login'),
},
```typescript
在这里插入代码片
```(六)、 登录页
src\views\sys\login\Login.vue
src\views\sys\login\LoginForm.vue
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin">
在handleLogin()处理登录请求
async function handleLogin() {
const data = await validForm(); //验证表单
if (!data) return;
try {
loading.value = true;
const {userInfo} = await userStore.login( //提交登录请求,处理验证过程
toRaw({
password: data.password,
username: data.account,
captcha: data.inputCode,
checkKey: randCodeData.checkKey,
mode: 'none', //不要默认的错误提示
})
);
if (userInfo) {
notification.success({
message: t('sys.login.loginSuccessTitle'),
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
duration: 3,
});
}
} catch (error) {
notification.error({
message: t('sys.api.errorTip'),
description: error.message || t('sys.api.networkExceptionMsg'),
duration: 3,
});
loading.value = false;
}
}
src\store\modules\user.ts //
/**
* 登录事件
*/
async login(
params: LoginParams & {
goHome?: boolean;
mode?: ErrorMessageMode;
},
): Promise<GetUserInfoModel | null> {
try {
const { goHome = true, mode, ...loginParams } = params;
const data = await loginApi(loginParams, mode); //登录成功,返回结果数据
const { token } = data;
// save token保存访问令牌
this.setToken(token);
return this.afterLoginAction(goHome,data); //获取登录用户数据
} catch (error) {
return Promise.reject(error); //登录失败
}
},
**登录完成后处理**
/**
* 登录完成处理
* @param goHome
*/
async afterLoginAction(goHome?: boolean,data?:any): Promise<any | null> {
if (!this.getToken) return null;
//获取用户信息
const userInfo = await this.getUserInfoAction(); //获取用户信息
const sessionTimeout = this.sessionTimeout;
if (sessionTimeout) {
this.setSessionTimeout(false);
} else {
const permissionStore = usePermissionStore();
if (!permissionStore.isDynamicAddedRoute) {
const routes = await permissionStore.buildRoutesAction(); //构建当前权限许可的用户路由,装入菜单与角色权限
routes.forEach((route) => {
router.addRoute(route as unknown as RouteRecordRaw);
});
router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
permissionStore.setDynamicAddedRoute(true);
}
await this.setLoginInfo(data);
goHome && (await router.replace(userInfo && userInfo.homePath || PageEnum.BASE_HOME)); //跳转向用户主页或根目录
}
return data;
},
BASE_HOME = '/dashboard/analysis',
根目录:有权限的初始访问路径(首页)
export const RootRoute: AppRouteRecordRaw = {
path: '/',
name: 'Root',
redirect: PageEnum.BASE_HOME, //指向BASE_HOME = '/dashboard/analysis'
meta: {
title: 'Root',
},
(七)、 主页生成
src\router\routes\modules\dashboard.ts
const dashboard: AppRouteModule = {
path: '/dashboard',
name: 'Dashboard',
component: LAYOUT, //导入 import('/@/layouts/default/index.vue')
redirect: '/dashboard/analysis',
meta: {
orderNo: 10,
icon: 'ion:grid-outline',
title: t('routes.dashboard.dashboard'),
},
children: [
{
path: 'analysis',
name: 'Analysis',
component: () => import('/@/views/dashboard/Analysis/index.vue'), //主页文件
meta: {
// affix: true,
title: t('routes.dashboard.analysis'),
},
},
{
path: 'workbench',
name: 'Workbench',
component: () => import('/@/views/dashboard/workbench/index.vue'), //工作页文件
meta: {
title: t('routes.dashboard.workbench'),
},
},
],
};
(八)、 菜单管理:页面构造与组件访问
父级Dashboard对应组件:layouts\default\index.vue
子级Analysis对应组件:/@/views/dashboard/Analysis/index
(九),主页右边栏布局
文件
src\layouts\default\index.vue
布局页
<template>
<Layout :class="prefixCls" v-bind="lockEvents">
<LayoutFeatures /> //页面头部特征值
<LayoutHeader fixed v-if="getShowFullHeaderRef" /> //头部功能区(不显示)
<Layout :class="[layoutClass]">
<LayoutSideBar v-if="getShowSidebar || getIsMobile" /> //左边菜单栏
<Layout :class="`${prefixCls}-main`">
<LayoutMultipleHeader /> //右边双层头部栏(头部功能区(显示))
<LayoutContent /> //内容组件挂载区域(中间内容区)
<LayoutFooter /> //脚部
</Layout>
</Layout>
</Layout>
</template>
src\layouts\default\setting\index.vue
<template>
<LayoutLockPage />
<BackTop v-if="getUseOpenBackTop" :target="getTarget" />
<SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" />
<SessionTimeoutLogin v-if="getIsSessionTimeout" />
</template>
配置功能页(导航栏样式,系统主题颜色,等)
src\layouts\default\feature\index.vue
<template>
<div @click="openDrawer(true)">
<Icon icon="ion:settings-outline" />
<SettingDrawer @register="register" />
</div>
</template>
src\layouts\default\setting\SettingDrawer.tsx
输出
<TypePicker
<ThemeColorPicker
等等
布局锁
src\layouts\default\feature\index.vue
<LayoutLockPage />
(十)页面控制锁功能
src\views\sys\lock\index.vue
用户可以给页面加锁,方针其他人进入页面错误操作
<template>
<transition name="fade-bottom" mode="out-in">
<LockPage v-if="getIsLock" />
</transition>
</template>
页面锁文件
src\views\sys\lock\LockPage.vue
(十一),页面头部控制
<LayoutHeader fixed v-if="getShowFullHeaderRef" />
头部菜单栏
src\layouts\default\header\index.vue
(十二)、 多重Tab标签栏MultipleTabs
<MultipleTabs v-if="getShowTabs" />
src\layouts\default\tabs\index.vue
(后面还有多重标签栏的控制开闭src\store\modules\multipleTab.ts)
(十三)、 多重标签栏初始化函数initAffixTabs()
setup() {
const affixTextList = initAffixTabs(); //初始化标签,增加一个固定标签
const activeKeyRef = ref('');
useTabsDrag(affixTextList);
const tabStore = useMultipleTabStore();//引入标签显示状态存储库
const userStore = useUserStore();//引入用户首选状态存储库
const router = useRouter(); //引入路由器
const { prefixCls } = useDesign('multiple-tabs');
const go = useGo(); //引入跳转方法
const { getShowQuick, getShowRedo, getShowFold, getTabsTheme } = useMultipleTabSetting();
const getTabsState = computed(() => {
return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
});
(十四)、 多重菜单栏-左边标签菜单栏
<template v-for="item in getTabsState" :key="item.query ? item.fullPath : item.path">
<TabPane :closable="!(item && item.meta && item.meta.affix)">
<template #tab>
<TabContent :tabItem="item" />
</template>
</TabPane>
</template>
(十五)、 多重菜单栏-右边标签菜单栏
(十六)、 内容区域挂载
src\layouts\default\content\index.vue
<div :class="[prefixCls, getLayoutContentMode]" v-loading="getOpenPageLoading && getPageLoading">
<PageLayout /> //内容组件挂载区
<!-- update-begin-author:zyf date:20211129 for:qiankun 挂载子应用盒子 -->
<div id="content" class="app-view-box" v-if="openQianKun=='true'"></div> //乾坤微服务区
<!-- update-end-author:zyf date:20211129 for: qiankun 挂载子应用盒子-->
</div>
</template>
(十七)、 组件挂载
src\layouts\page\index.vue
<template>
<RouterView>
<template #default="{ Component, route }"> //传入组件
<keep-alive v-if="openCache" :include="getCaches">
<component :is="Component" :key="route.fullPath" />//1,可缓存挂载
</keep-alive>
<component v-else :is="Component" :key="route.fullPath" />//2,不缓存挂载
</template>
</RouterView>
<FrameLayout v-if="getCanEmbedIFramePage" /> //3,iframe挂载
</template>
注意:动态组件挂载标签<component :is= 的用法,参考其他博文
(十八)、 多重标签栏的控制useMultipleTabs
从(src\layouts\default\tabs\index.vue)中引入辅助
import { useMultipleTabStore } from ‘/@/store/modules/multipleTab’;(重要!!!)
和src\layouts\default\tabs\useMultipleTabs.ts
src\store\modules\multipleTab.ts
(十九). 1 定义多重标签栏MultipleTab
export const useMultipleTabStore = defineStore({
id: ‘app-multiple-tab’,
(二十).2 跳转标签函数goToPage()
goToPage(router: Router) {
(二十一).3 增加标签函数addTab()
async addTab(route: RouteLocationNormalized) {
(二十二) .4 关闭标签closeTab()
async closeTab(tab: RouteLocationNormalized, router: Router) {
(二十三)、 标签栏面板容器TabContent
src\layouts\default\tabs\components\TabContent.vue
标签面板控制(下拉控制栏,控制关闭)
src\layouts\default\tabs\useTabDropdown.ts
(二十四)、 路由事件监听与触发routeChange
src\logics\mitt\routeChange.ts 路由事件监听与触发
src\utils\mitt.ts 事件维护库(各种事件库)
(二十五)、 左边竖栏(竖型菜单栏)
<LayoutSideBar v-if="getShowSidebar || getIsMobile" />
src\layouts\default\sider\index.vue
<MixSider v-else-if="getIsMixSidebar" />
src\layouts\default\sider\MixSider.vue
<Sider v-else />
<ScrollContainer :class="`${prefixCls}-menu-list__content`">
src\components\Container\src\ScrollContainer.vue
<SimpleMenu>
src\components\SimpleMenu\src\SimpleMenu.vue
输出菜单文字
<SimpleMenuTag>
src\components\SimpleMenu\src\SimpleMenuTag.vue
<Menu>
<MenuItem>
边栏布局
src\layouts\default\sider\LayoutSider.vue
LayoutMenu菜单布局
src\layouts\default\menu\index.vue
选择条件输出SimpleMenu(竖向菜单)或BasicMenu(横向菜单)
renderHeader()和renderMenu()
竖向子菜单
(二十六)、 内容页面组成相关文件
src\components\Page\src\PageWrapper.vue—PageWrapper
src\components\Page\index.ts
src\components\Table\src\components\EditTableHeaderIcon.vue—EditTableHeaderIcon
src\components\Table\src\components\HeaderCell.vue—TableHeaderCell
src\components\Table\src\componentMap.ts页面元素:输入,按钮,等
src\components\Table\src\components\editable\CellComponent.ts
src\components\Table\src\components\editable\helper.ts
src\components\Table\src\components\editable\EditableCell.vue
src\components\Table\src\components\settings\ColumnSetting.vue
src\components\Table\src\components\settings\RedoSetting.vue
src\components\Table\src\components\settings\FullScreenSetting.vue
src\components\Table\src\components\settings\index.vue
BasicTableTitle
BasicTableHeader
BasicTableFooter
src\components\Table\src\BasicTable.vue
TableImage
src\utils\common\renderUtils.ts
src\views\system\user\user.data.ts
src\components\jeecg\thirdApp\jThirdApp.api.ts
src\hooks\system\useListPage.ts