提交 31e2715e 作者: vben

chore: detail optimization

上级 74378960
...@@ -74,9 +74,7 @@ function injectCdnjs(html: string) { ...@@ -74,9 +74,7 @@ function injectCdnjs(html: string) {
export async function runUpdateHtml() { export async function runUpdateHtml() {
const outDir = viteConfig.outDir || 'dist'; const outDir = viteConfig.outDir || 'dist';
const indexPath = getCwdPath(outDir, 'index.html'); const indexPath = getCwdPath(outDir, 'index.html');
if (!existsSync(`${indexPath}`)) { if (!existsSync(indexPath)) return;
return;
}
try { try {
let processedHtml = ''; let processedHtml = '';
const rawHtml = readFileSync(indexPath, 'utf-8'); const rawHtml = readFileSync(indexPath, 'utf-8');
...@@ -92,7 +90,9 @@ export async function runUpdateHtml() { ...@@ -92,7 +90,9 @@ export async function runUpdateHtml() {
} }
if (minify) { if (minify) {
const { enable, ...miniOpt } = minify; const { enable, ...miniOpt } = minify;
processedHtml = HtmlMinifier.minify(processedHtml, miniOpt); if (enable) {
processedHtml = HtmlMinifier.minify(processedHtml, miniOpt);
}
} }
writeFileSync(indexPath, processedHtml); writeFileSync(indexPath, processedHtml);
......
// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
// TODO 目前还不能监听文件新增及删除 内容已经改变,缓存问题?
// 可以使用,先不打算集成
import { join } from 'path';
import { lstatSync } from 'fs';
import glob from 'glob';
import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
import { Transform } from 'vite/dist/node/transform.js';
const modulesDir: string = join(process.cwd(), '/node_modules/');
interface SharedConfig {
root?: string;
alias?: Record<string, string>;
resolvers?: Resolver[];
}
function template(template: string) {
return (data: { [x: string]: any }) => {
return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
};
}
const globbyTransform = function (config: SharedConfig): Transform {
const resolver = createResolver(
config.root || process.cwd(),
config.resolvers || [],
config.alias || {}
);
const cache = new Map();
const urlMap = new Map();
return {
test({ path }) {
const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
try {
return (
!filePath.startsWith(modulesDir) &&
/\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
lstatSync(filePath).isFile()
);
} catch {
return false;
}
},
transform({ code, path, isBuild }) {
let result = cache.get(path);
if (!result) {
const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?path)?!([^'"]+)\2/g;
const lastImport = urlMap.get(path);
const match = code.match(reg);
if (lastImport && match) {
code = code.replace(lastImport, match[0]);
}
result = code.replace(reg, (_, g1, g2, g3, g4) => {
const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
// resolve path
const resolvedFilePath = g4.startsWith('.')
? resolver.resolveRelativeRequest(filePath, g4)
: { pathname: resolver.requestToFile(g4) };
const files = glob.sync(resolvedFilePath.pathname, { dot: true });
let templateStr = 'import #name# from #file#'; // import default
let name = g1;
const m = g1.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
const m2 = g1.match(/\*\s+as\s+(\w+)/); // import * as all module
if (m) {
templateStr = `import { ${m[1]} as #name# } from #file#`;
name = m[3] || m[1];
} else if (m2) {
templateStr = 'import * as #name# from #file#';
name = m2[1];
}
const temRender = template(templateStr);
const groups: Array<string>[] = [];
const replaceFiles = files.map((f, i) => {
const file = g2 + resolver.fileToRequest(f) + g2;
groups.push([name + i, file]);
return temRender({ name: name + i, file });
});
urlMap.set(path, replaceFiles.join('\n'));
return (
replaceFiles.join('\n') +
(g3 ? '\n' + groups.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '') +
`\nconst ${name} = { ${groups.map((v) => v[0]).join(',')} }\n`
);
});
if (isBuild) cache.set(path, result);
}
return result;
},
};
};
export default globbyTransform;
...@@ -124,28 +124,24 @@ export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.pr ...@@ -124,28 +124,24 @@ export function getEnvConfig(match = 'VITE_GLOB_', confFiles = ['.env', '.env.pr
return envConfig; return envConfig;
} }
export function successConsole(message: any) { function consoleFn(color: string, message: any) {
console.log( console.log(
chalk.blue.bold('**************** ') + chalk.blue.bold('**************** ') +
chalk.green.bold('✨ ' + message) + (chalk as any)[color].bold(message) +
chalk.blue.bold(' ****************') chalk.blue.bold(' ****************')
); );
} }
export function successConsole(message: any) {
consoleFn('green', '✨ ' + message);
}
export function errorConsole(message: any) { export function errorConsole(message: any) {
console.log( consoleFn('red', '✨ ' + message);
chalk.blue.bold('**************** ') +
chalk.red.bold('✨ ' + message) +
chalk.blue.bold(' ****************')
);
} }
export function warnConsole(message: any) { export function warnConsole(message: any) {
console.log( consoleFn('yellow', '✨ ' + message);
chalk.blue.bold('**************** ') +
chalk.yellow.bold('✨ ' + message) +
chalk.blue.bold(' ****************')
);
} }
export function getCwdPath(...dir: string[]) { export function getCwdPath(...dir: string[]) {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, computed, watch, onMounted, unref, toRef } from 'vue'; import { defineComponent, reactive, computed, watch, onMounted, unref, toRef } from 'vue';
import { countToProps } from './props'; import { countToProps } from './props';
import { useRaf } from '/@/hooks/event/useRaf'; import { useRaf } from '/@/hooks/event/useRaf';
import { isNumber } from '/@/utils/is'; import { isNumber } from '/@/utils/is';
...@@ -37,12 +36,14 @@ ...@@ -37,12 +36,14 @@
remaining: null, remaining: null,
rAF: null, rAF: null,
}); });
onMounted(() => { onMounted(() => {
if (props.autoplay) { if (props.autoplay) {
start(); start();
} }
emit('mounted'); emit('mounted');
}); });
const getCountDown = computed(() => { const getCountDown = computed(() => {
return props.startVal > props.endVal; return props.startVal > props.endVal;
}); });
...@@ -61,6 +62,7 @@ ...@@ -61,6 +62,7 @@
state.paused = false; state.paused = false;
state.rAF = requestAnimationFrame(count); state.rAF = requestAnimationFrame(count);
} }
function pauseResume() { function pauseResume() {
if (state.paused) { if (state.paused) {
resume(); resume();
...@@ -70,6 +72,7 @@ ...@@ -70,6 +72,7 @@
state.paused = true; state.paused = true;
} }
} }
function pause() { function pause() {
cancelAnimationFrame(state.rAF); cancelAnimationFrame(state.rAF);
} }
......
...@@ -7,7 +7,7 @@ import { Menu } from 'ant-design-vue'; ...@@ -7,7 +7,7 @@ import { Menu } from 'ant-design-vue';
import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum'; import { MenuModeEnum, MenuTypeEnum } from '/@/enums/menuEnum';
import { menuStore } from '/@/store/modules/menu'; import { menuStore } from '/@/store/modules/menu';
import { getSlot } from '/@/utils/helper/tsxHelper'; import { getSlot } from '/@/utils/helper/tsxHelper';
import { ScrollContainer } from '/@/components/Container/index'; // import { ScrollContainer } from '/@/components/Container/index';
import SearchInput from './SearchInput.vue'; import SearchInput from './SearchInput.vue';
import './index.less'; import './index.less';
import { menuHasChildren } from './helper'; import { menuHasChildren } from './helper';
...@@ -67,6 +67,7 @@ export default defineComponent({ ...@@ -67,6 +67,7 @@ export default defineComponent({
return { return {
height: `calc(100% - ${offset}px)`, height: `calc(100% - ${offset}px)`,
position: 'relative', position: 'relative',
overflow: 'auto',
}; };
}); });
...@@ -246,8 +247,9 @@ export default defineComponent({ ...@@ -246,8 +247,9 @@ export default defineComponent({
onClick={handleInputClick} onClick={handleInputClick}
collapsed={getCollapsedState} collapsed={getCollapsedState}
/> />
<section style={unref(getMenuWrapStyle)}> <section style={unref(getMenuWrapStyle)} class="basic-menu__wrap">
<ScrollContainer>{() => renderMenu()}</ScrollContainer> {renderMenu()}
{/* <ScrollContainer>{() => renderMenu()}</ScrollContainer> */}
</section> </section>
</section> </section>
); );
......
...@@ -14,6 +14,30 @@ ...@@ -14,6 +14,30 @@
} }
.basic-menu { .basic-menu {
&__wrap {
/* 滚动槽 */
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
// TODO 滚动条样式-待修改
&::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0);
}
/* 滚动条滑块 */
&::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
border-radius: 4px;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
}
::-webkit-scrollbar-thumb:hover {
background: @border-color-dark;
}
}
.ant-menu-submenu:first-of-type { .ant-menu-submenu:first-of-type {
margin-top: 4px; margin-top: 4px;
} }
...@@ -95,14 +119,14 @@ ...@@ -95,14 +119,14 @@
.ant-menu-submenu-active, .ant-menu-submenu-active,
.ant-menu-submenu-title:hover { .ant-menu-submenu-title:hover {
background: @top-menu-active-bg-color; background: @top-menu-active-bg-color;
border-radius: 6px 6px 0 0; // border-radius: 6px 6px 0 0;
} }
.basic-menu-item__level1 { .basic-menu-item__level1 {
&.ant-menu-item-selected, &.ant-menu-item-selected,
&.ant-menu-submenu-selected { &.ant-menu-submenu-selected {
background: @top-menu-active-bg-color; background: @top-menu-active-bg-color;
border-radius: 6px 6px 0 0; // border-radius: 6px 6px 0 0;
} }
} }
...@@ -148,6 +172,10 @@ ...@@ -148,6 +172,10 @@
} }
.basic-menu-item__level1 { .basic-menu-item__level1 {
> .ant-menu-sub > li {
background-color: @sub-menu-item-dark-bg-color;
}
margin-bottom: 0; margin-bottom: 0;
&.top-active-menu { &.top-active-menu {
...@@ -179,7 +207,7 @@ ...@@ -179,7 +207,7 @@
.ant-menu-submenu-title { .ant-menu-submenu-title {
height: @app-menu-item-height; height: @app-menu-item-height;
margin: 0; // margin: 0;
line-height: @app-menu-item-height; line-height: @app-menu-item-height;
} }
} }
......
...@@ -18,4 +18,4 @@ ...@@ -18,4 +18,4 @@
// app menu // app menu
// left-menu // left-menu
@app-menu-item-height: 44px; @app-menu-item-height: 48px;
import type { AppRouteRecordRaw } from '/@/router/types.d';
import { useTimeout } from '/@/hooks/core/useTimeout'; import { useTimeout } from '/@/hooks/core/useTimeout';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { TabItem, tabStore } from '/@/store/modules/tab'; import { TabItem, tabStore } from '/@/store/modules/tab';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import router from '/@/router'; import router from '/@/router';
import { ref } from 'vue'; import { ref } from 'vue';
import { pathToRegexp } from 'path-to-regexp';
const activeKeyRef = ref<string>(''); const activeKeyRef = ref<string>('');
...@@ -68,7 +68,11 @@ export function useTabs() { ...@@ -68,7 +68,11 @@ export function useTabs() {
function getTo(path: string): any { function getTo(path: string): any {
const routes = router.getRoutes(); const routes = router.getRoutes();
const fn = (p: string): any => { const fn = (p: string): any => {
const to = routes.find((item) => item.path === p); const to = routes.find((item) => {
if (item.path === '/:path(.*)*') return;
const regexp = pathToRegexp(item.path);
return regexp.test(p);
});
if (!to) return ''; if (!to) return '';
if (!to.redirect) return to; if (!to.redirect) return to;
if (to.redirect) { if (to.redirect) {
...@@ -88,12 +92,13 @@ export function useTabs() { ...@@ -88,12 +92,13 @@ export function useTabs() {
resetCache: () => canIUseFn() && resetCache(), resetCache: () => canIUseFn() && resetCache(),
addTab: (path: PageEnum, goTo = false, replace = false) => { addTab: (path: PageEnum, goTo = false, replace = false) => {
const to = getTo(path); const to = getTo(path);
if (!to) return; if (!to) return;
useTimeout(() => { useTimeout(() => {
tabStore.addTabByPathAction((to as unknown) as AppRouteRecordRaw); tabStore.addTabByPathAction();
}, 0); }, 0);
activeKeyRef.value = to.path; activeKeyRef.value = path;
goTo && replace ? router.replace : router.push(to.path); goTo && replace ? router.replace : router.push(path);
}, },
activeKeyRef, activeKeyRef,
}; };
......
...@@ -82,10 +82,13 @@ export default defineComponent({ ...@@ -82,10 +82,13 @@ export default defineComponent({
{() => ( {() => (
<> <>
{isLock && <LockPage />} {isLock && <LockPage />}
{!unref(getFullContent) && unref(isShowMixHeaderRef) && unref(showHeaderRef) && ( {!unref(getFullContent) && unref(isShowMixHeaderRef) && unref(showHeaderRef) && (
<LayoutHeader /> <LayoutHeader />
)} )}
{showSettingButton && <SettingBtn />} {showSettingButton && <SettingBtn />}
<Layout> <Layout>
{() => ( {() => (
<> <>
...@@ -102,7 +105,9 @@ export default defineComponent({ ...@@ -102,7 +105,9 @@ export default defineComponent({
{() => <MultipleTabs />} {() => <MultipleTabs />}
</Layout.Header> </Layout.Header>
)} )}
{useOpenBackTop && <BackTop target={getTarget} />} {useOpenBackTop && <BackTop target={getTarget} />}
<div class={[`default-layout__main`, fixedHeaderCls]}> <div class={[`default-layout__main`, fixedHeaderCls]}>
{openPageLoading && ( {openPageLoading && (
<FullLoading <FullLoading
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
// ref, // ref,
unref, unref,
onMounted, onMounted,
toRaw,
} from 'vue'; } from 'vue';
import { Tabs } from 'ant-design-vue'; import { Tabs } from 'ant-design-vue';
import TabContent from './TabContent'; import TabContent from './TabContent';
...@@ -73,11 +74,7 @@ export default defineComponent({ ...@@ -73,11 +74,7 @@ export default defineComponent({
routes && routes &&
routes.forEach((route) => { routes.forEach((route) => {
if (route.meta && route.meta.affix) { if (route.meta && route.meta.affix) {
tabs.push({ tabs.push(toRaw(route) as TabItem);
path: route.path,
name: route.name,
meta: { ...route.meta },
});
} }
}); });
return tabs; return tabs;
...@@ -114,7 +111,7 @@ export default defineComponent({ ...@@ -114,7 +111,7 @@ export default defineComponent({
}; };
return ( return (
<span> <span>
<TabContent {...tabContentProps} /> <TabContent {...(tabContentProps as any)} />
</span> </span>
); );
} }
......
...@@ -40,7 +40,8 @@ export default defineComponent({ ...@@ -40,7 +40,8 @@ export default defineComponent({
<RouterView> <RouterView>
{{ {{
default: ({ Component, route }: { Component: any; route: RouteLocation }) => { default: ({ Component, route }: { Component: any; route: RouteLocation }) => {
const name = route.meta.inTab ? ' ' : null; // 已经位于tab内的不再显示动画
const name = route.meta.inTab ? 'fade' : null;
const Content = openCache ? ( const Content = openCache ? (
<KeepAlive max={max} include={cacheTabs}> <KeepAlive max={max} include={cacheTabs}>
<Component {...route.params} /> <Component {...route.params} />
......
...@@ -7,7 +7,7 @@ import { createProgressGuard } from './progressGuard'; ...@@ -7,7 +7,7 @@ import { createProgressGuard } from './progressGuard';
import { createPermissionGuard } from './permissionGuard'; import { createPermissionGuard } from './permissionGuard';
import { createPageLoadingGuard } from './pageLoadingGuard'; import { createPageLoadingGuard } from './pageLoadingGuard';
import { useSetting } from '/@/hooks/core/useSetting'; import { useSetting } from '/@/hooks/core/useSetting';
import { getIsOpenTab } from '/@/utils/helper/routeHelper'; import { getIsOpenTab, setCurrentTo } from '/@/utils/helper/routeHelper';
const { projectSetting } = useSetting(); const { projectSetting } = useSetting();
export function createGuard(router: Router) { export function createGuard(router: Router) {
...@@ -17,7 +17,7 @@ export function createGuard(router: Router) { ...@@ -17,7 +17,7 @@ export function createGuard(router: Router) {
axiosCanceler = new AxiosCanceler(); axiosCanceler = new AxiosCanceler();
} }
router.beforeEach(async (to) => { router.beforeEach(async (to) => {
const isOpen = getIsOpenTab(to.path); const isOpen = getIsOpenTab(to.fullPath);
to.meta.inTab = isOpen; to.meta.inTab = isOpen;
try { try {
if (closeMessageOnSwitch) { if (closeMessageOnSwitch) {
...@@ -30,6 +30,8 @@ export function createGuard(router: Router) { ...@@ -30,6 +30,8 @@ export function createGuard(router: Router) {
} catch (error) { } catch (error) {
console.warn('basic guard error:' + error); console.warn('basic guard error:' + error);
} }
setCurrentTo(to);
return true;
}); });
openNProgress && createProgressGuard(router); openNProgress && createProgressGuard(router);
createPermissionGuard(router); createPermissionGuard(router);
......
...@@ -2,6 +2,7 @@ import type { Router } from 'vue-router'; ...@@ -2,6 +2,7 @@ import type { Router } from 'vue-router';
import { tabStore } from '/@/store/modules/tab'; import { tabStore } from '/@/store/modules/tab';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { userStore } from '/@/store/modules/user'; import { userStore } from '/@/store/modules/user';
import { getParams } from '/@/utils/helper/routeHelper';
export function createPageLoadingGuard(router: Router) { export function createPageLoadingGuard(router: Router) {
let isFirstLoad = true; let isFirstLoad = true;
...@@ -29,9 +30,16 @@ export function createPageLoadingGuard(router: Router) { ...@@ -29,9 +30,16 @@ export function createPageLoadingGuard(router: Router) {
} }
return true; return true;
}); });
router.afterEach(async (to) => { router.afterEach(async (to, from) => {
const { openRouterTransition, openPageLoading } = appStore.getProjectConfig; const { openRouterTransition, openPageLoading } = appStore.getProjectConfig;
if ((!openRouterTransition && openPageLoading) || isFirstLoad || to.meta.afterCloseLoading) { const realToPath = to.path.replace(getParams(to), '');
const realFormPath = from.path.replace(getParams(from), '');
if (
(!openRouterTransition && openPageLoading) ||
isFirstLoad ||
to.meta.afterCloseLoading ||
realToPath === realFormPath
) {
setTimeout(() => { setTimeout(() => {
appStore.commitPageLoadingState(false); appStore.commitPageLoadingState(false);
}, 110); }, 110);
......
...@@ -107,7 +107,8 @@ export async function getFlatChildrenMenus(children: Menu[]) { ...@@ -107,7 +107,8 @@ export async function getFlatChildrenMenus(children: Menu[]) {
function basicFilter(routes: RouteRecordNormalized[]) { function basicFilter(routes: RouteRecordNormalized[]) {
return (menu: Menu) => { return (menu: Menu) => {
const matchRoute = routes.find((route) => route.path === menu.path); const matchRoute = routes.find((route) => route.path === menu.path);
if (!matchRoute) return false;
if (!matchRoute) return true;
menu.icon = menu.icon || matchRoute.meta.icon; menu.icon = menu.icon || matchRoute.meta.icon;
menu.meta = matchRoute.meta; menu.meta = matchRoute.meta;
return true; return true;
......
...@@ -45,6 +45,20 @@ const menu: MenuModule = { ...@@ -45,6 +45,20 @@ const menu: MenuModule = {
path: '/full-screen', path: '/full-screen',
name: '全屏', name: '全屏',
}, },
{
path: '/testTab',
name: '带参Tab',
children: [
{
path: '/id1',
name: '带参tab1',
},
{
path: '/id2',
name: '带参tab2',
},
],
},
], ],
}, },
}; };
......
...@@ -3,8 +3,6 @@ import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types'; ...@@ -3,8 +3,6 @@ import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
import { DEFAULT_LAYOUT_COMPONENT, PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant'; import { DEFAULT_LAYOUT_COMPONENT, PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '../constant';
import { genRouteModule } from '/@/utils/helper/routeHelper'; import { genRouteModule } from '/@/utils/helper/routeHelper';
import LoginRoute from './modules/sys';
import dashboard from './modules/dashboard'; import dashboard from './modules/dashboard';
// demo // demo
...@@ -48,5 +46,14 @@ export const RootRoute: AppRouteRecordRaw = { ...@@ -48,5 +46,14 @@ export const RootRoute: AppRouteRecordRaw = {
children: [], children: [],
}; };
export const LoginRoute: AppRouteRecordRaw = {
path: '/login',
name: 'Login',
component: () => import('/@/views/sys/login/Login.vue'),
meta: {
title: '登录',
},
};
// 基础路由 不用权限 // 基础路由 不用权限
export const basicRoutes = [LoginRoute, RootRoute]; export const basicRoutes = [LoginRoute, RootRoute];
...@@ -96,5 +96,13 @@ export default { ...@@ -96,5 +96,13 @@ export default {
title: '全屏', title: '全屏',
}, },
}, },
{
path: '/testTab/:id',
name: 'TestTab',
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
meta: {
title: 'Tab带参',
},
},
], ],
} as AppRouteModule; } as AppRouteModule;
import type { AppRouteRecordRaw } from '/@/router/types';
const routes: AppRouteRecordRaw = {
path: '/login',
name: 'Login',
component: () => import('/@/views/sys/login/Login.vue'),
meta: {
title: '登录',
},
};
export default routes;
...@@ -39,6 +39,7 @@ export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> { ...@@ -39,6 +39,7 @@ export interface AppRouteRecordRaw extends Omit<RouteRecordRaw, 'meta'> {
components?: any; components?: any;
children?: AppRouteRecordRaw[]; children?: AppRouteRecordRaw[];
props?: any; props?: any;
fullPath?: string;
} }
export interface Menu { export interface Menu {
......
...@@ -11,6 +11,7 @@ import { appStore } from '/@/store/modules/app'; ...@@ -11,6 +11,7 @@ import { appStore } from '/@/store/modules/app';
import store from '/@/store'; import store from '/@/store';
import router from '/@/router'; import router from '/@/router';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant'; import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
import { getCurrentTo } from '/@/utils/helper/routeHelper';
type CacheName = string | symbol | null | undefined; type CacheName = string | symbol | null | undefined;
/** /**
...@@ -18,7 +19,10 @@ type CacheName = string | symbol | null | undefined; ...@@ -18,7 +19,10 @@ type CacheName = string | symbol | null | undefined;
*/ */
// declare namespace TabsStore { // declare namespace TabsStore {
export interface TabItem { export interface TabItem {
path: string; fullPath: string;
path?: string;
params?: any;
query?: any;
name?: CacheName; name?: CacheName;
meta?: RouteMeta; meta?: RouteMeta;
} }
...@@ -86,20 +90,21 @@ class Tab extends VuexModule { ...@@ -86,20 +90,21 @@ class Tab extends VuexModule {
*/ */
@Mutation @Mutation
commitAddTab(route: AppRouteRecordRaw | TabItem): void { commitAddTab(route: AppRouteRecordRaw | TabItem): void {
const { path, name, meta } = route; const { path, name, meta, fullPath, params, query } = route as TabItem;
// 404 页面不需要添加tab // 404 页面不需要添加tab
if (path === PageEnum.ERROR_PAGE) { if (path === PageEnum.ERROR_PAGE) {
return; return;
} else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) { } else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) {
return; return;
} }
// 已经存在的页面,不重复添加tab // 已经存在的页面,不重复添加tab
const hasTab = this.tabsState.some((tab) => { const hasTab = this.tabsState.some((tab) => {
return tab.path === path; return tab.fullPath === fullPath;
}); });
if (hasTab) return; if (hasTab) return;
this.tabsState.push({ path, name, meta }); this.tabsState.push({ path, fullPath, name, meta, params, query });
if (unref(getOpenKeepAliveRef) && name) { if (unref(getOpenKeepAliveRef) && name) {
const noKeepAlive = meta && meta.ignoreKeepAlive; const noKeepAlive = meta && meta.ignoreKeepAlive;
const hasName = this.keepAliveTabsState.includes(name); const hasName = this.keepAliveTabsState.includes(name);
...@@ -113,9 +118,9 @@ class Tab extends VuexModule { ...@@ -113,9 +118,9 @@ class Tab extends VuexModule {
@Mutation @Mutation
commitCloseTab(route: AppRouteRecordRaw | TabItem): void { commitCloseTab(route: AppRouteRecordRaw | TabItem): void {
try { try {
const { path, name, meta: { affix } = {} } = route; const { fullPath, name, meta: { affix } = {} } = route;
if (affix) return; if (affix) return;
const index = this.tabsState.findIndex((item) => item.path === path); const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
index !== -1 && this.tabsState.splice(index, 1); index !== -1 && this.tabsState.splice(index, 1);
if (unref(getOpenKeepAliveRef) && name) { if (unref(getOpenKeepAliveRef) && name) {
...@@ -153,7 +158,7 @@ class Tab extends VuexModule { ...@@ -153,7 +158,7 @@ class Tab extends VuexModule {
@Mutation @Mutation
closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void { closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void {
this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.path)); this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
if (unref(getOpenKeepAliveRef) && nameList) { if (unref(getOpenKeepAliveRef) && nameList) {
this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter( this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter(
(item) => !nameList.includes(item as string) (item) => !nameList.includes(item as string)
...@@ -172,7 +177,7 @@ class Tab extends VuexModule { ...@@ -172,7 +177,7 @@ class Tab extends VuexModule {
for (const item of leftTabs) { for (const item of leftTabs) {
const affix = item.meta ? item.meta.affix : false; const affix = item.meta ? item.meta.affix : false;
if (!affix) { if (!affix) {
pathList.push(item.path); pathList.push(item.fullPath);
nameList.push(item.name as string); nameList.push(item.name as string);
} }
} }
...@@ -181,13 +186,19 @@ class Tab extends VuexModule { ...@@ -181,13 +186,19 @@ class Tab extends VuexModule {
} }
@Action @Action
addTabByPathAction(to: AppRouteRecordRaw): void { addTabByPathAction(): void {
to && this.commitAddTab((to as unknown) as AppRouteRecordRaw); const toRoute = getCurrentTo();
if (!toRoute) return;
const { meta } = toRoute;
if (meta && meta.affix) {
return;
}
this.commitAddTab((toRoute as unknown) as AppRouteRecordRaw);
} }
@Action @Action
closeRightTabAction(route: AppRouteRecordRaw | TabItem): void { closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
const index = this.tabsState.findIndex((item) => item.path === route.path); const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
if (index >= 0 && index < this.tabsState.length - 1) { if (index >= 0 && index < this.tabsState.length - 1) {
const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length); const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
...@@ -197,7 +208,7 @@ class Tab extends VuexModule { ...@@ -197,7 +208,7 @@ class Tab extends VuexModule {
for (const item of rightTabs) { for (const item of rightTabs) {
const affix = item.meta ? item.meta.affix : false; const affix = item.meta ? item.meta.affix : false;
if (!affix) { if (!affix) {
pathList.push(item.path); pathList.push(item.fullPath);
nameList.push(item.name as string); nameList.push(item.name as string);
} }
} }
...@@ -207,16 +218,16 @@ class Tab extends VuexModule { ...@@ -207,16 +218,16 @@ class Tab extends VuexModule {
@Action @Action
closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void { closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void {
const closePathList = this.tabsState.map((item) => item.path); const closePathList = this.tabsState.map((item) => item.fullPath);
const pathList: string[] = []; const pathList: string[] = [];
const nameList: string[] = []; const nameList: string[] = [];
closePathList.forEach((path) => { closePathList.forEach((path) => {
if (path !== route.path) { if (path !== route.fullPath) {
const closeItem = this.tabsState.find((item) => item.path === path); const closeItem = this.tabsState.find((item) => item.path === path);
if (!closeItem) return; if (!closeItem) return;
const affix = closeItem.meta ? closeItem.meta.affix : false; const affix = closeItem.meta ? closeItem.meta.affix : false;
if (!affix) { if (!affix) {
pathList.push(closeItem.path); pathList.push(closeItem.fullPath);
nameList.push(closeItem.name as string); nameList.push(closeItem.name as string);
} }
} }
......
declare module 'ant-design-vue/es/locale/zh_CN'; declare module 'ant-design-vue/es/locale/zh_CN';
declare module 'vue-draggable-resizable'; declare module 'globby!/@/router/routes/modules/**/*.@(ts)';
declare module 'globby!/@/router/menus/modules/**/*.@(ts)';
declare const React: string; declare const React: string;
declare module '*.bmp' { declare module '*.bmp' {
const src: string; const src: string;
......
...@@ -16,9 +16,6 @@ class EventHub { ...@@ -16,9 +16,6 @@ class EventHub {
emit(eventName: string, data?: any) { emit(eventName: string, data?: any) {
if (this.cache[eventName] === undefined) return; if (this.cache[eventName] === undefined) return;
console.log('======================');
console.log(this.cache, eventName);
console.log('======================');
this.cache[eventName].forEach((fn) => fn(data)); this.cache[eventName].forEach((fn) => fn(data));
} }
off(eventName: string, fn: (data: any) => void) { off(eventName: string, fn: (data: any) => void) {
......
...@@ -4,7 +4,6 @@ import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types'; ...@@ -4,7 +4,6 @@ import type { MenuModule, Menu, AppRouteRecordRaw } from '/@/router/types';
import { findPath, forEach, treeMap, treeToList } from './treeHelper'; import { findPath, forEach, treeMap, treeToList } from './treeHelper';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
//
export function getAllParentPath(treeData: any[], path: string) { export function getAllParentPath(treeData: any[], path: string) {
const menuList = findPath(treeData, (n) => n.path === path) as Menu[]; const menuList = findPath(treeData, (n) => n.path === path) as Menu[];
return (menuList || []).map((item) => item.path); return (menuList || []).map((item) => item.path);
...@@ -14,6 +13,7 @@ export function flatMenus(menus: Menu[]) { ...@@ -14,6 +13,7 @@ export function flatMenus(menus: Menu[]) {
return treeToList(menus); return treeToList(menus);
} }
// 拼接父级路径
function joinParentPath(list: any, node: any) { function joinParentPath(list: any, node: any) {
let allPaths = getAllParentPath(list, node.path); let allPaths = getAllParentPath(list, node.path);
...@@ -26,7 +26,6 @@ function joinParentPath(list: any, node: any) { ...@@ -26,7 +26,6 @@ function joinParentPath(list: any, node: any) {
parentPath += /^\//.test(p) ? p : `/${p}`; parentPath += /^\//.test(p) ? p : `/${p}`;
}); });
} }
node.path = `${parentPath}${/^\//.test(node.path) ? node.path : `/${node.path}`}`.replace( node.path = `${parentPath}${/^\//.test(node.path) ? node.path : `/${node.path}`}`.replace(
/\/\//g, /\/\//g,
'/' '/'
...@@ -34,6 +33,7 @@ function joinParentPath(list: any, node: any) { ...@@ -34,6 +33,7 @@ function joinParentPath(list: any, node: any) {
return node; return node;
} }
// 解析菜单模块
export function transformMenuModule(menuModule: MenuModule): Menu { export function transformMenuModule(menuModule: MenuModule): Menu {
const { menu } = menuModule; const { menu } = menuModule;
......
import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types'; import type { AppRouteModule, AppRouteRecordRaw } from '/@/router/types';
import type { RouteRecordRaw } from 'vue-router'; import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
import { tabStore } from '/@/store/modules/tab'; import { tabStore } from '/@/store/modules/tab';
import { createRouter, createWebHashHistory } from 'vue-router'; import { createRouter, createWebHashHistory } from 'vue-router';
import { toRaw } from 'vue'; import { toRaw } from 'vue';
import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant'; import { PAGE_LAYOUT_COMPONENT } from '/@/router/constant';
let currentTo: RouteLocationNormalized | null = null;
export function getCurrentTo() {
return currentTo;
}
export function setCurrentTo(to: RouteLocationNormalized) {
currentTo = to;
}
// 转化路由模块
// 将多级转成2层。keepAlive问题
export function genRouteModule(moduleList: AppRouteModule[]) { export function genRouteModule(moduleList: AppRouteModule[]) {
const ret: AppRouteRecordRaw[] = []; const ret: AppRouteRecordRaw[] = [];
for (const routeMod of moduleList) { for (const routeMod of moduleList) {
...@@ -27,6 +39,7 @@ export function genRouteModule(moduleList: AppRouteModule[]) { ...@@ -27,6 +39,7 @@ export function genRouteModule(moduleList: AppRouteModule[]) {
return ret as RouteRecordRaw[]; return ret as RouteRecordRaw[];
} }
// 动态引入
function asyncImportRoute(routes: AppRouteRecordRaw[]) { function asyncImportRoute(routes: AppRouteRecordRaw[]) {
routes.forEach((item) => { routes.forEach((item) => {
const { component, children } = item; const { component, children } = item;
...@@ -37,6 +50,7 @@ function asyncImportRoute(routes: AppRouteRecordRaw[]) { ...@@ -37,6 +50,7 @@ function asyncImportRoute(routes: AppRouteRecordRaw[]) {
}); });
} }
// 将后台对象转成路由对象
export function transformObjToRoute(routeList: AppRouteModule[]) { export function transformObjToRoute(routeList: AppRouteModule[]) {
routeList.forEach((route) => { routeList.forEach((route) => {
asyncImportRoute(route.routes); asyncImportRoute(route.routes);
...@@ -48,6 +62,7 @@ export function transformObjToRoute(routeList: AppRouteModule[]) { ...@@ -48,6 +62,7 @@ export function transformObjToRoute(routeList: AppRouteModule[]) {
return routeList; return routeList;
} }
//
export function getIsOpenTab(toPath: string) { export function getIsOpenTab(toPath: string) {
const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig; const { openKeepAlive, multiTabsSetting: { show } = {} } = appStore.getProjectConfig;
...@@ -57,3 +72,13 @@ export function getIsOpenTab(toPath: string) { ...@@ -57,3 +72,13 @@ export function getIsOpenTab(toPath: string) {
} }
return false; return false;
} }
export function getParams(data: any = {}) {
const { params = {} } = data;
let ret = '';
Object.keys(params).forEach((key) => {
const p = params[key];
ret += `/${p}`;
});
return ret;
}
<template>
<div class="p-4"> Current Param : {{ params }} </div>
</template>
<script lang="ts">
import { computed, defineComponent, unref } from 'vue';
import { useRouter } from 'vue-router';
export default defineComponent({
setup() {
const { currentRoute } = useRouter();
return {
params: computed(() => {
return unref(currentRoute).params;
}),
};
},
});
</script>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div /> <div />
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, onBeforeMount, unref } from 'vue'; import { defineComponent, unref } from 'vue';
import { appStore } from '/@/store/modules/app'; import { appStore } from '/@/store/modules/app';
...@@ -11,21 +11,19 @@ ...@@ -11,21 +11,19 @@
name: 'Redirect', name: 'Redirect',
setup() { setup() {
const { currentRoute, replace } = useRouter(); const { currentRoute, replace } = useRouter();
onBeforeMount(() => { const { params, query } = unref(currentRoute);
const { params, query } = unref(currentRoute); const { path } = params;
const { path } = params; const _path = Array.isArray(path) ? path.join('/') : path;
const _path = Array.isArray(path) ? path.join('/') : path; replace({
replace({ path: '/' + _path,
path: '/' + _path, query,
query,
});
const { openRouterTransition, openPageLoading } = appStore.getProjectConfig;
if (openRouterTransition && openPageLoading) {
setTimeout(() => {
appStore.setPageLoadingAction(false);
}, 0);
}
}); });
const { openRouterTransition, openPageLoading } = appStore.getProjectConfig;
if (openRouterTransition && openPageLoading) {
setTimeout(() => {
appStore.setPageLoadingAction(false);
}, 0);
}
return {}; return {};
}, },
}); });
......
...@@ -71,7 +71,7 @@ const viteConfig: UserConfig = { ...@@ -71,7 +71,7 @@ const viteConfig: UserConfig = {
* boolean | 'terser' | 'esbuild' * boolean | 'terser' | 'esbuild'
* @default 'terser' * @default 'terser'
*/ */
minify: isDevFn() ? false : 'terser', minify: 'terser',
/** /**
* 基本公共路径 * 基本公共路径
* @default '/' * @default '/'
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论