From 0a709907bf12087e2f76aa3fc319bf8853d33263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=87=E7=BA=AF?= Date: Tue, 22 Dec 2020 17:54:46 +0800 Subject: [PATCH] feat: plugin-layout --- package-lock.json | 2 +- packages/fes-plugin-layout/README.md | 5 + packages/fes-plugin-layout/package.json | 3 +- packages/fes-plugin-layout/src/helpers.js | 1 - .../src/helpers/addAccessTag.js | 35 ++++ .../fes-plugin-layout/src/helpers/index.js | 65 ++++++++ packages/fes-plugin-layout/src/index.js | 64 ++++---- .../src/template/runtime.tpl | 45 +++--- .../src/views/BaseLayout.vue | 151 ++++++++++++++++++ packages/fes-plugin-layout/src/views/Menu.vue | 104 ++++++++++++ .../fes-plugin-layout/src/views/layout.vue | 99 ------------ .../src/plugins/commands/dev/index.js | 1 - .../src/plugins/misc/route/index.js | 7 + packages/fes-template/.fes.js | 10 +- packages/fes-template/src/app.js | 11 +- .../src/components/PageLoading.vue | 2 +- .../src/components/UserCenter.vue | 15 ++ packages/fes-template/src/pages/index.vue | 3 +- packages/fes-template/src/pages/onepiece.vue | 4 +- 19 files changed, 463 insertions(+), 164 deletions(-) create mode 100644 packages/fes-plugin-layout/README.md delete mode 100644 packages/fes-plugin-layout/src/helpers.js create mode 100644 packages/fes-plugin-layout/src/helpers/addAccessTag.js create mode 100644 packages/fes-plugin-layout/src/helpers/index.js create mode 100644 packages/fes-plugin-layout/src/views/Menu.vue delete mode 100644 packages/fes-plugin-layout/src/views/layout.vue create mode 100644 packages/fes-template/src/components/UserCenter.vue diff --git a/package-lock.json b/package-lock.json index f571eb63..f714bd41 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "fes.js", - "version": "0.1.0", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/fes-plugin-layout/README.md b/packages/fes-plugin-layout/README.md new file mode 100644 index 00000000..46ae75dd --- /dev/null +++ b/packages/fes-plugin-layout/README.md @@ -0,0 +1,5 @@ +主题: light/dark +布局: 左右(上/下)、上/下、上/下(左/右) +固定Header: 是/否 +固定sidebar: 是/否 +multi tabs: 是/否 diff --git a/packages/fes-plugin-layout/package.json b/packages/fes-plugin-layout/package.json index 88da06ce..bdb34f5a 100644 --- a/packages/fes-plugin-layout/package.json +++ b/packages/fes-plugin-layout/package.json @@ -15,6 +15,7 @@ "license": "MIT", "peerDependencies": { "vue": "^3.0.0", - "@webank/fes": "^2.0.0" + "@webank/fes": "^2.0.0", + "ant-design-vue": "2.0.0-rc.3" } } diff --git a/packages/fes-plugin-layout/src/helpers.js b/packages/fes-plugin-layout/src/helpers.js deleted file mode 100644 index b9743ef1..00000000 --- a/packages/fes-plugin-layout/src/helpers.js +++ /dev/null @@ -1 +0,0 @@ -export const noop = () => { }; diff --git a/packages/fes-plugin-layout/src/helpers/addAccessTag.js b/packages/fes-plugin-layout/src/helpers/addAccessTag.js new file mode 100644 index 00000000..feedb371 --- /dev/null +++ b/packages/fes-plugin-layout/src/helpers/addAccessTag.js @@ -0,0 +1,35 @@ +import { unref, computed } from 'vue'; +import { useAccess } from '@webank/fes'; + +if (!useAccess) { + throw new Error( + '[plugin-layout]: pLugin-layout依赖plugin-access,请先安装plugin-access!' + ); +} + +const hasAccess = (item) => { + let res; + if (item.path && (!item.children || item.children.length === 0)) { + res = useAccess(item.path); + } else if (item.children && item.children.length > 0) { + res = computed(() => item.children.some(child => hasAccess(child))); + } + return res; +}; + +const addAcessTag = (arr) => { + if (Array.isArray(arr)) { + arr.forEach((item) => { + item.access = hasAccess(item); + if (item.children && item.children.length > 0) { + addAcessTag(item.children); + } + }); + } +}; + +export default function (menus) { + const originData = unref(menus); + addAcessTag(originData); + return originData; +} diff --git a/packages/fes-plugin-layout/src/helpers/index.js b/packages/fes-plugin-layout/src/helpers/index.js new file mode 100644 index 00000000..484d4343 --- /dev/null +++ b/packages/fes-plugin-layout/src/helpers/index.js @@ -0,0 +1,65 @@ +export const noop = () => {}; + +const matchName = (config, name) => { + let res; + if (Array.isArray(config)) { + for (let i = 0; i < config.length; i++) { + const item = config[i]; + if (item.meta && item.meta.name === name) { + res = item.meta; + res.path = item.path; + break; + } + if (item.children && item.children.length > 0) { + res = matchName(item.children, name); + if (res) { + break; + } + } + } + } + return res; +}; + +const matchPath = (config, path) => { + let res = {}; + if (Array.isArray(config)) { + for (let i = 0; i < config.length; i++) { + const item = config[i]; + if (item.path && item.path === path) { + res = item.meta; + res.path = item.path; + break; + } + if (item.children && item.children.length > 0) { + res = matchPath(item.children, path); + if (res) { + break; + } + } + } + } + return res; +}; + +export const fillMenuData = (menuConfig, routeConfig, dep = 0) => { + dep += 1; + if (dep > 3) { + throw new Error('[plugin-layout]: menu层级不能超出三层!'); + } + const arr = []; + if (Array.isArray(menuConfig) && Array.isArray(routeConfig)) { + menuConfig.forEach((item) => { + if (item.path !== undefined && item.path !== null) { + Object.assign(item, matchPath(routeConfig, item.path)); + } else { + Object.assign(item, matchName(routeConfig, item.name)); + } + if (item.children && item.children.length > 0) { + item.children = fillMenuData(item.children, routeConfig, dep); + } + arr.push(item); + }); + } + return arr; +}; diff --git a/packages/fes-plugin-layout/src/index.js b/packages/fes-plugin-layout/src/index.js index 71a8174b..1e7eda2b 100644 --- a/packages/fes-plugin-layout/src/index.js +++ b/packages/fes-plugin-layout/src/index.js @@ -1,4 +1,4 @@ -import { readFileSync } from 'fs'; +import { readFileSync, copyFileSync, statSync } from 'fs'; import { join } from 'path'; const namespace = 'plugin-layout'; @@ -9,53 +9,55 @@ export default (api) => { } = api; api.describe({ + key: 'layout', config: { schema(joi) { - return joi.object({ - menus: joi.array() - }); + return joi.object(); }, - default: {} + onChange: api.ConfigChangeType.regenerateTmpFiles } }); - const absoluteFilePath = join(namespace, 'core.js'); - const absRuntimeFilePath = join(namespace, 'runtime.js'); api.onGenerateFiles(() => { // 文件写出 - const { menus = [] } = api.config.layout || {}; - - console.log(menus); - - // api.writeTmpFile({ - // path: absoluteFilePath, - // content: Mustache.render( - // readFileSync(join(__dirname, 'template/core.tpl'), 'utf-8'), - // { - // REPLACE_ROLES: JSON.stringify(roles) - // } - // ) - // }); + const userConfig = api.config.layout || {}; api.writeTmpFile({ path: absRuntimeFilePath, - content: readFileSync( - join(__dirname, 'template/runtime.tpl'), - 'utf-8' + content: Mustache.render( + readFileSync(join(__dirname, 'template/runtime.tpl'), 'utf-8'), + { + REPLACE_USER_CONFIG: JSON.stringify(userConfig) + } ) }); }); - // api.addPluginExports(() => [ - // { - // specifiers: ['access', 'useAccess'], - // source: absoluteFilePath - // } - // ]); + let generatedOnce = false; + api.onGenerateFiles(() => { + if (generatedOnce) return; + generatedOnce = true; + const cwd = join(__dirname, '../src'); + const files = api.utils.glob.sync('**/*', { + cwd + }); + const base = join(api.paths.absTmpPath, namespace); + files.forEach((file) => { + if (file.indexOf('template') !== -1) return; + if (file === 'index.js') return; + const source = join(cwd, file); + const target = join(base, file); + if (statSync(source).isDirectory()) { + api.utils.mkdirp.sync(target); + } else { + copyFileSync(source, target); + } + }); + }); - // api.addRuntimePluginKey(() => 'noAccessHandler'); + api.addRuntimePluginKey(() => 'layout'); - // api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); + api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); }; diff --git a/packages/fes-plugin-layout/src/template/runtime.tpl b/packages/fes-plugin-layout/src/template/runtime.tpl index 7fc09b78..34817e1c 100644 --- a/packages/fes-plugin-layout/src/template/runtime.tpl +++ b/packages/fes-plugin-layout/src/template/runtime.tpl @@ -1,23 +1,30 @@ +import { reactive, toRefs } from "vue"; +import { getRoutes, plugin, ApplyPluginsType } from "@@/core/coreExports"; +import BaseLayout from "./views/BaseLayout.vue"; +import { fillMenuData } from "./helpers"; + +const userConfig = reactive({{{REPLACE_USER_CONFIG}}}); export function rootContainer(childComponent, args) { - const useRuntimeConfig = - plugin.applyPlugins({ - key: "initialStateConfig", - type: ApplyPluginsType.modify, - initialValue: {}, - }) || {}; - return { - setup() { - const { loading } = useModel("@@initialState") || {}; - return () => { - if (loading.value) { - return useRuntimeConfig.loading ? ( - - ) : ( - <> - ); + const runtimeConfig = plugin.applyPlugins({ + key: "layout", + type: ApplyPluginsType.modify, + initialValue: {}, + }); + const routeConfig = getRoutes(); + userConfig.menus = fillMenuData(userConfig.menus, routeConfig); + return () => { + const slots = { + default: () => , + userCenter: () => { + if(runtimeConfig.userCenter){ + return } - return ; - }; - }, + return <> + } + }; + return ( + + + ); }; } \ No newline at end of file diff --git a/packages/fes-plugin-layout/src/views/BaseLayout.vue b/packages/fes-plugin-layout/src/views/BaseLayout.vue index e69de29b..1bf08293 100644 --- a/packages/fes-plugin-layout/src/views/BaseLayout.vue +++ b/packages/fes-plugin-layout/src/views/BaseLayout.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/packages/fes-plugin-layout/src/views/Menu.vue b/packages/fes-plugin-layout/src/views/Menu.vue new file mode 100644 index 00000000..00053c21 --- /dev/null +++ b/packages/fes-plugin-layout/src/views/Menu.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/packages/fes-plugin-layout/src/views/layout.vue b/packages/fes-plugin-layout/src/views/layout.vue deleted file mode 100644 index d31e3806..00000000 --- a/packages/fes-plugin-layout/src/views/layout.vue +++ /dev/null @@ -1,99 +0,0 @@ - - - - - diff --git a/packages/fes-preset-built-in/src/plugins/commands/dev/index.js b/packages/fes-preset-built-in/src/plugins/commands/dev/index.js index ad6151dd..3c03fbcf 100644 --- a/packages/fes-preset-built-in/src/plugins/commands/dev/index.js +++ b/packages/fes-preset-built-in/src/plugins/commands/dev/index.js @@ -33,7 +33,6 @@ export default (api) => { description: 'start a dev server for development', async fn({ args = {} }) { const defaultPort = process.env.PORT || args.port || api.config.devServer?.port; - console.log(api.config.devServer); port = await portfinder.getPortPromise({ port: defaultPort ? parseInt(String(defaultPort), 10) : 8000 }); diff --git a/packages/fes-preset-built-in/src/plugins/misc/route/index.js b/packages/fes-preset-built-in/src/plugins/misc/route/index.js index 2afb5d61..2855b2c1 100644 --- a/packages/fes-preset-built-in/src/plugins/misc/route/index.js +++ b/packages/fes-preset-built-in/src/plugins/misc/route/index.js @@ -267,5 +267,12 @@ export default function (api) { }); }); + api.addCoreExports(() => [ + { + specifiers: ['getRoutes'], + source: absCoreFilePath + } + ]); + api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); } diff --git a/packages/fes-template/.fes.js b/packages/fes-template/.fes.js index 3afe65a6..8d38133d 100644 --- a/packages/fes-template/.fes.js +++ b/packages/fes-template/.fes.js @@ -1,15 +1,19 @@ -// fes.config.js 只负责管理 cli 相关的配置 +// .fes.js 只负责管理编译时配置,只能使用plain Object export default { access: { roles: { - admin: ["/"] + admin: ["/", "/onepiece"] } }, layout: { + title: "Fes.js", + logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', menus: [{ - path: '/' + name: 'index' + }, { + name: 'onepiece' }] }, devServer: { diff --git a/packages/fes-template/src/app.js b/packages/fes-template/src/app.js index 70e65954..e837a94a 100644 --- a/packages/fes-template/src/app.js +++ b/packages/fes-template/src/app.js @@ -1,6 +1,6 @@ import { access } from '@webank/fes'; import PageLoading from '@/components/PageLoading.vue'; - +import UserCenter from '@/components/UserCenter.vue'; export const beforeRender = { loading: , @@ -10,10 +10,13 @@ export const beforeRender = { setTimeout(() => { setRole('admin'); resolve({ - a: 1, - b: 2 + userName: 'harrywan' }); - }, 3000); + }, 1000); }); } }; + +export const layout = { + userCenter: +}; diff --git a/packages/fes-template/src/components/PageLoading.vue b/packages/fes-template/src/components/PageLoading.vue index bc678fd3..88c79423 100644 --- a/packages/fes-template/src/components/PageLoading.vue +++ b/packages/fes-template/src/components/PageLoading.vue @@ -4,7 +4,7 @@ diff --git a/packages/fes-template/src/pages/index.vue b/packages/fes-template/src/pages/index.vue index 418cdbd3..d96cf094 100644 --- a/packages/fes-template/src/pages/index.vue +++ b/packages/fes-template/src/pages/index.vue @@ -6,8 +6,9 @@ { + "name": "index", "title": "首页", - "layout": "false" + "layout": false }