From 95a2bd884dd9846a56cda7c4c3ee4a41ce631b7c Mon Sep 17 00:00:00 2001 From: kailong321200875 <321200875@qq.com> Date: Sun, 9 Jan 2022 14:28:51 +0800 Subject: [PATCH] style(Icon): delete default color wip(router): async import route developing --- mock/user/index.ts | 2 +- src/components/Icon/src/Icon.vue | 2 +- src/locales/en.ts | 4 +- src/locales/zh-CN.ts | 4 +- src/router/helper.ts | 27 +++++ src/router/index.ts | 61 +++++++++++ src/store/modules/permission.ts | 180 +++++++++++++++++++++++++++++++ src/utils/index.ts | 20 ++++ src/views/Level/Menu111.vue | 5 + src/views/Level/Menu12.vue | 5 + src/views/Level/Menu2.vue | 5 + 11 files changed, 311 insertions(+), 4 deletions(-) create mode 100644 src/store/modules/permission.ts create mode 100644 src/views/Level/Menu111.vue create mode 100644 src/views/Level/Menu12.vue create mode 100644 src/views/Level/Menu2.vue diff --git a/mock/user/index.ts b/mock/user/index.ts index 8d76ef6d2..26aa0c8a9 100644 --- a/mock/user/index.ts +++ b/mock/user/index.ts @@ -3,7 +3,7 @@ import { MockMethod } from 'vite-plugin-mock' const { result_code } = config -const timeout = 2000 +const timeout = 1000 const List: { username: string diff --git a/src/components/Icon/src/Icon.vue b/src/components/Icon/src/Icon.vue index cdcf2d9d2..bc77efc42 100644 --- a/src/components/Icon/src/Icon.vue +++ b/src/components/Icon/src/Icon.vue @@ -13,7 +13,7 @@ const props = defineProps({ // icon name icon: propTypes.string, // icon color - color: propTypes.string.def('#888'), + color: propTypes.string, // icon size size: propTypes.number.def(16) }) diff --git a/src/locales/en.ts b/src/locales/en.ts index 909b8ceb0..4acc3e380 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -23,7 +23,9 @@ export default { forgetPassword: 'Forget password' }, router: { - login: 'Login' + login: 'Login', + level: 'Multi level menu', + menu: 'Menu' }, mock: { loginErr: 'Wrong account or password' diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 6e0529829..3fbf63f45 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -23,7 +23,9 @@ export default { forgetPassword: '忘记密码' }, router: { - login: '登录' + login: '登录', + level: '多级菜单', + menu: '菜单' }, mock: { loginErr: '账号或密码错误' diff --git a/src/router/helper.ts b/src/router/helper.ts index e69de29bb..39c087fa3 100644 --- a/src/router/helper.ts +++ b/src/router/helper.ts @@ -0,0 +1,27 @@ +import ParentLayout from '@/components/ParentView/index.vue' +import type { RouteLocationNormalized, RouteRecordNormalized } from 'vue-router' + +export const getParentLayout = (name: string) => { + return () => + new Promise((resolve) => { + resolve({ + ...ParentLayout, + name + }) + }) +} + +export function getRoute(route: RouteLocationNormalized): RouteLocationNormalized { + if (!route) return route + const { matched, ...opt } = route + return { + ...opt, + matched: (matched + ? matched.map((item) => ({ + meta: item.meta, + name: item.name, + path: item.path + })) + : undefined) as RouteRecordNormalized[] + } +} diff --git a/src/router/index.ts b/src/router/index.ts index 361580544..12daa2dc2 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -37,6 +37,67 @@ export const constantRouterMap: AppRouteRecordRaw[] = [ } ] +// export const asyncRouterMap: AppRouteRecordRaw[] = [ +// { +// path: '/level', +// component: Layout, +// redirect: '/level/menu1/menu1-1/menu1-1-1', +// name: 'Level', +// meta: { +// title: t('router.level') +// }, +// children: [ +// { +// path: 'menu1', +// name: 'Menu1', +// component: getParentLayout('Menu1'), +// redirect: '/level/menu1/menu1-1/menu1-1-1', +// meta: { +// title: `${t('router.menu')}1` +// }, +// children: [ +// { +// path: 'menu1-1', +// name: 'Menu11', +// component: getParentLayout('Menu11Demo'), +// redirect: '/level/menu1/menu1-1/menu1-1-1', +// meta: { +// title: `${t('router.menu')}1-1`, +// alwaysShow: true +// }, +// children: [ +// { +// path: 'menu1-1-1', +// name: 'Menu111', +// component: () => import('@/views/Level/Menu111.vue'), +// meta: { +// title: `${t('router.menu')}1-1-1` +// } +// } +// ] +// }, +// { +// path: 'menu1-2', +// name: 'Menu12', +// component: () => import('@/views/Level/Menu12.vue'), +// meta: { +// title: `${t('router.menu')}1-2` +// } +// } +// ] +// }, +// { +// path: 'menu2', +// name: 'Menu2Demo', +// component: () => import('@/views/Level/Menu2.vue'), +// meta: { +// title: `${t('router.menu')}2` +// } +// } +// ] +// } +// ] + const router = createRouter({ history: createWebHashHistory(), strict: true, diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts new file mode 100644 index 000000000..918ef5fef --- /dev/null +++ b/src/store/modules/permission.ts @@ -0,0 +1,180 @@ +// import { defineStore } from 'pinia' +// import { asyncRouterMap, constantRouterMap } from '@/router' +// import { useCache } from '@/hooks/web/useCache' +// import { getParentLayout } from '@/router/helper' +// import { store } from '../index' +// import { useAppStoreWithOut } from '@/store/modules/app' +// import { isUrl } from '@/utils/is' +// import { deepClone } from '@/utils' + +// const { wsCache } = useCache() + +// const appStore = useAppStoreWithOut() + +// const modules = import.meta.glob('../../views/**/*.{vue,tsx}') + +// /* Layout */ +// const Layout = () => import('@/layout/index.vue') + +// export interface PermissionState { +// routers: AppRouteRecordRaw[] +// addRouters: AppRouteRecordRaw[] +// isAddRouters: boolean +// activeTab: string +// menuTabRouters: AppRouteRecordRaw[] +// } + +// export const usePermissionStore = defineStore({ +// id: 'permission', +// state: (): PermissionState => ({ +// routers: [], +// addRouters: [], +// isAddRouters: false, +// menuTabRouters: [], +// activeTab: '' +// }), +// getters: { +// getRouters(): AppRouteRecordRaw[] { +// return this.routers +// }, +// getAddRouters(): AppRouteRecordRaw[] { +// return this.addRouters +// }, +// getIsAddRouters(): boolean { +// return this.isAddRouters +// }, +// getActiveTab(): string { +// return this.activeTab +// }, +// getMenuTabRouters(): AppRouteRecordRaw[] { +// return this.menuTabRouters +// } +// }, +// actions: { +// generateRoutes(): Promise { +// return new Promise((resolve) => { +// // 路由权限控制 +// let routerMap: AppRouteRecordRaw[] = [] +// if (wsCache.get(appStore.getUserInfo).roleName === 'admin') { +// // 模拟前端控制权限 +// routerMap = generateRoutesFn(deepClone(asyncRouterMap, ['component'])) +// } else { +// // 模拟后端控制权限 +// routerMap = getFilterRoutes(wsCache.get(appStore.getUserInfo).checkedNodes) +// } +// // const routerMap: AppRouteRecordRaw[] = generateRoutesFn(deepClone(asyncRouterMap, ['component'])) +// // 动态路由,404一定要放到最后面 +// this.addRouters = routerMap.concat([ +// { +// path: '/:path(.*)*', +// redirect: '/404', +// name: '404', +// meta: { +// hidden: true, +// breadcrumb: false +// } +// } +// ]) +// // 渲染菜单的所有路由 +// this.routers = deepClone(constantRouterMap, ['component']).concat(routerMap) +// resolve() +// }) +// }, +// setIsAddRouters(state: boolean): void { +// this.isAddRouters = state +// }, +// setMenuTabRouters(routers: AppRouteRecordRaw[]): void { +// this.menuTabRouters = routers +// }, +// setAcitveTab(activeTab: string): void { +// this.activeTab = activeTab +// } +// } +// }) + +// // 路由过滤,主要用于权限控制 +// function generateRoutesFn(routes: AppRouteRecordRaw[], basePath = '/'): AppRouteRecordRaw[] { +// const res: AppRouteRecordRaw[] = [] + +// for (const route of routes) { +// // skip some route +// if (route.meta && route.meta.hidden && !route.meta.showMainRoute) { +// continue +// } + +// let onlyOneChild: Nullable = null + +// if (route.children && route.children.length === 1 && !route.meta.alwaysShow) { +// onlyOneChild = ( +// isUrl(route.children[0].path) +// ? route.children[0].path +// : path.resolve(path.resolve(basePath, route.path), route.children[0].path) +// ) as string +// } + +// let data: Nullable = null + +// // 如不需要路由权限,可注释以下逻辑 +// // 权限过滤,通过获取登录信息里面的角色权限,动态的渲染菜单。 +// const list = wsCache.get(appStore.getUserInfo).checkedNodes +// // 开发者可以根据实际情况进行扩展 +// for (const item of list) { +// // 通过路径去匹配 +// if (isUrl(item.path) && (onlyOneChild === item.path || route.path === item.path)) { +// data = Object.assign({}, route) +// } else { +// const routePath = path.resolve(basePath, onlyOneChild || route.path) +// if (routePath === item.path || (route.meta && route.meta.followRoute === item.path)) { +// data = Object.assign({}, route) +// } +// } +// } +// // 如不需要路由权限,解注释下面一行 +// // data = Object.assign({}, route) + +// // recursive child routes +// if (route.children && data) { +// data.children = generateRoutesFn(route.children, path.resolve(basePath, data.path)) +// } +// if (data) { +// res.push(data as AppRouteRecordRaw) +// } +// } +// return res +// } + +// // 模拟后端过滤路由 +// function getFilterRoutes(routes: AppRouteRecordRaw[]): AppRouteRecordRaw[] { +// const res: AppRouteRecordRaw[] = [] + +// for (const route of routes) { +// const data: AppRouteRecordRaw = { +// path: route.path, +// name: route.name, +// redirect: route.redirect, +// meta: {} +// } +// data.meta = Object.assign({}, route.meta || {}, { title: route.meta.title }) +// if (route.component) { +// // 动态加载路由文件,可根据实际情况进行自定义逻辑 +// const component = route.component as string +// data.component = ( +// component === '#' +// ? Layout +// : component.includes('##') +// ? getParentLayout(component.split('##')[1]) +// : modules[`../../${route.component}.vue`] || modules[`../../${route.component}.tsx`] +// ) +// } +// // recursive child routes +// if (route.children) { +// data.children = getFilterRoutes(route.children) +// } +// res.push(data as AppRouteRecordRaw) +// } +// return res +// } + +// export function usePermissionStoreWithOut() { +// return usePermissionStore(store) +// } diff --git a/src/utils/index.ts b/src/utils/index.ts index 0904c63ce..bcab95d42 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -34,3 +34,23 @@ export function underlineToHump(str: string): string { return letter.toUpperCase() }) } + +/** + * 对象数组深拷贝 + * @param {Array,Object} source 需要深拷贝的对象数组 + * @param {Array} noClone 不需要深拷贝的属性集合 + */ +export function deepClone(source: any, noClone: string[] = []): any { + if (!source && typeof source !== 'object') { + throw new Error('error arguments deepClone') + } + const targetObj: any = source.constructor === Array ? [] : {} + Object.keys(source).forEach((keys: string) => { + if (source[keys] && typeof source[keys] === 'object' && noClone.indexOf(keys) === -1) { + targetObj[keys] = deepClone(source[keys], noClone) + } else { + targetObj[keys] = source[keys] + } + }) + return targetObj +} diff --git a/src/views/Level/Menu111.vue b/src/views/Level/Menu111.vue new file mode 100644 index 000000000..05fcc496f --- /dev/null +++ b/src/views/Level/Menu111.vue @@ -0,0 +1,5 @@ + + + diff --git a/src/views/Level/Menu12.vue b/src/views/Level/Menu12.vue new file mode 100644 index 000000000..446e8c929 --- /dev/null +++ b/src/views/Level/Menu12.vue @@ -0,0 +1,5 @@ + + + diff --git a/src/views/Level/Menu2.vue b/src/views/Level/Menu2.vue new file mode 100644 index 000000000..98823cdf8 --- /dev/null +++ b/src/views/Level/Menu2.vue @@ -0,0 +1,5 @@ + + +