feat: plugin-access 70%

This commit is contained in:
万纯 2020-12-10 16:55:17 +08:00
parent 8fc1141056
commit 4fcdd6c641
14 changed files with 225 additions and 62 deletions

View File

@ -4,7 +4,7 @@ import { join } from 'path';
// utils must build before core // utils must build before core
// runtime must build before renderer-react // runtime must build before renderer-react
const headPkgs = ['fes-runtime', 'fes-core', 'fes', 'fes-plugin-built-in', 'fes-plugin-request', 'fes-plugin-access']; const headPkgs = ['fes-runtime', 'fes-core', 'fes', 'fes-plugin-built-in', 'fes-plugin-request', 'fes-plugin-access', 'fes-plugin-initstate'];
const tailPkgs = []; const tailPkgs = [];
// const otherPkgs = readdirSync(join(__dirname, 'packages')).filter( // const otherPkgs = readdirSync(join(__dirname, 'packages')).filter(
// (pkg) => // (pkg) =>

View File

@ -109,12 +109,12 @@ export default (api) => {
}); });
}); });
// api.addExports(() => [ api.addExports(() => [
// { {
// exportAll: true, specifiers: ['access', 'useAccess'],
// source: absoluteFilePath source: absoluteFilePath
// } }
// ]); ]);
api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`);
}; };

View File

@ -1,18 +0,0 @@
import { hasAccess } from './core';
export function onRouterCreated({ router }) {
router.beforeEach(async (to, from, next) => {
let path;
if (to.matched.length === 1) {
path = to.matched[0].path;
} else {
path = to.path;
}
const canRoute = await hasAccess(path);
if (canRoute) {
next();
} else {
next(false);
}
});
}

View File

@ -1,48 +1,137 @@
const roles = {{{REPLACE_ROLES}}}; import { reactive, computed } from "vue";
let allowPageIds = []; function isPromise(obj) {
return (
!!obj &&
(typeof obj === "object" || typeof obj === "function") &&
typeof obj.then === "function"
);
}
const get = () => Promise.all(allowPageIds).then(data => data.reduce((merge, cur) => merge.concat(cur), [])); const state = reactive({
roles: {{{REPLACE_ROLES}}},
currentRoleId: "",
currentAccessIds: ["/"],
});
export const setPageIds = (pageIds) => { const rolePromiseList = [];
if (Array.isArray(pageIds)) { const accessPromiseList = [];
allowPageIds = pageIds.map(id => Promise.resolve(id));
} else { const getAllowAccessIds = () => {
allowPageIds = [Promise.resolve(pageIds)]; if (
Array.isArray(state.currentAccessIds) &&
state.currentAccessIds.length > 0
) {
return state.currentAccessIds;
} }
const roleAccessIds = state.roles[state.currentRoleId];
if (Array.isArray(roleAccessIds) && roleAccessIds.length > 0) {
return roleAccessIds;
}
return [];
}; };
export const setRoleId = async (roleId) => { const _syncSetAccessIds = (promise) => {
console.log('setRole'); accessPromiseList.push(promise);
const _roleId = await Promise.resolve(roleId); promise
if (typeof _roleId !== 'string') { .then((accessIds) => {
throw new Error( setAccess(accessIds);
'[plugin-access]: roleId必须是string或者Promise的结果必须是string', })
); .catch((e) => {
} console.error(e);
setPageIds(roles[_roleId]); })
.then(() => {
const index = accessPromiseList.indexOf(promise);
if (index !== -1) {
accessPromiseList.splice(index, 1);
}
});
}; };
export const hasAccess = async (path) => { const setAccess = (accessIds) => {
const allowPage = await get(); if (isPromise(accessIds)) {
if (!Array.isArray(allowPage) || allowPage.length === 0) { return _syncSetAccessIds(accessIds);
}
if (!Array.isArray(accessIds)) {
throw new Error("[plugin-access]: pageIds必须是array");
}
state.currentAccessIds = accessIds;
};
const _syncSetRoleId = (promise) => {
rolePromiseList.push(promise);
promise
.then((roleId) => {
setRole(roleId);
})
.catch((e) => {
console.error(e);
})
.then(() => {
const index = rolePromiseList.indexOf(promise);
if (index !== -1) {
rolePromiseList.splice(index, 1);
}
});
};
const setRole = async (roleId) => {
if (isPromise(roleId)) {
return _syncSetRoleId(roleId);
}
if (typeof roleId !== "string") {
throw new Error("[plugin-access]: roleId必须是string");
}
state.currentRoleId = roleId;
};
const match = (path, accessIds) => {
if (!Array.isArray(accessIds) || accessIds.length === 0) {
return false; return false;
} }
path = path.split('?')[0]; path = path.split("?")[0];
// 进入"/"路由时此时path为“” // 进入"/"路由时此时path为“”
if (path === '') { if (path === "") {
path = '/'; path = "/";
} }
const len = allowPage.length; const len = accessIds.length;
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
if (path === allowPage[i]) { if (path === accessIds[i]) {
return true; return true;
} }
// 支持*匹配 // 支持*匹配
const reg = new RegExp(`^${allowPage[i].replace('*', '.+')}$`); const reg = new RegExp(`^${accessIds[i].replace("*", ".+")}$`);
if (reg.test(path)) { if (reg.test(path)) {
return true; return true;
} }
} }
return false; return false;
}
const hasLoading = ()=>{
return rolePromiseList.length || accessPromiseList.length
}
const hasAccess = async (path) => {
if(!hasLoading()){
return match(path, getAllowAccessIds())
}
await Promise.all(rolePromiseList.concat(accessPromiseList));
return match(path, getAllowAccessIds())
}; };
const allowPageIds = computed(getAllowAccessIds);
export const access = {
hasAccess,
hasLoading,
setRole,
setAccess
}
export const useAccess = (path) => {
const result = computed(() => {
return match(path, allowPageIds.value);
});
return result;
}

View File

@ -1,4 +1,4 @@
import { hasAccess } from './core'; import { access } from './core';
export function onRouterCreated({ router }) { export function onRouterCreated({ router }) {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
@ -8,7 +8,7 @@ export function onRouterCreated({ router }) {
} else { } else {
path = to.path; path = to.path;
} }
const canRoute = await hasAccess(path); const canRoute = await access.hasAccess(path);
if (canRoute) { if (canRoute) {
next(); next();
} else { } else {

View File

@ -21,4 +21,11 @@ export default function (api) {
}) })
}); });
}); });
api.addExports(() => [
{
specifiers: ['router'],
source: absoluteFilePath
}
]);
} }

View File

@ -31,3 +31,5 @@ export const createRouter = () => {
return router; return router;
}; };
export { router }

View File

@ -0,0 +1,3 @@
export default {
disableTypeCheck: false,
};

View File

@ -0,0 +1,19 @@
{
"name": "@webank/fes-plugin-initstate",
"version": "1.0.0",
"description": "",
"main": "lib/index.js",
"files": [
"lib"
],
"module": "dist/index.esm.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT",
"peerDependencies": {
"@webank/fes": "^2.0.0"
}
}

View File

@ -0,0 +1,21 @@
import { readFileSync } from 'fs';
import { join } from 'path';
const namespace = 'plugin-initstate';
export default (api) => {
api.addRuntimePluginKey(() => 'initstate');
const absRuntimeFilePath = join(namespace, 'runtime.js');
api.onGenerateFiles(() => {
api.writeTmpFile({
path: absRuntimeFilePath,
content: readFileSync(join(__dirname, 'template/runtime.tpl'), 'utf-8')
});
});
api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`);
};

View File

@ -0,0 +1,28 @@
import { defineComponent } from 'vue'
export function rootContainer(childComponent, args){
console.log(childComponent, args)
const App = {
setup() {
const state = reactive({
loading: true
})
onMounted(()=>{
setTimeout(() => {
state.loading = false
}, 3000);
})
return () => {
if(state.loading){
return (
<>
<div>loading</div>
</>
)
}
return <childComponent />
}
}
}
return App
}

View File

@ -34,7 +34,6 @@
"dependencies": { "dependencies": {
"vue": "^3.0.2", "vue": "^3.0.2",
"@webank/fes": "^2.0.0", "@webank/fes": "^2.0.0",
"@webank/fes-plugin-request": "^1.0.0",
"@webank/fes-plugin-access": "^1.0.0" "@webank/fes-plugin-access": "^1.0.0"
} }
} }

View File

@ -1,2 +0,0 @@
// 配置fes-plugin-request
export const request = {};

View File

@ -1,17 +1,32 @@
<template> <template>
<div> <div>
fes & 拉夫德鲁 fes & 拉夫德鲁 <br />
accessOnepicess: {{accessOnepicess}}
</div> </div>
</template> </template>
<script> <script>
import { ref } from 'vue'; import { ref, onMounted } from 'vue';
import { useAccess, access, router } from '@webank/fes';
const { setAccess } = access;
export default { export default {
setup() { setup() {
const fes = ref('fes upgrade to vue3'); const fes = ref('fes upgrade to vue3');
const accessOnepicess = useAccess('/onepiece');
onMounted(() => {
console.log('mounted!');
console.log(router);
setAccess(new Promise((resolve, reject) => {
setTimeout(() => {
resolve(['/', '/onepiece']);
}, 3000);
}));
// router.push('/onepiece');
});
return { return {
fes fes,
accessOnepicess
}; };
} }
}; };