diff --git a/config/config.ts b/config/config.ts index 11e31a68..9a3c3b8a 100644 --- a/config/config.ts +++ b/config/config.ts @@ -2,13 +2,13 @@ export default { theme: { 'primary-color': '#1d39c4', }, - logo: '/favicon.ico', - title: 'Jetlinks', + logo: '/favicon.ico', // 浏览器标签页logo + title: 'Jetlinks', // 浏览器标签页title layout: { - title: '物联网平台', - logo: '/icons/icon-192x192.png', - siderWidth: 208, - headerHeight: 48, + title: '物联网平台', // 平台title + logo: '/icons/icon-192x192.png', // 平台logo + siderWidth: 208, // 左侧菜单栏宽度 + headerHeight: 48, // 头部高度 collapsedWidth: 48, mode: 'inline', theme: 'light', // 'dark' 'light' diff --git a/src/App.vue b/src/App.vue index 0bd59e76..02bc5677 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,31 +1,8 @@ diff --git a/src/components/Layout/BlankLayoutPage.vue b/src/components/Layout/BlankLayoutPage.vue new file mode 100644 index 00000000..69d6fa16 --- /dev/null +++ b/src/components/Layout/BlankLayoutPage.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/src/components/Layout/components/Header/Header.tsx b/src/components/Layout/components/Header/Header.tsx index ad36951b..f3ff3654 100644 --- a/src/components/Layout/components/Header/Header.tsx +++ b/src/components/Layout/components/Header/Header.tsx @@ -8,6 +8,9 @@ import { defaultSettingProps } from 'components/Layout/defaultSetting' import PropTypes from 'ant-design-vue/es/_util/vue-types' import { CustomRender, MenuDataItem, ProProps, RightContentRender, WithFalse } from 'components/Layout/typings' import './index.less' +import { omit } from 'lodash-es' +import { RouteRecordRaw } from 'vue-router' +import { clearMenuItem } from 'components/Layout/utils' export const headerProps = { ...defaultSettingProps, @@ -66,48 +69,60 @@ export default defineComponent({ const context = useRouteContext(); + const noChildrenMenuData = (menuData || []).map((item) => ({ + ...item, + children: undefined, + })) as RouteRecordRaw[]; + + const clearMenuData = clearMenuItem(noChildrenMenuData); + return () => ( -
-
-
-
- - {defaultRenderLogo(logo, logoStyle)} -

{ title }

-
+ <> +
+ -
- onOpenKeys && onOpenKeys($event), - 'onUpdate:selectedKeys': ($event: string[]) => onSelect && onSelect($event), - }} - /> -
-
-
- { - rightSize.value = width +
+ onOpenKeys && onOpenKeys($event), + 'onUpdate:selectedKeys': ($event: string[]) => onSelect && onSelect($event), }} - > - { - rightContentRender && typeof rightContentRender === 'function' ? ( -
{rightContentRender({...props})}
- ) : rightContentRender - } - + /> +
+
+
+ { + rightSize.value = width + }} + > + { + rightContentRender && typeof rightContentRender === 'function' ? ( +
{rightContentRender({...props})}
+ ) : rightContentRender + } +
+
-
+ ) } }) \ No newline at end of file diff --git a/src/components/Layout/components/Header/index.less b/src/components/Layout/components/Header/index.less index 54a179ba..d9734f2f 100644 --- a/src/components/Layout/components/Header/index.less +++ b/src/components/Layout/components/Header/index.less @@ -1,4 +1,9 @@ .header-content { + position: relative; + width: 100%; + height: 100%; + box-shadow: 0 1px 4px 0 rgb(0 21 41 / 12%); + transition: background .3s,width .2s; &.light { background-color: #fff; diff --git a/src/components/Layout/components/Header/index.tsx b/src/components/Layout/components/Header/index.tsx index 12534a81..ad2a8461 100644 --- a/src/components/Layout/components/Header/index.tsx +++ b/src/components/Layout/components/Header/index.tsx @@ -21,7 +21,7 @@ export const HeaderView = defineComponent({ inheritAttrs: false, props: headerViewProps, setup(props) { - const { headerHeight, navTheme, onCollapse } = toRefs(props); + const { headerHeight, onCollapse } = toRefs(props); const context = useRouteContext(); @@ -30,22 +30,35 @@ export const HeaderView = defineComponent({ ); return () => ( - -
+ - + +
+ + ) } }) \ No newline at end of file diff --git a/src/components/Layout/components/SiderMenu/BaseMenu.tsx b/src/components/Layout/components/SiderMenu/BaseMenu.tsx index ffcb60e9..c73f5002 100644 --- a/src/components/Layout/components/SiderMenu/BaseMenu.tsx +++ b/src/components/Layout/components/SiderMenu/BaseMenu.tsx @@ -122,7 +122,9 @@ class MenuUtil { title={defaultTitle} key={item.path} icon={} - /> + > + {this.getNavMenuItems(item.children)} + ) } @@ -144,7 +146,7 @@ class MenuUtil { const target = (meta.target || null) as string | null; const hasUrl = isUrl(item.path); const CustomTag: any = (target && 'a') || this.RouterLink; - const props = { to: { name: item.name, ...item.meta } }; + const props = { to: { path: item.path, ...item.meta } }; const attrs = hasUrl || target ? { ...item.meta, href: item.path, target } : {}; const icon = (item.meta?.icon && ) || undefined; @@ -191,13 +193,14 @@ export default defineComponent({ } emit('update:selectedKeys', args.selectedKeys); }; + const handleClick: MenuClickEventHandler = (args: MenuInfo) => { emit('click', args); }; return () => ( = (props, { slots, emit}) => { const { collapsed, - siderWidth, collapsedWidth = 48, menuExtraRender = false, menuContentRender = false, @@ -97,15 +99,17 @@ const SiderMenu: FunctionalComponent = (props, { slots, emit}) = const extraDom = menuExtraRender && menuExtraRender(props); - const handleSelect = () => { - + const handleSelect = ($event: string[]) => { + if (props.onSelect) { + props.onSelect([context.selectedKeys[0], ...$event]); + } } const defaultMenuDom = ( = (props, { slots, emit}) = /> ) + const Style = computed(() => { + return { + overflow: 'hidden', + height: '100vh', + zIndex: 18, + paddingTop: `${props.headerHeight}px`, + flex: `0 0 ${sSideWidth.value}px`, + minWidth: `${sSideWidth.value}px`, + maxWidth: `${sSideWidth.value}px`, + width: `${sSideWidth.value}px`, + transition: 'background-color 0.3s ease 0s, min-width 0.3s ease 0s, max-width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) 0s' + } + }) + return ( <> +
= (props, { slots, emit}) = props.onCollapse?.(collapse); }} collapsedWidth={collapsedWidth} - style={{ - overflow: 'hidden', - height: '100vh', - }} - width={siderWidth} + style={omit(Style.value, ['transition'])} + width={sSideWidth.value} theme={props.theme as 'dark' | 'light'} + class={'pro-layout-sider'} >
{(menuContentRender && menuContentRender(props, defaultMenuDom)) || defaultMenuDom} diff --git a/src/components/Layout/index.ts b/src/components/Layout/index.ts index de6cf140..d51eb779 100644 --- a/src/components/Layout/index.ts +++ b/src/components/Layout/index.ts @@ -1 +1,3 @@ -export { default as ProLayout } from './BasicLayout'; \ No newline at end of file +export { default as ProLayout } from './BasicLayout'; +export { default as BasicLayoutPage } from './BasicLayoutPage.vue' +export { default as BlankLayoutPage } from './BlankLayoutPage.vue' \ No newline at end of file diff --git a/src/components/Layout/utils.ts b/src/components/Layout/utils.ts index 550d2f9d..2422b857 100644 --- a/src/components/Layout/utils.ts +++ b/src/components/Layout/utils.ts @@ -9,7 +9,7 @@ export function clearMenuItem(menusData: RouteRecord[] | RouteRecordRaw[]): Rout return menusData .map((item: RouteRecord | RouteRecordRaw) => { const finalItem = { ...item }; - if (!finalItem.name || finalItem.meta?.hideInMenu) { + if (finalItem.meta?.hideInMenu) { return null; } @@ -17,7 +17,7 @@ export function clearMenuItem(menusData: RouteRecord[] | RouteRecordRaw[]): Rout if ( !finalItem.meta?.hideChildInMenu && finalItem.children.some( - (child: RouteRecord | RouteRecordRaw) => child && child.name && !child.meta?.hideInMenu + (child: RouteRecord | RouteRecordRaw) => child && !child.meta?.hideInMenu ) ) { return { @@ -45,4 +45,4 @@ export function flatMap(menusData: RouteRecord[]): MenuDataItem[] { return finalItem; }) .filter((item) => item) as MenuDataItem[]; -} \ No newline at end of file +} diff --git a/src/components/index.ts b/src/components/index.ts index ed95c26d..e4292ac5 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -9,6 +9,7 @@ import Search from './Search' import NormalUpload from './NormalUpload/index.vue' import FileFormat from './FileFormat/index.vue' import JUpload from './JUpload/index.vue' +import { BasicLayoutPage, BlankLayoutPage } from './Layout' export default { install(app: App) { @@ -22,5 +23,7 @@ export default { .component('NormalUpload', NormalUpload) .component('FileFormat', FileFormat) .component('JUpload', JUpload) + .component('BasicLayoutPage', BasicLayoutPage) + .component('BlankLayoutPage', BlankLayoutPage) } } diff --git a/src/router/index.ts b/src/router/index.ts index 11ffce4c..af006514 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,11 +1,12 @@ -import { createRouter, createWebHashHistory } from 'vue-router'; +import { createRouter, createWebHashHistory } from 'vue-router' import menus, { LoginPath } from './menu' -import { LocalStore } from "@/utils/comm"; -import { TOKEN_KEY } from "@/utils/variable"; +import { getToken } from '@/utils/comm' +import { useUserInfo } from '@/store/userInfo' +import { useSystem } from '@/store/system' const router = createRouter({ - history: createWebHashHistory(), - routes: menus + history: createWebHashHistory(), + routes: menus }) const filterPath = [ @@ -14,17 +15,45 @@ const filterPath = [ ] router.beforeEach((to, from, next) => { - const token = LocalStore.get(TOKEN_KEY) - // TODO 切换路由取消请求 - if (token || filterPath.includes(to.path)) { - next() - } else { - if (to.path === LoginPath) { - next() + // TODO 切换路由取消请求 + const isFilterPath = filterPath.includes(to.path) + if (isFilterPath) { + next() + } else { + const token = getToken() + if (token) { + if (to.path === LoginPath) { + next({ path: '/' }) + } else { + const userInfo = useUserInfo() + const system = useSystem() + if (!userInfo.$state.userInfos.username) { + userInfo.getUserInfo() + system.getSystemVersion().then((menuData: any[]) => { + menuData.forEach(r => { + router.addRoute('main', r) + }) + const redirect = decodeURIComponent((from.query.redirect as string) || to.path) + if(to.path === redirect) { + next({ ...to, replace: true }) + } else { + next({ path: redirect }) + } + }) + } else { - next({ path: LoginPath }) + next() } + } + + } else { + if (to.path === LoginPath) { + next() + } else { + next({ path: LoginPath }) + } } + } }) export default router \ No newline at end of file diff --git a/src/router/menu.ts b/src/router/menu.ts index 78683b84..b59a12d4 100644 --- a/src/router/menu.ts +++ b/src/router/menu.ts @@ -1,145 +1,205 @@ export const LoginPath = '/login' +import { BasicLayoutPage, BlankLayoutPage } from '@/components/Layout' export default [ // { - // path: '/', - // redirect: LoginPath + // path: '/iot', + // redirect: '/iot/device', + // meta: { + // title: '物联网', + // icon: 'EditOutlined' + // }, + // component: BasicLayoutPage, + // children: [ + // { + // path: '/iot/device', + // redirect: '/iot/device/instance', + // meta: { + // title: '设备管理', + // icon: 'EditOutlined' + // }, + // component: BlankLayoutPage, + // children: [ + // { + // path: '/iot/device/instance', + // component: () => import('@/views/demo/Search.vue'), + // meta: { + // title: '设备' + // }, + // }, + // { + // path: '/iot/device/instance2', + // component: () => import('@/views/demo/Search.vue'), + // meta: { + // title: '设备2' + // }, + // } + // ] + // } + // ] // }, // { - // path: '/init', - // component: () => import('@/view/InitPage.vue') + // path: '/iot2', + // redirect: '/iot2/device', + // meta: { + // title: '物联网2' + // }, + // component: BasicLayoutPage, + // children: [ + // { + // path: '/iot2/device', + // redirect: '/iot2/device/instance', + // meta: { + // title: '设备管理2' + // }, + // component: BlankLayoutPage, + // children: [ + // { + // path: '/iot2/device/instance', + // component: () => import('@/views/demo/Search.vue'), + // meta: { + // title: '设备2' + // }, + // } + // ] + // } + // ] // }, // { - // path: LoginPath, - // name: 'login', - // component: () => import('@/view/Login/index.vue') + // path: '/init-home', + // component: () => import('@/view/init-home/index.vue') // }, + { + path: LoginPath, + name: 'login', + component: () => import('@/views/user/Login/index.vue') + }, // { // path: '/initsetting', // component: () => import('@/view/Login/initSet.vue') // } // start: 测试用, 可删除 - { - path: '/login', - component: () => import('@/views/user/Login/index.vue') - }, - { - path: '/demo', - component: () => import('@/views/demo/index.vue') - }, - { - path: '/account/center/bind', - component: () => import('@/views/account/Center/bind/index.vue') - }, - { - path: '/iot/home', - component: () => import('@/views/home/index.vue') - }, - { - path: '/table', - component: () => import('@/views/demo/table/index.vue') - }, - { - path: '/form', - component: () => import('@/views/demo/Form.vue') - }, - { - path: '/search', - component: () => import('@/views/demo/Search.vue') - }, - { - path: '/notice/Config', - component: () => import('@/views/notice/Config/index.vue') - }, - { - path: '/notice/Config/detail/:id', - component: () => import('@/views/notice/Config/Detail/index.vue') - }, - { - path: '/notice/Template', - component: () => import('@/views/notice/Template/index.vue') - }, - { - path: '/notice/Template/detail/:id', - component: () => import('@/views/notice/Template/Detail/index.vue') - }, - // end: 测试用, 可删除 - - // 设备管理 - { - path: '/device/Instance', - component: () => import('@/views/device/Instance/index.vue') - }, - // link 运维管理 - { - path: '/link/log', - component: () => import('@/views/link/Log/index.vue') - }, - { - path: '/link/certificate', - component: () => import('@/views/link/Certificate/index.vue') - }, - { - path: '/link/certificate/detail/add', - component: () => import('@/views/link/Certificate/Detail/index.vue') - }, - { - path: '/link/accessConfig', - component: () => import('@/views/link/AccessConfig/index.vue') - }, - { - path: '/link/accessConfig/detail/add', - component: () => import('@/views/link/AccessConfig/Detail/index.vue') - }, - // system 系统管理 - { - path:'/system/Basis', - component: ()=>import('@/views/system/Basis/index.vue') - }, - { - path:'/system/api', - component: ()=>import('@/views/system/apiPage/index.vue') - }, - { - path:'/system/Role', - component: ()=>import('@/views/system/Role/index.vue') - }, - { - path:'/system/Role/detail/:id', - component: ()=>import('@/views/system/Role/Detail/index.vue') - }, - { - path:'/system/Permission', - component: ()=>import('@/views/system/Permission/index.vue') - }, - // 初始化 + // { + // path: '/login', + // component: () => import('@/views/user/Login/index.vue') + // }, + // { + // path: '/demo', + // component: () => import('@/views/demo/index.vue') + // }, + // { + // path: '/account/center/bind', + // component: () => import('@/views/account/Center/bind/index.vue') + // }, + // { + // path: '/iot/home', + // component: () => import('@/views/home/index.vue') + // }, + // { + // path: '/table', + // component: () => import('@/views/demo/table/index.vue') + // }, + // { + // path: '/form', + // component: () => import('@/views/demo/Form.vue') + // }, + // { + // path: '/search', + // component: () => import('@/views/demo/Search.vue') + // }, + // { + // path: '/notice/Config', + // component: () => import('@/views/notice/Config/index.vue') + // }, + // { + // path: '/notice/Config/detail/:id', + // component: () => import('@/views/notice/Config/Detail/index.vue') + // }, + // { + // path: '/notice/Template', + // component: () => import('@/views/notice/Template/index.vue') + // }, + // { + // path: '/notice/Template/detail/:id', + // component: () => import('@/views/notice/Template/Detail/index.vue') + // }, + // // end: 测试用, 可删除 + // + // // 设备管理 + // { + // path: '/device/Instance', + // component: () => import('@/views/device/Instance/index.vue') + // }, + // // link 运维管理 + // { + // path: '/link/log', + // component: () => import('@/views/link/Log/index.vue') + // }, + // { + // path: '/link/certificate', + // component: () => import('@/views/link/Certificate/index.vue') + // }, + // { + // path: '/link/certificate/detail/add', + // component: () => import('@/views/link/Certificate/Detail/index.vue') + // }, + // { + // path: '/link/accessConfig', + // component: () => import('@/views/link/AccessConfig/index.vue') + // }, + // { + // path: '/link/accessConfig/detail/add', + // component: () => import('@/views/link/AccessConfig/Detail/index.vue') + // }, + // // system 系统管理 + // { + // path:'/system/Basis', + // component: ()=>import('@/views/system/Basis/index.vue') + // }, + // { + // path:'/system/api', + // component: ()=>import('@/views/system/apiPage/index.vue') + // }, + // { + // path:'/system/Role', + // component: ()=>import('@/views/system/Role/index.vue') + // }, + // { + // path:'/system/Role/detail/:id', + // component: ()=>import('@/views/system/Role/Detail/index.vue') + // }, + // { + // path:'/system/Permission', + // component: ()=>import('@/views/system/Permission/index.vue') + // }, + // // 初始化 { path: '/init-home', component: () => import('@/views/init-home/index.vue') }, - // 物联卡 iot-card - { - path: '/iot-card/Home', - component: () => import('@/views/iot-card/Home/index.vue') - }, - { - path: '/iot-card/Dashboard', - component: () => import('@/views/iot-card/Dashboard/index.vue') - }, - // 北向输出 - { - path: '/northbound/DuerOS', - component: () => import('@/views/northbound/DuerOS/index.vue') - }, - { - path: '/northbound/AliCloud', - component: () => import('@/views/northbound/AliCloud/index.vue') - }, - - // 产品分类 - { - path: '/iot/device/Category', - component: () => import('@/views/device/Category/index.vue') - } + // // 物联卡 iot-card + // { + // path: '/iot-card/Home', + // component: () => import('@/views/iot-card/Home/index.vue') + // }, + // { + // path: '/iot-card/Dashboard', + // component: () => import('@/views/iot-card/Dashboard/index.vue') + // }, + // // 北向输出 + // { + // path: '/northbound/DuerOS', + // component: () => import('@/views/northbound/DuerOS/index.vue') + // }, + // { + // path: '/northbound/AliCloud', + // component: () => import('@/views/northbound/AliCloud/index.vue') + // }, + // + // // 产品分类 + // { + // path: '/iot/device/Category', + // component: () => import('@/views/device/Category/index.vue') + // } ] \ No newline at end of file diff --git a/src/store/menu.ts b/src/store/menu.ts index b03e4202..b9187e59 100644 --- a/src/store/menu.ts +++ b/src/store/menu.ts @@ -1,9 +1,12 @@ import { defineStore } from "pinia"; +import { queryOwnThree } from '@/api/system/menu' +import { filterAsnycRouter } from '@/utils/menu' export const useMenuStore = defineStore({ id: 'menu', state: () => ({ - menus: {} as {[key: string]: string}, + menus: {}, + menusKey: [] }), getters: { hasPermission(state) { @@ -19,6 +22,47 @@ export const useMenuStore = defineStore({ } return false } + }, + }, + actions: { + queryMenuTree(isCommunity = false): Promise { + return new Promise(async (res) => { + //过滤非集成的菜单 + const params = [ + { + terms: [ + { + terms: [ + { + column: 'owner', + termType: 'eq', + value: 'iot', + }, + { + column: 'owner', + termType: 'isnull', + value: '1', + type: 'or', + }, + ], + }, + ], + }, + ]; + const resp = await queryOwnThree({ paging: false, terms: params }) + if (resp.success) { + const menus = filterAsnycRouter(resp.result) + // menus.push({ + // path: '/', + // redirect: menus[0]?.path, + // meta: { + // hideInMenu: true + // } + // }) + this.menus = menus + res(menus) + } + }) } } }) \ No newline at end of file diff --git a/src/store/system.ts b/src/store/system.ts new file mode 100644 index 00000000..e4d37681 --- /dev/null +++ b/src/store/system.ts @@ -0,0 +1,24 @@ +import { defineStore } from 'pinia'; +import { systemVersion } from '@/api/comm' +import { useMenuStore } from './menu' + +export const useSystem = defineStore('system', { + state: () => ({ + isCommunity: false + }), + actions: { + getSystemVersion(): Promise { + return new Promise(async(res, rej) => { + const resp = await systemVersion() + if (resp.success && resp.result) { + const isCommunity = resp.result.edition === 'community' + this.isCommunity = isCommunity + // 获取菜单 + const menu = useMenuStore() + const menuData: any[] = await menu.queryMenuTree(isCommunity) + res(menuData) + } + }) + } + } +}) \ No newline at end of file diff --git a/src/store/userInfo.ts b/src/store/userInfo.ts index 4cf56cc6..3a6de12e 100644 --- a/src/store/userInfo.ts +++ b/src/store/userInfo.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia'; -import { authLogin } from '@/api/login'; +import { authLogin, userDetail } from '@/api/login'; import { LocalStore } from '@/utils/comm'; import { TOKEN_KEY } from '@/utils/variable'; @@ -38,5 +38,17 @@ export const useUserInfo = defineStore('userInfo', { }); }); }, + getUserInfo() { + return new Promise((res, rej) => { + userDetail().then(resp => { + if (resp.success) { + res(true) + this.userInfos = resp.result + } else { + rej() + } + }).catch(() => rej()) + }) + } }, }); diff --git a/src/utils/encodeQuery.ts b/src/utils/encodeQuery.ts index 19d11640..748bba26 100644 --- a/src/utils/encodeQuery.ts +++ b/src/utils/encodeQuery.ts @@ -1,3 +1,5 @@ +import { isObject } from 'lodash-es' + export default function encodeQuery(params: any) { if (!params) return {}; const queryParam = { @@ -15,7 +17,7 @@ export default function encodeQuery(params: any) { terms[k] === '' || terms[k] === undefined || terms[k].length === 0 || - terms[k] === {} || + (isObject(terms[k]) && Object.keys(terms[k]).length === 0) || terms[k] === null ) ) { diff --git a/src/utils/menu.ts b/src/utils/menu.ts new file mode 100644 index 00000000..22230e84 --- /dev/null +++ b/src/utils/menu.ts @@ -0,0 +1,111 @@ +const pagesComponent = import.meta.glob('../views/system/**/*.vue', { eager: true }); +import { BlankLayoutPage, BasicLayoutPage } from 'components/Layout' + +type ExtraRouteItem = { + code: string + name: string + url?: string +} +// 额外子级路由 +const extraRouteObj = { + 'media/Cascade': { + children: [ + { code: 'Save', name: '新增' }, + { code: 'Channel', name: '选择通道' }, + ], + }, + 'media/Device': { + children: [ + { code: 'Save', name: '详情' }, + { code: 'Channel', name: '通道列表' }, + { code: 'Playback', name: '回放' }, + ], + }, + 'rule-engine/Scene': { + children: [ + { code: 'Save', name: '详情' }, + { code: 'Save2', name: '测试详情' }, + ], + }, + 'rule-engine/Alarm/Configuration': { + children: [{ code: 'Save', name: '详情' }], + }, + 'device/Firmware': { + children: [{ code: 'Task', name: '升级任务' }], + }, + demo: { + children: [{ code: 'AMap', name: '地图' }], + }, + 'system/Platforms': { + children: [ + { code: 'Api', name: '赋权' }, + { code: 'View', name: 'Api详情' }, + ], + }, + 'system/DataSource': { + children: [{ code: 'Management', name: '管理' }], + }, + 'system/Menu': { + children: [{ code: 'Setting', name: '菜单配置' }], + }, + 'system/Apply': { + children: [ + { code: 'Api', name: '赋权' }, + { code: 'View', name: 'Api详情' }, + { code: 'Save', name: '详情' }, + ], + }, +}; + + +const resolveComponent = (name: any) => { + // TODO 暂时用system进行测试 + const importPage = pagesComponent[`../views/${name}/index.vue`]; + // if (!importPage) { + // throw new Error(`Unknown page ${name}. Is it located under Pages with a .vue extension?`); + // } + + //@ts-ignore + return !importPage ? BlankLayoutPage : importPage.default + // return importPage.default +} + +const findChildrenRoute = (code: string, url: string): ExtraRouteItem[] => { + if (extraRouteObj[code]) { + return extraRouteObj[code].children.map((route: ExtraRouteItem) => { + return { + url: `${url}/${route.code}`, + code: route.code, + name: route.name + } + }) + } + return [] +} + +export function filterAsnycRouter(asyncRouterMap: any, parentCode = '', level = 1) { + return asyncRouterMap.map((route: any) => { + + route.path = `${route.url}` + route.meta = { + icon: route.icon, + title: route.name + } + + // 查看是否有隐藏子路由 + route.children = route.children && route.children.length ? [...route.children, ...findChildrenRoute(route.code, route.url)] : findChildrenRoute(route.code, route.url) + + // TODO 查看是否具有详情页 + // route.children = [...route.children, ] + + if (route.children && route.children.length) { + route.component = () => level === 1 ? BasicLayoutPage : BlankLayoutPage + route.children = filterAsnycRouter(route.children, `${parentCode}/${route.code}`, level + 1) + route.redirect = route.children[0].url + } else { + route.component = resolveComponent(route.code); + } + console.log(route.code, route) + return route + }) +} \ No newline at end of file diff --git a/src/utils/request.ts b/src/utils/request.ts index cc606fea..9e43cb5b 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -118,6 +118,7 @@ const errorHandler = (error: any) => { const status = error.response.status if (status === 403) { Notification.error({ + key: '403', message: 'Forbidden', description: (data.message + '').substr(0, 90) }) @@ -129,22 +130,25 @@ const errorHandler = (error: any) => { }, 0) } else if (status === 500) { Notification.error({ + key: '500', message: 'Server Side Error', description: (data.message + '').substr(0, 90) }) } else if (status === 400) { Notification.error({ + key: '400', message: 'Request Error', description: (data.message + '').substr(0, 90) }) } else if (status === 401) { Notification.error({ + key: '401', message: 'Unauthorized', description: 'Authorization verification failed' }) setTimeout(() => { router.replace({ - name: 'login' + path: LoginPath }) }, 0) } diff --git a/tsconfig.json b/tsconfig.json index ca353357..e9e42eed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,7 +22,7 @@ "store/*": ["./src/store/*"], "style/*": ["./src/style/*"], }, - "types": ["ant-design-vue/typings/global"], + "types": ["ant-design-vue/typings/global", "vite/client"], "suppressImplicitAnyIndexErrors": true }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],