feat: 优化plugin-access和plugin-layout

plugin-access:
1. 添加<Access />组件控制权限
2. 添加v-access指令控制权限
3. 权限的范围改为role和accesId的并集

plugin-layout:
1. 判断是否加载locale插件改为使用api.hasPlugins
2. 提示优化
This commit is contained in:
万纯 2021-01-14 12:56:31 +08:00
parent c91d0b5845
commit 6f6bf341dd
9 changed files with 102 additions and 28 deletions

View File

@ -0,0 +1,2 @@

View File

@ -23,6 +23,7 @@ export default (api) => {
const absRuntimeFilePath = join(namespace, 'runtime.js'); const absRuntimeFilePath = join(namespace, 'runtime.js');
const generatedOnce = false;
api.onGenerateFiles(() => { api.onGenerateFiles(() => {
// 文件写出 // 文件写出
const { roles = {} } = api.config.access || {}; const { roles = {} } = api.config.access || {};
@ -37,12 +38,10 @@ export default (api) => {
) )
}); });
api.writeTmpFile({ api.copyTmpFiles({
path: absRuntimeFilePath, namespace,
content: readFileSync( path: join(__dirname, 'runtime'),
join(__dirname, 'runtime/runtime.tpl'), ignore: ['.tpl']
'utf-8'
)
}); });
}); });

View File

@ -1,4 +1,6 @@
import { reactive, computed, inject } from "vue"; import { reactive, computed, inject } from "vue";
import createDirective from "./createDirective";
import createComponent from "./createComponent";
const accessKey = Symbol("plugin-access"); const accessKey = Symbol("plugin-access");
@ -20,17 +22,11 @@ const rolePromiseList = [];
const accessPromiseList = []; const accessPromiseList = [];
const getAllowAccessIds = () => { const getAllowAccessIds = () => {
if (
Array.isArray(state.currentAccessIds) &&
state.currentAccessIds.length > 0
) {
return state.currentAccessIds;
}
const roleAccessIds = state.roles[state.currentRoleId]; const roleAccessIds = state.roles[state.currentRoleId];
if (Array.isArray(roleAccessIds) && roleAccessIds.length > 0) { if (Array.isArray(roleAccessIds) && roleAccessIds.length > 0) {
return roleAccessIds; return state.currentAccessIds.concat(roleAccessIds);
} }
return []; return state.currentAccessIds;
}; };
const _syncSetAccessIds = (promise) => { const _syncSetAccessIds = (promise) => {
@ -55,11 +51,18 @@ const setAccess = (accessIds) => {
return _syncSetAccessIds(accessIds); return _syncSetAccessIds(accessIds);
} }
if (!Array.isArray(accessIds)) { if (!Array.isArray(accessIds)) {
throw new Error("[plugin-access]: pageIds必须是array"); throw new Error("[plugin-access]: argument to the setAccess() must be array or promise");
} }
state.currentAccessIds = accessIds; state.currentAccessIds = accessIds;
}; };
const addAccess = (accessId) => {
if (typeof accessId !== 'string') {
throw new Error("[plugin-access]: argument to the addAccess() must be string");
}
state.currentAccessIds.push(accessId);
};
const _syncSetRoleId = (promise) => { const _syncSetRoleId = (promise) => {
rolePromiseList.push(promise); rolePromiseList.push(promise);
promise promise
@ -82,12 +85,15 @@ const setRole = async (roleId) => {
return _syncSetRoleId(roleId); return _syncSetRoleId(roleId);
} }
if (typeof roleId !== "string") { if (typeof roleId !== "string") {
throw new Error("[plugin-access]: roleId必须是string"); throw new Error("[plugin-access]: argument to the setRole() must be string or promise");
} }
state.currentRoleId = roleId; state.currentRoleId = roleId;
}; };
const match = (path, accessIds) => { const match = (path, accessIds) => {
if(path === null || path === undefined) {
return false;
}
if (!Array.isArray(accessIds) || accessIds.length === 0) { if (!Array.isArray(accessIds) || accessIds.length === 0) {
return false; return false;
} }
@ -131,6 +137,8 @@ export const install = (app) => {
return result; return result;
}; };
app.provide(accessKey, useAccess); app.provide(accessKey, useAccess);
app.directive("access", createDirective(useAccess));
app.component("Access", createComponent(useAccess));
}; };
export const access = { export const access = {
@ -138,6 +146,7 @@ export const access = {
hasLoading, hasLoading,
setRole, setRole,
setAccess, setAccess,
addAccess
}; };
export const useAccess = (path) => { export const useAccess = (path) => {

View File

@ -0,0 +1,7 @@
export default function createComponent(useAccess) {
return (props, { slots }) => {
const access = useAccess(props.id);
if (!access.value || !slots.default) return null;
return slots.default();
};
}

View File

@ -0,0 +1,46 @@
import { watch } from 'vue';
const cache = new WeakMap();
const setDispaly = (el, access) => {
if (access.value) {
el.style.display = el._display;
} else {
el.style.display = 'none';
}
};
export default function createDirective(useAccess) {
return {
beforeMount(el) {
const ctx = {};
ctx.watch = (path) => {
el._display = el._display || el.style.display;
const access = useAccess(path);
setDispaly(el, access);
return watch(access, () => {
setDispaly(el, access);
});
};
cache.set(el, ctx);
},
mounted(el, binding) {
const ctx = cache.get(el);
if (ctx.unwatch) {
ctx.unwatch();
}
ctx.unwatch = ctx.watch(binding.value);
},
updated(el, binding) {
const ctx = cache.get(el);
if (ctx.unwatch) {
ctx.unwatch();
}
ctx.unwatch = ctx.watch(binding.value);
},
beforeUnmount(el) {
const ctx = cache.get(el);
if (ctx.unwatch) {
ctx.unwatch();
}
}
};
}

View File

@ -1,5 +1,5 @@
import { access, install } from "./core"; import { plugin, ApplyPluginsType } from '@@/core/coreExports';
import { plugin, ApplyPluginsType } from "@@/core/coreExports"; import { access, install } from './core';
export function onRouterCreated({ router }) { export function onRouterCreated({ router }) {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
@ -14,11 +14,11 @@ export function onRouterCreated({ router }) {
next(); next();
} else { } else {
const runtimeConfig = plugin.applyPlugins({ const runtimeConfig = plugin.applyPlugins({
key: "access", key: 'access',
type: ApplyPluginsType.modify, type: ApplyPluginsType.modify,
initialValue: null, initialValue: {}
}); });
if (runtimeConfig.noAccessHandler && typeof runtimeConfig.noAccessHandler === "function") { if (runtimeConfig.noAccessHandler && typeof runtimeConfig.noAccessHandler === 'function') {
runtimeConfig.noAccessHandler(router, to, from); runtimeConfig.noAccessHandler(router, to, from);
} }
next(false); next(false);
@ -27,5 +27,5 @@ export function onRouterCreated({ router }) {
} }
export function onAppCreated({ app }) { export function onAppCreated({ app }) {
install(app) install(app);
} }

View File

@ -26,6 +26,10 @@ export default (api) => {
api.onGenerateFiles(() => { api.onGenerateFiles(() => {
const { name } = api.pkg; const { name } = api.pkg;
const HAS_LOCALE = api.hasPlugins(['@webank/fes-plugin-locale']);
const HAS_ACCESS = api.hasPlugins(['@webank/fes-plugin-access']);
// .fes配置 // .fes配置
const userConfig = { const userConfig = {
title: name, title: name,
@ -38,7 +42,7 @@ export default (api) => {
readFileSync(join(__dirname, 'runtime/index.tpl'), 'utf-8'), readFileSync(join(__dirname, 'runtime/index.tpl'), 'utf-8'),
{ {
REPLACE_USER_CONFIG: JSON.stringify(userConfig), REPLACE_USER_CONFIG: JSON.stringify(userConfig),
HAS_LOCALE: api.pkg.dependencies?.['@webank/fes-plugin-locale'] HAS_LOCALE
} }
) )
}); });

View File

@ -1,9 +1,9 @@
import { unref, computed } from 'vue'; import { unref, computed } from 'vue';
import { useAccess } from '@webank/fes'; import { useAccess } from '../../plugin-access/core';
if (!useAccess) { if (!useAccess) {
throw new Error( throw new Error(
'[plugin-layout]: pLugin-layout依赖plugin-access请先安装plugin-access' '[plugin-layout]: pLugin-layout depends on plugin-accessplease install plugin-access first'
); );
} }

View File

@ -2,7 +2,8 @@
<div class="haizekuo"> <div class="haizekuo">
<div>国际化 {{t("test")}}</div> <div>国际化 {{t("test")}}</div>
fes & 拉夫德鲁 <br /> fes & 拉夫德鲁 <br />
accessOnepicess: {{accessOnepicess}} <access :id="accessId"> accessOnepicess1 <input /> </access>
<div v-access="accessId"> accessOnepicess2 <input /> </div>
<input /> <input />
</div> </div>
</template> </template>
@ -15,27 +16,33 @@
<script> <script>
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { import {
useAccess, useRouter, useI18n, setLocale access, useAccess, useRouter, useI18n, setLocale
} from '@webank/fes'; } from '@webank/fes';
export default { export default {
setup() { setup() {
const fes = ref('fes upgrade to vue3'); const fes = ref('fes upgrade to vue3');
const accessOnepicess = useAccess('/onepiece'); const accessOnepicess = useAccess('/onepiece1');
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
const accessId = ref('/onepiece1');
onMounted(() => { onMounted(() => {
console.log(router); console.log(router);
console.log('mounted1!!'); console.log('mounted1!!');
setTimeout(() => { setTimeout(() => {
setLocale('en-US'); setLocale('en-US');
access.addAccess('/onepiece1');
}, 2000); }, 2000);
setTimeout(() => {
accessId.value = '11';
}, 4000);
// router.push('/onepiece'); // router.push('/onepiece');
}); });
onMounted(() => { onMounted(() => {
console.log('mounted2!!'); console.log('mounted2!!');
}); });
return { return {
accessId,
fes, fes,
accessOnepicess, accessOnepicess,
t t