diff --git a/README.md b/README.md
index 2218fed6..d33d095b 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ npm run dev
npm install vue-router@next
```
-src 下创建 router/index.ts
+src 下创建 router/interface.ts
```typescript
import {createRouter, createWebHashHistory, RouteRecordRaw} from 'vue-router'
@@ -71,7 +71,7 @@ export default router
npm install vuex@next
```
-src 下创建 store/index.ts
+src 下创建 store/interface.ts
```typescript
import {InjectionKey} from 'vue'
diff --git a/package.json b/package.json
index 3005ed75..a158d0ed 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"dependencies": {
"axios": "^0.24.0",
"element-plus": "^1.2.0-beta.3",
+ "path-to-regexp": "^6.2.0",
"vue": "^3.2.16",
"vue-router": "^4.0.12",
"vuex": "^4.0.2"
diff --git a/src/components/Breadcrumb/index.vue b/src/components/Breadcrumb/index.vue
new file mode 100644
index 00000000..e3c3daf3
--- /dev/null
+++ b/src/components/Breadcrumb/index.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
+ {{ item.meta.title }}
+
+ {{ item.meta.title }}
+
+
+
+
+
+
+
+
diff --git a/src/components/Hamburger/index.vue b/src/components/Hamburger/index.vue
new file mode 100644
index 00000000..368b0021
--- /dev/null
+++ b/src/components/Hamburger/index.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
deleted file mode 100644
index 86b77187..00000000
--- a/src/components/HelloWorld.vue
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
- 点击+1
-
-
-
-
-
diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue
new file mode 100644
index 00000000..b07ded2a
--- /dev/null
+++ b/src/components/SvgIcon/index.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
diff --git a/src/layout/components/AppMain.vue b/src/layout/components/AppMain.vue
new file mode 100644
index 00000000..f6a3286f
--- /dev/null
+++ b/src/layout/components/AppMain.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue
new file mode 100644
index 00000000..9921a1f9
--- /dev/null
+++ b/src/layout/components/Navbar.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layout/components/Sidebar/Link.vue b/src/layout/components/Sidebar/Link.vue
new file mode 100644
index 00000000..530b3d5b
--- /dev/null
+++ b/src/layout/components/Sidebar/Link.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
diff --git a/src/layout/components/Sidebar/Logo.vue b/src/layout/components/Sidebar/Logo.vue
new file mode 100644
index 00000000..040fab64
--- /dev/null
+++ b/src/layout/components/Sidebar/Logo.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
diff --git a/src/layout/components/Sidebar/SidebarItem.vue b/src/layout/components/Sidebar/SidebarItem.vue
new file mode 100644
index 00000000..386f4c6d
--- /dev/null
+++ b/src/layout/components/Sidebar/SidebarItem.vue
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{
+ t("route." + item.meta.title)
+ }}
+
+
+
+
+
+
+
+
diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue
new file mode 100644
index 00000000..36f13a25
--- /dev/null
+++ b/src/layout/components/Sidebar/index.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layout/components/index.ts b/src/layout/components/index.ts
new file mode 100644
index 00000000..86e2d4ce
--- /dev/null
+++ b/src/layout/components/index.ts
@@ -0,0 +1,3 @@
+export { default as Navbar } from './Navbar.vue'
+export { default as Sidebar } from './Sidebar/index.vue'
+export { default as AppMain } from './AppMain.vue'
diff --git a/src/layout/index.vue b/src/layout/index.vue
index 11cade38..c1d3027a 100644
--- a/src/layout/index.vue
+++ b/src/layout/index.vue
@@ -1,57 +1,93 @@
-
- Header
-
- Aside
-
-
-
-
- Footer
-
-
-
+
-
\ No newline at end of file
+
diff --git a/src/layout/mixin/ResizeHandler.ts b/src/layout/mixin/ResizeHandler.ts
new file mode 100644
index 00000000..e3a0326c
--- /dev/null
+++ b/src/layout/mixin/ResizeHandler.ts
@@ -0,0 +1,63 @@
+import {userStore} from '@/store'
+import {computed, watch} from "vue";
+import { useRoute } from 'vue-router'
+const store = userStore()
+
+const {body} = document
+const WIDTH = 992 // refer to Bootstrap's responsive design
+
+
+export default function () {
+ const device = computed(() => {
+ return store.state.app.device
+ })
+
+ const sidebar = computed(() => {
+ return store.state.app.sidebar
+ })
+
+ const isMobile = () => {
+ const rect = body.getBoundingClientRect()
+ return rect.width - 1 < WIDTH
+ }
+
+ const resizeHandler = () => {
+ if (!document.hidden) {
+ store.dispatch('app/toggleDevice', isMobile() ? 'mobile' : 'desktop')
+ if (isMobile()) {
+ store.dispatch('app/closeSideBar', {withoutAnimation: true})
+ }
+ }
+ }
+
+ const resizeMounted = () => {
+ if(isMobile()){
+ store.dispatch('app/toggleDevice', 'mobile')
+ store.dispatch('app/closeSideBar', {withoutAnimation: true})
+ }
+ }
+ const addEventListenerOnResize = () => {
+ window.addEventListener('resize', resizeHandler)
+ }
+
+ const removeEventListenerResize = () => {
+ window.removeEventListener('resize', resizeHandler)
+ }
+
+
+ const currentRoute = useRoute()
+ const watchRouter = watch(() => currentRoute.name, () => {
+ if (store.state.app.device === 'mobile' && store.state.app.sidebar.opened) {
+ store.dispatch('app/closeSideBar', false)
+ }
+ })
+
+ return {
+ device,
+ sidebar,
+ resizeMounted,
+ addEventListenerOnResize,
+ removeEventListenerResize,
+ watchRouter
+ }
+}
diff --git a/src/store/index.ts b/src/store/index.ts
index 13688675..5b335b88 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -1,24 +1,25 @@
import {InjectionKey} from 'vue'
import {createStore,useStore as baseUseStore ,Store} from 'vuex'
+import {RootStateTypes} from "@store/interface";
-export interface State {
- count: number
+// Vite 使用特殊的 import.meta.glob 函数从文件系统导入多个模块
+// see https://cn.vitejs.dev/guide/features.html#glob-import
+const moduleFiles = import.meta.globEager('./modules/*.ts')
+const paths:string[]=[]
+
+for (const path in moduleFiles) {
+ paths.push(path)
}
-export const key: InjectionKey> = Symbol()
+const modules = paths.reduce((modules: { [x: string]: any }, modulePath: string) => {
+ const moduleKey = modulePath.replace(/^\.\/modules\/(.*)\.\w+$/, '$1');
+ modules[moduleKey] = moduleFiles[modulePath].default;
+ return modules;
+}, {});
-export const store = createStore({
- state() {
- return {
- count: 0
- }
- },
- mutations: {
- increment(state: { count: number }) {
- state.count++
- }
- }
-})
+export const key: InjectionKey> = Symbol()
+
+export const store = createStore({modules})
export function userStore(){
return baseUseStore(key)
diff --git a/src/store/interface.ts b/src/store/interface.ts
index 8350855b..817987a9 100644
--- a/src/store/interface.ts
+++ b/src/store/interface.ts
@@ -8,7 +8,16 @@ export interface UserState {
}
+export interface AppState {
+ device: string,
+ sidebar: {
+ opened: boolean,
+ withoutAnimation: boolean
+ }
+}
+
// 顶级类型声明
export interface RootStateTypes {
- user: UserState
+ user: UserState,
+ app:AppState
}
\ No newline at end of file
diff --git a/src/store/modules/app.ts b/src/store/modules/app.ts
new file mode 100644
index 00000000..6670c712
--- /dev/null
+++ b/src/store/modules/app.ts
@@ -0,0 +1,47 @@
+import {Module} from "vuex";
+import {RootStateTypes, AppState} from "@store/interface";
+import {Local} from "@utils/storage";
+
+const appModule: Module = {
+ namespaced: true,
+ state: {
+ device: 'desktop',
+ sidebar: {
+ opened: Local.get('sidebarStatus') ? !!+Local.get('sidebarStatus') : true,
+ withoutAnimation: false
+ }
+ },
+ mutations: {
+ TOGGLE_SIDEBAR: state => {
+ state.sidebar.opened = !state.sidebar.opened
+ state.sidebar.withoutAnimation = false
+ if (state.sidebar.opened) {
+ Local.set('sidebarStatus', 1)
+ } else {
+ Local.set('sidebarStatus', 0)
+ }
+ },
+ CLOSE_SIDEBAR: (state, withoutAnimation) => {
+ Local.set('sidebarStatus', 0)
+ state.sidebar.opened = false
+ state.sidebar.withoutAnimation = withoutAnimation
+ },
+ TOGGLE_DEVICE: (state, device) => {
+ state.device = device
+ }
+ },
+ actions: {
+ toggleSideBar({commit}) {
+ commit('TOGGLE_SIDEBAR')
+ },
+ closeSideBar({commit}, {withoutAnimation}) {
+ commit('CLOSE_SIDEBAR', withoutAnimation)
+ },
+ toggleDevice({commit}, device) {
+ commit('TOGGLE_DEVICE', device)
+ }
+ }
+}
+
+export default appModule;
+
diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts
index 4b1d280b..48cf5afe 100644
--- a/src/store/modules/user.ts
+++ b/src/store/modules/user.ts
@@ -1,8 +1,7 @@
import {Module} from "vuex";
import {UserState, RootStateTypes} from "@store/interface";
import {Local} from "@utils/storage";
-import {getUserInfo, login,logout} from "@api/login"
-
+import {getUserInfo, login, logout} from "@api/login"
const getDefaultState = () => {
return {
@@ -14,7 +13,6 @@ const getDefaultState = () => {
}
}
-
const userModule: Module = {
namespaced: true,
state: {
@@ -104,12 +102,12 @@ const userModule: Module = {
/**
* 注销
*/
- logout({commit,state}){
+ logout({commit, state}) {
return new Promise(((resolve, reject) => {
- logout().then(()=>{
+ logout().then(() => {
Local.remove('token')
commit('RESET_STATE')
- }).catch(error=>{
+ }).catch(error => {
reject(error)
})
}))
diff --git a/src/utils/validate.ts b/src/utils/validate.ts
new file mode 100644
index 00000000..e35c2faf
--- /dev/null
+++ b/src/utils/validate.ts
@@ -0,0 +1,12 @@
+/**
+ * Created by PanJiaChen on 16/11/18.
+ */
+
+/**
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal(path : string) {
+ return /^(https?:|mailto:|tel:)/.test(path)
+}
+