mirror of https://github.com/dtm-labs/dtm.git
30 changed files with 9183 additions and 0 deletions
@ -0,0 +1,68 @@ |
|||
module.exports = { |
|||
parser: "vue-eslint-parser", |
|||
"env": { |
|||
"browser": true, |
|||
"es2021": true |
|||
}, |
|||
"extends": [ |
|||
"plugin:@typescript-eslint/recommended", |
|||
"plugin:vue/vue3-recommended" |
|||
], |
|||
"parserOptions": { |
|||
"parser": "@typescript-eslint/parser", |
|||
"sourceType": "module", |
|||
ecmaFeature: { |
|||
jsx: true, |
|||
tsx: true |
|||
} |
|||
}, |
|||
"plugins": [ |
|||
"@typescript-eslint" |
|||
], |
|||
"rules": { |
|||
'vue/max-attributes-per-line': ['error', { |
|||
singleline: 10, |
|||
multiline: { |
|||
max: 1, |
|||
allowFirstLine: false |
|||
} |
|||
}], |
|||
'vue/singleline-html-element-content-newline': 'off', |
|||
'vue/multiline-html-element-content-newline': 'off', |
|||
'vue/html-indent': ['error', 4], |
|||
indent: ['error', 4], // 4行缩进
|
|||
'vue/script-indent': ['error', 4], |
|||
quotes: ['error', 'single'], // 单引号
|
|||
// 'vue/html-quotes': ['error', 'single'],
|
|||
semi: ['error', 'never'], // 禁止使用分号
|
|||
'space-infix-ops': ['error', { int32Hint: false }], // 要求操作符周围有空格
|
|||
'no-multi-spaces': 'error', // 禁止多个空格
|
|||
'no-whitespace-before-property': 'error', // 禁止在属性前使用空格
|
|||
'space-before-blocks': 'error', // 在块之前强制保持一致的间距
|
|||
'space-before-function-paren': ['error', 'never'], // 在“ function”定义打开括号之前强制不加空格
|
|||
'space-in-parens': ['error', 'never'], // 强制括号左右的不加空格
|
|||
'spaced-comment': ['error', 'always'], // 注释间隔
|
|||
'template-tag-spacing': ['error', 'always'], // 在模板标签及其文字之间需要空格
|
|||
'no-var': 'error', |
|||
'prefer-destructuring': ['error', { // 优先使用数组和对象解构
|
|||
array: true, |
|||
object: true |
|||
}, { |
|||
enforceForRenamedProperties: false |
|||
}], |
|||
'comma-dangle': ['error', 'never'], // 最后一个属性不允许有逗号
|
|||
'arrow-spacing': 'error', // 箭头函数空格
|
|||
'prefer-template': 'error', |
|||
'template-curly-spacing': 'error', |
|||
'quote-props': ['error', 'as-needed'], // 对象字面量属性名称使用引号
|
|||
'object-curly-spacing': ['error', 'always'], // 强制在花括号中使用一致的空格
|
|||
'no-unneeded-ternary': 'error', // 禁止可以表达为更简单结构的三元操作符
|
|||
'no-restricted-syntax': ['error', 'WithStatement', 'BinaryExpression[operator="in"]'], // 禁止with/in语句
|
|||
'no-lonely-if': 'error', // 禁止 if 语句作为唯一语句出现在 else 语句块中
|
|||
'newline-per-chained-call': ['error', { ignoreChainWithDepth: 2 }], // 要求方法链中每个调用都有一个换行符
|
|||
// 路径别名设置
|
|||
'no-submodule-imports': ['off', '/@'], |
|||
'no-implicit-dependencies': ['off', ['/@']], |
|||
'@typescript-eslint/no-explicit-any': 'off' // 类型可以使用any
|
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
# Logs |
|||
logs |
|||
*.log |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
lerna-debug.log* |
|||
|
|||
node_modules |
|||
dist |
|||
dist-ssr |
|||
*.local |
|||
|
|||
# Editor directories and files |
|||
.vscode/* |
|||
!.vscode/extensions.json |
|||
.idea |
|||
.DS_Store |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
|||
@ -0,0 +1 @@ |
|||
# DTM-Admin |
|||
@ -0,0 +1,13 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<link rel="icon" href="/favicon.ico" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<title>Vite App</title> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<script type="module" src="/src/main.ts"></script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because it is too large
@ -0,0 +1,36 @@ |
|||
{ |
|||
"name": "dtm-admin", |
|||
"private": true, |
|||
"version": "0.0.0", |
|||
"scripts": { |
|||
"dev": "vite", |
|||
"build": "vite build", |
|||
"preview": "vite preview" |
|||
}, |
|||
"dependencies": { |
|||
"ant-design-vue": "^3.1.1", |
|||
"vue": "^3.2.25" |
|||
}, |
|||
"devDependencies": { |
|||
"@types/node": "^17.0.23", |
|||
"@types/nprogress": "^0.2.0", |
|||
"@typescript-eslint/eslint-plugin": "^5.18.0", |
|||
"@typescript-eslint/parser": "^5.18.0", |
|||
"@vitejs/plugin-vue": "^2.3.0", |
|||
"autoprefixer": "^10.4.4", |
|||
"axios": "^0.26.1", |
|||
"eslint": "^8.13.0", |
|||
"eslint-plugin-vue": "^8.6.0", |
|||
"nprogress": "^0.2.0", |
|||
"pinia": "^2.0.0-rc.10", |
|||
"postcss": "^8.4.12", |
|||
"postcss-import": "^14.1.0", |
|||
"postcss-nested": "^5.0.6", |
|||
"postcss-simple-vars": "^6.0.3", |
|||
"typescript": "^4.5.4", |
|||
"vite": "^2.9.1", |
|||
"vite-plugin-svg-icons": "^1.1.0", |
|||
"vue-router": "^4.0.13", |
|||
"vue-tsc": "^0.29.8" |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,6 @@ |
|||
<template> |
|||
<router-view /> |
|||
</template> |
|||
|
|||
<script setup lang="ts"></script> |
|||
|
|||
|
After Width: | Height: | Size: 6.7 KiB |
@ -0,0 +1,42 @@ |
|||
<template> |
|||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" /> |
|||
<svg v-else :class="svgClass" aria-hidden="true"> |
|||
<use :xlink:href="iconName" /> |
|||
</svg> |
|||
</template> |
|||
<script setup lang='ts'> |
|||
|
|||
const props = defineProps({ |
|||
iconClass: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
className: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}) |
|||
|
|||
const isExternal = /^(https?:|mailto:|tel:)/.test(props.iconClass) |
|||
const iconName = `#icon-${props.iconClass}` |
|||
const svgClass = props.className ? `svg-icon ${props.className}` : 'svg-icon ' |
|||
const styleExternalIcon = () => { |
|||
return { |
|||
mask: `url(${props.iconClass}) no-repeat 50% 50%`, |
|||
'-webkit-mask': `url(${props.iconClass}) no-repeat 50% 50%` |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="postcss" scoped> |
|||
.svg-icon { |
|||
vertical-align: -0.15em; |
|||
fill: currentColor; |
|||
overflow: hidden; |
|||
} |
|||
.svg-external-icon { |
|||
background-color: currentColor; |
|||
mask-size: cover !important; |
|||
display: inline-block; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,63 @@ |
|||
<template> |
|||
<a-layout style="height: 730px"> |
|||
<a-layout-sider width="200" style="background: #fff"> |
|||
<Sidebar /> |
|||
</a-layout-sider> |
|||
<a-layout style="padding: 0 24px 24px"> |
|||
<a-breadcrumb style="margin: 16px 0"> |
|||
<a-breadcrumb-item>{{ mainNav }}</a-breadcrumb-item> |
|||
<a-breadcrumb-item>{{ subNav }}</a-breadcrumb-item> |
|||
<a-breadcrumb-item>{{ page }}</a-breadcrumb-item> |
|||
</a-breadcrumb> |
|||
<a-layout-content |
|||
:style="{ background: '#fff', padding: '24px', margin: 0, minHeight: '280px' }" |
|||
> |
|||
<Content /> |
|||
</a-layout-content> |
|||
</a-layout> |
|||
</a-layout> |
|||
</template> |
|||
|
|||
<script setup lang='ts'> |
|||
import Sidebar from './components/sidebar.vue' |
|||
import Content from './components/content.vue' |
|||
import { useRoute } from 'vue-router' |
|||
import { useLayoutStore } from '../store/modules/layout' |
|||
import { IMenubarList } from '../type/store/layout' |
|||
import { findCurrentMenubar } from '../utils/util' |
|||
import { computed, onMounted, ref } from 'vue' |
|||
|
|||
const route = useRoute() |
|||
const { getMenubar } = useLayoutStore() |
|||
|
|||
const mainNav = computed(() => { |
|||
const currentMenubar = findCurrentMenubar(getMenubar.menuList, true) |
|||
return currentMenubar?.meta.title |
|||
}) |
|||
|
|||
const subNav = computed(() => { |
|||
let subNav = '' |
|||
const currentMenubar = findCurrentMenubar(getMenubar.menuList, true) |
|||
currentMenubar.children?.forEach(v => { |
|||
if (route.path.indexOf(v.path) !== -1) { |
|||
subNav = v.meta.title |
|||
} |
|||
}) |
|||
|
|||
return subNav |
|||
}) |
|||
|
|||
const page = computed(() => { |
|||
let page = '' |
|||
const currentMenubar = findCurrentMenubar(getMenubar.menuList, true) |
|||
currentMenubar.children?.forEach(v => { |
|||
v.children?.forEach(vv => { |
|||
if (route.path == vv.path) { |
|||
page = vv.meta.title |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
return page |
|||
}) |
|||
</script> |
|||
@ -0,0 +1,17 @@ |
|||
<template> |
|||
<router-view v-slot="{Component}"> |
|||
<transition name="fade-transform" mode="out-in"> |
|||
<keep-alive> |
|||
<component :is="Component" :key="key" /> |
|||
</keep-alive> |
|||
</transition> |
|||
</router-view> |
|||
</template> |
|||
<script setup lang='ts'> |
|||
import { computed } from 'vue' |
|||
import { useRoute } from 'vue-router' |
|||
|
|||
const route = useRoute() |
|||
|
|||
const key = computed(() => route.path) |
|||
</script> |
|||
@ -0,0 +1,39 @@ |
|||
<template> |
|||
<div> |
|||
<a-layout-header class="header"> |
|||
<svg-icon class="logo" style="width: 36px; height: 36px;" icon-class="svg-dtm" /> |
|||
<a-menu |
|||
v-model:selectedKeys="activeMenu" |
|||
theme="dark" |
|||
mode="horizontal" |
|||
:style="{ lineHeight: '64px' }" |
|||
@select="onOpenChange" |
|||
> |
|||
<a-menu-item v-for="v in getMenubar.menuList" :key="v.path">{{ v.meta.title }}</a-menu-item> |
|||
</a-menu> |
|||
</a-layout-header> |
|||
</div> |
|||
</template> |
|||
<script setup lang='ts'> |
|||
import { computed, ref } from 'vue'; |
|||
import { useRoute, useRouter } from 'vue-router'; |
|||
import { useLayoutStore } from '/@/store/modules/layout' |
|||
|
|||
const route = useRoute() |
|||
const router = useRouter() |
|||
const { getMenubar } = useLayoutStore() |
|||
const firstRedirectPath = '/dashboard' |
|||
|
|||
const activeMenu = ref([route.meta.activeMenu !== firstRedirectPath ? route.meta.activeMenu : '/']) |
|||
|
|||
const onOpenChange = (d:any) => { |
|||
router.push({ path: d.key }) |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.logo { |
|||
float: left; |
|||
margin: 16px 24px 16px 0; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,57 @@ |
|||
<template> |
|||
<a-menu |
|||
v-model:selectedKeys="activeMenu" |
|||
v-model:openKeys="openKeys" |
|||
mode="inline" |
|||
:style="{ height: '100%', borderRight: 0 }" |
|||
@select="onOpenChange" |
|||
> |
|||
<a-sub-menu v-for="v in filterSubMenubarData" :key="v.path"> |
|||
<template #title> |
|||
<span> |
|||
{{ v.meta.title }} |
|||
</span> |
|||
</template> |
|||
<a-menu-item v-for="vv in v.children" :key="vv.path">{{ vv.meta.title }}</a-menu-item> |
|||
</a-sub-menu> |
|||
</a-menu> |
|||
</template> |
|||
|
|||
<script setup lang='ts'> |
|||
import { ref, computed } from 'vue' |
|||
import { useRoute, useRouter } from 'vue-router' |
|||
import { useLayoutStore } from '/@/store/modules/layout' |
|||
import { IMenubarList } from '/@/type/store/layout' |
|||
import { findCurrentMenubar } from '/@/utils/util' |
|||
|
|||
const route = useRoute() |
|||
const router = useRouter() |
|||
const { getMenubar } = useLayoutStore() |
|||
|
|||
const filterSubMenubarData = computed(() => { |
|||
return findCurrentMenubar(getMenubar.menuList) as IMenubarList[] |
|||
}) |
|||
|
|||
const activeMenu = computed({ |
|||
get: () => { |
|||
return [route.path] |
|||
}, |
|||
set: (val) => { |
|||
// do nothing, just for eliminate warn |
|||
} |
|||
}) |
|||
|
|||
const openKeys = computed({ |
|||
get: () => { |
|||
const pos = route.path.lastIndexOf('/') |
|||
return [route.path.substring(0, pos)] |
|||
}, |
|||
set: (val) => { |
|||
// do onthing, just for eliminate warn |
|||
} |
|||
}) |
|||
|
|||
const onOpenChange = (d:any) => { |
|||
router.push({ path: d.key }) |
|||
} |
|||
</script> |
|||
@ -0,0 +1,12 @@ |
|||
<script setup lang="ts"> |
|||
import Header from './components/header.vue' |
|||
</script> |
|||
|
|||
<template> |
|||
<a-layout> |
|||
<a-layout-header class="header"> |
|||
<Header /> |
|||
</a-layout-header> |
|||
<router-view /> |
|||
</a-layout> |
|||
</template> |
|||
@ -0,0 +1,17 @@ |
|||
import { createApp } from 'vue' |
|||
import App from './App.vue' |
|||
import router from '/@/router/index' |
|||
import { pinia } from '/@/store' |
|||
import '/@/permission' |
|||
|
|||
import Antd from 'ant-design-vue' |
|||
import 'ant-design-vue/dist/antd.css' |
|||
import 'virtual:svg-icons-register' |
|||
import SvgIcon from '/@/components/SvgIcon/index.vue' |
|||
|
|||
const app = createApp(App) |
|||
app.use(Antd) |
|||
app.use(router) |
|||
app.use(pinia) |
|||
app.component('SvgIcon', SvgIcon) |
|||
app.mount('#app') |
|||
@ -0,0 +1,23 @@ |
|||
import router from '/@/router' |
|||
import { configure, start, done } from 'nprogress' |
|||
import { useLayoutStore } from './store/modules/layout' |
|||
|
|||
configure({ showSpinner: false }) |
|||
|
|||
const defaultRoutePath = '/' |
|||
|
|||
router.beforeEach((to) => { |
|||
start() |
|||
|
|||
const { getMenubar, concatAllowRoutes } = useLayoutStore() |
|||
|
|||
if (getMenubar.menuList.length === 0) { |
|||
concatAllowRoutes() |
|||
|
|||
return to.fullPath |
|||
} |
|||
}) |
|||
|
|||
router.afterEach(() => { |
|||
done() |
|||
}) |
|||
@ -0,0 +1,18 @@ |
|||
const modules = import.meta.glob('../views/**/**.vue') |
|||
const components: IObject<() => Promise<typeof import('*.vue')>> = { |
|||
LayoutHeader: (() => import('/@/layout/index.vue')) as unknown as () => Promise<typeof import('*.vue')> |
|||
} |
|||
|
|||
Object.keys(modules).forEach(key => { |
|||
const nameMatch = key.match(/^\.\.\/views\/(.+)\.vue/) |
|||
if (!nameMatch) return |
|||
if (nameMatch[1].includes('_Components')) return |
|||
const indexMatch = nameMatch[1].match(/(.*)\/Index$/i) |
|||
let name = indexMatch ? indexMatch[1] : nameMatch[1]; |
|||
[name] = name.split('/').splice(-1) |
|||
components[name] = modules[key] as () => Promise<typeof import('*.vue')> |
|||
}) |
|||
|
|||
export { |
|||
components |
|||
} |
|||
@ -0,0 +1,109 @@ |
|||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' |
|||
import { IMenubarList } from '../type/store/layout'; |
|||
import { components } from './asyncRouter'; |
|||
|
|||
const Components: IObject<() => Promise<typeof import('*.vue')>> = Object.assign({}, components, { |
|||
LayoutHeader: (() => import('/@/layout/index.vue')) as unknown as () => Promise<typeof import('*.vue')>, |
|||
LayoutMain: (() => import('/@/layout/aside.vue')) as unknown as () => Promise<typeof import('*.vue')> |
|||
}) |
|||
|
|||
export const allowRouter: Array<IMenubarList> = [ |
|||
{ |
|||
name: 'Dashboard', |
|||
path: '/', |
|||
redirect: '/dashboard/sub1/1', |
|||
component: Components['LayoutHeader'], |
|||
meta: { title: '首页', activeMenu: '/dashboard' }, |
|||
children: [ |
|||
{ |
|||
name: 'SubNav1', |
|||
path: '/dashboard/sub1', |
|||
component: Components['LayoutMain'], |
|||
meta: { title: '子导航1' }, |
|||
children: [ |
|||
{ |
|||
name: 'Page1', |
|||
path: '/dashboard/sub1/1', |
|||
component: Components['DashboardPage1'], |
|||
meta: { title: '子页面1' }, |
|||
}, { |
|||
name: 'Page2', |
|||
path: '/dashboard/sub1/2', |
|||
component: Components['DashboardPage2'], |
|||
meta: { title: '子页面2' }, |
|||
} |
|||
] |
|||
}, { |
|||
name: 'SubNav2', |
|||
path: '/dashboard/sub2', |
|||
component: Components['LayoutMain'], |
|||
meta: { title: '子导航2' }, |
|||
children: [ |
|||
{ |
|||
name: 'Page21', |
|||
path: '/dashboard/sub2/1', |
|||
component: Components['DashboardPage1'], |
|||
meta: { title: '子页面21' }, |
|||
}, { |
|||
name: 'Page22', |
|||
path: '/dashboard/sub2/2', |
|||
component: Components['DashboardPage2'], |
|||
meta: { title: '子页面22' }, |
|||
} |
|||
] |
|||
} |
|||
] |
|||
}, { |
|||
name: 'Nav2', |
|||
path: '/nav2', |
|||
redirect: '/nav2/sub2/1', |
|||
component: Components['LayoutHeader'], |
|||
meta: { title: '导航2', activeMenu: '/nav2' }, |
|||
children: [ |
|||
{ |
|||
name: 'Nav2Sub1', |
|||
path: '/nav2/sub1', |
|||
component: Components['LayoutMain'], |
|||
meta: { title: '子导航1' }, |
|||
children: [ |
|||
{ |
|||
name: 'Nav2Page1', |
|||
path: '/nav2/sub1/1', |
|||
component: Components['DashboardPage1'], |
|||
meta: { title: '子页面1' }, |
|||
}, { |
|||
name: 'Nav2Page2', |
|||
path: '/nav2/sub1/2', |
|||
component: Components['DashboardPage2'], |
|||
meta: { title: '子页面2' }, |
|||
} |
|||
] |
|||
}, { |
|||
name: 'Nav2Sub2', |
|||
path: '/nav2/sub2', |
|||
component: Components['LayoutMain'], |
|||
meta: { title: '子导航2' }, |
|||
children: [ |
|||
{ |
|||
name: 'Nav2Page21', |
|||
path: '/nav2/sub2/1', |
|||
component: Components['DashboardPage1'], |
|||
meta: { title: '子页面21' }, |
|||
}, { |
|||
name: 'Nav2Page22', |
|||
path: '/nav2/sub2/2', |
|||
component: Components['DashboardPage2'], |
|||
meta: { title: '子页面22' }, |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
] |
|||
|
|||
const router = createRouter({ |
|||
history: createWebHistory(), |
|||
routes: allowRouter as RouteRecordRaw[] |
|||
}) |
|||
|
|||
export default router |
|||
@ -0,0 +1,2 @@ |
|||
import { createPinia } from 'pinia' |
|||
export const pinia = createPinia() |
|||
@ -0,0 +1,32 @@ |
|||
import { defineStore } from 'pinia'; |
|||
import { allowRouter } from '/@/router'; |
|||
import { ILayout, IMenubar, IMenubarList, IStatus } from '/@/type/store/layout'; |
|||
import { findCurrentMenubar } from '/@/utils/util'; |
|||
|
|||
export const useLayoutStore = defineStore({ |
|||
id: 'layout', |
|||
state: ():ILayout => ({ |
|||
menubar: { |
|||
menuList: [] |
|||
}, |
|||
status: { |
|||
isLoading: false |
|||
}, |
|||
}), |
|||
getters: { |
|||
getMenubar(): IMenubar { |
|||
return this.menubar |
|||
}, |
|||
getStatus(): IStatus { |
|||
return this.status |
|||
}, |
|||
}, |
|||
actions: { |
|||
setRoutes(data: Array<IMenubarList>): void { |
|||
this.menubar.menuList = data |
|||
}, |
|||
concatAllowRoutes(): void { |
|||
allowRouter.reverse().forEach(v => this.menubar.menuList.unshift(v)) |
|||
}, |
|||
} |
|||
}) |
|||
@ -0,0 +1,11 @@ |
|||
export {} |
|||
declare global { |
|||
interface IObject<T> { |
|||
[index: string]: T |
|||
} |
|||
interface ImportMetaEnv { |
|||
VITE_APP_TITLE: string |
|||
VITE_PORT: number |
|||
VITE_PROXY: string |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
declare module '*.vue' { |
|||
import { defineComponent } from 'vue'; |
|||
const Component: ReturnType<typeof defineComponent> |
|||
export default Component |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
export interface IMenubar { |
|||
menuList: Array<IMenubarList> |
|||
} |
|||
|
|||
export interface ILayout { |
|||
menubar: IMenubar |
|||
status: IStatus |
|||
} |
|||
|
|||
export interface IStatus { |
|||
isLoading: boolean |
|||
} |
|||
|
|||
export interface IMenubarList { |
|||
parentId?: number | string |
|||
id?: number | string |
|||
name: string |
|||
path: string |
|||
redirect?: string |
|||
meta: { |
|||
icon?: string |
|||
title: string |
|||
permission?: string[] |
|||
activeMenu?: string |
|||
hidden?: boolean |
|||
alwaysShow?: boolean |
|||
} |
|||
component: (() => Promise<typeof import('*.vue')>) | string |
|||
children?: Array<IMenubarList> |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
import { useRoute } from 'vue-router'; |
|||
import { IMenubarList } from '../type/store/layout'; |
|||
|
|||
export const findCurrentMenubar = (menuList: IMenubarList[], root?:boolean) => { |
|||
const route = useRoute() |
|||
let arr:IMenubarList[] | IMenubarList = [] |
|||
for (let i = 0; i < menuList.length; i++) { |
|||
const v = menuList[i]; |
|||
const usePath = v.meta.activeMenu || v.redirect || v.path; |
|||
const pos = usePath.lastIndexOf('/') |
|||
const rootPath = pos == 0 ? usePath : usePath.substring(0, pos) |
|||
if (route.path.indexOf(rootPath) !== -1) { |
|||
if (!root) { |
|||
arr = v.children as IMenubarList[] |
|||
} else { |
|||
arr = v |
|||
} |
|||
break |
|||
} |
|||
} |
|||
|
|||
return arr |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
<script setup lang='ts'> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<h1>Page1</h1> |
|||
</div> |
|||
</template> |
|||
@ -0,0 +1,9 @@ |
|||
<script setup lang='ts'> |
|||
|
|||
</script> |
|||
|
|||
<template> |
|||
<div> |
|||
<h1>Page2</h1> |
|||
</div> |
|||
</template> |
|||
@ -0,0 +1,21 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"target": "esnext", |
|||
"useDefineForClassFields": true, |
|||
"module": "esnext", |
|||
"moduleResolution": "node", |
|||
"strict": true, |
|||
"jsx": "preserve", |
|||
"sourceMap": true, |
|||
"resolveJsonModule": true, |
|||
"esModuleInterop": true, |
|||
"baseUrl": ".", |
|||
"paths": { |
|||
"/@/*": ["src/*"], |
|||
}, |
|||
"lib": ["esnext", "dom"], |
|||
"types": ["vite/client", "node"] |
|||
}, |
|||
"include": ["**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.vue"], |
|||
"exclude": ["node_modules"] |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
import { ConfigEnv, UserConfigExport } from 'vite'; |
|||
import path from 'path'; |
|||
import vue from '@vitejs/plugin-vue'; |
|||
import viteSvgIcons from 'vite-plugin-svg-icons'; |
|||
|
|||
const setAlias = (alias: [string, string][]) => alias.map((v) => { |
|||
return { find: v[0], replacement: path.resolve(__dirname, v[1]) }; |
|||
}); |
|||
|
|||
export default ({}: ConfigEnv): UserConfigExport => { |
|||
return { |
|||
resolve: { |
|||
alias: setAlias([['/@', 'src']]), |
|||
}, |
|||
plugins: [ |
|||
vue(), |
|||
viteSvgIcons({ |
|||
iconDirs: [path.resolve(process.cwd(), 'src/icons')], |
|||
symbolId: 'icon-[dir]-[name]' |
|||
}) |
|||
], |
|||
css: { |
|||
postcss: { |
|||
plugins: [ |
|||
require('autoprefixer'), |
|||
require('postcss-simple-vars'), |
|||
require('postcss-import') |
|||
] |
|||
} |
|||
} |
|||
}; |
|||
}; |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue