导航模式
@@ -124,14 +124,21 @@
-
-
diff --git a/vue/template/src/layout/component/SettingDrawer/style.scss b/vue/template/src/layout/component/SettingDrawer/style.scss
new file mode 100644
index 0000000..70eef94
--- /dev/null
+++ b/vue/template/src/layout/component/SettingDrawer/style.scss
@@ -0,0 +1,17 @@
+@import "~@/asset/style/var";
+@import "./component/checkbox/style";
+
+.drawer-container {
+ padding: 24px;
+ font-size: 14px;
+ line-height: 1.5;
+ word-wrap: break-word;
+
+ .drawer-item {
+ display: flex;
+ justify-content: space-between;
+ color: $--color-text-regular;
+ font-size: 14px;
+ padding: 12px 0;
+ }
+}
diff --git a/vue/template/src/layout/index.vue b/vue/template/src/layout/index.vue
index 093989c..5866b0c 100644
--- a/vue/template/src/layout/index.vue
+++ b/vue/template/src/layout/index.vue
@@ -1,90 +1,101 @@
+
+
+
+
+ openSettingDrawer() {
+ appMutations.showSettingDrawer(true)
+ },
-
+
diff --git a/vue/template/src/layout/mixin/decideRouterTransition.js b/vue/template/src/layout/mixin/decideRouterTransition.js
deleted file mode 100644
index e0666b7..0000000
--- a/vue/template/src/layout/mixin/decideRouterTransition.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import {getters as pageGetters, mutations as pageViewMutations} from "@/layout/store/page"
-
-export default {
- watch: {
- $route(to, from) {
- this.decideRouteTransition(to, from)
- }
- },
-
- methods: {
- //根据访问的tab页的左右顺序来确定路由动画
- decideRouteTransition(to, from) {
- const {next, prev} = pageGetters.transition
-
- let transitionName = prev
-
- //这里认为页签数量不会太多,所以为了可读性使用两次循环查找
- const fromIndex = this.visitedViews.findIndex(i => i.path === from.path)
- const toIndex = this.visitedViews.findIndex(i => i.path === to.path)
-
- //新开tab也认为顺序高于上一个tab
- if (toIndex === -1 || fromIndex < toIndex) {
- transitionName = next
- }
-
- pageViewMutations.transition({curr: transitionName})
- },
- }
-}
diff --git a/vue/template/src/layout/mixin/hamburger.js b/vue/template/src/layout/mixin/hamburger.js
deleted file mode 100644
index f798b00..0000000
--- a/vue/template/src/layout/mixin/hamburger.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import Hamburger from '@/layout/component/Hamburger'
-import {getters as appGetters} from "@/layout/store/app"
-import {getters as asideGetters} from "@/layout/store/aside"
-import {getSidebarMenus} from "@/layout/util"
-
-/**
- * 汉堡包的渲染条件混入
- */
-
-export default {
- components: {Hamburger},
-
- computed: {
- //渲染汉堡包的条件
- //①侧边栏有菜单
- //②移动端 或
- //③桌面端且汉堡包位置正确(侧边栏引入则需要是aside,反之需要是head)
- //④桌面端且是双层侧边栏导航
- //⑤桌面端且是侧边栏导航或混合导航时,未设置侧边栏自动隐藏
- renderHamburger() {
- if (getSidebarMenus().length <= 0) return false
-
- const isMobile = appGetters.isMobile,
- correctPosition =
- asideGetters.hamburgerPosition === (this.$options.name === 'navbar' ? 'head' : 'aside'),
- correctMode =
- ['aside', 'mix'].includes(appGetters.navMode) && !asideGetters.autoHide
- || appGetters.navMode === 'aside-two-part'
-
- return isMobile || correctPosition && correctMode
- }
- }
-}
diff --git a/vue/template/src/layout/mixin/menu.js b/vue/template/src/layout/mixin/menu.js
deleted file mode 100644
index a811c23..0000000
--- a/vue/template/src/layout/mixin/menu.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * 顶部菜单和侧边栏菜单的公共混入
- */
-import {mutations as tagsViewMutations} from "@/layout/store/tagsView"
-import {refreshPage} from "@/util/route"
-import {isExternal} from "@/util/validate"
-import {findComponentByTag} from "@/util/vue"
-
-export default {
- data() {
- return {
- //当前激活的菜单的fullPath
- //之所以手动维护是因为el-menu在点击后就会设置activeIndex
- activeMenu: '',
-
- //用于判断鼠标是否在弹出菜单内
- openedMenuNum: 0
- }
- },
-
- methods: {
- //点击菜单后的动作
- actionOnSelectMenu(fullPath, refreshWhenSame = true) {
- //外部链接时打开新窗口
- if (isExternal(fullPath)) {
- window.open(fullPath)
- return this.resetActiveMenu()
- }
-
- //触发的菜单路径是当前路由时,根据参数判断是否进行刷新
- if (this.$route.path === fullPath) {
- if (!refreshWhenSame) return
- tagsViewMutations.delCacheOnly(this.$route)
- this.$nextTick(() => refreshPage())
- }
- else this.$router.push(fullPath)
- },
-
- //由于侧边栏菜单数组更新后,el-menu不一定会更新(当数组中不存在单级菜单时)
- //所以手动更新el-menu的当前高亮菜单
- resetActiveMenu() {
- const menu = this.$_getElMenuInstance()
- menu && menu.updateActiveIndex(this.activeMenu)
- },
-
- //获取el-menu实例
- //目前被侧边栏和双层侧边栏的主菜单使用
- $_getElMenuInstance() {
- if (!this.$_elMenuInstance) {
- this.$_elMenuInstance = findComponentByTag(this, 'el-menu')
- }
-
- return this.$_elMenuInstance
- }
- }
-}
diff --git a/vue/template/src/layout/mixin/menuSearch.js b/vue/template/src/layout/mixin/menuSearch.js
deleted file mode 100644
index ccdf1ba..0000000
--- a/vue/template/src/layout/mixin/menuSearch.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * 侧边栏搜索框混入
- */
-import MenuSearch from '@/layout/component/Aside/component/MenuSearch'
-import {trim} from "@/util"
-import {findComponentByTag} from "@/util/vue"
-
-export default {
- components: {MenuSearch},
-
- methods: {
- $_getNavMenuInstance() {
- if (!this.$_navMenuInstance) {
- this.$_navMenuInstance = findComponentByTag(this, 'nav-menu')
- }
-
- return this.$_navMenuInstance
- },
-
- handlerSearch(v) {
- this.$_getNavMenuInstance().realSearchWord = trim(v)
- }
- }
-}
diff --git a/vue/template/src/layout/mixin/tagsViewPersistent.js b/vue/template/src/layout/mixin/tagsViewPersistent.js
index 2ddc36c..492f108 100644
--- a/vue/template/src/layout/mixin/tagsViewPersistent.js
+++ b/vue/template/src/layout/mixin/tagsViewPersistent.js
@@ -4,7 +4,7 @@
* 页签变化时写入本地存储
*/
-import {getters as tagsViewGetters, mutations as tagsViewMutations} from "@/layout/store/tagsView"
+import {tagsViewGetters, tagsViewMutations} from "el-admin-layout"
import {debounce} from "@/util"
import {getTagsView, setTagsView} from "@/util/storage"
@@ -27,7 +27,7 @@ export default {
if (!v) return setTagsView()
//启用时先存储一次(仅在mounted后,否则此时页签数据不完整)
- this._isMounted && this.persistentTagsView(this.visitedViews)
+ this._isMounted && this.persistentTagsView(tagsViewGetters.visitedViews)
this.watchVisitedViewsCallback = this.$watch('visitedViews', this.persistentTagsView)
}
diff --git a/vue/template/src/layout/mixin/tagsViewShortcut.js b/vue/template/src/layout/mixin/tagsViewShortcut.js
index f6b0a5d..358d414 100644
--- a/vue/template/src/layout/mixin/tagsViewShortcut.js
+++ b/vue/template/src/layout/mixin/tagsViewShortcut.js
@@ -4,7 +4,7 @@
* ctrl + ←,上一个页签
*/
-import {getters as tagsViewGetters} from "@/layout/store/tagsView"
+import {tagsViewGetters} from "el-admin-layout"
export default {
computed: {
@@ -28,20 +28,36 @@ export default {
methods: {
//上一个页签
gotoViewFront() {
- if (this.visitedViews.length <= 1) return
- let index = this.visitedViews.findIndex(view => view.path === this.$route.path)
+ const views = tagsViewGetters.visitedViews
+
+ if (views.length <= 1) return
+
+ let index = views.findIndex(view => view.path === this.$route.path)
+
if (index < 0) return
- if (index === 0) index = this.visitedViews.length
- return this.$router.push({path: this.visitedViews[index - 1].path})
+
+ if (index === 0) {
+ index = views.length
+ }
+
+ return this.$router.push({path: views[index - 1].path})
},
//下一个页签
gotoViewBehind() {
- if (this.visitedViews.length <= 1) return
- let index = this.visitedViews.findIndex(view => view.path === this.$route.path)
+ const views = tagsViewGetters.visitedViews
+
+ if (views.length <= 1) return
+
+ let index = views.findIndex(view => view.path === this.$route.path)
+
if (index < 0) return
- if (index + 1 > this.visitedViews.length - 1) index = -1
- return this.$router.push({path: this.visitedViews[index + 1].path})
+
+ if (index + 1 > views.length - 1) {
+ index = -1
+ }
+
+ return this.$router.push({path: views[index + 1].path})
},
//快捷键监听
diff --git a/vue/template/src/layout/store/app.js b/vue/template/src/layout/store/app.js
deleted file mode 100644
index 28a1d94..0000000
--- a/vue/template/src/layout/store/app.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import Vue from 'vue'
-import {debounce, isEmpty} from "@/util"
-import {isMobile} from "@/util/browser"
-import {createGetters, createMutations} from "@/util/observable"
-
-const state = {
- //区分pc和移动端
- isMobile: isMobile(),
-
- //设置抽屉的显隐
- //放这里的原因是navbar可能会重新渲染,从而导致抽屉的重新渲染
- showSettingDrawer: false,
-
- //当前激活的顶部菜单的fullPath
- activeRootMenu: '',
-
- //所有的树形菜单,每个元素为顶部菜单,顶部菜单的子级(如果有)为侧边栏菜单
- menus: [],
-
- //导航模式,'aside'、'aside-two-part'、'head'、'mix'
- navMode: 'mix'
-}
-
-const store = Vue.observable(state)
-
-export const getters = createGetters(store)
-
-export const mutations = {
- ...createMutations(store),
-
- menus(v) {
- sort(v)
- store.menus = v
- }
-}
-
-//菜单排序
-function sort(routes) {
- if (!Array.isArray(routes) || routes.length === 0) {
- return
- }
-
- //菜单排序值的空值处理
- const getSortValue = item => {
- const sort = deepGetSortValue(item)
- return isEmpty(sort) ? 10000 : sort
- }
-
- //获取菜单的排序值
- const deepGetSortValue = item => {
- const {children = [], meta: {hidden, sort} = {}} = item
-
- if (hidden) return null
-
- if (!isEmpty(sort)) return sort
-
- //如果只有一个子节点,那么取子节点的排序值
- if (children.length === 1) {
- return deepGetSortValue(children[0])
- }
-
- return null
- }
-
- //对根节点排序
- routes.sort((pre, next) => {
- pre = getSortValue(pre)
- next = getSortValue(next)
- if (pre < next) return -1
- if (pre === next) return 0
- return 1
- })
-
- //对每一个根节点的子级排序
- routes.forEach(route => {
- const {children} = route
- children && children.length && sort(children)
- })
-}
-
-window.addEventListener('resize', debounce(() => {
- !document.hidden && mutations.isMobile(isMobile())
-}))
diff --git a/vue/template/src/layout/store/aside.js b/vue/template/src/layout/store/aside.js
deleted file mode 100644
index b39f84f..0000000
--- a/vue/template/src/layout/store/aside.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * 侧边栏的响应式数据
- */
-import Vue from 'vue'
-import {bindThis} from "@/util"
-import {createGetters, createMutations} from "@/util/observable"
-import {getters as appGetters} from "./app"
-
-const state = {
- //抽屉模式时的显隐
- show: false,
-
- //主题,light 或 dark
- theme: 'light',
-
- //手风琴效果
- uniqueOpen: true,
-
- //是否折叠
- collapse: false,
-
- //折叠时显示上级
- showParentOnCollapse: false,
-
- //自动隐藏
- autoHide: false,
-
- //汉堡包的位置,aside 或 head
- hamburgerPosition: 'aside',
-
- //是否显示搜索框
- search: true
-}
-
-const store = Vue.observable(state)
-
-export const getters = createGetters(store)
-
-export const mutations = bindThis({
- ...createMutations(store),
-
- /*移动端或设置了侧边栏自动隐藏时打开关闭抽屉,否则展开折叠*/
- open() {
- if (appGetters.isMobile || store.autoHide) {
- store.show = true
- }
- else store.collapse = false
- },
- close() {
- if (appGetters.isMobile || store.autoHide) {
- store.show = false
- }
- else store.collapse = true
- },
- //切换侧边栏的状态
- switch(action) {
- switch (action) {
- case 'open':
- return this.open()
- case 'close':
- return this.close()
- default :
- let open = true
- if (appGetters.isMobile) {
- open = !store.show
- }
- else open = store.collapse
- return open ? this.open() : this.close()
- }
- }
-})
diff --git a/vue/template/src/layout/store/navbar.js b/vue/template/src/layout/store/navbar.js
deleted file mode 100644
index c804ee4..0000000
--- a/vue/template/src/layout/store/navbar.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import Vue from 'vue'
-import {createGetters, createMutations} from "@/util/observable"
-
-const state = {
- //主题,light 或 dark
- theme: 'light',
-}
-
-const store = Vue.observable(state)
-
-export const getters = createGetters(store)
-
-export const mutations = createMutations(store)
diff --git a/vue/template/src/layout/store/page.js b/vue/template/src/layout/store/page.js
deleted file mode 100644
index 97a61d8..0000000
--- a/vue/template/src/layout/store/page.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 路由页面的响应式数据
- */
-import Vue from 'vue'
-import {bindThis} from "@/util"
-import {createGetters, createMutations} from "@/util/observable"
-
-const state = {
- //路由过渡动画
- transition: {
- //当未启用多页签时的路由动画
- default: 'el-fade-in-linear',
- //要访问的tab顺序高于上一个访问的tab时的路由动画
- next: 'left-out',
- //要访问的tab顺序不高于上一个访问的tab时的路由动画
- prev: 'right-out',
- //当前使用的路由动画
- curr: 'el-fade-in-linear'
- },
-
- /*iframe的控制*/
- showIframe: false,
- currentIframe: '',
- iframeList: [],
-
- //是否显示侧边栏或顶部导航栏的logo
- showLogo: true,
- //分层结构,上下('top-bottom')、左右('left-right')
- position: 'left-right',
- //是否显示页头
- showPageHeader: true,
- //是否显示返回顶部按钮
- showBackToTop: true
-}
-
-const store = Vue.observable(state)
-
-export const getters = createGetters(store)
-
-export const mutations = bindThis({
- ...createMutations(store),
-
- //修改transition时使用Object.assign
- transition(obj) {
- Object.assign(store.transition, obj)
- },
-
- addIframe(src) {
- !store.iframeList.includes(src) && store.iframeList.push(src)
- },
- delIframe(src) {
- const index = store.iframeList.findIndex(i => i === src)
- index > -1 && store.iframeList.splice(index, 1)
- },
- openIframe({src}) {
- store.showIframe = true
- store.currentIframe = src
- this.addIframe(src)
- },
- closeIframe({src, del}) {
- store.showIframe = false
- store.currentIframe = ''
- del && this.delIframe(src)
- }
-})
diff --git a/vue/template/src/layout/store/tagsView.js b/vue/template/src/layout/store/tagsView.js
deleted file mode 100644
index de31a2d..0000000
--- a/vue/template/src/layout/store/tagsView.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/**
- * 多页签的响应式数据
- */
-import Vue from 'vue'
-import {getters as pageGetters, mutations as pageMutations} from "@/layout/store/page"
-import {getRouterViewCacheKey} from "@/layout/util"
-import {bindThis} from "@/util"
-import {createGetters, createMutations} from "@/util/observable"
-
-const state = {
- //是否启用
- enabled: true,
- //是否启用快捷键切换功能
- shortcut: true,
- //是否将页签持久化到sessionStorage
- persistent: true,
-
- //显示的页签,vue-router的routeConfig对象数组
- visitedViews: [],
-
- //缓存的页签,用于:include
- cachedViews: []
-}
-
-const store = Vue.observable(state)
-
-export const getters = createGetters(store)
-
-export const mutations = bindThis({
- ...createMutations(store),
-
- /**
- * 多页签的启用/停用
- * 停用时会移除所有缓存,并且重置路由过渡动画
- * @param v 启用为true,停用为false
- */
- enabled(v) {
- store.enabled = v
-
- if (!v) {
- pageMutations.transition({curr: pageGetters.transition.default})
- this.delAllTagAndCache()
- }
- },
-
- /**
- * 在页签栏上添加一个页签,path已存在的不会重复添加,调用时需要保证meta.title有值
- * @param view {routeConfig}
- */
- addTagOnly(view) {
- const {name, path, fullPath, meta} = view
-
- if (store.visitedViews.some(v => v.path === path)) {
- return
- }
-
- store.visitedViews.push({name, path, fullPath, meta: {...meta}})
- },
-
- /**
- * 将传入的routeConfig加入的缓存中
- * 以下调用无效:设置了不缓存、是iframe页、未设置唯一标识、已缓存
- * @param view {routeConfig}
- */
- addCacheOnly(view) {
- const {noCache, iframe, usePathKey, useFullPathKey} = view.meta || {}
-
- if (noCache || iframe || !view.name && !usePathKey && !useFullPathKey) {
- return
- }
-
- const key = getRouterViewCacheKey(view)
-
- if (store.cachedViews.includes(key)) {
- return
- }
-
- store.cachedViews.push(key)
- },
-
- /**
- * 同时调用{@link #addTagOnly}、{@link #addCacheOnly}
- * @param view {routeConfig}
- */
- addTagAndCache(view) {
- this.addTagOnly(view)
- this.addCacheOnly(view)
- },
-
- /**
- * 根据path从页签栏中移除一个页签
- * @param view {path},routeConfig
- */
- delTagOnly(view) {
- const index = store.visitedViews.findIndex(i => i.path === view.path)
- index > -1 && store.visitedViews.splice(index, 1)
- },
-
- /**
- * 删除对应的缓存
- * @param view {routeConfig}
- */
- delCacheOnly(view) {
- const key = getRouterViewCacheKey(view)
- const index = store.cachedViews.indexOf(key)
- index > -1 && store.cachedViews.splice(index, 1)
- },
-
- /**
- * 同时调用{@link #delTagOnly}、{@link #delCacheOnly},移除iframe页
- * @param view {routeConfig}
- */
- delTagAndCache(view) {
- this.delTagOnly(view)
- this.delCacheOnly(view)
-
- const iframe = view.meta && view.meta.iframe
- iframe && pageMutations.delIframe(iframe)
- },
-
- /**
- * 从页签栏上移除除了routeConfig以外的所有非固定页签
- * 并且从中移除除了routeConfig以外的所有缓存
- * @param view {routeConfig}
- */
- delOtherTagAndCache(view) {
- const visitedViews = store.visitedViews.filter(v => v.meta.affix || v.path === view.path)
- const key = store.cachedViews.find(key => key === getRouterViewCacheKey(view))
-
- store.visitedViews = visitedViews
- store.cachedViews = key ? [key] : []
- },
-
- /**
- * 从页签栏上移除所有非固定页签,并且移除的所有缓存
- */
- delAllTagAndCache() {
- store.visitedViews = store.visitedViews.filter(tag => tag.meta && tag.meta.affix)
- store.cachedViews = []
- }
-})
diff --git a/vue/template/src/layout/style.scss b/vue/template/src/layout/style.scss
new file mode 100644
index 0000000..00f200e
--- /dev/null
+++ b/vue/template/src/layout/style.scss
@@ -0,0 +1,6 @@
+@import "~el-admin-layout/src/style";
+
+@import "./component/Footer/style";
+@import "./component/SettingDrawer/style";
+
+
diff --git a/vue/template/src/layout/util.js b/vue/template/src/layout/util.js
deleted file mode 100644
index e50283a..0000000
--- a/vue/template/src/layout/util.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import {getters as appGetters} from "@/layout/store/app"
-
-//获取路由页面缓存所需的key
-export function getRouterViewCacheKey({name, path, fullPath, meta = {}}) {
- const {usePathKey, useFullPathKey} = meta
- return usePathKey ? path : useFullPathKey ? fullPath : name
-}
-
-//获取侧边栏的菜单,如果是双层侧边栏导航时,获取的是子菜单
-export function getSidebarMenus() {
- const menus = appGetters.menus
-
- if (!Array.isArray(menus)) {
- return []
- }
-
- //移动端时,侧边栏只会按侧边栏导航模式渲染
- if (appGetters.isMobile) {
- return menus
- }
-
- switch (appGetters.navMode) {
- case 'aside':
- return menus
- case 'head':
- return []
- case 'aside-two-part':
- case 'mix':
- const root = menus.find(i => i.path === appGetters.activeRootMenu)
- return root ? root.children || [] : []
- default:
- return []
- }
-}
-
-//根据路由获取当前激活的菜单
-export function getActiveMenuByRoute({path, meta}) {
- return meta.activeMenu || path
-}
diff --git a/vue/template/src/main.js b/vue/template/src/main.js
index 815a2b6..921f6a8 100644
--- a/vue/template/src/main.js
+++ b/vue/template/src/main.js
@@ -6,11 +6,9 @@ import App from '@/App'
import store from '@/store'
import router from '@/router'
import '@/asset/icon'
-import filters from './filter'
Vue.use(Element)
Vue.use(ElementPersonal)
-Vue.use(filters)
Vue.config.productionTip = false
diff --git a/vue/template/src/router/guardian/avoidReuse.js b/vue/template/src/router/guardian/avoidReuse.js
index d7c6c67..b87e2bd 100644
--- a/vue/template/src/router/guardian/avoidReuse.js
+++ b/vue/template/src/router/guardian/avoidReuse.js
@@ -16,7 +16,7 @@ export default function (router) {
}
window.addEventListener('unhandledrejection', event => {
- if (event.reason.stack.startsWith('Error: Redirected when going from')) {
+ if (event.reason.stack && event.reason.stack.startsWith('Error: Redirected when going from')) {
event.preventDefault()
}
})
diff --git a/vue/template/src/router/guardian/iframe.js b/vue/template/src/router/guardian/iframe.js
index 0bacebd..13df8a6 100644
--- a/vue/template/src/router/guardian/iframe.js
+++ b/vue/template/src/router/guardian/iframe.js
@@ -1,4 +1,4 @@
-import {mutations as pageMutations} from "@/layout/store/page"
+import {pageMutations} from "el-admin-layout"
const beforeEach = (to, from, next) => {
//从iframe页面离开时,判断是否需要删除iframe
diff --git a/vue/template/src/router/util.js b/vue/template/src/router/util.js
index d81b344..6024fe9 100644
--- a/vue/template/src/router/util.js
+++ b/vue/template/src/router/util.js
@@ -4,17 +4,6 @@ import Page500 from '@/view/_app/500'
import {isEmpty} from "@/util"
import {isExternal, isString} from "@/util/validate"
-//json字符串转路由配置
-export function str2routeConfig(str) {
- const parseOpt = (key, value) => {
- if (key === 'dynamicTitle' && isString(value)) {
- return isEmpty(value) ? undefined : eval(`(${value})`)
- }
- return value
- }
- return JSON.parse(str, parseOpt)
-}
-
//根据json数组生成路由
export function generateRoutes(jsonTree) {
//将深度为2的节点合并为由其最末子节点组成的数组
diff --git a/vue/template/src/store/module/resource.js b/vue/template/src/store/module/resource.js
index 8f5aa1d..0b5e631 100644
--- a/vue/template/src/store/module/resource.js
+++ b/vue/template/src/store/module/resource.js
@@ -1,5 +1,5 @@
import path from 'path'
-import {mutations as appMutations} from "@/layout/store/app"
+import {appMutations} from "el-admin-layout"
import {addDynamicRoutes} from '@/router'
import {getDynamicRoutes} from '@/router/define'
import {metaExtend} from "@/router/util"
diff --git a/vue/template/src/store/module/user.js b/vue/template/src/store/module/user.js
index 0868184..4551931 100644
--- a/vue/template/src/store/module/user.js
+++ b/vue/template/src/store/module/user.js
@@ -1,8 +1,7 @@
import {createMutations} from "@/store/util"
import {emptyOrDefault} from "@/util"
import {getUser, setUser} from "@/util/storage"
-import {mutations as tagsViewMutations} from "@/layout/store/tagsView"
-import {elError} from "@/util/message"
+import {tagsViewMutations} from "el-admin-layout"
//刷新时从本地存储中获取用户信息
const user = getUser()
diff --git a/vue/template/src/util/auth.js b/vue/template/src/util/auth.js
index c317257..800a4c6 100644
--- a/vue/template/src/util/auth.js
+++ b/vue/template/src/util/auth.js
@@ -1,5 +1,4 @@
import store from '@/store'
-import {uppercaseFirst} from "@/filter"
import {isEmpty} from "@/util"
/**
@@ -30,24 +29,6 @@ export function auth(path) {
return true
}
-/**
- * what i can
- * 批量生成canXxx的计算属性
- *
- * @param apiMap {object}
- * @return {object}
- */
-export function wic(apiMap) {
- const attrs = {}
-
- Object.entries(apiMap).forEach(([key, value]) => {
- const attrKey = `can${uppercaseFirst(key)}`
- attrs[attrKey] = () => auth(value.url)
- })
-
- return attrs
-}
-
/**
* 判断是否已登录,已登录则返回true
*
diff --git a/vue/template/src/util/browser.js b/vue/template/src/util/browser.js
deleted file mode 100644
index f23c986..0000000
--- a/vue/template/src/util/browser.js
+++ /dev/null
@@ -1,223 +0,0 @@
-import cssVar from '@/asset/style/var.scss'
-
-const maxMobileWidth = parseFloat(cssVar.maxMobileWidth)
-
-/**
- * 根据body宽度判断是否为移动端,是则返回true
- *
- * @return {boolean}
- */
-export function isMobile() {
- const rect = document.body.getBoundingClientRect()
- return rect.width <= maxMobileWidth
-}
-
-/**
- * 判断是否为dom元素,是则返回true
- *
- * @param obj
- * @return {boolean}
- */
-export function isDom(obj) {
- return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string'
-}
-
-/**
- * 获取元素的内宽(扣除左右padding后)
- *
- * @param el {HTMLElement}
- * @return {number}
- */
-export function getElementInnerWidth(el) {
- if (!el) return 0
-
- const style = window.getComputedStyle(el)
-
- return parseFloat(style.width) - (parseFloat(style.paddingLeft) + parseFloat(style.paddingRight))
-}
-
-/**
- * 获取元素的真实高度
- *
- * @param el {HTMLElement}
- * @param style 元素的style键值对
- * @return {number}
- */
-export function getElementHeight(el, style) {
- if (!el) return 0
-
- const node = el.cloneNode(true)
- node.style.opacity = '0'
-
- if (style) {
- Object.keys(style).forEach(item => {
- node.style[item] = style[item]
- })
- }
-
- const id = 'temp-id-' + Date.now()
- node.setAttribute('id', id)
- document.body.append(node)
-
- const height = node.offsetHeight
- document.body.removeChild(node)
-
- return height
-}
-
-/**
- * 获取元素距离其容器的顶部距离
- *
- * @param el {HTMLElement} 目标元素
- * @param container {HTMLElement|Window} 容器元素
- * @return {number}
- */
-export function getTopDistance(el, container) {
- if (!el) return 0
-
- if (!el.getClientRects().length) {
- return 0
- }
-
- const rect = el.getBoundingClientRect()
-
- if (rect.width || rect.height) {
- if (container === window) {
- container = el.ownerDocument.documentElement
- return rect.top - container.clientTop
- }
- return rect.top - container.getBoundingClientRect().top
- }
-
- return rect.top
-}
-
-/**
- * 加载js或css
- *
- * @param url {string} 资源地址
- * @param type {string} 'js'或'css'
- * @return {Promise} 加载成功返回url(若资源此前已加载,返回undefined)
- */
-export function loadExternalResource(url, type = 'js') {
- return new Promise((resolve, reject) => {
- let tag
-
- if (type === "css") {
- const links = Array.from(document.getElementsByTagName('link'))
- if (links.some(link => link.getAttribute('href') === url)) {
- return resolve()
- }
-
- tag = document.createElement("link")
- tag.rel = "stylesheet"
- tag.href = url
- }
- else if (type === "js") {
- const scripts = Array.from(document.getElementsByTagName('script'))
- if (scripts.some(script => script.getAttribute('src') === url)) {
- return resolve()
- }
-
- tag = document.createElement("script")
- tag.src = url
- }
-
- if (tag) {
- tag.onload = () => resolve(url)
- tag.onerror = () => reject(url)
- document.head.appendChild(tag)
- }
- else reject(`没有这个东东,url:${url},type:${type}`)
- })
-}
-
-/**
- * 将dom按最小距离垂直地滚动至视窗内
- * 比如dom在视窗下,那么会滚动到视窗底部
- *
- * @param child {HTMLElement} 需要滚动的dom
- * @param parent {HTMLElement|Window} 包含child的容器
- */
-export function scrollIntoViewVertically(child, parent = window) {
- const {scrollTop, scrollHeight, offsetHeight: containerHeight} = parent
-
- //当菜单高度不足以滚动时跳过
- if (scrollHeight <= containerHeight) return
-
- const elHeight = child.offsetHeight, between = getTopDistance(child, parent)
-
- //计算需要滚动的距离,undefined说明不需要滚动
- let distance
-
- if (between < 0) distance = between
- else if (between + elHeight > containerHeight) {
- distance = between + elHeight - containerHeight
- }
-
- if (distance !== undefined) {
- parent.scrollTo({top: scrollTop + distance, behavior: 'smooth'})
- }
-}
-
-/**
- * 平滑滚动至指定的位置
- *
- * @param el {Window|HTMLElement|string|function} 滚动容器,或可用于querySelector的字符串,或一个返回DOM的函数
- * @param position {number} 滚动的目的地
- * @param options 配置项
- * @param options.callback {function} 滚动完成的回调
- * @param options.duration {number} 滚动耗时
- * @param options.direction {string} 滚动方向,top滚动至距元素顶部distance的位置,left滚动至距元素左边distance的位置
- */
-export function scrollTo(el, position, options) {
- const {callback, duration = 300, direction = 'top'} = options || {}
-
- if (typeof el === 'string') {
- el = document.querySelector(el)
- }
- else if (typeof el === 'function') {
- el = el()
- }
-
- if (!isDom(el)) return
-
- const toTop = direction === 'top'
- const elPosition = getScroll(el, toTop)
- const scrollFunc = (el => {
- if (el === window) {
- return toTop
- ? y => el.scrollTo(window.pageXOffset, window.pageYOffset + y)
- : x => el.scrollTo(window.pageXOffset + x, window.pageYOffset)
- }
- return toTop
- ? y => el.scrollTop += y
- : x => el.scrollLeft += x
- })(el)
-
- let times = duration / 16, distance = (position - elPosition) / (times + 1)
-
- const frameFunc = () => {
- if (times > 0) {
- scrollFunc(distance)
- times--
- return window.requestAnimationFrame(frameFunc)
- }
- typeof callback === 'function' && callback()
- }
-
- return window.requestAnimationFrame(frameFunc)
-}
-
-/**
- * 获取元素的滚动距离
- *
- * @param el {Window|HTMLElement}
- * @param top {boolean} 是否获取垂直的滚动距离
- * @return {number}
- */
-export function getScroll(el, top) {
- return el === window
- ? el[top ? 'pageYOffset' : 'pageXOffset']
- : el[top ? 'scrollTop' : 'scrollLeft']
-}
diff --git a/vue/template/src/util/element-ui/elForm.js b/vue/template/src/util/element-ui/elForm.js
deleted file mode 100644
index e69de29..0000000
diff --git a/vue/template/src/util/element-ui/elMenu.js b/vue/template/src/util/element-ui/elMenu.js
deleted file mode 100644
index 29eaa6e..0000000
--- a/vue/template/src/util/element-ui/elMenu.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import {scrollIntoViewVertically} from "@/util/browser"
-
-/**
- * 将当前激活的菜单移动到视窗中(仅限垂直菜单)
- *
- * @param menu el-menu实例
- */
-export function moveToActiveMenuVertically(menu) {
- if (!menu) return
-
- const cur = menu.activeIndex
- if (!cur) return
-
- const curInstance = menu.items[cur]
- if (!curInstance) return
-
- let el = curInstance.$el
-
- //当侧边栏折叠时,需要滚动至可视区域的元素是激活菜单的最顶层父节点
- if (menu.collapse) {
- let rootParent = curInstance
- while (rootParent.$parent.$options.componentName !== 'ElMenu') {
- rootParent = rootParent.$parent
- }
- el = rootParent.$el
- }
-
- /*
- * 这里考虑了菜单展开时的200ms动画时间
- * 为什么不分情况讨论?比如当subMenu已经是展开状态时,无需延时滚动
- * 但这种情况无法判断,因为这时menu.openedMenus已经包含了subMenu,无论subMenu之前是否展开
- * 所以统一延时300ms
- * */
- window.setTimeout(() => scrollIntoViewVertically(el, menu.$el), 300)
-}
diff --git a/vue/template/src/util/element-ui/elTree.js b/vue/template/src/util/element-ui/elTree.js
deleted file mode 100644
index d43f7dc..0000000
--- a/vue/template/src/util/element-ui/elTree.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * el-tree展开折叠控制
- *
- * @param ref el-tree实例
- * @param action 'expand' | 'collapse'
- * @param level 展开的节点最大深度,为0时匹配全部节点
- * @param func 自定义展开的函数,传入一个node,返回boolean,优先使用
- */
-export function expandControl(ref, action = 'expand', level = 1, func) {
- const handler = function () {
- if (typeof func === 'function') {
- return node => func(node)
- }
-
- const expand = action === 'expand'
- const forAll = level === 0
-
- return node => node.expanded = forAll || node.level <= level ? expand : !expand
- }()
-
- ref.store._getAllNodes().forEach(handler)
-}
diff --git a/vue/template/src/util/index.js b/vue/template/src/util/index.js
index 56773e6..2034d42 100644
--- a/vue/template/src/util/index.js
+++ b/vue/template/src/util/index.js
@@ -1,12 +1,6 @@
-/**
- * 判断是否为空值,undefined、null、'' 都视为空值
- *
- * @param str 不定参数
- * @return {boolean} 若为空值,返回true,否则返回false
- */
-export function isEmpty(...str) {
- return str.some(i => i === undefined || i === null || i === '')
-}
+import {isEmpty, getInitialValue, debounce, deepClone} from "el-admin-layout/src/util"
+
+export {isEmpty, getInitialValue, debounce, deepClone}
/**
* 当传入空值时,返回默认值
@@ -33,37 +27,6 @@ export function replaceAll(str, substr, replacement) {
return str.replace(new RegExp(substr, 'gm'), replacement)
}
-/**
- * 根据传入值的类型,返回基础起始值
- *
- * @param v
- * @return {boolean|{}|string|*[]|number|null}
- */
-export function getInitialValue(v) {
- if (v === undefined || v === null) return null
- if (typeof v === 'string') return ''
- if (typeof v === 'boolean') return false
- if (typeof v === 'number') return 0
- if (typeof v === 'object') return {}
- if (Array.isArray(v)) return []
-}
-
-/**
- * 简单重置对象属性,遇到对象时会递归重置
- * 重置方法使用{@link #getInitialValue}
- *
- * @param obj 需要重置的对象
- */
-export function resetObj(obj) {
- if (isEmpty(obj)) return
- Object.keys(obj).forEach(key => {
- if (obj[key] !== null && typeof obj[key] === 'object') {
- resetObj(obj[key])
- }
- else obj[key] = getInitialValue(obj[key])
- })
-}
-
/**
* 将source合并到target中
* 仅对target中存在的键进行合并
@@ -99,171 +62,3 @@ export function mergeObj(target, source) {
target[key] = source[key]
}
}
-
-/**
- * 日期格式化
- *
- * @param fmt {*|string} 格式,y(+..y)-年、M(+M)-月、d(+d)-天、H(+H)-时、m(+m)-分、s(+s)-秒、S-毫秒
- * @param date {Date} 可选,被格式化的日期
- * @return {string} 格式化后的日期字符串
- */
-export function timeFormat(fmt, date = new Date()) {
- if (isEmpty(fmt)) fmt = 'yyyy-MM-dd HH:mm:ss'
-
- const o = {
- "M+": date.getMonth() + 1, //月份
- "d+": date.getDate(), //日
- "H+": date.getHours(), //小时
- "m+": date.getMinutes(), //分
- "s+": date.getSeconds(), //秒
- "S": date.getMilliseconds() //毫秒
- }
-
- if (/(y+)/.test(fmt)) {
- const replace = (date.getFullYear() + "").substring(4 - RegExp.$1.length)
- fmt = fmt.replace(RegExp.$1, [...replace].join(''))
- }
-
- for (const k in o) {
- if (new RegExp(`(${k})`).test(fmt)) {
- const firstMatch = RegExp.$1
- const replace = firstMatch.length === 1 ? o[k] + "" : ("00" + o[k]).substring(("" + o[k]).length)
- fmt = fmt.replace(firstMatch, [...replace].join(''))
- }
- }
-
- return fmt
-}
-
-/**
- * 防抖
- *
- * @param func {function} 原函数
- * @param wait {number} 防抖间隔,单位毫秒
- * @param immediate {boolean} 是否立即执行一次
- * @return {function} 经过防抖包装后的函数
- */
-export function debounce(func, wait = 100, immediate = false) {
- let timeout, args, context, timestamp, result
-
- const later = function () {
- // 据上一次触发时间间隔
- const last = new Date().getTime() - timestamp
-
- // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
- if (last < wait && last > 0) {
- timeout = window.setTimeout(later, wait - last)
- }
- else {
- timeout = null
- // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
- if (!immediate) {
- result = func.apply(context, args)
- if (!timeout) context = args = null
- }
- }
- }
-
- return function () {
- context = this
- args = arguments
- timestamp = new Date().getTime()
- const callNow = immediate && !timeout
- // 如果延时不存在,重新设定延时
- if (!timeout) timeout = window.setTimeout(later, wait)
- if (callNow) {
- result = func.apply(context, args)
- context = args = null
- }
-
- return result
- }
-}
-
-export function throttle(func, delay = 100) {
- let timeoutID
- let lastExec = 0
-
- function wrapper() {
- const self = this
- const elapsed = Date.now() - lastExec
- const args = arguments
-
- function exec() {
- lastExec = Date.now()
- func.apply(self, args)
- }
-
- window.clearTimeout(timeoutID)
-
- if (elapsed > delay) exec()
- else timeoutID = window.setTimeout(exec, delay - elapsed)
- }
-
- return wrapper
-}
-
-/**
- * 循环等待成功事件
- *
- * @param success {function} 返回true时说明成功
- * @param callback {function} 成功后的回调
- * @param interval {number} 循环间隔,毫秒
- * @param maxTryTime {number} 最大循环次数,超出reject,小于1视为Infinity
- * @return {Promise}
- */
-export function waitUntilSuccess(success, callback, interval = 1000, maxTryTime = 0) {
- return new Promise((resolve, reject) => {
- let fun, count = 0
-
- const check = () => {
- if (success()) {
- window.clearInterval(fun)
- typeof callback === 'function' && callback()
- return resolve()
- }
- if (maxTryTime >= 1 && ++count >= maxTryTime) {
- return reject()
- }
- }
-
- if (success()) return check()
-
- fun = window.setInterval(check, interval)
- })
-}
-
-//将传入对象的所有函数的this绑定为其自身
-export function bindThis(obj, root = obj) {
- if (!obj || typeof obj !== 'object') return
-
- Object.entries(obj).forEach(([k, v]) => {
- if (typeof v === 'function') {
- obj[k] = v.bind(root)
- }
- bindThis(v, root)
- })
-
- return obj
-}
-
-export function deepClone(source) {
- if (source === null || typeof source !== 'object' || source instanceof Promise) {
- return source
- }
-
- if (Array.isArray(source)) {
- return source.map(i => deepClone(i))
- }
- else {
- return Object.keys(source).reduce((obj, key) => {
- obj[key] = deepClone(source[key])
- return obj
- }, {})
- }
-}
-
-//有空值判断的trim
-export function trim(str) {
- return isEmpty(str) ? str : str.trim()
-}
diff --git a/vue/template/src/util/message.js b/vue/template/src/util/message.js
index 39285cc..d4c5df4 100644
--- a/vue/template/src/util/message.js
+++ b/vue/template/src/util/message.js
@@ -1,10 +1,5 @@
import Message from '@ele/component/Message'
import {MessageBox} from 'element-ui'
-import {isEmpty} from "@/util"
-
-export function elError(msg = '操作失败') {
- Message.error(msg)
-}
export function elSuccess(message = '操作成功') {
Message.success({
@@ -13,14 +8,6 @@ export function elSuccess(message = '操作成功') {
})
}
-export function elAlert(msg, callback = () => ({})) {
- return MessageBox.alert(msg, {
- type: 'warning',
- cancelButtonClass: 'is-plain',
- callback
- })
-}
-
export function elConfirm(msg = '确认进行该操作?', ignoreReject = true) {
const promise = MessageBox.confirm(msg, {
type: 'warning',
@@ -33,20 +20,3 @@ export function elConfirm(msg = '确认进行该操作?', ignoreReject = true)
return promise
}
-
-export function elPrompt(msg) {
- return new Promise(resolve => {
- MessageBox.prompt(msg, {
- type: 'warning',
- cancelButtonClass: 'is-plain',
- inputType: 'textarea',
- inputValidator: str => {
- if (isEmpty(str)) return '请输入内容'
- if (str.length > 200) return '长度最多200'
- return true
- }
- })
- .then(({value}) => resolve(value))
- .catch(() => ({}))
- })
-}
diff --git a/vue/template/src/util/observable.js b/vue/template/src/util/observable.js
deleted file mode 100644
index 1f133bb..0000000
--- a/vue/template/src/util/observable.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import {getInitialValue} from "@/util"
-
-//为Vue.observer返回的对象设置getter
-export function createGetters(store) {
- const getters = Object.create({})
- Object.defineProperties(
- getters,
- Object.keys(store).reduce((obj, key) => {
- obj[key] = {
- enumerable: true,
- get() {
- return store[key]
- }
- }
- return obj
- }, {})
- )
- return getters
-}
-
-//设置mutation
-export function createMutations(store, all = false) {
- const keys = Object.keys(store)
- const obj = {}
- keys.forEach(key => {
- obj[key] = v => store[key] = v
- })
- if (all) {
- obj['$all'] = v => {
- keys.forEach(key => {
- store[key] = v && v[key] || getInitialValue(store[key])
- })
- }
- }
- return obj
-}
diff --git a/vue/template/src/util/route.js b/vue/template/src/util/route.js
deleted file mode 100644
index 4e94bba..0000000
--- a/vue/template/src/util/route.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * 路由控制工具类
- */
-
-import {isEmpty} from "@/util"
-import {isString} from "@/util/validate"
-import router from '@/router'
-import {mutations as tagsViewMutations} from "@/layout/store/tagsView"
-
-/**
- * 路由刷新
- *
- * @param route {string|route} 需要刷新的路由,不传时为当前路由,如果是字符串时请确保以'/'开头
- * @param replace {boolean} 是否使用replace进行跳转
- * @return {Promise} 返回vue-router跳转的结果
- */
-export function refreshPage(route = router.currentRoute, replace = true) {
- const target = `/redirect${isString(route) ? route : route.fullPath}`
- return router[replace ? 'replace' : 'push'](target)
-}
-
-/**
- * 关闭当前页,如果传入next则跳转到next页面
- *
- * @param next {string|route} 跳转的目标页面,作为第一个参数传入vue-router.replace
- * @return {undefined|Promise} 仅在next有值时,返回vue-router.replace的结果
- */
-export function closeCurrentPage(next) {
- tagsViewMutations.delTagAndCache(router.currentRoute)
- if (!isEmpty(next)) {
- return router.replace(next)
- }
-}
diff --git a/vue/template/src/util/storage.js b/vue/template/src/util/storage.js
index 7475c05..e74758d 100644
--- a/vue/template/src/util/storage.js
+++ b/vue/template/src/util/storage.js
@@ -39,16 +39,6 @@ export function set(key, obj, storage = window.sessionStorage, useZip = defaultU
storage.setItem(`${keyPrefix}${key}`, item)
}
-/**
- * 判断本地存储中是否存在指定键名
- * @param key {string} 键名,自动加上统一前缀
- * @param storage {Storage} window.sessionStorage或window.localStorage
- * @return {boolean} 存在则返回true
- */
-export function exist(key, storage = window.sessionStorage) {
- return !isEmpty(storage.getItem(`${keyPrefix}${key}`))
-}
-
/**
* 根据指定键名,移除本地存储对应项
* @param key {string} 键名,自动加上统一前缀
diff --git a/vue/template/src/util/tree.js b/vue/template/src/util/tree.js
index 2cd0d40..29e0797 100644
--- a/vue/template/src/util/tree.js
+++ b/vue/template/src/util/tree.js
@@ -1,127 +1,3 @@
-import {deepClone} from "@/util"
-
-const DEFAULT_PROPS = {
- id: 'id',
- pid: 'pid',
- children: 'children',
- rootPredicate: 0,
- leafHasChildren: false
-}
-
-/**
- * 列表转树形结构
- *
- * @param list {array}
- * @param props 树的配置项
- * @param props.id {string} 节点的id属性名称
- * @param props.pid {string} 节点的父级id属性名称
- * @param props.children {string} 节点的子级节点属性名称
- * @param props.rootPredicate {*|function} 根节点的判定方法,传入函数时参数为节点对象
- * @param props.leafHasChildren {boolean} 叶子节点是否能有children属性
- * @return {array}
- */
-export function createTree(list, props = {}) {
- if (!list || list.length <= 0) return []
-
- const {
- id = DEFAULT_PROPS.id,
- pid = DEFAULT_PROPS.pid,
- children = DEFAULT_PROPS.children,
- rootPredicate = DEFAULT_PROPS.rootPredicate,
- leafHasChildren = DEFAULT_PROPS.leafHasChildren
- } = props
-
- const info = {}
-
- list.forEach(i => {
- info[i[id]] = i
- if (leafHasChildren) i[children] = []
- })
-
- const predicate = (() => {
- return typeof rootPredicate === 'function'
- ? rootPredicate
- : key => key === rootPredicate
- })()
-
- return list.filter(node => {
- const key = node[pid]
- const parent = info[key]
- if (parent) {
- if (!parent[children]) parent[children] = []
- parent[children].push(node)
- }
- return predicate(key, node)
- })
-}
-
-/**
- * 完全树full,拿到某些带value的节点数组limit,获得裁剪后的树
- * 只用于裁剪客户和供应商的行政区域树
- *
- * @param full {array}
- * @param limit {array}
- */
-export function createLimitTree(full, limit) {
- const map = limit.reduce((m, n) => {
- m[n.id] = n.value
- return m
- }, {})
-
- full = deepClone(full)
-
- const result = shakeTree(full, node => {
- const value = map[node.id]
- if (value !== undefined) {
- node.value = value
- return true
- }
- return false
- })
-
- result.forEach(i => calc(i))
-
- return result
-}
-
-/**
- * createLimitTree的另一版本
- *
- * @param fullMap 完全树的节点map
- * @param limit {array}
- */
-export function createLimitTreeByMap(fullMap, limit) {
- const resultNodes = {}
-
- //从该节点往上查找父节点
- function findParent(node) {
- //如果该节点已存在于结果集中,说明包含该节点的上级分支也全部存在,所以跳过
- if (resultNodes[node.id]) return
-
- //使用full中的数据,仅保留node的value
- const fullNode = fullMap[node.id]
- if (!fullNode) return
- resultNodes[fullNode.id] = {...node, ...fullNode}
-
- //查找父节点
- const parent = fullMap[fullNode.pid]
- if (!parent) return
-
- return findParent(parent)
- }
-
- for (const node of limit) {
- if (!fullMap[node.id]) continue
- findParent(node)
- }
-
- const result = createTree(Object.values(resultNodes), {rootPredicate: '0'})
-
- result.forEach(i => calc(i))
-
- return result
-}
-
/**
* 根据判断函数裁剪树,当节点不满足predicate且无下级节点时将被裁剪
* 此方法会改变原数组的children属性!
@@ -144,84 +20,3 @@ export function shakeTree(tree, predicate = () => true, childrenKey = 'children'
return predicate(data) || children && children.length > 0
})
}
-
-/**
- * 自底向上计算每个节点的value
- *
- * @param node
- * @param valueKey {string}
- * @param childrenKey {string}
- * @return {number}
- */
-function calc(node, valueKey = 'value', childrenKey = 'children') {
- if (!node) return 0
-
- const children = node[childrenKey]
- const childValue = node[valueKey] || 0
-
- if (!children) return childValue
-
- const value = childValue + children.reduce((v, child) => v + calc(child), 0)
-
- node[valueKey] = value
-
- return value
-}
-
-//树转一维id数组
-export function getNodeId(arr) {
- if (!arr) return []
-
- const res = []
-
- arr.forEach(i => {
- res.push(i.id)
- if (i.children && i.children.length > 0) {
- res.push(...getNodeId(i.children))
- }
- })
-
- return res
-}
-
-//树转一维数组
-export function flatTree(tree, childrenKey = 'children') {
- const result = []
- tree.forEach(node => {
- if (node[childrenKey]) {
- result.push(node)
- result.push.apply(result, flatTree(node[childrenKey], childrenKey))
- }
- else result.push(node)
- })
- return result
-}
-
-export function getNodesByDfs(node) {
- const nodes = []
- const stack = [node]
-
- while (stack.length > 0) {
- const item = stack.pop()
- nodes.push(item)
- const children = item.children
- for (let i = children.length - 1; i >= 0; i--) {
- stack.push(children[i])
- }
- }
-
- return nodes
-}
-
-export function getNodesByBfs(node) {
- const nodes = []
- const queue = [node]
-
- while (queue.length > 0) {
- const item = queue.shift()
- nodes.push(item)
- queue.push(...item.children)
- }
-
- return nodes
-}
diff --git a/vue/template/src/util/validate.js b/vue/template/src/util/validate.js
index 2bcd9df..eb14b00 100644
--- a/vue/template/src/util/validate.js
+++ b/vue/template/src/util/validate.js
@@ -2,49 +2,6 @@ export function isString(str) {
return typeof str === 'string' || str instanceof String
}
-export function isInteger(v) {
- const t = parseFloat(v)
- return t.toString() !== 'NaN' && t < 2147483647 && t > -2147483648
-}
-
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
-
-export function isEmail(email) {
- const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
- return reg.test(email)
-}
-
-export function isImage(suffix) {
- const reg = /\.(png|jpg|gif|jpeg|webp|bmp)$/
- return reg.test(suffix.toLowerCase())
-}
-
-export function isDoc(suffix) {
- return /\.(doc|docx)$/.test(suffix.toLowerCase())
-}
-
-export function isPdf(suffix) {
- return /\.pdf$/.test(suffix.toLowerCase())
-}
-
-export function isPpt(suffix) {
- return /\.(ppt|pptx)$/.test(suffix.toLowerCase())
-}
-
-export function isRar(suffix) {
- return /\.rar$/.test(suffix.toLowerCase())
-}
-
-export function isXls(suffix) {
- return /\.(xls|xlsx)$/.test(suffix.toLowerCase())
-}
-
-export function isTxt(suffix) {
- return /\.txt$/.test(suffix.toLowerCase())
-}
-
-export function isZip(suffix) {
- return /\.zip$/.test(suffix.toLowerCase())
-}
diff --git a/vue/template/src/util/vue.js b/vue/template/src/util/vue.js
deleted file mode 100644
index bcb6d1b..0000000
--- a/vue/template/src/util/vue.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * 根据组件标签名称获取组件实例
- * 使用广度优先搜索
- *
- * @param instance 从哪个组件实例开始查找,一般是this
- * @param tag 要查找的组件的标签名称
- */
-export function findComponentByTag(instance, tag) {
- if (!instance || !tag) return
-
- const queue = [instance]
-
- while (queue.length > 0) {
- const item = queue.shift()
- const {$options, $children} = item
-
- if ($options._componentTag === tag) return item
-
- if (Array.isArray($children)) {
- queue.push(...$children)
- }
- }
-}
diff --git a/vue/template/src/view/_common/SkeletonPage/style.scss b/vue/template/src/view/_common/SkeletonPage/style.scss
index aaa2b99..59b2b9e 100644
--- a/vue/template/src/view/_common/SkeletonPage/style.scss
+++ b/vue/template/src/view/_common/SkeletonPage/style.scss
@@ -1,4 +1,4 @@
-@import "~@/asset/style/var";
+@import "~el-admin-layout/src/style/var";
.skeleton-page-wrapper {
margin: $page-view-margin;
diff --git a/vue/template/vue.config.js b/vue/template/vue.config.js
index e429e3e..e724b9b 100644
--- a/vue/template/vue.config.js
+++ b/vue/template/vue.config.js
@@ -14,7 +14,7 @@ module.exports = {
runtimeCompiler: true,
lintOnSave: false,
productionSourceMap: settings.isDev,
- parallel: true,
+ transpileDependencies: ['el-admin-layout'],
devServer: {
port: process.env.port || 8079,
contentBasePublicPath: settings.contextPath,