From 2cc83296951261b7c6384275638bf87e8059beb4 Mon Sep 17 00:00:00 2001
From: sheng <905537351@qq.com>
Date: Wed, 27 May 2026 18:07:48 +0800
Subject: [PATCH] refactor: remove old demo pages and static menu logic
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 删除大量旧的示例页面、组件示例和静态菜单配置
2. 新增菜单扁平数组转树形结构工具函数
3. 重构菜单加载逻辑,改为从后端动态获取并格式化
4. 新增全局权限检查方法和自定义权限指令
5. 优化侧边栏菜单路由跳转逻辑,自动跳转第一个有权限的子页面
6. 移除路由中对旧demo模块的引用
---
docs/menu-permission-migration.md | 601 ++++++++++
src/api/demo.js | 86 --
src/api/menu.js | 13 +
.../header-aside/components/mixin/menu.js | 41 +-
src/libs/util.js | 29 +
src/main.js | 29 +-
src/menu/index.js | 84 +-
src/menu/modules/demo-components.js | 88 --
src/menu/modules/demo-playground.js | 133 ---
src/menu/modules/demo-plugins.js | 29 -
src/plugin/d2admin/index.js | 21 +
src/router/modules/components.js | 41 -
src/router/modules/playground.js | 47 -
src/router/modules/plugins.js | 24 -
src/router/modules/production-master-data.js | 18 -
src/router/routes.js | 9 +-
src/store/modules/d2admin/modules/menu.js | 92 +-
src/views/demo/components/container/api.vue | 104 --
.../demo/components/container/card-bs.vue | 16 -
.../demo/components/container/card-slot.vue | 16 -
src/views/demo/components/container/card.vue | 14 -
.../container/components/d2-demo-article.vue | 50 -
.../demo/components/container/full-bs.vue | 16 -
.../demo/components/container/full-slot.vue | 16 -
src/views/demo/components/container/full.vue | 14 -
.../demo/components/container/ghost-bs.vue | 20 -
.../demo/components/container/ghost-slot.vue | 20 -
src/views/demo/components/container/ghost.vue | 18 -
.../demo/components/container/md/long.md | 53 -
.../demo/components/container/md/short.md | 17 -
src/views/demo/components/countup/index.vue | 94 --
.../demo/components/editor-quill/index.vue | 49 -
.../demo/components/editor-quill/value.js | 6 -
.../demo/components/editor-ueditor/index.vue | 33 -
.../demo/components/highlight/code/css.js | 8 -
.../demo/components/highlight/code/html.js | 8 -
.../components/highlight/code/javascript.js | 3 -
.../demo/components/highlight/code/scss.js | 8 -
src/views/demo/components/highlight/index.vue | 38 -
.../icon/components/d2-icon-cell.vue | 82 --
src/views/demo/components/icon/data/index.js | 1004 -----------------
src/views/demo/components/icon/icon-svg.vue | 42 -
src/views/demo/components/icon/icon.vue | 22 -
src/views/demo/components/icon/list.vue | 46 -
src/views/demo/components/icon/select-svg.vue | 24 -
src/views/demo/components/icon/select.vue | 56 -
src/views/demo/components/index/index.vue | 21 -
src/views/demo/components/json-tree/index.vue | 24 -
src/views/demo/components/layout/grid.vue | 122 --
.../demo/components/layout/splitpane.vue | 37 -
src/views/demo/components/markdown/md/doc.md | 38 -
src/views/demo/components/markdown/source.vue | 17 -
src/views/demo/components/markdown/url.vue | 6 -
.../playground/add-routes/alternates/1.vue | 5 -
.../playground/add-routes/alternates/2.vue | 5 -
.../playground/add-routes/alternates/3.vue | 5 -
.../demo/playground/add-routes/routes.vue | 109 --
src/views/demo/playground/db/all/index.vue | 33 -
.../demo/playground/db/page-public/index.vue | 127 ---
.../db/page-snapshot-public/index.vue | 114 --
.../db/page-snapshot-user/index.vue | 114 --
.../demo/playground/db/page-user/index.vue | 139 ---
src/views/demo/playground/db/public/index.vue | 123 --
src/views/demo/playground/db/user/index.vue | 125 --
src/views/demo/playground/env/index.vue | 16 -
.../demo/playground/frame/d2-doc/index.vue | 3 -
.../demo/playground/frame/html/index.vue | 3 -
.../demo/playground/frame/report/index.vue | 3 -
src/views/demo/playground/index/index.vue | 21 -
src/views/demo/playground/locales/index.vue | 22 -
src/views/demo/playground/log/ajax/index.vue | 20 -
.../playground/log/console/image/demo.png | Bin 66362 -> 0 bytes
.../demo/playground/log/console/index.vue | 67 --
src/views/demo/playground/log/error/index.vue | 18 -
src/views/demo/playground/log/log/index.vue | 28 -
src/views/demo/playground/page-argu/get.vue | 16 -
src/views/demo/playground/page-argu/send.vue | 55 -
src/views/demo/playground/page-cache/off.vue | 17 -
src/views/demo/playground/page-cache/on.vue | 18 -
.../demo/playground/page-cache/params.vue | 42 -
.../playground/store/fullscreen/index.vue | 19 -
.../demo/playground/store/gray/index.vue | 87 --
.../demo/playground/store/menu/index.vue | 148 ---
.../demo/playground/store/page/index.vue | 98 --
.../demo/playground/store/size/index.vue | 39 -
.../demo/playground/store/theme/index.vue | 74 --
.../playground/store/transition/index.vue | 26 -
src/views/demo/playground/store/ua/index.vue | 23 -
.../demo/plugins/clipboard-polyfill/index.vue | 82 --
src/views/demo/plugins/day/index.vue | 73 --
src/views/demo/plugins/export/table.vue | 72 --
src/views/demo/plugins/export/txt.vue | 47 -
src/views/demo/plugins/import/csv.vue | 62 -
src/views/demo/plugins/import/xlsx.vue | 64 --
src/views/demo/plugins/index/index.vue | 21 -
src/views/demo/plugins/js-cookie/index.vue | 54 -
96 files changed, 799 insertions(+), 4985 deletions(-)
create mode 100644 docs/menu-permission-migration.md
delete mode 100644 src/api/demo.js
create mode 100644 src/api/menu.js
delete mode 100644 src/menu/modules/demo-components.js
delete mode 100644 src/menu/modules/demo-playground.js
delete mode 100644 src/menu/modules/demo-plugins.js
delete mode 100644 src/router/modules/components.js
delete mode 100644 src/router/modules/playground.js
delete mode 100644 src/router/modules/plugins.js
delete mode 100644 src/router/modules/production-master-data.js
delete mode 100644 src/views/demo/components/container/api.vue
delete mode 100644 src/views/demo/components/container/card-bs.vue
delete mode 100644 src/views/demo/components/container/card-slot.vue
delete mode 100644 src/views/demo/components/container/card.vue
delete mode 100644 src/views/demo/components/container/components/d2-demo-article.vue
delete mode 100644 src/views/demo/components/container/full-bs.vue
delete mode 100644 src/views/demo/components/container/full-slot.vue
delete mode 100644 src/views/demo/components/container/full.vue
delete mode 100644 src/views/demo/components/container/ghost-bs.vue
delete mode 100644 src/views/demo/components/container/ghost-slot.vue
delete mode 100644 src/views/demo/components/container/ghost.vue
delete mode 100644 src/views/demo/components/container/md/long.md
delete mode 100644 src/views/demo/components/container/md/short.md
delete mode 100644 src/views/demo/components/countup/index.vue
delete mode 100644 src/views/demo/components/editor-quill/index.vue
delete mode 100644 src/views/demo/components/editor-quill/value.js
delete mode 100644 src/views/demo/components/editor-ueditor/index.vue
delete mode 100644 src/views/demo/components/highlight/code/css.js
delete mode 100644 src/views/demo/components/highlight/code/html.js
delete mode 100644 src/views/demo/components/highlight/code/javascript.js
delete mode 100644 src/views/demo/components/highlight/code/scss.js
delete mode 100644 src/views/demo/components/highlight/index.vue
delete mode 100644 src/views/demo/components/icon/components/d2-icon-cell.vue
delete mode 100644 src/views/demo/components/icon/data/index.js
delete mode 100644 src/views/demo/components/icon/icon-svg.vue
delete mode 100644 src/views/demo/components/icon/icon.vue
delete mode 100644 src/views/demo/components/icon/list.vue
delete mode 100644 src/views/demo/components/icon/select-svg.vue
delete mode 100644 src/views/demo/components/icon/select.vue
delete mode 100644 src/views/demo/components/index/index.vue
delete mode 100644 src/views/demo/components/json-tree/index.vue
delete mode 100644 src/views/demo/components/layout/grid.vue
delete mode 100644 src/views/demo/components/layout/splitpane.vue
delete mode 100644 src/views/demo/components/markdown/md/doc.md
delete mode 100644 src/views/demo/components/markdown/source.vue
delete mode 100644 src/views/demo/components/markdown/url.vue
delete mode 100644 src/views/demo/playground/add-routes/alternates/1.vue
delete mode 100644 src/views/demo/playground/add-routes/alternates/2.vue
delete mode 100644 src/views/demo/playground/add-routes/alternates/3.vue
delete mode 100644 src/views/demo/playground/add-routes/routes.vue
delete mode 100644 src/views/demo/playground/db/all/index.vue
delete mode 100644 src/views/demo/playground/db/page-public/index.vue
delete mode 100644 src/views/demo/playground/db/page-snapshot-public/index.vue
delete mode 100644 src/views/demo/playground/db/page-snapshot-user/index.vue
delete mode 100644 src/views/demo/playground/db/page-user/index.vue
delete mode 100644 src/views/demo/playground/db/public/index.vue
delete mode 100644 src/views/demo/playground/db/user/index.vue
delete mode 100644 src/views/demo/playground/env/index.vue
delete mode 100644 src/views/demo/playground/frame/d2-doc/index.vue
delete mode 100644 src/views/demo/playground/frame/html/index.vue
delete mode 100644 src/views/demo/playground/frame/report/index.vue
delete mode 100644 src/views/demo/playground/index/index.vue
delete mode 100644 src/views/demo/playground/locales/index.vue
delete mode 100644 src/views/demo/playground/log/ajax/index.vue
delete mode 100644 src/views/demo/playground/log/console/image/demo.png
delete mode 100644 src/views/demo/playground/log/console/index.vue
delete mode 100644 src/views/demo/playground/log/error/index.vue
delete mode 100644 src/views/demo/playground/log/log/index.vue
delete mode 100644 src/views/demo/playground/page-argu/get.vue
delete mode 100644 src/views/demo/playground/page-argu/send.vue
delete mode 100644 src/views/demo/playground/page-cache/off.vue
delete mode 100644 src/views/demo/playground/page-cache/on.vue
delete mode 100644 src/views/demo/playground/page-cache/params.vue
delete mode 100644 src/views/demo/playground/store/fullscreen/index.vue
delete mode 100644 src/views/demo/playground/store/gray/index.vue
delete mode 100644 src/views/demo/playground/store/menu/index.vue
delete mode 100644 src/views/demo/playground/store/page/index.vue
delete mode 100644 src/views/demo/playground/store/size/index.vue
delete mode 100644 src/views/demo/playground/store/theme/index.vue
delete mode 100644 src/views/demo/playground/store/transition/index.vue
delete mode 100644 src/views/demo/playground/store/ua/index.vue
delete mode 100644 src/views/demo/plugins/clipboard-polyfill/index.vue
delete mode 100644 src/views/demo/plugins/day/index.vue
delete mode 100644 src/views/demo/plugins/export/table.vue
delete mode 100644 src/views/demo/plugins/export/txt.vue
delete mode 100644 src/views/demo/plugins/import/csv.vue
delete mode 100644 src/views/demo/plugins/import/xlsx.vue
delete mode 100644 src/views/demo/plugins/index/index.vue
delete mode 100644 src/views/demo/plugins/js-cookie/index.vue
diff --git a/docs/menu-permission-migration.md b/docs/menu-permission-migration.md
new file mode 100644
index 00000000..b44b2b8d
--- /dev/null
+++ b/docs/menu-permission-migration.md
@@ -0,0 +1,601 @@
+# Menu 权限迁移方案
+
+> 参照项目:`D:\code\company\SCTMES_MES_V5\vue-app`(以下简称"源项目")
+
+---
+
+## 一、源项目(SCTMES)Menu 权限架构
+
+### 1.1 后端接口
+
+```
+GET system_settings/menu_configuration/menu/all
+```
+
+API 文件:[src/api/system_settings/menu_configuration/menu.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\api\system_settings\menu_configuration\menu.js)
+
+返回当前用户可见的**扁平数组**,字段如下:
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| `menu_id` | number | 主键,用于构建父子关系 |
+| `parent_id` | number | 父节点 ID,`0` 表示顶栏根节点 |
+| `url` | string | 前端路由路径,如 `/system_settings/user_management/user` |
+| `name` | string | 菜单显示名称 |
+| `icon` | string | 图标名(FontAwesome) |
+| `is_navi` | number | 是否作为导航菜单展示(1=是) |
+| `status` | number | 启用/禁用 |
+| `type` | string | 菜单类型 |
+| `params` | string | 额外参数 |
+| `sort` | number | 排序 |
+| `remark` | string | 备注 |
+
+### 1.2 菜单数据全链路
+
+```
+登录成功 → account.login() → dispatch('load')
+ │
+ ▼
+ account.load()
+ │
+ ...加载 user/theme/transition/page/menu/size/color...
+ │
+ ▼
+ dispatch('d2admin/menu/sourceDataLoad')
+ │
+ ┌────────────┴────────────┐
+ │ │
+ localStorage localStorage 为空
+ 有缓存 且有 token
+ │ │
+ ▼ ▼
+ 直接读缓存 GET /menu/all 后端接口
+ │
+ ▼
+ 写入 localStorage 缓存
+ │
+ └────────────┬────────────┘
+ │
+ ▼
+ menu.install(this, sourceData)
+```
+
+**Store 文件**:[src/store/modules/d2admin/modules/menu.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\store\modules\d2admin\modules\menu.js)
+
+```js
+state: {
+ header: [],
+ aside: [],
+ asideCollapse: setting.menu.asideCollapse,
+ asideTransition: setting.menu.asideTransition,
+ authKey: {}, // ← 权限字典 { '/path': '菜单名', ... }
+ sourceData: [] // ← 菜单源数据(来自后端或本地缓存)
+}
+```
+
+### 1.3 `sourceDataLoad` action 核心逻辑
+
+```js
+async sourceDataLoad({ state, dispatch }) {
+ // 1. 优先从 localStorage 读取缓存
+ state.sourceData = await dispatch('d2admin/db/get', {
+ dbName: 'database',
+ path: '$menu.sourceData',
+ defaultValue: [],
+ user: true
+ }, { root: true })
+
+ // 2. 缓存为空且已登录 → 调后端获取
+ if (!state.sourceData.length && util.cookies.get('token')) {
+ const res = await getMenuAll(null)
+ state.sourceData = res.data || []
+ await dispatch('d2admin/db/set', {
+ dbName: 'database',
+ path: '$menu.sourceData',
+ value: state.sourceData,
+ user: true
+ }, { root: true })
+ }
+
+ // 3. 处理为 header/aside/authKey
+ menu.install(this, state.sourceData)
+}
+```
+
+### 1.4 `menu.install()` — 扁平数据 → 菜单树 + 权限字典
+
+**文件**:[src/menu/index.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\menu\index.js)
+
+```js
+export default {
+ install(vm, source) {
+ // 1. 构建权限字典 { '/path': '菜单名' }
+ vm.commit('d2admin/menu/headerAuth', source)
+
+ // 2. 扁平数据转为 {header: [], aside: []} 树结构
+ const { header, aside } = getMenuData(source)
+
+ // 3. 写入 store → 触发菜单渲染
+ vm.commit('d2admin/menu/headerSet', header)
+ vm.commit('d2admin/menu/asideSet', aside)
+ }
+}
+```
+
+`getMenuData()` 核心流程:
+
+```
+source (扁平数组)
+ │
+ ├── 过滤: is_navi !== 1 的跳过
+ │
+ ├── parent_id === 0 → 推入 header[]
+ │
+ └── 全部节点 → 推入 aside[]
+ │
+ ▼
+ util.formatDataToTree(aside) { menu_id ↔ parent_id }
+ │
+ ▼
+ 树形结构 aside
+```
+
+**`headerAuth` mutation**:遍历 `source`,将每个有 `url` 的节点写入 `authKey[url] = name`:
+
+```js
+headerAuth(state, source) {
+ let auth = {}
+ source.forEach(value => {
+ if (value.url) {
+ auth[value.url] = value.name
+ }
+ })
+ state.authKey = auth
+}
+```
+
+### 1.5 权限控制系统
+
+**`$permission()` 方法** — 定义在 [src/plugin/d2admin/index.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\plugin\d2admin\index.js#L50):
+
+```js
+Vue.prototype.$permission = (value, type = 'menu') => {
+ let path = ''
+ const auth = store.state.d2admin.menu.authKey
+
+ switch (type) {
+ case 'menu': // 直接用 URL 查
+ path = value
+ break
+ case 'router': // 路由 name → URL
+ path = value.name.replace(/-/g, '/')
+ path.slice(0, 1) !== '/' && (path = '/' + path)
+ break
+ }
+
+ return !!(path && Object.prototype.hasOwnProperty.call(auth, path))
+}
+```
+
+**`v-permission` 指令** — 定义在 [src/main.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\main.js#L72-L78):
+
+```js
+Vue.directive('permission', {
+ bind: (el, binding) => {
+ if (!Vue.prototype.$permission(binding.value)) {
+ el.parentNode ? el.parentNode.removeChild(el) : el.style.display = 'none'
+ }
+ }
+})
+```
+
+使用示例:
+```html
+新增用户
+```
+
+### 1.6 菜单导航权限过滤
+
+**Menu Mixin** — [src/layout/header-aside/components/mixin/menu.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\layout\header-aside\components\mixin\menu.js):
+
+点击顶栏一级菜单时,不直接跳转,而是查找第一个有权限的子路由:
+
+```js
+getRouterAuthPath(index, indexPath) {
+ // 子路由直接访问
+ if (index === '/index' || !indexPath || indexPath.length > 1) {
+ this.$router.push({ path: index })
+ return
+ }
+
+ // 查找一级路由下第一个有权限的子路由
+ let router = null
+ for (const value of frameInRoutes) {
+ if (value.path === index) {
+ router = value.children
+ break
+ }
+ }
+
+ if (!router) {
+ this.$router.push({ path: index })
+ return
+ }
+
+ for (const value of router) {
+ const newPath = index + '/' + value.path
+ if (this.$permission(newPath)) {
+ this.$router.push({ path: newPath })
+ break
+ }
+ }
+}
+```
+
+### 1.7 路由 — 全部静态注册
+
+路由在 [src/router/routes.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\router\routes.js) 中**全部静态定义**,不使用 `addRoute`。
+
+路由守卫([src/router/index.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\router\index.js))仅判断 token 是否存在,不校验具体路由权限。权限控制在**菜单渲染**和**菜单点击时**完成。
+
+### 1.8 main.js 启动流程
+
+[src/main.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\main.js#L108-L137)
+
+```js
+created() {
+ // 仅初始化页面池,不再设置静态菜单
+ this.$store.commit('d2admin/page/init', frameInRoutes)
+ // 静态菜单设置已注释:
+ // this.$store.commit('d2admin/menu/headerSet', menuHeader)
+ // this.$store.commit('d2admin/search/init', menuHeader)
+},
+mounted() {
+ this.$store.dispatch('d2admin/account/load') // → sourceDataLoad → 获取菜单
+},
+watch: {
+ // $route.matched 切换侧边栏的 watch 已注释
+}
+```
+
+---
+
+## 二、mes-ui 当前现状 vs 目标
+
+| 模块 | mes-ui 现状 | 源项目(目标) |
+|------|-----------|---------------|
+| 菜单数据来源 | `src/menu/modules/*.js` 静态硬编码 | 后端 `GET /menu/all` + localStorage 缓存 |
+| `sourceDataLoad` | 仅 localStorage 读取,不参与菜单构建 | localStorage 兜底 + 调后端 → `menu.install()` |
+| 权限字典 | 无 | `authKey: { '/path': 'name' }` |
+| 菜单树构建 | 编译时 `supplementPath()` | 运行时 `getMenuData()` + `formatDataToTree()` |
+| 权限检查 | 无 | `$permission()` + `v-permission` 指令 |
+| 菜单点击 | 直接 `$router.push` | `getRouterAuthPath()` 查找首个有权限子路由 |
+| main.js 菜单初始化 | `created` 中 `headerSet(menuHeader)` | 注释掉静态菜单,由 `mounted` 中的 `load()` 触发 |
+| 路由注册 | 全部静态 | 全部静态(一致) |
+| 路由守卫 | 仅 token 检查 | 仅 token 检查(一致) |
+
+---
+
+## 三、迁移计划
+
+### 阶段 1️⃣:约定后端接口格式
+
+后端接口:`GET /api/menu/all`(或复用源项目的 `system_settings/menu_configuration/menu/all`)
+
+返回格式(扁平数组):
+
+```json
+{
+ "code": 0,
+ "data": [
+ { "menu_id": 1, "parent_id": 0, "url": "/index", "name": "首页", "icon": "home", "is_navi": 1 },
+ { "menu_id": 2, "parent_id": 0, "url": "/production_master_data", "name": "生产主数据", "icon": "cogs", "is_navi": 1 },
+ { "menu_id": 3, "parent_id": 2, "url": "/production_master_data/factory_model/factory_area", "name": "工厂区域", "icon": "map-marker", "is_navi": 1 }
+ ]
+}
+```
+
+### 阶段 2️⃣:新增/改造 API 层
+
+**新增** `src/api/menu.js`(参照源项目 [menu.js](file:///D:\code\company\SCTMES_MES_V5\vue-app\src\api\system_settings\menu_configuration\menu.js)):
+
+```js
+import { request } from '@/api/_service'
+
+export function getMenuAll(data) {
+ return request({
+ url: 'menu/all',
+ method: 'get',
+ params: {
+ method: 'system_settings_menu_configuration_menu_all',
+ platform: 'background',
+ ...data
+ }
+ })
+}
+```
+
+### 阶段 3️⃣:改造 `menu.js` Store
+
+**改造** [src/store/modules/d2admin/modules/menu.js](file:///d:\code\mes\mes-ui\src\store\modules\d2admin\modules\menu.js)
+
+| 改动 | 内容 |
+|------|------|
+| state | 新增 `authKey: {}` |
+| `sourceDataLoad` action | 改为:localStorage 兜底 → 调后端 → `menu.install()` |
+| mutations | 新增 `headerAuth(state, source)` → 构建 `authKey` 字典 |
+
+```js
+// 关键变更 — sourceDataLoad:
+async sourceDataLoad({ state, commit, dispatch }) {
+ // 1. 先读 localStorage 缓存
+ state.sourceData = await dispatch('d2admin/db/get', {
+ dbName: 'database',
+ path: '$menu.sourceData',
+ defaultValue: [],
+ user: true
+ }, { root: true })
+
+ // 2. 缓存为空且已登录 → 调后端
+ if (!state.sourceData.length && util.cookies.get('token')) {
+ const res = await getMenuAll()
+ state.sourceData = res || []
+ await dispatch('d2admin/db/set', {
+ dbName: 'database',
+ path: '$menu.sourceData',
+ value: state.sourceData,
+ user: true
+ }, { root: true })
+ }
+
+ // 3. 构建菜单树 + 权限字典
+ menuUtil.install(this, state.sourceData)
+}
+```
+
+### 阶段 4️⃣:改造 `src/menu/index.js` — 从静态导出变为工具模块
+
+将 [src/menu/index.js](file:///d:\code\mes\mes-ui\src\menu\index.js) 从"导出静态菜单配置"改为"菜单处理工具"(参照源项目):
+
+```js
+import util from '@/libs/util'
+
+function getMenuData(arr) {
+ let tree = { header: [], aside: [] }
+
+ arr.forEach(value => {
+ if (!value.is_navi) return // 过滤非导航菜单
+
+ const menuItem = {
+ path: value.url,
+ title: value.name,
+ icon: value.icon,
+ type: value.type,
+ params: value.params
+ }
+
+ if (value.parent_id === 0) {
+ tree.header.push({ ...menuItem })
+ }
+
+ menuItem.menu_id = value.menu_id
+ menuItem.parent_id = value.parent_id
+ tree.aside.push(menuItem)
+ })
+
+ // 扁平数组转树
+ tree.aside = util.formatDataToTree(tree.aside)
+ return tree
+}
+
+export default {
+ install(vm, source) {
+ vm.commit('d2admin/menu/headerAuth', source)
+ const { header, aside } = getMenuData(source)
+ vm.commit('d2admin/menu/headerSet', header)
+ vm.commit('d2admin/menu/asideSet', aside)
+ }
+}
+```
+
+原有的静态菜单模块(`src/menu/modules/demo-*.js`)可保留但不再被引用,后续按需清理。
+
+### 阶段 5️⃣:增加权限控制基础设施
+
+#### 5.1 `$permission` 方法
+
+**改造** `src/plugin/d2admin/index.js`,新增:
+
+```js
+Vue.prototype.$permission = (value, type = 'menu') => {
+ let path = ''
+ const auth = store.state.d2admin.menu.authKey
+
+ switch (type) {
+ case 'menu':
+ path = value
+ break
+ case 'router':
+ path = value.name.replace(/-/g, '/')
+ path.slice(0, 1) !== '/' && (path = '/' + path)
+ break
+ }
+
+ return !!(path && Object.prototype.hasOwnProperty.call(auth, path))
+}
+```
+
+#### 5.2 `v-permission` 指令
+
+**改造** `src/main.js`,新增:
+
+```js
+Vue.directive('permission', {
+ bind: (el, binding) => {
+ if (!Vue.prototype.$permission(binding.value)) {
+ el.parentNode ? el.parentNode.removeChild(el) : el.style.display = 'none'
+ }
+ }
+})
+```
+
+#### 5.3 菜单点击权限过滤
+
+**改造** [src/layout/header-aside/components/mixin/menu.js](file:///d:\code\mes\mes-ui\src\layout\header-aside\components\mixin\menu.js),增加 `getRouterAuthPath` 方法:
+
+```js
+import { frameInRoutes } from '@/router/routes'
+
+methods: {
+ handleMenuSelect(index, indexPath) {
+ if (/^d2-menu-empty-\d+$/.test(index) || index === undefined) {
+ this.$message.warning('临时菜单')
+ } else if (/^https:\/\/|http:\/\//.test(index)) {
+ util.open(index)
+ } else {
+ this.getRouterAuthPath(index, indexPath)
+ }
+ },
+
+ getRouterAuthPath(index, indexPath) {
+ if (index === '/index' || !indexPath || indexPath.length > 1) {
+ this.$router.push({ path: index })
+ return
+ }
+
+ let router = null
+ for (const value of frameInRoutes) {
+ if (value.path === index) {
+ router = value.children
+ break
+ }
+ }
+
+ if (!router) {
+ this.$router.push({ path: index })
+ return
+ }
+
+ for (const value of router) {
+ const newPath = index + '/' + value.path
+ if (this.$permission(newPath)) {
+ this.$router.push({ path: newPath })
+ break
+ }
+ }
+ }
+}
+```
+
+### 阶段 6️⃣:改造 `main.js` 启动流程
+
+**改造** [src/main.js](file:///d:\code\mes\mes-ui\src\main.js):
+
+```js
+created() {
+ this.$store.commit('d2admin/page/init', frameInRoutes)
+ // 注释掉静态菜单设置:
+ // this.$store.commit('d2admin/menu/headerSet', menuHeader)
+ // this.$store.commit('d2admin/search/init', menuHeader)
+},
+mounted() {
+ this.$store.commit('d2admin/releases/versionShow')
+ this.$store.dispatch('d2admin/account/load') // → sourceDataLoad → 获取后端菜单
+ this.$store.commit('d2admin/ua/get')
+ this.$store.dispatch('d2admin/fullscreen/listen')
+},
+watch: {
+ // 注释掉 $route.matched 侧边栏切换(由 store.aside 直接驱动)
+ // '$route.matched': { ... }
+}
+```
+
+### 阶段 7️⃣:增加 `util.formatDataToTree` 工具函数
+
+**改造** `src/libs/util.js`,新增:
+
+```js
+util.formatDataToTree = (data, key = 'menu_id', pid = 'parent_id') => {
+ if (!data || data.length <= 0) return []
+
+ let map = {}
+ data.forEach(value => { map[value[key]] = { ...value } })
+
+ let tree = []
+ data.forEach(item => {
+ const id = item[key]
+ if (map[id][pid] && map[map[id][pid]]) {
+ if (!map[map[id][pid]].children) {
+ map[map[id][pid]].children = []
+ }
+ map[map[id][pid]].children.push(map[id])
+ } else {
+ tree.push(map[id])
+ }
+ })
+ return tree
+}
+```
+
+---
+
+## 四、影响的文件清单
+
+| 文件 | 改动类型 | 说明 |
+|------|----------|------|
+| `src/api/menu.js` | **新增** | 菜单 API(`getMenuAll`) |
+| `src/store/modules/d2admin/modules/menu.js` | **改造** | `sourceDataLoad` 加后端调用 + `headerAuth` mutation + `authKey` state |
+| `src/menu/index.js` | **重写** | 从静态配置改为 `install()` 工具模块 |
+| `src/plugin/d2admin/index.js` | **改造** | 新增 `$permission` 方法 |
+| `src/main.js` | **改造** | 注释静态菜单设置;新增 `v-permission` 指令 |
+| `src/layout/header-aside/components/mixin/menu.js` | **改造** | 增加 `getRouterAuthPath` 权限过滤 |
+| `src/libs/util.js` | **改造** | 新增 `formatDataToTree` 工具函数 |
+| `src/menu/modules/demo-*.js` | **后续可删** | 静态菜单数据不再使用,单独清理 |
+
+---
+
+## 五、完整时序图
+
+```
+ 用户登录
+ │
+ ▼
+ login/index.vue → dispatch('d2admin/account/login')
+ │
+ ▼
+ account.js login action
+ ├── loginAdminUser() → 后端登录接口
+ ├── util.cookies.set() → 存 token/uuid
+ ├── dispatch('d2admin/user/set') → 存用户信息
+ └── dispatch('load')
+ │
+ ├── d2admin/user/load → 加载用户名
+ ├── d2admin/theme/load → 加载主题
+ ├── d2admin/transition/load → 加载过渡效果
+ ├── d2admin/page/openedLoad → 加载标签页
+ ├── d2admin/menu/asideLoad → 加载侧边栏收起设置
+ ├── d2admin/size/load → 加载全局尺寸
+ ├── d2admin/color/load → 加载颜色设置
+ └── d2admin/menu/sourceDataLoad
+ │
+ ├── 先读 localStorage 缓存
+ ├── 缓存空 → GET /api/menu/all 后端接口
+ ├── 写入 localStorage 缓存
+ └── menu.install(this, sourceData)
+ ├── headerAuth → 构建 authKey 权限字典
+ ├── getMenuData → 扁平 → {header, aside} 树
+ ├── headerSet → 顶栏菜单渲染
+ └── asideSet → 侧边栏菜单渲染
+ │
+ ▼
+ 跳转到首页 → 菜单已按权限渲染
+```
+
+---
+
+## 六、注意事项
+
+1. **路由仍是静态注册的**:mes-ui 不需要改造成动态 `addRoute`,路由全部在 `router/routes.js` 中静态定义即可,权限通过菜单显示/隐藏 + `getRouterAuthPath` 控制。
+2. **不要删除源项目代码**:源项目在 `D:\code\company\SCTMES_MES_V5\vue-app`,仅作为参照,不对其做任何修改。
+3. **localStorage 缓存**是离线兜底:首次登录调后端,后续从缓存读取;注销时清空缓存。
+4. **`block` cookie**:已在登录页 `mounted` 中设为 `'false'`,注销时设为 `'true'`,用于控制错误日志是否弹出提示。
diff --git a/src/api/demo.js b/src/api/demo.js
deleted file mode 100644
index ad10d27a..00000000
--- a/src/api/demo.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import { find, map, random } from 'lodash'
-import faker from 'faker/locale/zh_CN'
-import { requestForMock, mock } from '@/api/_service.js'
-import * as tools from '@/api/_tools.js'
-
-const db = [
- { id: '1', name: '用户 1', address: '上海市普陀区金沙江路 1518 弄' },
- { id: '2', name: '用户 2', address: '上海市普陀区金沙江路 1517 弄' },
- { id: '3', name: '用户 3', address: '上海市普陀区金沙江路 1519 弄' },
- { id: '4', name: '用户 4', address: '上海市普陀区金沙江路 1516 弄' }
-]
-
-/**
- * @description 列表
- */
-export function DEMO_MOCK_LIST () {
- // 模拟数据
- mock
- .onAny('/demo/business/issues/142/fetch')
- .reply(...tools.responseSuccess({ list: db }))
- // 接口请求
- return requestForMock({
- url: '/demo/business/issues/142/fetch',
- method: 'get'
- })
-}
-
-/**
- * @description 详情
- * @param {String} id 项目 ID
- */
-export function DEMO_MOCK_DETAIL (id) {
- // 模拟数据
- mock
- .onAny('/demo/business/issues/142/detail')
- .reply(config => tools.responseSuccess(find(db, { id: config.params.id })))
- // 接口请求
- return requestForMock({
- url: '/demo/business/issues/142/detail',
- method: 'get',
- params: {
- id
- }
- })
-}
-
-/**
- * @description 列表
- */
-export function DEMO_MOCK_LIST2 (params = {}) {
- // 模拟数据
- mock
- .onAny('/demo/business/table/1/fetch')
- .reply(config => tools.responseSuccess({
- page: {
- total: 1000
- },
- list: map(Array(config.params.pageSize), () => ({
- key: faker.random.uuid(),
- value: [10, 100, 200, 500][random(0, 3)],
- type: faker.random.boolean(),
- admin: faker.name.firstName() + faker.name.lastName(),
- adminNote: faker.random.words(),
- dateTimeCreat: faker.date.past(),
- used: faker.random.boolean(),
- dateTimeUse: faker.date.past()
- }))
- }))
- // 接口请求
- return requestForMock({
- url: '/demo/business/table/1/fetch',
- method: 'get',
- params
- })
-}
-
-/**
- * @description 错误日志示例 请求一个不存在的地址
- */
-export function DEMO_LOG_AJAX () {
- // 接口请求
- return requestForMock({
- url: '/invalid-url',
- method: 'get'
- })
-}
diff --git a/src/api/menu.js b/src/api/menu.js
new file mode 100644
index 00000000..955c1195
--- /dev/null
+++ b/src/api/menu.js
@@ -0,0 +1,13 @@
+import { request } from '@/api/_service'
+
+const urls = 'system_settings/menu_configuration/menu/'
+
+export function getMenuAll (data) {
+ return request({
+ url: urls + 'all',
+ method: 'get',
+ params: {
+ ...data
+ }
+ })
+}
diff --git a/src/layout/header-aside/components/mixin/menu.js b/src/layout/header-aside/components/mixin/menu.js
index 7160b58f..8ed3a1d1 100644
--- a/src/layout/header-aside/components/mixin/menu.js
+++ b/src/layout/header-aside/components/mixin/menu.js
@@ -1,4 +1,5 @@
import util from '@/libs/util.js'
+import { frameInRoutes } from '@/router/routes'
export default {
methods: {
@@ -8,9 +9,43 @@ export default {
} else if (/^https:\/\/|http:\/\//.test(index)) {
util.open(index)
} else {
- this.$router.push({
- path: index
- })
+ this.getRouterAuthPath(index, indexPath)
+ }
+ },
+ /**
+ * 点击菜单时进行权限过滤,查找第一个有权限的子路由
+ * @param {String} index 选中菜单项的 index (path)
+ * @param {Array} indexPath 选中菜单项的 index path
+ */
+ getRouterAuthPath (index, indexPath) {
+ // 首页或子级路由直接访问
+ if (index === '/index' || !indexPath || indexPath.length > 1) {
+ this.$router.push({ path: index })
+ return
+ }
+
+ // 查找一级路由下是否存在子路由
+ let router = null
+ for (const value of frameInRoutes) {
+ if (value.path === index) {
+ router = value.children
+ break
+ }
+ }
+
+ // 不存在子路由则直接进入
+ if (!router) {
+ this.$router.push({ path: index })
+ return
+ }
+
+ // 存在子路由时,跳转第一个有权限的子页面
+ for (const value of router) {
+ const newPath = index + '/' + value.path
+ if (this.$permission(newPath)) {
+ this.$router.push({ path: newPath })
+ break
+ }
}
}
}
diff --git a/src/libs/util.js b/src/libs/util.js
index 9711c6a9..e7dba3fe 100644
--- a/src/libs/util.js
+++ b/src/libs/util.js
@@ -8,6 +8,35 @@ const util = {
log
}
+/**
+ * 扁平数组转树形结构
+ * @param {Array} data 扁平数组
+ * @param {String} key 主键字段名
+ * @param {String} pid 父节点字段名
+ */
+util.formatDataToTree = (data, key = 'menu_id', pid = 'parent_id') => {
+ if (!data || data.length <= 0) {
+ return []
+ }
+
+ const map = {}
+ data.forEach(value => { map[value[key]] = { ...value } })
+
+ const tree = []
+ data.forEach(item => {
+ const id = item[key]
+ if (map[id][pid] && map[map[id][pid]]) {
+ if (!map[map[id][pid]].children) {
+ map[map[id][pid]].children = []
+ }
+ map[map[id][pid]].children.push(map[id])
+ } else {
+ tree.push(map[id])
+ }
+ })
+ return tree
+}
+
/**
* @description 更新标题
* @param {String} title 标题
diff --git a/src/main.js b/src/main.js
index d6d65b41..8802faa1 100644
--- a/src/main.js
+++ b/src/main.js
@@ -9,12 +9,20 @@ import store from '@/store/index'
// 菜单和路由设置
import router from './router'
-import { menuHeader, menuAside } from '@/menu'
import { frameInRoutes } from '@/router/routes'
// 核心插件
Vue.use(d2Admin)
+// 权限控制指令
+Vue.directive('permission', {
+ bind: (el, binding) => {
+ if (!Vue.prototype.$permission(binding.value)) {
+ el.parentNode ? el.parentNode.removeChild(el) : el.style.display = 'none'
+ }
+ }
+})
+
new Vue({
router,
store,
@@ -23,31 +31,16 @@ new Vue({
created () {
// 处理路由 得到每一级的路由设置
this.$store.commit('d2admin/page/init', frameInRoutes)
- // 设置顶栏菜单
- this.$store.commit('d2admin/menu/headerSet', menuHeader)
- // 初始化菜单搜索功能
- this.$store.commit('d2admin/search/init', menuHeader)
+ // 静态菜单和搜索由 account.load → sourceDataLoad 从后端动态加载
},
mounted () {
// 展示系统信息
this.$store.commit('d2admin/releases/versionShow')
- // 用户登录后从数据库加载一系列的设置
+ // 用户登录后从数据库加载一系列的设置(含菜单)
this.$store.dispatch('d2admin/account/load')
// 获取并记录用户 UA
this.$store.commit('d2admin/ua/get')
// 初始化全屏监听
this.$store.dispatch('d2admin/fullscreen/listen')
- },
- watch: {
- // 检测路由变化切换侧边栏内容
- '$route.matched': {
- handler (matched) {
- if (matched.length > 0) {
- const _side = menuAside.filter(menu => menu.path === matched[0].path)
- this.$store.commit('d2admin/menu/asideSet', _side.length > 0 ? _side[0].children : [])
- }
- },
- immediate: true
- }
}
}).$mount('#app')
diff --git a/src/menu/index.js b/src/menu/index.js
index ccbe36e1..0cee7b17 100644
--- a/src/menu/index.js
+++ b/src/menu/index.js
@@ -1,42 +1,52 @@
-import { uniqueId } from 'lodash'
-
-// 插件
-import demoPlugins from './modules/demo-plugins'
-// 组件
-import demoComponents from './modules/demo-components'
-// 功能
-import demoPlayground from './modules/demo-playground'
+import util from '@/libs/util'
/**
- * @description 给菜单数据补充上 path 字段
- * @description https://github.com/d2-projects/d2-admin/issues/209
- * @param {Array} menu 原始的菜单数据
+ * 将后端返回的扁平菜单数组转为 { header: [], aside: [] } 树结构
+ * @param {Array} arr 后端返回的扁平菜单数据
*/
-function supplementPath (menu) {
- return menu.map(e => ({
- ...e,
- path: e.path || uniqueId('d2-menu-empty-'),
- ...e.children ? {
- children: supplementPath(e.children)
- } : {}
- }))
+function getMenuData (arr) {
+ const tree = { header: [], aside: [] }
+
+ arr.forEach(value => {
+ if (!value.is_navi) {
+ return
+ }
+
+ const menuItem = {
+ path: value.url,
+ title: value.name,
+ icon: value.icon,
+ type: value.type,
+ params: value.params
+ }
+
+ // parent_id 为 0 的节点放入顶栏
+ if (value.parent_id === 0) {
+ tree.header.push({ ...menuItem })
+ }
+
+ // 所有节点保留 menu_id / parent_id 用于构建侧栏树形结构
+ menuItem.menu_id = value.menu_id
+ menuItem.parent_id = value.parent_id
+ tree.aside.push(menuItem)
+ })
+
+ // 扁平 aside 数组转为嵌套树
+ tree.aside = util.formatDataToTree(tree.aside)
+
+ return tree
}
-// 菜单 侧边栏
-export const menuAside = supplementPath([
- demoComponents,
- demoPlugins,
- demoPlayground
-])
-
-// 菜单 顶栏
-export const menuHeader = supplementPath([
- {
- path: '/index',
- title: '首页',
- icon: 'home'
- },
- demoPlayground,
- demoComponents,
- demoPlugins
-])
+export default {
+ /**
+ * 由 sourceDataLoad 调用,将菜单源数据写入 store
+ * @param {Object} vm vuex store 实例 (this)
+ * @param {Array} source 后端返回的扁平菜单数组
+ */
+ install (vm, source) {
+ vm.commit('d2admin/menu/headerAuth', source)
+ const { header, aside } = getMenuData(source)
+ vm.commit('d2admin/menu/headerSet', header)
+ vm.commit('d2admin/menu/asideSet', aside)
+ }
+}
diff --git a/src/menu/modules/demo-components.js b/src/menu/modules/demo-components.js
deleted file mode 100644
index 2ff907dd..00000000
--- a/src/menu/modules/demo-components.js
+++ /dev/null
@@ -1,88 +0,0 @@
-export default {
- path: '/demo/components',
- title: '组件',
- icon: 'puzzle-piece',
- children: [
- { path: '/demo/components/index', title: '扩展组件', icon: 'home' },
- {
- path: '/demo/components/container',
- title: '布局容器',
- icon: 'window-restore',
- children: [
- {
- title: '填充型',
- children: [
- { path: '/demo/components/container/full', title: '基础', icon: '' },
- { path: '/demo/components/container/full-slot', title: '插槽', icon: '' },
- { path: '/demo/components/container/full-bs', title: '滚动优化', icon: '' }
- ]
- },
- {
- title: '隐形模式',
- children: [
- { path: '/demo/components/container/ghost', title: '基础', icon: '' },
- { path: '/demo/components/container/ghost-slot', title: '插槽', icon: '' },
- { path: '/demo/components/container/ghost-bs', title: '滚动优化', icon: '' }
- ]
- },
- {
- title: '卡片型',
- children: [
- { path: '/demo/components/container/card', title: '基础', icon: '' },
- { path: '/demo/components/container/card-slot', title: '插槽', icon: '' },
- { path: '/demo/components/container/card-bs', title: '滚动优化', icon: '' }
- ]
- },
- {
- title: '方法',
- children: [
- { path: '/demo/components/container/api?bs=false', title: '滚动控制', icon: '' },
- { path: '/demo/components/container/api?bs=true', title: '滚动控制 BS', icon: '' }
- ]
- }
- ]
- },
- {
- path: '/demo/components/layout/grid',
- title: '高级布局',
- icon: 'tasks',
- children: [
- { path: '/demo/components/layout/grid', title: '拖拽位置和大小' },
- { path: '/demo/components/layout/splitpane', title: '区域划分' }
- ]
- },
- {
- path: '/demo/components/editor',
- title: '编辑器',
- icon: 'pencil-square-o',
- children: [
- { path: '/demo/components/editor-ueditor', title: 'UEditor', icon: '' },
- { path: '/demo/components/editor-quill', title: 'Quill', icon: '' }
- ]
- },
- {
- path: '/demo/components/icon',
- title: '图标',
- icon: 'star',
- children: [
- { path: '/demo/components/icon/icon', title: '图标组件' },
- { path: '/demo/components/icon/icon-svg', title: 'svg 图标组件' },
- { path: '/demo/components/icon/select', title: '图标选择器' },
- { path: '/demo/components/icon/select-svg', title: 'svg 图标选择器' },
- { path: '/demo/components/icon/list', title: 'FontAwesome' }
- ]
- },
- {
- path: '/demo/components/markdown',
- title: 'markdown 解析',
- icon: 'file-text-o',
- children: [
- { path: '/demo/components/markdown/source', title: '指定资源' },
- { path: '/demo/components/markdown/url', title: '异步加载文件' }
- ]
- },
- { path: '/demo/components/countup', title: '数字动画', icon: 'motorcycle' },
- { path: '/demo/components/highlight', title: '代码高亮显示', icon: 'code' },
- { path: '/demo/components/json-tree', title: 'JSON 展示', icon: 'sitemap' }
- ]
-}
diff --git a/src/menu/modules/demo-playground.js b/src/menu/modules/demo-playground.js
deleted file mode 100644
index d002744d..00000000
--- a/src/menu/modules/demo-playground.js
+++ /dev/null
@@ -1,133 +0,0 @@
-export default {
- path: '/demo/playground',
- title: '功能',
- icon: 'flask',
- children: [
- { path: '/demo/playground/index', title: '功能', icon: 'home' },
- {
- title: 'svg 菜单图标',
- iconSvg: 'd2-admin',
- children: [
- { title: 'add', iconSvg: 'add' },
- { title: 'alarm', iconSvg: 'alarm' },
- { title: 'camera', iconSvg: 'camera' },
- { title: 'history', iconSvg: 'history' },
- { title: 'like', iconSvg: 'like' },
- { title: 'love', iconSvg: 'love' },
- { title: 'message', iconSvg: 'message' },
- { title: 'notice', iconSvg: 'notice' },
- { title: 'search', iconSvg: 'search' },
- { title: 'share', iconSvg: 'share' },
- { title: 'star', iconSvg: 'star' },
- { title: 'user', iconSvg: 'user' }
- ]
- },
- {
- title: '空菜单演示',
- icon: 'folder-o',
- children: [
- {
- title: '正在开发 1',
- children: [
- { title: '正在开发 1-1' },
- { title: '正在开发 1-2' }
- ]
- },
- { title: '正在开发 2' },
- { title: '正在开发 3' }
- ]
- },
- {
- path: '/demo/playground/frame',
- title: '内嵌网页',
- icon: 'globe',
- children: [
- { path: '/demo/playground/frame/d2-doc', title: 'D2Admin 中文文档', iconSvg: 'd2-admin' },
- { path: '/demo/playground/frame/html', title: '静态 HTML', icon: 'code' },
- { path: '/demo/playground/frame/report', title: '构建分析', icon: 'pie-chart' }
- ]
- },
- {
- title: '新窗口打开链接',
- icon: 'link',
- children: [
- { path: 'https://github.com/d2-projects/d2-admin', title: 'D2Admin Github', icon: 'github' },
- { path: 'https://juejin.im/user/57a48b632e958a006691b946/posts', title: '掘金', icon: 'globe' },
- { path: 'https://my.oschina.net/u/3871516', title: '开源中国', icon: 'globe' },
- { path: 'https://www.zhihu.com/people/fairy-ever/activities', title: '知乎', icon: 'globe' },
- { path: 'https://segmentfault.com/blog/liyang-note-book', title: 'segmentfault 专栏', icon: 'globe' },
- { path: 'http://www.fairyever.com/', title: 'www.fairyever.com', icon: 'globe' }
- ]
- },
- {
- path: '/demo/playground/store',
- title: '全局状态管理',
- icon: 'bolt',
- children: [
- { path: '/demo/playground/store/page', title: '多标签页控制', icon: 'window-restore' },
- { path: '/demo/playground/store/menu', title: '菜单控制', icon: 'bars' },
- { path: '/demo/playground/store/size', title: '全局尺寸', icon: 'font' },
- { path: '/demo/playground/store/ua', title: '浏览器信息', icon: 'info-circle' },
- { path: '/demo/playground/store/gray', title: '灰度模式', icon: 'eye' },
- { path: '/demo/playground/store/fullscreen', title: '全屏', icon: 'arrows-alt' },
- { path: '/demo/playground/store/theme', title: '主题', icon: 'diamond' },
- { path: '/demo/playground/store/transition', title: '页面过渡开关', icon: 'toggle-on' }
- ]
- },
- {
- path: '/demo/playground/page-cache',
- title: '页面缓存',
- icon: 'hdd-o',
- children: [
- { path: '/demo/playground/page-cache/on', title: '开启缓存' },
- { path: '/demo/playground/page-cache/off', title: '关闭缓存' },
- { path: '/demo/playground/page-cache/params/1', title: '带参路由缓存 1' },
- { path: '/demo/playground/page-cache/params/2', title: '带参路由缓存 2' }
- ]
- },
- {
- path: '/demo/playground/page-argu',
- title: '参数传递和留存',
- icon: 'assistive-listening-systems',
- children: [
- { path: '/demo/playground/page-argu/send', title: '发送' },
- { path: '/demo/playground/page-argu/get/username-from-menu?userid=userid-from-menu', title: '接收' }
- ]
- },
- {
- path: '/demo/playground/db',
- title: '数据持久化',
- icon: 'database',
- children: [
- { path: '/demo/playground/db/all', title: '总览', icon: 'table' },
- { path: '/demo/playground/db/public', title: '公共存储', icon: 'users' },
- { path: '/demo/playground/db/user', title: '私有数据', icon: 'user' },
- { path: '/demo/playground/db/page-public', title: '路由存储', icon: 'file-o' },
- { path: '/demo/playground/db/page-user', title: '私有路由存储', icon: 'file-o' },
- { path: '/demo/playground/db/page-snapshot-public', title: '路由快照', icon: 'file' },
- { path: '/demo/playground/db/page-snapshot-user', title: '私有路由快照', icon: 'file' }
- ]
- },
- {
- path: '/demo/playground/log',
- title: '日志',
- icon: 'bullseye',
- children: [
- { path: '/demo/playground/log/log', title: '日志记录', icon: 'dot-circle-o' },
- { path: '/demo/playground/log/error', title: '错误捕捉', icon: 'bug' },
- { path: '/demo/playground/log/ajax', title: 'Ajax 错误', icon: 'bug' },
- { path: '/demo/playground/log/console', title: '控制台日志', icon: 'lightbulb-o' }
- ]
- },
- {
- path: '/demo/playground/add-routes',
- title: '动态添加路由',
- icon: 'plus-square',
- children: [
- { path: '/demo/playground/add-routes/routes', title: '添加页面', icon: 'file-o' }
- ]
- },
- { path: '/demo/playground/env', title: '环境信息', icon: 'exclamation-circle' },
- { path: '/demo/playground/locales', title: '国际化', icon: 'language' }
- ]
-}
diff --git a/src/menu/modules/demo-plugins.js b/src/menu/modules/demo-plugins.js
deleted file mode 100644
index 1cb550db..00000000
--- a/src/menu/modules/demo-plugins.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export default {
- path: '/demo/plugins',
- title: '插件',
- icon: 'plug',
- children: [
- { path: '/demo/plugins/index', title: '插件', icon: 'home' },
- {
- path: '/demo/plugins/import',
- title: '导入',
- icon: 'download',
- children: [
- { path: '/demo/plugins/import/csv', title: 'csv' },
- { path: '/demo/plugins/import/xlsx', title: 'xlsx' }
- ]
- },
- {
- path: '/demo/plugins/export',
- title: '导出',
- icon: 'upload',
- children: [
- { path: '/demo/plugins/export/table', title: '表格' },
- { path: '/demo/plugins/export/txt', title: '文本' }
- ]
- },
- { path: '/demo/plugins/clipboard-polyfill', title: '剪贴板访问', icon: 'clipboard' },
- { path: '/demo/plugins/day', title: '日期计算', icon: 'clock-o' },
- { path: '/demo/plugins/js-cookie', title: 'Cookie 读写', icon: 'asterisk' }
- ]
-}
diff --git a/src/plugin/d2admin/index.js b/src/plugin/d2admin/index.js
index 7c739e91..7f56e3c2 100644
--- a/src/plugin/d2admin/index.js
+++ b/src/plugin/d2admin/index.js
@@ -10,6 +10,8 @@ import '@/assets/svg-icons'
// 国际化
import i18n from '@/i18n.js'
+import store from '@/store'
+
// 功能插件
import pluginError from '@/plugin/error'
import pluginLog from '@/plugin/log'
@@ -28,6 +30,25 @@ export default {
Vue.prototype.$version = process.env.VUE_APP_VERSION
// 构建时间
Vue.prototype.$buildTime = process.env.VUE_APP_BUILD_TIME
+
+ // 权限检查方法
+ Vue.prototype.$permission = (value, type = 'menu') => {
+ let path = ''
+ const auth = store.state.d2admin.menu.authKey
+
+ switch (type) {
+ case 'menu':
+ path = value
+ break
+ case 'router':
+ path = value.name.replace(/-/g, '/')
+ path.slice(0, 1) !== '/' && (path = '/' + path)
+ break
+ }
+
+ return !!(path && Object.prototype.hasOwnProperty.call(auth, path))
+ }
+
// Element
Vue.use(ElementUI, {
i18n: (key, value) => i18n.t(key, value)
diff --git a/src/router/modules/components.js b/src/router/modules/components.js
deleted file mode 100644
index c1a0f402..00000000
--- a/src/router/modules/components.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import layoutHeaderAside from '@/layout/header-aside'
-
-// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载
-const _import = require('@/libs/util.import.' + process.env.NODE_ENV)
-
-const meta = { auth: true }
-
-export default {
- path: '/demo/components',
- name: 'demo-components',
- meta,
- redirect: { name: 'demo-components-index' },
- component: layoutHeaderAside,
- children: [
- { path: 'container/full', name: 'demo-components-container-full', component: _import('demo/components/container/full.vue'), meta: { ...meta, title: '布局组件 填充' } },
- { path: 'container/full-slot', name: 'demo-components-container-full-slot', component: _import('demo/components/container/full-slot.vue'), meta: { ...meta, title: '布局组件 填充 插槽' } },
- { path: 'container/full-bs', name: 'demo-components-container-full-bs', component: _import('demo/components/container/full-bs.vue'), meta: { ...meta, title: '布局组件 填充 滚动优化' } },
- { path: 'container/ghost', name: 'demo-components-container-ghost', component: _import('demo/components/container/ghost.vue'), meta: { ...meta, title: '布局组件 隐形' } },
- { path: 'container/ghost-slot', name: 'demo-components-container-ghost-slot', component: _import('demo/components/container/ghost-slot.vue'), meta: { ...meta, title: '布局组件 隐形 插槽' } },
- { path: 'container/ghost-bs', name: 'demo-components-container-ghost-bs', component: _import('demo/components/container/ghost-bs.vue'), meta: { ...meta, title: '布局组件 隐形 滚动优化' } },
- { path: 'container/card', name: 'demo-components-container-card', component: _import('demo/components/container/card.vue'), meta: { ...meta, title: '布局组件 卡片' } },
- { path: 'container/card-slot', name: 'demo-components-container-card-slot', component: _import('demo/components/container/card-slot.vue'), meta: { ...meta, title: '布局组件 卡片 插槽' } },
- { path: 'container/card-bs', name: 'demo-components-container-card-bs', component: _import('demo/components/container/card-bs.vue'), meta: { ...meta, title: '布局组件 卡片 滚动优化' } },
- { path: 'container/api', name: 'demo-components-container-api', component: _import('demo/components/container/api.vue'), meta: { ...meta, title: '布局组件 API' } },
- { path: 'countup', name: 'demo-components-countup', component: _import('demo/components/countup'), meta: { ...meta, title: '数字动画' } },
- { path: 'editor-ueditor', name: 'demo-components-editor-ueditor', component: _import('demo/components/editor-ueditor'), meta: { ...meta, title: 'UEditor' } },
- { path: 'editor-quill', name: 'demo-components-editor-quill', component: _import('demo/components/editor-quill'), meta: { ...meta, title: '富文本编辑器' } },
- { path: 'highlight', name: 'demo-components-highlight', component: _import('demo/components/highlight'), meta: { ...meta, title: '代码高亮组件' } },
- { path: 'icon/icon', name: 'demo-components-icon-icon', component: _import('demo/components/icon/icon.vue'), meta: { ...meta, title: '图标组件' } },
- { path: 'icon/icon-svg', name: 'demo-components-icon-icon-svg', component: _import('demo/components/icon/icon-svg.vue'), meta: { ...meta, title: 'svg 图标' } },
- { path: 'icon/select', name: 'demo-components-icon-select', component: _import('demo/components/icon/select.vue'), meta: { ...meta, title: '图标选择器' } },
- { path: 'icon/select-svg', name: 'demo-components-icon-select-svg', component: _import('demo/components/icon/select-svg.vue'), meta: { ...meta, title: 'svg 图标选择器' } },
- { path: 'icon/list', name: 'demo-components-icon-list', component: _import('demo/components/icon/list.vue'), meta: { ...meta, title: '图标列表' } },
- { path: 'index', name: 'demo-components-index', component: _import('demo/components/index'), meta: { ...meta, title: '组件首页' } },
- { path: 'json-tree', name: 'demo-components-json-tree', component: _import('demo/components/json-tree'), meta: { ...meta, title: 'JSON 展示' } },
- { path: 'layout/grid', name: 'demo-components-layout-grid', component: _import('demo/components/layout/grid.vue'), meta: { ...meta, title: '拖拽网格布局' } },
- { path: 'layout/splitpane', name: 'demo-components-layout-splitpane', component: _import('demo/components/layout/splitpane.vue'), meta: { ...meta, title: '区域布局' } },
- { path: 'markdown/source', name: 'demo-components-markdown-source', component: _import('demo/components/markdown/source.vue'), meta: { ...meta, title: 'markdown指定资源渲染' } },
- { path: 'markdown/url', name: 'demo-components-markdown-url', component: _import('demo/components/markdown/url.vue'), meta: { ...meta, title: 'markdown指定url渲染' } }
- ]
-}
diff --git a/src/router/modules/playground.js b/src/router/modules/playground.js
deleted file mode 100644
index 3dcc763e..00000000
--- a/src/router/modules/playground.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import layoutHeaderAside from '@/layout/header-aside'
-
-// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载
-const _import = require('@/libs/util.import.' + process.env.NODE_ENV)
-
-const meta = { auth: true }
-
-export default {
- path: '/demo/playground',
- name: 'demo-playground',
- meta,
- redirect: { name: 'demo-playground-index' },
- component: layoutHeaderAside,
- children: [
- { path: 'index', name: 'demo-playground-index', component: _import('demo/playground/index'), meta: { ...meta, title: '功能首页' } },
- { path: 'store/page', name: 'demo-playground-store-page', component: _import('demo/playground/store/page'), meta: { ...meta, cache: true, title: '多标签页控制' } },
- { path: 'store/menu', name: 'demo-playground-store-menu', component: _import('demo/playground/store/menu'), meta: { ...meta, title: '菜单控制' } },
- { path: 'store/size', name: 'demo-playground-store-size', component: _import('demo/playground/store/size'), meta: { ...meta, title: '全局尺寸' } },
- { path: 'store/ua', name: 'demo-playground-store-ua', component: _import('demo/playground/store/ua'), meta: { ...meta, title: '浏览器信息' } },
- { path: 'store/gray', name: 'demo-playground-store-gray', component: _import('demo/playground/store/gray'), meta: { ...meta, title: '灰度模式' } },
- { path: 'store/fullscreen', name: 'demo-playground-store-fullscreen', component: _import('demo/playground/store/fullscreen'), meta: { ...meta, title: '全屏' } },
- { path: 'store/theme', name: 'demo-playground-store-theme', component: _import('demo/playground/store/theme'), meta: { ...meta, title: '主题' } },
- { path: 'store/transition', name: 'demo-playground-store-transition', component: _import('demo/playground/store/transition'), meta: { ...meta, title: '页面过渡开关' } },
- { path: 'page-cache/on', name: 'demo-playground-page-cache-on', component: _import('demo/playground/page-cache/on.vue'), meta: { ...meta, cache: true, title: '开启缓存' } },
- { path: 'page-cache/off', name: 'demo-playground-page-cache-off', component: _import('demo/playground/page-cache/off.vue'), meta: { ...meta, title: '关闭缓存' } },
- { path: 'page-cache/params/:id', name: 'demo-playground-page-cache-params', component: _import('demo/playground/page-cache/params.vue'), meta: { ...meta, cache: true, title: '带参路由缓存' }, props: true },
- { path: 'page-argu/send', name: 'demo-playground-page-argu-send', component: _import('demo/playground/page-argu/send.vue'), meta: { ...meta, title: '参数传递 发送' } },
- { path: 'page-argu/get/:username', name: 'demo-playground-page-argu-get', component: _import('demo/playground/page-argu/get.vue'), meta: { ...meta, title: '参数传递 接收' } },
- { path: 'db/all', name: 'demo-playground-db-all', component: _import('demo/playground/db/all'), meta: { ...meta, title: '总览' } },
- { path: 'db/public', name: 'demo-playground-db-public', component: _import('demo/playground/db/public'), meta: { ...meta, title: '公共存储' } },
- { path: 'db/user', name: 'demo-playground-db-user', component: _import('demo/playground/db/user'), meta: { ...meta, title: '私有存储' } },
- { path: 'db/page-public', name: 'demo-playground-db-page-public', component: _import('demo/playground/db/page-public'), meta: { ...meta, title: '路由存储' } },
- { path: 'db/page-user', name: 'demo-playground-db-page-user', component: _import('demo/playground/db/page-user'), meta: { ...meta, title: '私有路由存储' } },
- { path: 'db/page-snapshot-public', name: 'demo-playground-db-page-snapshot-public', component: _import('demo/playground/db/page-snapshot-public'), meta: { ...meta, title: '路由快照' } },
- { path: 'db/page-snapshot-user', name: 'demo-playground-db-page-snapshot-user', component: _import('demo/playground/db/page-snapshot-user'), meta: { ...meta, title: '私有路由快照' } },
- { path: 'log/ajax', name: 'demo-playground-log-ajax', component: _import('demo/playground/log/ajax'), meta: { ...meta, title: 'Ajax 错误' } },
- { path: 'log/console', name: 'demo-playground-log-console', component: _import('demo/playground/log/console'), meta: { ...meta, title: '控制台日志' } },
- { path: 'log/error', name: 'demo-playground-log-error', component: _import('demo/playground/log/error'), meta: { ...meta, title: '错误捕捉' } },
- { path: 'log/log', name: 'demo-playground-log-log', component: _import('demo/playground/log/log'), meta: { ...meta, title: '日志记录' } },
- { path: 'add-routes/routes', name: 'demo-playground-add-routes-routes', component: _import('demo/playground/add-routes/routes'), meta: { ...meta, title: '添加页面' } },
- { path: 'env', name: 'demo-playground-env', component: _import('demo/playground/env'), meta: { ...meta, title: '环境信息' } },
- { path: 'locales', name: 'demo-playground-locales', component: _import('demo/playground/locales'), meta: { ...meta, title: '国际化' } },
- { path: 'frame/html', name: 'demo-playground-frame-html', component: _import('demo/playground/frame/html'), meta: { ...meta, title: '静态 HTML' } },
- { path: 'frame/report', name: 'demo-playground-frame-report', component: _import('demo/playground/frame/report'), meta: { ...meta, title: 'Size report' } },
- { path: 'frame/d2-doc', name: 'demo-playground-frame-d2-doc', component: _import('demo/playground/frame/d2-doc'), meta: { ...meta, title: 'D2Admin 中文文档' } }
- ]
-}
diff --git a/src/router/modules/plugins.js b/src/router/modules/plugins.js
deleted file mode 100644
index 302506e4..00000000
--- a/src/router/modules/plugins.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import layoutHeaderAside from '@/layout/header-aside'
-
-// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载
-const _import = require('@/libs/util.import.' + process.env.NODE_ENV)
-
-const meta = { auth: true }
-
-export default {
- path: '/demo/plugins',
- name: 'demo-plugins',
- meta,
- redirect: { name: 'demo-plugins-index' },
- component: layoutHeaderAside,
- children: [
- { path: 'clipboard-polyfill', name: 'demo-plugins-clipboard-polyfill', component: _import('demo/plugins/clipboard-polyfill'), meta: { ...meta, title: '剪贴板访问' } },
- { path: 'day', name: 'demo-plugins-day', component: _import('demo/plugins/day'), meta: { ...meta, title: '日期计算' } },
- { path: 'export/table', name: 'demo-plugins-export-table', component: _import('demo/plugins/export/table.vue'), meta: { ...meta, title: '导出表格' } },
- { path: 'export/txt', name: 'demo-plugins-export-txt', component: _import('demo/plugins/export/txt.vue'), meta: { ...meta, title: '导出文本' } },
- { path: 'import/csv', name: 'demo-plugins-import-csv', component: _import('demo/plugins/import/csv.vue'), meta: { ...meta, title: '导入 csv' } },
- { path: 'import/xlsx', name: 'demo-plugins-import-xlsx', component: _import('demo/plugins/import/xlsx.vue'), meta: { ...meta, title: '导入 xlsx' } },
- { path: 'index', name: 'demo-plugins-index', component: _import('demo/plugins/index'), meta: { ...meta, title: '插件首页' } },
- { path: 'js-cookie', name: 'demo-plugins-js-cookie', component: _import('demo/plugins/js-cookie'), meta: { ...meta, title: 'Cookie' } }
- ]
-}
diff --git a/src/router/modules/production-master-data.js b/src/router/modules/production-master-data.js
deleted file mode 100644
index e91fc9a1..00000000
--- a/src/router/modules/production-master-data.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import layoutHeaderAside from '@/layout/header-aside'
-
-const meta = { auth: true }
-
-const _import = require('@/libs/util.import.' + process.env.NODE_ENV)
-
-export default {
- path: '/production_master_data',
- component: layoutHeaderAside,
- children: (pre => [
- {
- path: 'factory_model/factory_area',
- name: `${pre}factory_model-factory_area`,
- meta: { ...meta, cache: true, title: '工厂区域' },
- component: _import('production-master-data/factory-model/factory-area')
- }
- ])('production_master_data-')
-}
diff --git a/src/router/routes.js b/src/router/routes.js
index 52a7b00f..7652ebd2 100644
--- a/src/router/routes.js
+++ b/src/router/routes.js
@@ -1,9 +1,5 @@
-import playground from './modules/playground'
-import plugins from './modules/plugins'
-import components from './modules/components'
-import productionMasterData from './modules/production-master-data'
-
import layoutHeaderAside from '@/layout/header-aside'
+import productionMasterData from './modules/production-master-data'
// 由于懒加载页面太多的话会造成webpack热更新太慢,所以开发环境不使用懒加载,只有生产环境使用懒加载
const _import = require('@/libs/util.import.' + process.env.NODE_ENV)
@@ -53,9 +49,6 @@ const frameIn = [
}
]
},
- playground,
- plugins,
- components,
productionMasterData
]
diff --git a/src/store/modules/d2admin/modules/menu.js b/src/store/modules/d2admin/modules/menu.js
index 520e2d60..8a791ec4 100644
--- a/src/store/modules/d2admin/modules/menu.js
+++ b/src/store/modules/d2admin/modules/menu.js
@@ -1,5 +1,7 @@
-// 设置文件
import setting from '@/setting.js'
+import util from '@/libs/util'
+import menu from '@/menu'
+import { getMenuAll } from '@/api/menu'
export default {
namespaced: true,
@@ -12,19 +14,14 @@ export default {
asideCollapse: setting.menu.asideCollapse,
// 侧边栏折叠动画
asideTransition: setting.menu.asideTransition,
+ // 权限字典 { '/path': '菜单名' }
+ authKey: {},
// 菜单源数据
sourceData: []
},
actions: {
- /**
- * 设置侧边栏展开或者收缩
- * @param {Object} context
- * @param {Boolean} collapse is collapse
- */
async asideCollapseSet ({ state, dispatch }, collapse) {
- // store 赋值
state.asideCollapse = collapse
- // 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideCollapse',
@@ -32,14 +29,8 @@ export default {
user: true
}, { root: true })
},
- /**
- * 切换侧边栏展开和收缩
- * @param {Object} context
- */
async asideCollapseToggle ({ state, dispatch }) {
- // store 赋值
state.asideCollapse = !state.asideCollapse
- // 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideCollapse',
@@ -47,15 +38,8 @@ export default {
user: true
}, { root: true })
},
- /**
- * 设置侧边栏折叠动画
- * @param {Object} context
- * @param {Boolean} transition is transition
- */
async asideTransitionSet ({ state, dispatch }, transition) {
- // store 赋值
state.asideTransition = transition
- // 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideTransition',
@@ -63,14 +47,8 @@ export default {
user: true
}, { root: true })
},
- /**
- * 切换侧边栏折叠动画
- * @param {Object} context
- */
async asideTransitionToggle ({ state, dispatch }) {
- // store 赋值
state.asideTransition = !state.asideTransition
- // 持久化
await dispatch('d2admin/db/set', {
dbName: 'sys',
path: 'menu.asideTransition',
@@ -78,52 +56,58 @@ export default {
user: true
}, { root: true })
},
- /**
- * 持久化数据加载侧边栏设置
- * @param {Object} context
- */
async asideLoad ({ state, dispatch }) {
- // store 赋值
- const menu = await dispatch('d2admin/db/get', {
+ const menuSetting = await dispatch('d2admin/db/get', {
dbName: 'sys',
path: 'menu',
defaultValue: setting.menu,
user: true
}, { root: true })
- state.asideCollapse = menu.asideCollapse !== undefined ? menu.asideCollapse : setting.menu.asideCollapse
- state.asideTransition = menu.asideTransition !== undefined ? menu.asideTransition : setting.menu.asideTransition
+ state.asideCollapse = menuSetting.asideCollapse !== undefined ? menuSetting.asideCollapse : setting.menu.asideCollapse
+ state.asideTransition = menuSetting.asideTransition !== undefined ? menuSetting.asideTransition : setting.menu.asideTransition
},
- /**
- * 持久化数据加载菜单源数据
- * @param {Object} context
- */
- async sourceDataLoad ({ state, dispatch }) {
- const sourceData = await dispatch('d2admin/db/get', {
+ async sourceDataLoad ({ state, commit, dispatch }) {
+ // 优先从 localStorage 读取上次缓存的菜单数据
+ state.sourceData = await dispatch('d2admin/db/get', {
dbName: 'database',
path: '$menu.sourceData',
defaultValue: [],
user: true
}, { root: true })
- state.sourceData = sourceData
+
+ // 缓存为空且已登录时,从后端获取菜单
+ if (!state.sourceData.length && util.cookies.get('token')) {
+ const res = await getMenuAll()
+ state.sourceData = res || []
+ await dispatch('d2admin/db/set', {
+ dbName: 'database',
+ path: '$menu.sourceData',
+ value: state.sourceData,
+ user: true
+ }, { root: true })
+ }
+
+ // 构建菜单树和权限字典
+ menu.install(this, state.sourceData)
}
},
mutations: {
- /**
- * @description 设置顶栏菜单
- * @param {Object} state state
- * @param {Array} menu menu setting
- */
+ headerAuth (state, source) {
+ if (!source || source.length <= 0) {
+ return
+ }
+ const auth = {}
+ source.forEach(value => {
+ if (value.url) {
+ auth[value.url] = value.name
+ }
+ })
+ state.authKey = auth
+ },
headerSet (state, menu) {
- // store 赋值
state.header = menu
},
- /**
- * @description 设置侧边栏菜单
- * @param {Object} state state
- * @param {Array} menu menu setting
- */
asideSet (state, menu) {
- // store 赋值
state.aside = menu
}
}
diff --git a/src/views/demo/components/container/api.vue b/src/views/demo/components/container/api.vue
deleted file mode 100644
index e021348d..00000000
--- a/src/views/demo/components/container/api.vue
+++ /dev/null
@@ -1,104 +0,0 @@
-
- { scrollTop = y }">
-
-
-
-
-
-
-
-
-
-
-
- px
-
-
-
-
-
-
-
- 回到顶部
-
-
-
-
-
-
-
-
- 相对滚动 (0, 30) 像素
-
-
- 滚动到 (0, 100) 像素位置
-
-
- 滚动到垂直位置 100
-
-
-
-
-
-
diff --git a/src/views/demo/components/container/card-bs.vue b/src/views/demo/components/container/card-bs.vue
deleted file mode 100644
index e1312736..00000000
--- a/src/views/demo/components/container/card-bs.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- Header
-
- Footer
-
-
-
-
diff --git a/src/views/demo/components/container/card-slot.vue b/src/views/demo/components/container/card-slot.vue
deleted file mode 100644
index ff8b63df..00000000
--- a/src/views/demo/components/container/card-slot.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- Header
-
- Footer
-
-
-
-
diff --git a/src/views/demo/components/container/card.vue b/src/views/demo/components/container/card.vue
deleted file mode 100644
index ec121617..00000000
--- a/src/views/demo/components/container/card.vue
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/container/components/d2-demo-article.vue b/src/views/demo/components/container/components/d2-demo-article.vue
deleted file mode 100644
index 00dc1b43..00000000
--- a/src/views/demo/components/container/components/d2-demo-article.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/container/full-bs.vue b/src/views/demo/components/container/full-bs.vue
deleted file mode 100644
index 9a651025..00000000
--- a/src/views/demo/components/container/full-bs.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- Header
-
- Header
-
-
-
-
diff --git a/src/views/demo/components/container/full-slot.vue b/src/views/demo/components/container/full-slot.vue
deleted file mode 100644
index 087df2a9..00000000
--- a/src/views/demo/components/container/full-slot.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- Header
-
- Footer
-
-
-
-
diff --git a/src/views/demo/components/container/full.vue b/src/views/demo/components/container/full.vue
deleted file mode 100644
index 9d99c936..00000000
--- a/src/views/demo/components/container/full.vue
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/container/ghost-bs.vue b/src/views/demo/components/container/ghost-bs.vue
deleted file mode 100644
index bb41da3b..00000000
--- a/src/views/demo/components/container/ghost-bs.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- Header
-
-
-
-
-
- Footer
-
-
-
-
diff --git a/src/views/demo/components/container/ghost-slot.vue b/src/views/demo/components/container/ghost-slot.vue
deleted file mode 100644
index 831594da..00000000
--- a/src/views/demo/components/container/ghost-slot.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- Header
-
-
-
-
-
- Footer
-
-
-
-
diff --git a/src/views/demo/components/container/ghost.vue b/src/views/demo/components/container/ghost.vue
deleted file mode 100644
index 2c9872c3..00000000
--- a/src/views/demo/components/container/ghost.vue
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/container/md/long.md b/src/views/demo/components/container/md/long.md
deleted file mode 100644
index 59d2f891..00000000
--- a/src/views/demo/components/container/md/long.md
+++ /dev/null
@@ -1,53 +0,0 @@
-## vue.js
-
-**易用**
-
-已经会了 HTML、CSS、JavaScript?即刻阅读指南开始构建应用!
-
-**灵活**
-
-不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
-
-**高效**
-
-20kB min+gzip 运行大小
-
-超快虚拟 DOM
-
-最省心的优化
-
-**Vue.js 是什么**
-
-Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
-
-如果你已经是有经验的前端开发者,想知道 Vue 与其它库/框架有哪些区别,请查看对比其它框架。
-
-## Element
-
-Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
-
-**一致性** Consistency
-
-- 与现实生活一致:与现实生活的流程、逻辑保持一致,遵循用户习惯的语言和概念;
-
-- 在界面中一致:所有的元素和结构需保持一致,比如:设计样式、图标和文本、元素的位置等。
-
-**反馈** Feedback
-
-- 控制反馈:通过界面样式和交互动效让用户可以清晰的感知自己的操作;
-
-- 页面反馈:操作后,通过页面元素的变化清晰地展现当前状态。
-
-**效率** Efficiency
-
-- 简化流程:设计简洁直观的操作流程;
-
-- 清晰明确:语言表达清晰且表意明确,让用户快速理解进而作出决策;
-
-- 帮助用户识别:界面简单直白,让用户快速识别而非回忆,减少用户记忆负担。
-
-**可控** Controllability
-
-- 用户决策:根据场景可给予用户操作建议或安全提示,但不能代替用户进行决策;
-
-- 结果可控:用户可以自由的进行操作,包括撤销、回退和终止当前操作等。
\ No newline at end of file
diff --git a/src/views/demo/components/container/md/short.md b/src/views/demo/components/container/md/short.md
deleted file mode 100644
index 06496563..00000000
--- a/src/views/demo/components/container/md/short.md
+++ /dev/null
@@ -1,17 +0,0 @@
-## vue.js
-
-**易用**
-
-已经会了 HTML、CSS、JavaScript?即刻阅读指南开始构建应用!
-
-**灵活**
-
-不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
-
-**高效**
-
-20kB min+gzip 运行大小
-
-超快虚拟 DOM
-
-最省心的优化
\ No newline at end of file
diff --git a/src/views/demo/components/countup/index.vue b/src/views/demo/components/countup/index.vue
deleted file mode 100644
index 9e952b8d..00000000
--- a/src/views/demo/components/countup/index.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
- 数字动画组件
-
-
-
- 只设置目标数字
-
-
-
-
-
-
-
- 设置起止数值
-
-
-
-
-
-
-
- 小数位数
-
-
-
-
-
-
-
- 动画时长
-
-
-
-
-
-
-
- 回调函数
-
-
-
-
-
-
-
- 结束一秒后更新数值
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/editor-quill/index.vue b/src/views/demo/components/editor-quill/index.vue
deleted file mode 100644
index dc456e55..00000000
--- a/src/views/demo/components/editor-quill/index.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
-
- 添加一行
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/editor-quill/value.js b/src/views/demo/components/editor-quill/value.js
deleted file mode 100644
index 89744593..00000000
--- a/src/views/demo/components/editor-quill/value.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default `
-D2 Admin
-
-by
-vue.js
-
`
diff --git a/src/views/demo/components/editor-ueditor/index.vue b/src/views/demo/components/editor-ueditor/index.vue
deleted file mode 100644
index c2d0ab3f..00000000
--- a/src/views/demo/components/editor-ueditor/index.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
- Result
-
-
-
-
-
-
- 当前内容 x2
-
-
- 清空
-
-
-
-
-
-
diff --git a/src/views/demo/components/highlight/code/css.js b/src/views/demo/components/highlight/code/css.js
deleted file mode 100644
index f41e0a90..00000000
--- a/src/views/demo/components/highlight/code/css.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default `body {
- background-color: aliceblue;
- height: 100%;
-}
-.my-card {
- height: 300px;
- width: 300px;
-}`
diff --git a/src/views/demo/components/highlight/code/html.js b/src/views/demo/components/highlight/code/html.js
deleted file mode 100644
index 739a2b9d..00000000
--- a/src/views/demo/components/highlight/code/html.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default `
- Hello
- -
-
- Hello
-
-
-
`
diff --git a/src/views/demo/components/highlight/code/javascript.js b/src/views/demo/components/highlight/code/javascript.js
deleted file mode 100644
index ce752335..00000000
--- a/src/views/demo/components/highlight/code/javascript.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export default `[].forEach.call($$("*"), a => {
- a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
-})`
diff --git a/src/views/demo/components/highlight/code/scss.js b/src/views/demo/components/highlight/code/scss.js
deleted file mode 100644
index d914909c..00000000
--- a/src/views/demo/components/highlight/code/scss.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export default `body {
- background-color: aliceblue;
- height: 100%;
- .my-card {
- height: 300px;
- width: 300px;
- }
-}`
diff --git a/src/views/demo/components/highlight/index.vue b/src/views/demo/components/highlight/index.vue
deleted file mode 100644
index ea77e68a..00000000
--- a/src/views/demo/components/highlight/index.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- 代码高亮组件
-
- javascript
-
-
-
- css
-
-
-
- scss
-
-
-
- html
-
-
-
-
-
-
diff --git a/src/views/demo/components/icon/components/d2-icon-cell.vue b/src/views/demo/components/icon/components/d2-icon-cell.vue
deleted file mode 100644
index 603004f0..00000000
--- a/src/views/demo/components/icon/components/d2-icon-cell.vue
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
-
-
- Class
-
-
-
-
- HTML
-
-
-
-
- 组件
-
-
-
-
-
-
-
-
- {{icon}}
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/icon/data/index.js b/src/views/demo/components/icon/data/index.js
deleted file mode 100644
index 3283c245..00000000
--- a/src/views/demo/components/icon/data/index.js
+++ /dev/null
@@ -1,1004 +0,0 @@
-// 4.7.0
-
-export default [
- {
- title: '网页',
- icon: [
- 'address-book',
- 'address-book-o',
- 'address-card',
- 'address-card-o',
- 'adjust',
- 'american-sign-language-interpreting',
- 'anchor',
- 'archive',
- 'area-chart',
- 'arrows',
- 'arrows-h',
- 'arrows-v',
- 'asl-interpreting',
- 'assistive-listening-systems',
- 'asterisk',
- 'at',
- 'audio-description',
- 'automobile',
- 'balance-scale',
- 'ban',
- 'bank',
- 'bar-chart',
- 'bar-chart-o',
- 'barcode',
- 'bars',
- 'bath',
- 'bathtub',
- 'battery',
- 'battery-0',
- 'battery-1',
- 'battery-2',
- 'battery-3',
- 'battery-4',
- 'battery-empty',
- 'battery-full',
- 'battery-half',
- 'battery-quarter',
- 'battery-three-quarters',
- 'bed',
- 'beer',
- 'bell',
- 'bell-o',
- 'bell-slash',
- 'bell-slash-o',
- 'bicycle',
- 'binoculars',
- 'birthday-cake',
- 'blind',
- 'bluetooth',
- 'bluetooth-b',
- 'bolt',
- 'bomb',
- 'book',
- 'bookmark',
- 'bookmark-o',
- 'braille',
- 'briefcase',
- 'bug',
- 'building',
- 'building-o',
- 'bullhorn',
- 'bullseye',
- 'bus',
- 'cab',
- 'calculator',
- 'calendar',
- 'calendar-check-o',
- 'calendar-minus-o',
- 'calendar-o',
- 'calendar-plus-o',
- 'calendar-times-o',
- 'camera',
- 'camera-retro',
- 'car',
- 'caret-square-o-down',
- 'caret-square-o-left',
- 'caret-square-o-right',
- 'caret-square-o-up',
- 'cart-arrow-down',
- 'cart-plus',
- 'cc',
- 'certificate',
- 'check',
- 'check-circle',
- 'check-circle-o',
- 'check-square',
- 'check-square-o',
- 'child',
- 'circle',
- 'circle-o',
- 'circle-o-notch',
- 'circle-thin',
- 'clock-o',
- 'clone',
- 'close',
- 'cloud',
- 'cloud-download',
- 'cloud-upload',
- 'code',
- 'code-fork',
- 'coffee',
- 'cog',
- 'cogs',
- 'comment',
- 'comment-o',
- 'commenting',
- 'commenting-o',
- 'comments',
- 'comments-o',
- 'compass',
- 'copyright',
- 'creative-commons',
- 'credit-card',
- 'credit-card-alt',
- 'crop',
- 'crosshairs',
- 'cube',
- 'cubes',
- 'cutlery',
- 'index',
- 'database',
- 'deaf',
- 'deafness',
- 'desktop',
- 'diamond',
- 'dot-circle-o',
- 'download',
- 'drivers-license',
- 'drivers-license-o',
- 'edit',
- 'ellipsis-h',
- 'ellipsis-v',
- 'envelope',
- 'envelope-o',
- 'envelope-open',
- 'envelope-open-o',
- 'envelope-square',
- 'eraser',
- 'exchange',
- 'exclamation',
- 'exclamation-circle',
- 'exclamation-triangle',
- 'external-link',
- 'external-link-square',
- 'eye',
- 'eye-slash',
- 'eyedropper',
- 'fax',
- 'feed',
- 'female',
- 'fighter-jet',
- 'file-archive-o',
- 'file-audio-o',
- 'file-code-o',
- 'file-excel-o',
- 'file-image-o',
- 'file-movie-o',
- 'file-pdf-o',
- 'file-photo-o',
- 'file-picture-o',
- 'file-powerpoint-o',
- 'file-sound-o',
- 'file-video-o',
- 'file-word-o',
- 'file-zip-o',
- 'film',
- 'filter',
- 'fire',
- 'fire-extinguisher',
- 'flag',
- 'flag-checkered',
- 'flag-o',
- 'flash',
- 'flask',
- 'folder',
- 'folder-o',
- 'folder-open',
- 'folder-open-o',
- 'frown-o',
- 'futbol-o',
- 'gamepad',
- 'gavel',
- 'gear',
- 'gears',
- 'gift',
- 'glass',
- 'globe',
- 'graduation-cap',
- 'group',
- 'hand-grab-o',
- 'hand-lizard-o',
- 'hand-paper-o',
- 'hand-peace-o',
- 'hand-pointer-o',
- 'hand-rock-o',
- 'hand-scissors-o',
- 'hand-spock-o',
- 'hand-stop-o',
- 'handshake-o',
- 'hard-of-hearing',
- 'hashtag',
- 'hdd-o',
- 'headphones',
- 'heart',
- 'heart-o',
- 'heartbeat',
- 'history',
- 'home',
- 'hotel',
- 'hourglass',
- 'hourglass-1',
- 'hourglass-2',
- 'hourglass-3',
- 'hourglass-end',
- 'hourglass-half',
- 'hourglass-o',
- 'hourglass-start',
- 'i-cursor',
- 'id-badge',
- 'id-card',
- 'id-card-o',
- 'image',
- 'inbox',
- 'industry',
- 'info',
- 'info-circle',
- 'institution',
- 'key',
- 'keyboard-o',
- 'language',
- 'laptop',
- 'leaf',
- 'legal',
- 'lemon-o',
- 'level-down',
- 'level-up',
- 'life-bouy',
- 'life-buoy',
- 'life-ring',
- 'life-saver',
- 'lightbulb-o',
- 'line-chart',
- 'location-arrow',
- 'lock',
- 'low-vision',
- 'magic',
- 'magnet',
- 'mail-forward',
- 'mail-reply',
- 'mail-reply-all',
- 'male',
- 'map',
- 'map-marker',
- 'map-o',
- 'map-pin',
- 'map-signs',
- 'meh-o',
- 'microchip',
- 'microphone',
- 'microphone-slash',
- 'minus',
- 'minus-circle',
- 'minus-square',
- 'minus-square-o',
- 'mobile',
- 'mobile-phone',
- 'money',
- 'moon-o',
- 'mortar-board',
- 'motorcycle',
- 'mouse-pointer',
- 'music',
- 'navicon',
- 'newspaper-o',
- 'object-group',
- 'object-ungroup',
- 'paint-brush',
- 'paper-plane',
- 'paper-plane-o',
- 'paw',
- 'pencil',
- 'pencil-square',
- 'pencil-square-o',
- 'percent',
- 'phone',
- 'phone-square',
- 'photo',
- 'picture-o',
- 'pie-chart',
- 'plane',
- 'plug',
- 'plus',
- 'plus-circle',
- 'plus-square',
- 'plus-square-o',
- 'podcast',
- 'power-off',
- 'print',
- 'puzzle-piece',
- 'qrcode',
- 'question',
- 'question-circle',
- 'question-circle-o',
- 'quote-left',
- 'quote-right',
- 'random',
- 'recycle',
- 'refresh',
- 'registered',
- 'remove',
- 'reorder',
- 'reply',
- 'reply-all',
- 'retweet',
- 'road',
- 'rocket',
- 'rss',
- 'rss-square',
- 's15',
- 'search',
- 'search-minus',
- 'search-plus',
- 'send',
- 'send-o',
- 'server',
- 'share',
- 'share-alt',
- 'share-alt-square',
- 'share-square',
- 'share-square-o',
- 'shield',
- 'ship',
- 'shopping-bag',
- 'shopping-basket',
- 'shopping-cart',
- 'shower',
- 'sign-in',
- 'sign-language',
- 'sign-out',
- 'signal',
- 'signing',
- 'sitemap',
- 'sliders',
- 'smile-o',
- 'snowflake-o',
- 'soccer-ball-o',
- 'sort',
- 'sort-alpha-asc',
- 'sort-alpha-desc',
- 'sort-amount-asc',
- 'sort-amount-desc',
- 'sort-asc',
- 'sort-desc',
- 'sort-down',
- 'sort-numeric-asc',
- 'sort-numeric-desc',
- 'sort-up',
- 'space-shuttle',
- 'spinner',
- 'spoon',
- 'square',
- 'square-o',
- 'star',
- 'star-half',
- 'star-half-empty',
- 'star-half-full',
- 'star-half-o',
- 'star-o',
- 'sticky-note',
- 'sticky-note-o',
- 'street-view',
- 'suitcase',
- 'sun-o',
- 'support',
- 'tablet',
- 'tachometer',
- 'tag',
- 'tags',
- 'tasks',
- 'taxi',
- 'television',
- 'terminal',
- 'thermometer',
- 'thermometer-0',
- 'thermometer-1',
- 'thermometer-2',
- 'thermometer-3',
- 'thermometer-4',
- 'thermometer-empty',
- 'thermometer-full',
- 'thermometer-half',
- 'thermometer-quarter',
- 'thermometer-three-quarters',
- 'thumb-tack',
- 'thumbs-down',
- 'thumbs-o-down',
- 'thumbs-o-up',
- 'thumbs-up',
- 'ticket',
- 'times',
- 'times-circle',
- 'times-circle-o',
- 'times-rectangle',
- 'times-rectangle-o',
- 'tint',
- 'toggle-down',
- 'toggle-left',
- 'toggle-off',
- 'toggle-on',
- 'toggle-right',
- 'toggle-up',
- 'trademark',
- 'trash',
- 'trash-o',
- 'tree',
- 'trophy',
- 'truck',
- 'tty',
- 'tv',
- 'umbrella',
- 'universal-access',
- 'university',
- 'unlock',
- 'unlock-alt',
- 'unsorted',
- 'upload',
- 'user',
- 'user-circle',
- 'user-circle-o',
- 'user-o',
- 'user-plus',
- 'user-secret',
- 'user-times',
- 'users',
- 'vcard',
- 'vcard-o',
- 'video-camera',
- 'volume-control-phone',
- 'volume-down',
- 'volume-off',
- 'volume-up',
- 'warning',
- 'wheelchair',
- 'wheelchair-alt',
- 'wifi',
- 'window-close',
- 'window-close-o',
- 'window-maximize',
- 'window-minimize',
- 'window-restore',
- 'wrench'
- ]
- },
- {
- title: '辅助功能',
- icon: [
- 'american-sign-language-interpreting',
- 'asl-interpreting',
- 'assistive-listening-systems',
- 'audio-description',
- 'blind',
- 'braille',
- 'cc',
- 'deaf',
- 'deafness',
- 'hard-of-hearing',
- 'low-vision',
- 'question-circle-o',
- 'sign-language',
- 'signing',
- 'tty',
- 'universal-access',
- 'volume-control-phone',
- 'wheelchair',
- 'wheelchair-alt'
- ]
- },
- {
- title: '手势',
- icon: [
- 'hand-grab-o',
- 'hand-lizard-o',
- 'hand-o-down',
- 'hand-o-left',
- 'hand-o-right',
- 'hand-o-up',
- 'hand-paper-o',
- 'hand-peace-o',
- 'hand-pointer-o',
- 'hand-rock-o',
- 'hand-scissors-o',
- 'hand-spock-o',
- 'hand-stop-o',
- 'thumbs-down',
- 'thumbs-o-down',
- 'thumbs-o-up',
- 'thumbs-up'
- ]
- },
- {
- title: '运输',
- icon: [
- 'ambulance',
- 'automobile',
- 'bicycle',
- 'bus',
- 'cab',
- 'car',
- 'fighter-jet',
- 'motorcycle',
- 'plane',
- 'rocket',
- 'ship',
- 'space-shuttle',
- 'subway',
- 'taxi',
- 'train',
- 'truck',
- 'wheelchair',
- 'wheelchair-alt'
- ]
- },
- {
- title: '性别',
- icon: [
- 'genderless',
- 'intersex',
- 'mars',
- 'mars-double',
- 'mars-stroke',
- 'mars-stroke-h',
- 'mars-stroke-v',
- 'mercury',
- 'neuter',
- 'transgender',
- 'transgender-alt',
- 'venus',
- 'venus-double',
- 'venus-mars'
- ]
- },
- {
- title: '文件类型',
- icon: [
- 'file',
- 'file-archive-o',
- 'file-audio-o',
- 'file-code-o',
- 'file-excel-o',
- 'file-image-o',
- 'file-movie-o',
- 'file-o',
- 'file-pdf-o',
- 'file-photo-o',
- 'file-picture-o',
- 'file-powerpoint-o',
- 'file-sound-o',
- 'file-text',
- 'file-text-o',
- 'file-video-o',
- 'file-word-o',
- 'file-zip-o'
- ]
- },
- {
- title: '可旋转',
- icon: [
- 'circle-o-notch',
- 'cog',
- 'gear',
- 'refresh',
- 'spinner'
- ]
- },
- {
- title: '表单',
- icon: [
- 'check-square',
- 'check-square-o',
- 'circle',
- 'circle-o',
- 'dot-circle-o',
- 'minus-square',
- 'minus-square-o',
- 'plus-square',
- 'plus-square-o',
- 'square',
- 'square-o'
- ]
- },
- {
- title: '支付',
- icon: [
- 'cc-amex',
- 'cc-diners-club',
- 'cc-discover',
- 'cc-jcb',
- 'cc-mastercard',
- 'cc-paypal',
- 'cc-stripe',
- 'cc-visa',
- 'credit-card',
- 'credit-card-alt',
- 'google-wallet',
- 'paypal'
- ]
- },
- {
- title: '图表',
- icon: [
- 'area-chart',
- 'bar-chart',
- 'bar-chart-o',
- 'line-chart',
- 'pie-chart'
- ]
- },
- {
- title: '货币',
- icon: [
- 'bitcoin',
- 'btc',
- 'cny',
- 'dollar',
- 'eur',
- 'euro',
- 'gbp',
- 'gg',
- 'gg-circle',
- 'ils',
- 'inr',
- 'jpy',
- 'krw',
- 'money',
- 'rmb',
- 'rouble',
- 'rub',
- 'ruble',
- 'rupee',
- 'shekel',
- 'sheqel',
- 'try',
- 'turkish-lira',
- 'usd',
- 'won',
- 'yen'
- ]
- },
- {
- title: '文本编辑',
- icon: [
- 'align-center',
- 'align-justify',
- 'align-left',
- 'align-right',
- 'bold',
- 'chain',
- 'chain-broken',
- 'clipboard',
- 'columns',
- 'copy',
- 'cut',
- 'dedent',
- 'eraser',
- 'file',
- 'file-o',
- 'file-text',
- 'file-text-o',
- 'files-o',
- 'floppy-o',
- 'font',
- 'header',
- 'indent',
- 'italic',
- 'link',
- 'list',
- 'list-alt',
- 'list-ol',
- 'list-ul',
- 'outdent',
- 'paperclip',
- 'paragraph',
- 'paste',
- 'repeat',
- 'rotate-left',
- 'rotate-right',
- 'save',
- 'scissors',
- 'strikethrough',
- 'subscript',
- 'superscript',
- 'table',
- 'text-height',
- 'text-width',
- 'th',
- 'th-large',
- 'th-list',
- 'underline',
- 'undo',
- 'unlink'
- ]
- },
- {
- title: '指示方向',
- icon: [
- 'angle-double-down',
- 'angle-double-left',
- 'angle-double-right',
- 'angle-double-up',
- 'angle-down',
- 'angle-left',
- 'angle-right',
- 'angle-up',
- 'arrow-circle-down',
- 'arrow-circle-left',
- 'arrow-circle-o-down',
- 'arrow-circle-o-left',
- 'arrow-circle-o-right',
- 'arrow-circle-o-up',
- 'arrow-circle-right',
- 'arrow-circle-up',
- 'arrow-down',
- 'arrow-left',
- 'arrow-right',
- 'arrow-up',
- 'arrows',
- 'arrows-alt',
- 'arrows-h',
- 'arrows-v',
- 'caret-down',
- 'caret-left',
- 'caret-right',
- 'caret-square-o-down',
- 'caret-square-o-left',
- 'caret-square-o-right',
- 'caret-square-o-up',
- 'caret-up',
- 'chevron-circle-down',
- 'chevron-circle-left',
- 'chevron-circle-right',
- 'chevron-circle-up',
- 'chevron-down',
- 'chevron-left',
- 'chevron-right',
- 'chevron-up',
- 'exchange',
- 'hand-o-down',
- 'hand-o-left',
- 'hand-o-right',
- 'hand-o-up',
- 'long-arrow-down',
- 'long-arrow-left',
- 'long-arrow-right',
- 'long-arrow-up',
- 'toggle-down',
- 'toggle-left',
- 'toggle-right',
- 'toggle-up'
- ]
- },
- {
- title: '视频播放',
- icon: [
- 'arrows-alt',
- 'backward',
- 'compress',
- 'eject',
- 'expand',
- 'fast-backward',
- 'fast-forward',
- 'forward',
- 'pause',
- 'pause-circle',
- 'pause-circle-o',
- 'play',
- 'play-circle',
- 'play-circle-o',
- 'random',
- 'step-backward',
- 'step-forward',
- 'stop',
- 'stop-circle',
- 'stop-circle-o',
- 'youtube-play'
- ]
- },
- {
- title: '标志',
- icon: [
- '500px',
- 'adn',
- 'amazon',
- 'android',
- 'angellist',
- 'apple',
- 'bandcamp',
- 'behance',
- 'behance-square',
- 'bitbucket',
- 'bitbucket-square',
- 'bitcoin',
- 'black-tie',
- 'bluetooth',
- 'bluetooth-b',
- 'btc',
- 'buysellads',
- 'cc-amex',
- 'cc-diners-club',
- 'cc-discover',
- 'cc-jcb',
- 'cc-mastercard',
- 'cc-paypal',
- 'cc-stripe',
- 'cc-visa',
- 'chrome',
- 'codepen',
- 'codiepie',
- 'connectdevelop',
- 'contao',
- 'css3',
- 'dashcube',
- 'delicious',
- 'deviantart',
- 'digg',
- 'dribbble',
- 'dropbox',
- 'drupal',
- 'edge',
- 'eercast',
- 'empire',
- 'envira',
- 'etsy',
- 'expeditedssl',
- 'fa',
- 'facebook',
- 'facebook-f',
- 'facebook-official',
- 'facebook-square',
- 'firefox',
- 'first-order',
- 'flickr',
- 'font-awesome',
- 'fonticons',
- 'fort-awesome',
- 'forumbee',
- 'foursquare',
- 'free-code-camp',
- 'ge',
- 'get-pocket',
- 'gg',
- 'gg-circle',
- 'git',
- 'git-square',
- 'github',
- 'github-alt',
- 'github-square',
- 'gitlab',
- 'gittip',
- 'glide',
- 'glide-g',
- 'google',
- 'google-plus',
- 'google-plus-circle',
- 'google-plus-official',
- 'google-plus-square',
- 'google-wallet',
- 'gratipay',
- 'grav',
- 'hacker-news',
- 'houzz',
- 'html5',
- 'imdb',
- 'instagram',
- 'internet-explorer',
- 'ioxhost',
- 'joomla',
- 'jsfiddle',
- 'lastfm',
- 'lastfm-square',
- 'leanpub',
- 'linkedin',
- 'linkedin-square',
- 'linode',
- 'linux',
- 'maxcdn',
- 'meanpath',
- 'medium',
- 'meetup',
- 'mixcloud',
- 'modx',
- 'odnoklassniki',
- 'odnoklassniki-square',
- 'opencart',
- 'openid',
- 'opera',
- 'optin-monster',
- 'pagelines',
- 'paypal',
- 'pied-piper',
- 'pied-piper-alt',
- 'pied-piper-pp',
- 'pinterest',
- 'pinterest-p',
- 'pinterest-square',
- 'product-hunt',
- 'qq',
- 'quora',
- 'ra',
- 'ravelry',
- 'rebel',
- 'reddit',
- 'reddit-alien',
- 'reddit-square',
- 'renren',
- 'resistance',
- 'safari',
- 'scribd',
- 'sellsy',
- 'share-alt',
- 'share-alt-square',
- 'shirtsinbulk',
- 'simplybuilt',
- 'skyatlas',
- 'skype',
- 'slack',
- 'slideshare',
- 'snapchat',
- 'snapchat-ghost',
- 'snapchat-square',
- 'soundcloud',
- 'spotify',
- 'stack-exchange',
- 'stack-overflow',
- 'steam',
- 'steam-square',
- 'stumbleupon',
- 'stumbleupon-circle',
- 'superpowers',
- 'telegram',
- 'tencent-weibo',
- 'themeisle',
- 'trello',
- 'tripadvisor',
- 'tumblr',
- 'tumblr-square',
- 'twitch',
- 'twitter',
- 'twitter-square',
- 'usb',
- 'viacoin',
- 'viadeo',
- 'viadeo-square',
- 'vimeo',
- 'vimeo-square',
- 'vine',
- 'vk',
- 'wechat',
- 'weibo',
- 'weixin',
- 'whatsapp',
- 'wikipedia-w',
- 'windows',
- 'wordpress',
- 'wpbeginner',
- 'wpexplorer',
- 'wpforms',
- 'xing',
- 'xing-square',
- 'y-combinator',
- 'y-combinator-square',
- 'yahoo',
- 'yc',
- 'yc-square',
- 'yelp',
- 'yoast',
- 'youtube',
- 'youtube-play',
- 'youtube-square'
- ]
- },
- {
- title: '医疗',
- icon: [
- 'ambulance',
- 'h-square',
- 'heart',
- 'heart-o',
- 'heartbeat',
- 'hospital-o',
- 'medkit',
- 'plus-square',
- 'stethoscope',
- 'user-md',
- 'wheelchair',
- 'wheelchair-alt'
- ]
- }
-]
diff --git a/src/views/demo/components/icon/icon-svg.vue b/src/views/demo/components/icon/icon-svg.vue
deleted file mode 100644
index f55091cd..00000000
--- a/src/views/demo/components/icon/icon-svg.vue
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
- SVG图标组件
-
-
-
-
- {{icon}}
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/icon/icon.vue b/src/views/demo/components/icon/icon.vue
deleted file mode 100644
index ba4eb5c7..00000000
--- a/src/views/demo/components/icon/icon.vue
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
- 图标组件
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/icon/list.vue b/src/views/demo/components/icon/list.vue
deleted file mode 100644
index df9ed473..00000000
--- a/src/views/demo/components/icon/list.vue
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
- {{item.label}}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/icon/select-svg.vue b/src/views/demo/components/icon/select-svg.vue
deleted file mode 100644
index 6c3ecd76..00000000
--- a/src/views/demo/components/icon/select-svg.vue
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
- svg 图标选择器
-
-
一般用法 | {{icon || '未选择'}}
-
-
-
-
用户可以输入 | {{icon2 || '未选择'}}
-
-
-
-
-
-
diff --git a/src/views/demo/components/icon/select.vue b/src/views/demo/components/icon/select.vue
deleted file mode 100644
index 138c4e9d..00000000
--- a/src/views/demo/components/icon/select.vue
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
- 图标选择器
-
-
一般用法
-
-
- 选择的图标 {{icon}}
-
-
- 未选择
-
-
-
-
-
用户可以输入
-
-
- 选择的图标 {{icon2}}
-
-
- 未选择
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/index/index.vue b/src/views/demo/components/index/index.vue
deleted file mode 100644
index 62126807..00000000
--- a/src/views/demo/components/index/index.vue
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/json-tree/index.vue b/src/views/demo/components/json-tree/index.vue
deleted file mode 100644
index cd9c16d8..00000000
--- a/src/views/demo/components/json-tree/index.vue
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/layout/grid.vue b/src/views/demo/components/layout/grid.vue
deleted file mode 100644
index 875aa7bb..00000000
--- a/src/views/demo/components/layout/grid.vue
+++ /dev/null
@@ -1,122 +0,0 @@
-
-
-
-
-
- Card {{item.i}}
-
- 拖拽卡片调整位置
- 拖拽卡片右下角的手柄调整卡片大小
- 在控制台打印出数据变化
-
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/layout/splitpane.vue b/src/views/demo/components/layout/splitpane.vue
deleted file mode 100644
index eb07a75c..00000000
--- a/src/views/demo/components/layout/splitpane.vue
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
- 区域划分
-
-
- 左
-
-
- 右上
- 右下
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/components/markdown/md/doc.md b/src/views/demo/components/markdown/md/doc.md
deleted file mode 100644
index 189e9773..00000000
--- a/src/views/demo/components/markdown/md/doc.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# 一级标题
-
-| ID | Name | Email |
-| --- | --- | --- |
-| 0001 | FairyEver | 1711467488@qq.com |
-
-```
-// 注释
-[].forEach.call($$("*"), a => {
- a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)
-})
-```
-
-```
-
-```
-
-```
-body {
- background-color: #333;
-}
-```
-
-一般引用
-
-> 引用文字
-
-分享一个我很早前的一副设计作品 [in Lofter](http://fairyever.lofter.com/post/16ff00_6796fe8) 借此演示百度云链接的显示优化
-
-> https://pan.baidu.com/s/1kW6uUwB
-
-设计源文件
-
-> 链接: https://pan.baidu.com/s/1ggFW21l 密码: 877y
-
-[https://github.com/d2-projects](https://github.com/d2-projects)
\ No newline at end of file
diff --git a/src/views/demo/components/markdown/source.vue b/src/views/demo/components/markdown/source.vue
deleted file mode 100644
index 0a4bda98..00000000
--- a/src/views/demo/components/markdown/source.vue
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- 指定资源
-
-
-
-
-
diff --git a/src/views/demo/components/markdown/url.vue b/src/views/demo/components/markdown/url.vue
deleted file mode 100644
index 49461394..00000000
--- a/src/views/demo/components/markdown/url.vue
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- 异步加载文件
-
-
-
diff --git a/src/views/demo/playground/add-routes/alternates/1.vue b/src/views/demo/playground/add-routes/alternates/1.vue
deleted file mode 100644
index f99165a0..00000000
--- a/src/views/demo/playground/add-routes/alternates/1.vue
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- src/views/demo/playground/add-routes/alternates/1.vue
-
-
diff --git a/src/views/demo/playground/add-routes/alternates/2.vue b/src/views/demo/playground/add-routes/alternates/2.vue
deleted file mode 100644
index e03c9f47..00000000
--- a/src/views/demo/playground/add-routes/alternates/2.vue
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- src/views/demo/playground/add-routes/alternates/2.vue
-
-
diff --git a/src/views/demo/playground/add-routes/alternates/3.vue b/src/views/demo/playground/add-routes/alternates/3.vue
deleted file mode 100644
index 47670bc1..00000000
--- a/src/views/demo/playground/add-routes/alternates/3.vue
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- src/views/demo/playground/add-routes/alternates/3.vue
-
-
diff --git a/src/views/demo/playground/add-routes/routes.vue b/src/views/demo/playground/add-routes/routes.vue
deleted file mode 100644
index 1f18e316..00000000
--- a/src/views/demo/playground/add-routes/routes.vue
+++ /dev/null
@@ -1,109 +0,0 @@
-
-
-
-
-
-
-
-
- {{item.title}}
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/db/all/index.vue b/src/views/demo/playground/db/all/index.vue
deleted file mode 100644
index d5722d1d..00000000
--- a/src/views/demo/playground/db/all/index.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
- 重新获取本地数据
-
-
-
-
-
diff --git a/src/views/demo/playground/db/page-public/index.vue b/src/views/demo/playground/db/page-public/index.vue
deleted file mode 100644
index 69c8f1b5..00000000
--- a/src/views/demo/playground/db/page-public/index.vue
+++ /dev/null
@@ -1,127 +0,0 @@
-
-
-
-
-
-
-
- 增加不重复字段
- 增加
- 增加自定义字段
-
-
- 增加
- 删除字段
-
-
-
-
- 清空当前用户数据
- 清空
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/db/page-snapshot-public/index.vue b/src/views/demo/playground/db/page-snapshot-public/index.vue
deleted file mode 100644
index 48a5c337..00000000
--- a/src/views/demo/playground/db/page-snapshot-public/index.vue
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 立即创建
- 取消
-
-
-
-
- 删除当前页面快照
-
-
-
-
-
diff --git a/src/views/demo/playground/db/page-snapshot-user/index.vue b/src/views/demo/playground/db/page-snapshot-user/index.vue
deleted file mode 100644
index d59dc958..00000000
--- a/src/views/demo/playground/db/page-snapshot-user/index.vue
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 立即创建
- 取消
-
-
-
-
- 删除当前页面快照
-
-
-
-
-
diff --git a/src/views/demo/playground/db/page-user/index.vue b/src/views/demo/playground/db/page-user/index.vue
deleted file mode 100644
index 0283872d..00000000
--- a/src/views/demo/playground/db/page-user/index.vue
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
-
-
-
- 增加不重复字段
- 增加
- 增加自定义字段
-
-
- 增加
- 删除字段
-
-
-
-
- 清空当前用户数据
- 清空
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/db/public/index.vue b/src/views/demo/playground/db/public/index.vue
deleted file mode 100644
index 576b7ea5..00000000
--- a/src/views/demo/playground/db/public/index.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-
-
-
-
-
-
-
- 增加不重复字段
- 增加
- 增加自定义字段
-
-
- 增加
- 删除字段
-
-
-
-
- 清空当前用户数据
- 清空
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/db/user/index.vue b/src/views/demo/playground/db/user/index.vue
deleted file mode 100644
index bd523433..00000000
--- a/src/views/demo/playground/db/user/index.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
-
- 增加不重复字段
- 增加
- 增加自定义字段
-
-
- 增加
- 删除字段
-
-
-
-
- 清空当前用户数据
- 清空
-
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/env/index.vue b/src/views/demo/playground/env/index.vue
deleted file mode 100644
index 66bb400a..00000000
--- a/src/views/demo/playground/env/index.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
- process.env
-
-
-
-
-
diff --git a/src/views/demo/playground/frame/d2-doc/index.vue b/src/views/demo/playground/frame/d2-doc/index.vue
deleted file mode 100644
index 82e9b26b..00000000
--- a/src/views/demo/playground/frame/d2-doc/index.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/src/views/demo/playground/frame/html/index.vue b/src/views/demo/playground/frame/html/index.vue
deleted file mode 100644
index 8c4bafc9..00000000
--- a/src/views/demo/playground/frame/html/index.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/src/views/demo/playground/frame/report/index.vue b/src/views/demo/playground/frame/report/index.vue
deleted file mode 100644
index d1867ff6..00000000
--- a/src/views/demo/playground/frame/report/index.vue
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/src/views/demo/playground/index/index.vue b/src/views/demo/playground/index/index.vue
deleted file mode 100644
index 204fddf1..00000000
--- a/src/views/demo/playground/index/index.vue
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/locales/index.vue b/src/views/demo/playground/locales/index.vue
deleted file mode 100644
index d7da8fe5..00000000
--- a/src/views/demo/playground/locales/index.vue
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
- {{ language.label }}
-
-
-
-
-
-
-
-
diff --git a/src/views/demo/playground/log/ajax/index.vue b/src/views/demo/playground/log/ajax/index.vue
deleted file mode 100644
index 1e3fd621..00000000
--- a/src/views/demo/playground/log/ajax/index.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
- Ajax 错误
- 请打开浏览器控制台,然后点击下面的按钮,尝试访问一个不存在的网络地址
- 请求错误的地址
- 此错误已经被记录在日志页面,并在页面右上"日志按钮"区域显示提示信息
-
-
-
-
diff --git a/src/views/demo/playground/log/console/image/demo.png b/src/views/demo/playground/log/console/image/demo.png
deleted file mode 100644
index 35a5c716cffd640daf38b058ac428e434cd440bc..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 66362
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