{"score":42.24,"report":[{"format":"markup","foundDate":1638413755145,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/BaseLayout.vue","start":{"line":268,"column":9,"position":1782},"end":{"line":298,"column":26,"position":1928},"range":[8710,9627],"fragment":".layout-header {\n padding-left: 24px;\n color: hsla(0,0%,100%,.65);\n background: #001529;\n .layout-menu {\n line-height: 48px;\n }\n .layout-logo {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n min-width: 165px;\n height: 100%;\n overflow: hidden;\n transition: all .3s;\n .logo-img {\n height: 32px;\n width: auto;\n }\n .logo-name {\n overflow: hidden;\n margin: 0 0 0 12px;\n color: #fff;\n font-weight: 600;\n font-size: 18px;\n line-height: 32px;\n }\n }\n }\n }\n .layout-sider-fixed-stuff"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/BaseLayout.vue","start":{"line":233,"column":9,"position":1601},"end":{"line":263,"column":31,"position":1747},"range":[7656,8578],"fragment":".layout-header {\n padding-left: 24px;\n color: hsla(0,0%,100%,.65);\n background: #001529;\n .layout-menu {\n line-height: 48px;\n }\n .layout-logo {\n display: flex;\n justify-content: flex-start;\n align-items: center;\n min-width: 165px;\n height: 100%;\n overflow: hidden;\n transition: all .3s;\n .logo-img {\n height: 32px;\n width: auto;\n }\n .logo-name {\n overflow: hidden;\n margin: 0 0 0 12px;\n color: #fff;\n font-weight: 600;\n font-size: 18px;\n line-height: 32px;\n }\n }\n }\n }\n &.main-layout-navigation-mixin"}},{"format":"markup","foundDate":1638413755150,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/403.vue","start":{"line":2,"column":16,"position":24},"end":{"line":35,"column":2,"position":202},"range":[76,795],"fragment":"\">\n \n \n\n\n{\n \"layout\": false\n}\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/404.vue","start":{"line":2,"column":15,"position":24},"end":{"line":35,"column":2,"position":202},"range":[75,794],"fragment":"\">\n \n \n\n\n{\n \"layout\": false\n}\n\n"}},{"format":"javascript","foundDate":1638413755173,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/core/routes/routes.js","start":{"line":75,"column":3,"position":515},"end":{"line":93,"column":17,"position":639},"range":[1825,2184],"fragment":"}\n];\n return routes;\n}\n\nconst ROUTER_BASE = '';\nlet router = null;\nlet history = null;\nexport const createRouter = (routes) => {\n if (router) {\n return router;\n }\n const createHistory = plugin.applyPlugins({\n key: 'modifyCreateHistroy',\n type: ApplyPluginsType.modify,\n args: {\n base: ROUTER_BASE\n },\n initialValue: createWebHistory"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/core/routes/routes.js","start":{"line":26,"column":3,"position":184},"end":{"line":44,"column":21,"position":308},"range":[637,1000],"fragment":"}\n];\n return routes;\n}\n\nconst ROUTER_BASE = '';\nlet router = null;\nlet history = null;\nexport const createRouter = (routes) => {\n if (router) {\n return router;\n }\n const createHistory = plugin.applyPlugins({\n key: 'modifyCreateHistroy',\n type: ApplyPluginsType.modify,\n args: {\n base: ROUTER_BASE\n },\n initialValue: createWebHashHistory"}},{"format":"javascript","foundDate":1638413755174,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/core/routes/routes.js","start":{"line":93,"column":17,"position":640},"end":{"line":133,"column":2,"position":883},"range":[2184,2897],"fragment":",\n });\n history = createHistory(ROUTER_BASE);\n // 修改routes\n plugin.applyPlugins({\n key: 'patchRoutes',\n type: ApplyPluginsType.event,\n args: { routes },\n });\n router = createVueRouter({\n history,\n routes\n });\n\n plugin.applyPlugins({\n key: 'onRouterCreated',\n type: ApplyPluginsType.event,\n args: { router },\n });\n\n return router;\n};\n\nexport const getRouter = ()=>{\n if(!router){\n console.warn(`[preset-build-in] router is null`)\n }\n return router;\n}\n\nexport const getHistory = ()=>{\n if(!history){\n console.warn(`[preset-build-in] history is null`)\n }\n return history;\n}\n\nexport const destroyRouter = ()=>{\n router = null;\n history = null;\n}"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/core/routes/routes.js","start":{"line":44,"column":21,"position":309},"end":{"line":84,"column":2,"position":552},"range":[1000,1713],"fragment":",\n });\n history = createHistory(ROUTER_BASE);\n // 修改routes\n plugin.applyPlugins({\n key: 'patchRoutes',\n type: ApplyPluginsType.event,\n args: { routes },\n });\n router = createVueRouter({\n history,\n routes\n });\n\n plugin.applyPlugins({\n key: 'onRouterCreated',\n type: ApplyPluginsType.event,\n args: { router },\n });\n\n return router;\n};\n\nexport const getRouter = ()=>{\n if(!router){\n console.warn(`[preset-build-in] router is null`)\n }\n return router;\n}\n\nexport const getHistory = ()=>{\n if(!history){\n console.warn(`[preset-build-in] history is null`)\n }\n return history;\n}\n\nexport const destroyRouter = ()=>{\n router = null;\n history = null;\n}"}},{"format":"less","foundDate":1638413755332,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/styles/mixins/hairline.less","start":{"line":1,"column":1,"position":0},"end":{"line":173,"column":2,"position":1037},"range":[0,4232],"fragment":"@import \"../theme\";\n\n.scale-hairline-common(@color, @top, @right, @bottom, @left) {\n content: '';\n position: absolute;\n background-color: @color;\n display: block;\n z-index: 1;\n top: @top;\n right: @right;\n bottom: @bottom;\n left: @left;\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='top') {\n border-top: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-top: none;\n position: relative;\n\n &::before {\n .scale-hairline-common(@color, 0, auto, auto, 0);\n width: 100%;\n height: 1PX;\n transform-origin: 50% 50%;\n transform: scaleY(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleY(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='right') {\n border-right: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-right: none;\n position: relative;\n\n &::after {\n .scale-hairline-common(@color, 0, 0, auto, auto);\n width: 1PX;\n height: 100%;\n background: @color;\n transform-origin: 100% 50%;\n transform: scaleX(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleX(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='bottom') {\n border-bottom: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-bottom: none;\n position: relative;\n\n &::after {\n .scale-hairline-common(@color, auto, auto, 0, 0);\n width: 100%;\n height: 1PX;\n transform-origin: 50% 100%;\n transform: scaleY(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleY(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='left') {\n border-left: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-left: none;\n position: relative;\n\n &::before {\n .scale-hairline-common(@color, 0, auto, auto, 0);\n width: 1PX;\n height: 100%;\n transform-origin: 100% 50%;\n transform: scaleX(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleX(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base, @radius: 0) when (@direction ='all') {\n border: 1PX solid @color;\n border-radius: @radius;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n position: relative;\n border: none;\n\n &::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n width: 200%;\n height: 200%;\n border: 1PX solid @color;\n border-radius: @radius * 2;\n transform-origin: 0 0;\n transform: scale(0.5);\n box-sizing: border-box;\n pointer-events: none;\n }\n }\n }\n}\n\n.hairline-remove(@position) when (@position ='left') {\n border-left: 0;\n\n &:before {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='right') {\n border-right: 0;\n\n &:after {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='top') {\n border-top: 0;\n\n &:before {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='bottom') {\n border-bottom: 0;\n\n &:after {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='all') {\n border: 0;\n\n &:before {\n display: none !important;\n }\n}"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/create-fes-app/templates/app/h5/src/styles/mixins/hairline.less","start":{"line":1,"column":1,"position":0},"end":{"line":173,"column":2,"position":1037},"range":[0,4232],"fragment":"@import \"../theme\";\n\n.scale-hairline-common(@color, @top, @right, @bottom, @left) {\n content: '';\n position: absolute;\n background-color: @color;\n display: block;\n z-index: 1;\n top: @top;\n right: @right;\n bottom: @bottom;\n left: @left;\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='top') {\n border-top: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-top: none;\n position: relative;\n\n &::before {\n .scale-hairline-common(@color, 0, auto, auto, 0);\n width: 100%;\n height: 1PX;\n transform-origin: 50% 50%;\n transform: scaleY(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleY(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='right') {\n border-right: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-right: none;\n position: relative;\n\n &::after {\n .scale-hairline-common(@color, 0, 0, auto, auto);\n width: 1PX;\n height: 100%;\n background: @color;\n transform-origin: 100% 50%;\n transform: scaleX(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleX(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='bottom') {\n border-bottom: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-bottom: none;\n position: relative;\n\n &::after {\n .scale-hairline-common(@color, auto, auto, 0, 0);\n width: 100%;\n height: 1PX;\n transform-origin: 50% 100%;\n transform: scaleY(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleY(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base) when (@direction ='left') {\n border-left: 1PX solid @color;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n border-left: none;\n position: relative;\n\n &::before {\n .scale-hairline-common(@color, 0, auto, auto, 0);\n width: 1PX;\n height: 100%;\n transform-origin: 100% 50%;\n transform: scaleX(0.5);\n\n @media (min-resolution: 3dppx) {\n transform: scaleX(0.33);\n }\n }\n }\n }\n}\n\n.hairline(@direction, @color: @border-color-base, @radius: 0) when (@direction ='all') {\n border: 1PX solid @color;\n border-radius: @radius;\n\n html:not([data-scale]) & {\n @media (min-resolution: 2dppx) {\n position: relative;\n border: none;\n\n &::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n width: 200%;\n height: 200%;\n border: 1PX solid @color;\n border-radius: @radius * 2;\n transform-origin: 0 0;\n transform: scale(0.5);\n box-sizing: border-box;\n pointer-events: none;\n }\n }\n }\n}\n\n.hairline-remove(@position) when (@position ='left') {\n border-left: 0;\n\n &:before {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='right') {\n border-right: 0;\n\n &:after {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='top') {\n border-top: 0;\n\n &:before {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='bottom') {\n border-bottom: 0;\n\n &:after {\n display: none !important;\n }\n}\n\n.hairline-remove(@position) when (@position ='all') {\n border: 0;\n\n &:before {\n display: none !important;\n }\n}"}},{"format":"javascript","foundDate":1638413755409,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/throttle.js","start":{"line":2,"column":1,"position":1},"end":{"line":16,"column":2,"position":140},"range":[1,383],"fragment":"const throttleMap = new Map();\n\nexport default async (ctx, next) => {\n if (ctx.config.throttle) {\n if (throttleMap.get(ctx.key) >= Date.now()) {\n ctx.error = {\n type: 'FREQUENTLY',\n msg: '请求过于频繁'\n };\n return;\n }\n }\n await next();\n throttleMap.set(ctx.key, Date.now() + ctx.config.throttle);\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/throttle.js","start":{"line":2,"column":1,"position":1},"end":{"line":16,"column":2,"position":140},"range":[1,383],"fragment":"const throttleMap = new Map();\n\nexport default async (ctx, next) => {\n if (ctx.config.throttle) {\n if (throttleMap.get(ctx.key) >= Date.now()) {\n ctx.error = {\n type: 'FREQUENTLY',\n msg: '请求过于频繁'\n };\n return;\n }\n }\n await next();\n throttleMap.set(ctx.key, Date.now() + ctx.config.throttle);\n};"}},{"format":"javascript","foundDate":1638413755410,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/setDataField.js","start":{"line":1,"column":1,"position":0},"end":{"line":11,"column":2,"position":134},"range":[0,378],"fragment":"import { isObject } from './helpers';\n\n// FEATURE: 后续支持 a.b.c\nexport default async (ctx, next) => {\n const dataField = ctx.config.dataField ?? ctx.dataField;\n if (!ctx.error && ctx.response && isObject(ctx.response.data) && dataField) {\n ctx.response._rawData = ctx.response.data;\n ctx.response.data = ctx.response.data[dataField];\n }\n await next();\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/setDataField.js","start":{"line":1,"column":1,"position":0},"end":{"line":11,"column":2,"position":134},"range":[0,378],"fragment":"import { isObject } from './helpers';\n\n// FEATURE: 后续支持 a.b.c\nexport default async (ctx, next) => {\n const dataField = ctx.config.dataField ?? ctx.dataField;\n if (!ctx.error && ctx.response && isObject(ctx.response.data) && dataField) {\n ctx.response._rawData = ctx.response.data;\n ctx.response.data = ctx.response.data[dataField];\n }\n await next();\n};"}},{"format":"javascript","foundDate":1638413755411,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/scheduler.js","start":{"line":2,"column":1,"position":1},"end":{"line":33,"column":2,"position":307},"range":[1,952],"fragment":"class Scheduler {\n constructor() {\n this.middlewares = [];\n }\n\n use(fn) {\n if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');\n this.middlewares.push(fn);\n return this;\n }\n\n compose() {\n return (context, next) => {\n let index = -1;\n const dispatch = (i) => {\n if (i <= index) return Promise.reject(new Error('next() called multiple times'));\n index = i;\n let fn = this.middlewares[i];\n if (index === this.middlewares.length) fn = next;\n if (!fn) return Promise.resolve();\n try {\n return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));\n } catch (e) {\n return Promise.reject(e);\n }\n };\n return dispatch(0);\n };\n }\n}\n\nexport default new Scheduler();"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/scheduler.js","start":{"line":2,"column":1,"position":1},"end":{"line":33,"column":2,"position":307},"range":[1,952],"fragment":"class Scheduler {\n constructor() {\n this.middlewares = [];\n }\n\n use(fn) {\n if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');\n this.middlewares.push(fn);\n return this;\n }\n\n compose() {\n return (context, next) => {\n let index = -1;\n const dispatch = (i) => {\n if (i <= index) return Promise.reject(new Error('next() called multiple times'));\n index = i;\n let fn = this.middlewares[i];\n if (index === this.middlewares.length) fn = next;\n if (!fn) return Promise.resolve();\n try {\n return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));\n } catch (e) {\n return Promise.reject(e);\n }\n };\n return dispatch(0);\n };\n }\n}\n\nexport default new Scheduler();"}},{"format":"javascript","foundDate":1638413755412,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/resErrorProcess.js","start":{"line":1,"column":1,"position":0},"end":{"line":17,"column":2,"position":133},"range":[0,387],"fragment":"import { isObject } from './helpers';\n\n// 错误处理等副作用网上提\nexport default async (ctx, next) => {\n const {\n response,\n config\n } = ctx;\n if (!config.closeResDataCheck && response && isObject(response.data)) {\n const code = response.data.code;\n if (code !== '0') {\n ctx.error = response; // code 不为零进入 reject\n }\n }\n\n await next();\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/resErrorProcess.js","start":{"line":1,"column":1,"position":0},"end":{"line":17,"column":2,"position":133},"range":[0,387],"fragment":"import { isObject } from './helpers';\n\n// 错误处理等副作用网上提\nexport default async (ctx, next) => {\n const {\n response,\n config\n } = ctx;\n if (!config.closeResDataCheck && response && isObject(response.data)) {\n const code = response.data.code;\n if (code !== '0') {\n ctx.error = response; // code 不为零进入 reject\n }\n }\n\n await next();\n};"}},{"format":"javascript","foundDate":1638413755413,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/resDataAdaptor.js","start":{"line":1,"column":1,"position":0},"end":{"line":8,"column":2,"position":107},"range":[0,326],"fragment":"import { isFunction, isObject, isString } from './helpers';\n\nexport default async ({ response, responseDataAdaptor }, next) => {\n if (isFunction(responseDataAdaptor) && response && (isObject(response.data) || isString(response.data))) {\n response.data = responseDataAdaptor(response.data);\n }\n await next();\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/resDataAdaptor.js","start":{"line":1,"column":1,"position":0},"end":{"line":8,"column":2,"position":107},"range":[0,326],"fragment":"import { isFunction, isObject, isString } from './helpers';\n\nexport default async ({ response, responseDataAdaptor }, next) => {\n if (isFunction(responseDataAdaptor) && response && (isObject(response.data) || isString(response.data))) {\n response.data = responseDataAdaptor(response.data);\n }\n await next();\n};"}},{"format":"javascript","foundDate":1638413755426,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/request.js","start":{"line":40,"column":2,"position":356},"end":{"line":71,"column":5,"position":568},"range":[1252,1924],"fragment":"(fn)) {\n instance.interceptors[type].use(fn);\n }\n });\n}\n\nfunction addRequestInterceptors(instance, interceptors) {\n addInterceptors(instance, interceptors, 'request');\n}\n\nfunction addResponseInterceptors(instance, interceptors) {\n addInterceptors(instance, interceptors, 'response');\n}\n\nasync function axiosMiddleware(context, next) {\n try {\n context.response = await context.instance.request(context.config);\n } catch (error) {\n context.error = error;\n }\n\n await next();\n}\n\nfunction getRequestInstance() {\n const {\n responseDataAdaptor,\n requestInterceptors = [],\n responseInterceptors = [],\n errorHandler,\n ...otherConfigs\n } = _fes"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/request.js","start":{"line":23,"column":11,"position":209},"end":{"line":53,"column":7,"position":420},"range":[834,1563],"fragment":"(fn)) {\n instance.interceptors[type].use(fn);\n }\n });\n}\n\nfunction addRequestInterceptors(instance, interceptors) {\n addInterceptors(instance, interceptors, 'request');\n}\n\nfunction addResponseInterceptors(instance, interceptors) {\n addInterceptors(instance, interceptors, 'response');\n}\n\nasync function axiosMiddleware(context, next) {\n try {\n context.response = await context.instance.request(context.config);\n } catch (error) {\n context.error = error;\n }\n await next();\n}\n\nfunction getRequestInstance() {\n const {\n responseDataAdaptor,\n requestInterceptors = [],\n responseInterceptors = [],\n errorHandler,\n ...otherConfigs\n } = plugin"}},{"format":"javascript","foundDate":1638413755429,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/request.js","start":{"line":98,"column":8,"position":798},"end":{"line":110,"column":2,"position":881},"range":[2816,3034],"fragment":".compose()\n };\n} // DEPRECATED 废弃,使用 axios baseURL\n\n\nfunction handleApiPathBase(url, options = {}) {\n if (url.startsWith('http')) return url;\n\n if (options.base) {\n return `${options.base}${url}`;\n }\n\n return `"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/request.js","start":{"line":88,"column":10,"position":641},"end":{"line":99,"column":10,"position":722},"range":[2500,2738],"fragment":".compose()\n };\n}\n\n// DEPRECATED 废弃,使用 axios baseURL\nfunction handleApiPathBase(url, options = {}) {\n if (url.startsWith('http')) return url;\n\n if (options.base) {\n return `${options.base}${url}`;\n }\n return `/ras-mas"}},{"format":"javascript","foundDate":1638413755431,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/request.js","start":{"line":117,"column":2,"position":962},"end":{"line":181,"column":6,"position":1453},"range":[3254,4669],"fragment":"(options.method)) {\n options.data = data;\n } else {\n options.params = data;\n }\n\n return options;\n}\n\nlet currentRequestInstance = null;\n\nfunction createContext(userConfig) {\n return { ...currentRequestInstance.context,\n config: { ...currentRequestInstance.context.defaultConfig,\n ...userConfig\n }\n };\n}\n\nfunction getResponseCode(response) {\n if (response) {\n if (response._rawData) return response._rawData.code;\n if (response.data) return response.data.code;\n }\n\n return null;\n}\n\nfunction skipErrorHandlerToObj(skipErrorHandler = []) {\n if (!Array.isArray(skipErrorHandler)) {\n skipErrorHandler = [skipErrorHandler];\n }\n\n return skipErrorHandler.reduce((acc, cur) => {\n acc[cur] = true;\n return acc;\n }, {});\n}\n\nfunction handleRequestError({\n errorHandler = {},\n error,\n response,\n config\n}) {\n // 跳过所有错误类型处理\n if (config.skipErrorHandler === true) return;\n const skipObj = skipErrorHandlerToObj(config.skipErrorHandler);\n const resCode = getResponseCode(response);\n let errorKey = 'default';\n\n if (resCode && errorHandler[resCode]) {\n errorKey = resCode;\n } else if (error.type && errorHandler[error.type]) {\n errorKey = error.type;\n } else if (error.response && errorHandler[error.response.status]) {\n errorKey = error.response.status;\n }\n\n if (!skipObj[errorKey] && errorHandler[errorKey]) {\n return errorHandler[errorKey](error);\n }\n}\n\nconst"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/request.js","start":{"line":105,"column":24,"position":795},"end":{"line":171,"column":7,"position":1288},"range":[2949,4497],"fragment":"(options.method)) {\n options.data = data;\n } else {\n options.params = data;\n }\n return options;\n}\n\nlet currentRequestInstance = null;\n\nfunction createContext(userConfig) {\n return {\n ...currentRequestInstance.context,\n config: {\n ...currentRequestInstance.context.defaultConfig,\n ...userConfig\n }\n };\n}\n\n\nfunction getResponseCode(response) {\n if (response) {\n if (response._rawData) return response._rawData.code;\n if (response.data) return response.data.code;\n }\n return null;\n}\n\nfunction skipErrorHandlerToObj(skipErrorHandler = []) {\n if (!Array.isArray(skipErrorHandler)) {\n skipErrorHandler = [skipErrorHandler];\n }\n\n return skipErrorHandler.reduce((acc, cur) => {\n acc[cur] = true;\n return acc;\n }, {});\n}\n\nfunction handleRequestError({\n errorHandler = {},\n error,\n response,\n config\n}) {\n // 跳过所有错误类型处理\n if (config.skipErrorHandler === true) return;\n\n const skipObj = skipErrorHandlerToObj(config.skipErrorHandler);\n const resCode = getResponseCode(response);\n\n let errorKey = 'default';\n if (resCode && errorHandler[resCode]) {\n errorKey = resCode;\n } else if (error.type && errorHandler[error.type]) {\n errorKey = error.type;\n } else if (error.response && errorHandler[error.response.status]) {\n errorKey = error.response.status;\n }\n\n if (!skipObj[errorKey] && errorHandler[errorKey]) {\n return errorHandler[errorKey](error);\n }\n}\n\nexport"}},{"format":"javascript","foundDate":1638413755432,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/request.js","start":{"line":181,"column":1,"position":1453},"end":{"line":204,"column":8,"position":1662},"range":[4664,5274],"fragment":"const request = (url, data, options = {}) => {\n if (typeof options === 'string') {\n options = {\n method: options\n };\n }\n\n if (!currentRequestInstance) {\n currentRequestInstance = getRequestInstance();\n }\n\n const userConfig = userConfigHandler(url, data, options);\n const context = createContext(userConfig);\n return currentRequestInstance.request(context).then(async () => {\n if (!context.error) {\n return context.config.useResonse ? context.response : context.response.data;\n }\n\n await handleRequestError(context);\n return Promise.reject(context.error);\n });\n};\n\nexports"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/request.js","start":{"line":171,"column":2,"position":1290},"end":{"line":192,"column":9,"position":1497},"range":[4498,5163],"fragment":"const request = (url, data, options = {}) => {\n if (typeof options === 'string') {\n options = {\n method: options\n };\n }\n if (!currentRequestInstance) {\n currentRequestInstance = getRequestInstance();\n }\n const userConfig = userConfigHandler(url, data, options);\n const context = createContext(userConfig);\n\n return currentRequestInstance.request(context).then(async () => {\n if (!context.error) {\n return context.config.useResonse ? context.response : context.response.data;\n }\n await handleRequestError(context);\n return Promise.reject(context.error);\n });\n};\n\nfunction"}},{"format":"javascript","foundDate":1638413755437,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/preventRepeatReq.js","start":{"line":1,"column":1,"position":0},"end":{"line":64,"column":2,"position":546},"range":[0,1644],"fragment":"const requestMap = new Map();\n\nconst mergeRequestMap = new Map();\nconst requestQueue = new Map();\n\nfunction handleCachingStart(ctx) {\n const isRequesting = mergeRequestMap.get(ctx.key);\n if (isRequesting) {\n return new Promise((resolve) => {\n const queue = requestQueue.get(ctx.key) || [];\n requestQueue.set(ctx.key, queue.concat(resolve));\n });\n }\n mergeRequestMap.set(ctx.key, true);\n}\n\nfunction handleRepeatRequest(ctx) {\n const queue = requestQueue.get(ctx.key);\n if (queue && queue.length > 0) {\n queue.forEach((resolve) => {\n if (ctx.error) {\n resolve({\n error: ctx.error\n });\n } else {\n resolve({\n response: ctx.response\n });\n }\n });\n }\n requestQueue.delete(ctx.key);\n mergeRequestMap.delete(ctx.key);\n}\n\nexport default async (ctx, next) => {\n if (ctx.config.mergeRequest) {\n const result = await handleCachingStart(ctx);\n if (result) {\n Object.keys(result).forEach((key) => {\n ctx[key] = result[key];\n });\n return;\n }\n } else {\n if (requestMap.get(ctx.key) && !ctx.config.mergeRequest) {\n ctx.error = {\n type: 'REPEAT',\n msg: '重复请求',\n config: ctx.config\n };\n return;\n }\n requestMap.set(ctx.key, true);\n }\n\n await next();\n\n if (ctx.config.mergeRequest) {\n handleRepeatRequest(ctx);\n } else {\n requestMap.delete(ctx.key);\n }\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/preventRepeatReq.js","start":{"line":1,"column":1,"position":0},"end":{"line":64,"column":2,"position":546},"range":[0,1644],"fragment":"const requestMap = new Map();\n\nconst mergeRequestMap = new Map();\nconst requestQueue = new Map();\n\nfunction handleCachingStart(ctx) {\n const isRequesting = mergeRequestMap.get(ctx.key);\n if (isRequesting) {\n return new Promise((resolve) => {\n const queue = requestQueue.get(ctx.key) || [];\n requestQueue.set(ctx.key, queue.concat(resolve));\n });\n }\n mergeRequestMap.set(ctx.key, true);\n}\n\nfunction handleRepeatRequest(ctx) {\n const queue = requestQueue.get(ctx.key);\n if (queue && queue.length > 0) {\n queue.forEach((resolve) => {\n if (ctx.error) {\n resolve({\n error: ctx.error\n });\n } else {\n resolve({\n response: ctx.response\n });\n }\n });\n }\n requestQueue.delete(ctx.key);\n mergeRequestMap.delete(ctx.key);\n}\n\nexport default async (ctx, next) => {\n if (ctx.config.mergeRequest) {\n const result = await handleCachingStart(ctx);\n if (result) {\n Object.keys(result).forEach((key) => {\n ctx[key] = result[key];\n });\n return;\n }\n } else {\n if (requestMap.get(ctx.key) && !ctx.config.mergeRequest) {\n ctx.error = {\n type: 'REPEAT',\n msg: '重复请求',\n config: ctx.config\n };\n return;\n }\n requestMap.set(ctx.key, true);\n }\n\n await next();\n\n if (ctx.config.mergeRequest) {\n handleRepeatRequest(ctx);\n } else {\n requestMap.delete(ctx.key);\n }\n};"}},{"format":"javascript","foundDate":1638413755439,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/paramsProcess.js","start":{"line":1,"column":1,"position":0},"end":{"line":11,"column":2,"position":97},"range":[0,283],"fragment":"import { checkHttpRequestHasBody, trimObj } from './helpers';\n\nexport default async (ctx, next) => {\n const config = ctx.config;\n if (checkHttpRequestHasBody(config.method)) {\n trimObj(config.data);\n } else {\n trimObj(config.params);\n }\n await next();\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/paramsProcess.js","start":{"line":1,"column":1,"position":0},"end":{"line":11,"column":2,"position":97},"range":[0,283],"fragment":"import { checkHttpRequestHasBody, trimObj } from './helpers';\n\nexport default async (ctx, next) => {\n const config = ctx.config;\n if (checkHttpRequestHasBody(config.method)) {\n trimObj(config.data);\n } else {\n trimObj(config.params);\n }\n await next();\n};"}},{"format":"javascript","foundDate":1638413755442,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/helpers.js","start":{"line":5,"column":1,"position":2},"end":{"line":90,"column":2,"position":596},"range":[41,2028],"fragment":"export function typeOf(obj) {\n const map = {\n '[object Boolean]': 'boolean',\n '[object Number]': 'number',\n '[object String]': 'string',\n '[object Function]': 'function',\n '[object Array]': 'array',\n '[object Date]': 'date',\n '[object RegExp]': 'regExp',\n '[object Undefined]': 'undefined',\n '[object Null]': 'null',\n '[object Object]': 'object',\n '[object URLSearchParams]': 'URLSearchParams'\n };\n return map[Object.prototype.toString.call(obj)];\n}\n\nexport function isFunction(obj) {\n return typeOf(obj) === 'function';\n}\n\nexport function isDate(obj) {\n return typeOf(obj) === 'date';\n}\n\nexport function isString(obj) {\n return typeOf(obj) === 'string';\n}\n\nexport function isArray(obj) {\n return typeOf(obj) === 'array';\n}\n\nexport function isObject(obj) {\n return typeOf(obj) === 'object';\n}\n\nexport function isURLSearchParams(obj) {\n return typeOf(obj) === 'URLSearchParams';\n}\n\n// eslint-disable-next-line\nexport const isUndefined = val => val === undefined;\n\nexport const isDefined = val => val != null;\n\n\nexport function checkHttpRequestHasBody(method) {\n method = method.toUpperCase();\n const HTTP_METHOD = {\n GET: {\n request_body: false\n },\n POST: {\n request_body: true\n },\n PUT: {\n request_body: true\n },\n DELETE: {\n request_body: true\n },\n HEAD: {\n request_body: false\n },\n OPTIONS: {\n request_body: false\n },\n PATCH: {\n request_body: true\n }\n };\n return HTTP_METHOD[method].request_body;\n}\n\nexport function trimObj(obj) {\n if (isObject(obj)) {\n Object.entries(obj).forEach(([key, value]) => {\n if (isString(value)) {\n obj[key] = value.trim();\n } else if (isObject(value)) {\n trimObj(value);\n }\n });\n }\n}"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/helpers.js","start":{"line":5,"column":1,"position":2},"end":{"line":90,"column":2,"position":596},"range":[41,2028],"fragment":"export function typeOf(obj) {\n const map = {\n '[object Boolean]': 'boolean',\n '[object Number]': 'number',\n '[object String]': 'string',\n '[object Function]': 'function',\n '[object Array]': 'array',\n '[object Date]': 'date',\n '[object RegExp]': 'regExp',\n '[object Undefined]': 'undefined',\n '[object Null]': 'null',\n '[object Object]': 'object',\n '[object URLSearchParams]': 'URLSearchParams'\n };\n return map[Object.prototype.toString.call(obj)];\n}\n\nexport function isFunction(obj) {\n return typeOf(obj) === 'function';\n}\n\nexport function isDate(obj) {\n return typeOf(obj) === 'date';\n}\n\nexport function isString(obj) {\n return typeOf(obj) === 'string';\n}\n\nexport function isArray(obj) {\n return typeOf(obj) === 'array';\n}\n\nexport function isObject(obj) {\n return typeOf(obj) === 'object';\n}\n\nexport function isURLSearchParams(obj) {\n return typeOf(obj) === 'URLSearchParams';\n}\n\n// eslint-disable-next-line\nexport const isUndefined = val => val === undefined;\n\nexport const isDefined = val => val != null;\n\n\nexport function checkHttpRequestHasBody(method) {\n method = method.toUpperCase();\n const HTTP_METHOD = {\n GET: {\n request_body: false\n },\n POST: {\n request_body: true\n },\n PUT: {\n request_body: true\n },\n DELETE: {\n request_body: true\n },\n HEAD: {\n request_body: false\n },\n OPTIONS: {\n request_body: false\n },\n PATCH: {\n request_body: true\n }\n };\n return HTTP_METHOD[method].request_body;\n}\n\nexport function trimObj(obj) {\n if (isObject(obj)) {\n Object.entries(obj).forEach(([key, value]) => {\n if (isString(value)) {\n obj[key] = value.trim();\n } else if (isObject(value)) {\n trimObj(value);\n }\n });\n }\n}"}},{"format":"javascript","foundDate":1638413755450,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-request/cacheControl.js","start":{"line":1,"column":1,"position":0},"end":{"line":209,"column":2,"position":1521},"range":[0,5546],"fragment":"import {\n isObject, isString, isURLSearchParams, checkHttpRequestHasBody\n} from './helpers';\n/**\n * 缓存实现的功能\n * 1. 唯一定位一个请求(url, data | params, method)\n * 其中请求参数根据请求方法使用其中一个就够了\n * 一个请求同时包含 data | params 参数的设计本身不合理\n * 不对这种情况进行兼容\n * 2. 控制缓存内容的大小,localStorage 只有5M\n * 3. 控制缓存时间\n * session(存在内存中)\n * expireTime 存在localStoreage 中\n * 4. 成功的、且响应内容为json的请求进行缓存\n */\n\n/**\n * 配置数据\n * type: 'ram' | 'sessionStorage' | 'localStorage'\n * cacheTime: ''\n */\n\n\n/**\n * 缓存数据结构\n * cache: {\n * url: 'url', // 缓存 url\n * data: data, // 数据\n * expire: '' // 缓存时间\n * }\n */\n\n/**\n * 请求参数可以为如下类型\n * - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams\n * - Browser only: FormData, File, Blob\n * 只缓存参数类型为: string、plain object、URLSearchParams 或者无参数的 请求\n */\n\nconst CACHE_KEY_PREFIX = '__FES_REQUEST_CACHE:';\nconst CACHE_TYPE = {\n ram: 'ram',\n session: 'sessionStorage',\n local: 'localStorage'\n};\n\nconst CACHE_DATA_MAP = new Map();\n\nfunction genInnerKey(key, cacheType = 'ram') {\n if (cacheType !== CACHE_TYPE.ram) {\n return `${CACHE_KEY_PREFIX}${key}`;\n }\n return key;\n}\n\nfunction canCache(data) {\n return !data || isObject(data) || isString(data) || Array.isArray(data) || isURLSearchParams(data);\n}\n\nfunction setCacheData({\n key,\n cacheType = 'ram',\n data,\n cacheTime = 1000 * 60 * 3\n}) {\n const _key = genInnerKey(key, cacheType);\n\n const currentCacheData = {\n cacheType,\n data,\n cacheTime,\n expire: Date.now() + cacheTime\n };\n if (cacheType !== CACHE_TYPE.ram) {\n const cacheInstance = window[CACHE_TYPE[cacheType]];\n try {\n cacheInstance.setItem(_key, JSON.stringify(currentCacheData));\n } catch (e) {\n // setItem 出现异常,清理缓存\n for (const item in cacheInstance) {\n if (item.startsWith(CACHE_KEY_PREFIX) && Object.prototype.hasOwnProperty.call(cacheInstance, item)) {\n cacheInstance.removeItem(item);\n }\n }\n }\n } else {\n CACHE_DATA_MAP.set(_key, currentCacheData);\n }\n}\n\nfunction isExpire({ expire, cacheTime }) {\n if (!cacheTime || expire >= Date.now()) {\n return false;\n }\n return true;\n}\n\nfunction getCacheData({ key, cacheType = 'ram' }) {\n const _key = genInnerKey(key, cacheType);\n if (cacheType !== CACHE_TYPE.ram) {\n const cacheInstance = window[CACHE_TYPE[cacheType]];\n const text = cacheInstance.getItem(_key) || null;\n try {\n const currentCacheData = JSON.parse(text);\n if (currentCacheData && !isExpire(currentCacheData)) {\n return currentCacheData.data;\n }\n cacheInstance.removeItem(_key);\n return null;\n } catch (e) {\n cacheInstance.removeItem(_key);\n return null;\n }\n } else {\n const currentCacheData = CACHE_DATA_MAP.get(_key);\n if (currentCacheData && !isExpire(currentCacheData)) {\n return currentCacheData.data;\n }\n CACHE_DATA_MAP.delete(_key);\n return null;\n }\n}\n\n// 存储缓存队列\nconst cacheStartFlag = new Map();\nconst cachingQueue = new Map();\n\n/**\n * 等上一次请求结果\n * 1. 如果上一次请求成功,直接使用上一次的请求结果\n * 2. 如果上一次请求失败,重启本次请求\n */\nfunction handleCachingStart(ctx, config) {\n const _key = genInnerKey(ctx.key, config.cache.cacheType);\n const caching = cacheStartFlag.get(_key);\n if (caching) {\n return new Promise((resolve) => {\n const queue = cachingQueue.get(_key) || [];\n cachingQueue.set(_key, queue.concat(resolve));\n });\n }\n cacheStartFlag.set(_key, true);\n}\n\n// 有请求成功的\nfunction handleCachingQueueSuccess(ctx, config) {\n // 移除首次缓存 flag\n const _key = genInnerKey(ctx.key, config.cache.cacheType);\n const queue = cachingQueue.get(_key);\n if (queue && queue.length > 0) {\n queue.forEach((resolve) => {\n resolve({\n response: ctx.response\n });\n });\n }\n cachingQueue.delete(_key);\n cacheStartFlag.delete(_key);\n}\n\n// 处理请求失败\nfunction handleCachingQueueError(ctx, config) {\n const _key = genInnerKey(ctx.key, config.cache.cacheType);\n const queue = cachingQueue.get(_key);\n if (queue && queue.length > 0) {\n const firstResolve = queue.shift();\n firstResolve();\n cachingQueue.set(_key, queue);\n } else {\n cachingQueue.delete(_key);\n cacheStartFlag.delete(_key);\n }\n}\n\nexport default async (ctx, next) => {\n const { config } = ctx;\n if (config.cache) {\n const cacheData = getCacheData({ key: ctx.key, cacheType: config.cache.cacheType });\n if (cacheData) {\n ctx.response = {\n data: cacheData\n };\n return;\n }\n const result = await handleCachingStart(ctx, config);\n if (result) {\n Object.keys(result).forEach((key) => {\n ctx[key] = result[key];\n });\n return;\n }\n }\n await next();\n\n if (config.cache) {\n const requestdata = checkHttpRequestHasBody(config.method) ? config.data : config.params;\n if (!ctx.error && ctx.response && canCache(requestdata) && canCache(ctx.response.data)) {\n handleCachingQueueSuccess(ctx, config);\n\n setCacheData({\n key: ctx.key,\n data: ctx.response.data,\n ...config.cache\n });\n } else {\n handleCachingQueueError(ctx, config);\n }\n }\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-request/cacheControl.js","start":{"line":1,"column":1,"position":0},"end":{"line":209,"column":2,"position":1521},"range":[0,5546],"fragment":"import {\n isObject, isString, isURLSearchParams, checkHttpRequestHasBody\n} from './helpers';\n/**\n * 缓存实现的功能\n * 1. 唯一定位一个请求(url, data | params, method)\n * 其中请求参数根据请求方法使用其中一个就够了\n * 一个请求同时包含 data | params 参数的设计本身不合理\n * 不对这种情况进行兼容\n * 2. 控制缓存内容的大小,localStorage 只有5M\n * 3. 控制缓存时间\n * session(存在内存中)\n * expireTime 存在localStoreage 中\n * 4. 成功的、且响应内容为json的请求进行缓存\n */\n\n/**\n * 配置数据\n * type: 'ram' | 'sessionStorage' | 'localStorage'\n * cacheTime: ''\n */\n\n\n/**\n * 缓存数据结构\n * cache: {\n * url: 'url', // 缓存 url\n * data: data, // 数据\n * expire: '' // 缓存时间\n * }\n */\n\n/**\n * 请求参数可以为如下类型\n * - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams\n * - Browser only: FormData, File, Blob\n * 只缓存参数类型为: string、plain object、URLSearchParams 或者无参数的 请求\n */\n\nconst CACHE_KEY_PREFIX = '__FES_REQUEST_CACHE:';\nconst CACHE_TYPE = {\n ram: 'ram',\n session: 'sessionStorage',\n local: 'localStorage'\n};\n\nconst CACHE_DATA_MAP = new Map();\n\nfunction genInnerKey(key, cacheType = 'ram') {\n if (cacheType !== CACHE_TYPE.ram) {\n return `${CACHE_KEY_PREFIX}${key}`;\n }\n return key;\n}\n\nfunction canCache(data) {\n return !data || isObject(data) || isString(data) || Array.isArray(data) || isURLSearchParams(data);\n}\n\nfunction setCacheData({\n key,\n cacheType = 'ram',\n data,\n cacheTime = 1000 * 60 * 3\n}) {\n const _key = genInnerKey(key, cacheType);\n\n const currentCacheData = {\n cacheType,\n data,\n cacheTime,\n expire: Date.now() + cacheTime\n };\n if (cacheType !== CACHE_TYPE.ram) {\n const cacheInstance = window[CACHE_TYPE[cacheType]];\n try {\n cacheInstance.setItem(_key, JSON.stringify(currentCacheData));\n } catch (e) {\n // setItem 出现异常,清理缓存\n for (const item in cacheInstance) {\n if (item.startsWith(CACHE_KEY_PREFIX) && Object.prototype.hasOwnProperty.call(cacheInstance, item)) {\n cacheInstance.removeItem(item);\n }\n }\n }\n } else {\n CACHE_DATA_MAP.set(_key, currentCacheData);\n }\n}\n\nfunction isExpire({ expire, cacheTime }) {\n if (!cacheTime || expire >= Date.now()) {\n return false;\n }\n return true;\n}\n\nfunction getCacheData({ key, cacheType = 'ram' }) {\n const _key = genInnerKey(key, cacheType);\n if (cacheType !== CACHE_TYPE.ram) {\n const cacheInstance = window[CACHE_TYPE[cacheType]];\n const text = cacheInstance.getItem(_key) || null;\n try {\n const currentCacheData = JSON.parse(text);\n if (currentCacheData && !isExpire(currentCacheData)) {\n return currentCacheData.data;\n }\n cacheInstance.removeItem(_key);\n return null;\n } catch (e) {\n cacheInstance.removeItem(_key);\n return null;\n }\n } else {\n const currentCacheData = CACHE_DATA_MAP.get(_key);\n if (currentCacheData && !isExpire(currentCacheData)) {\n return currentCacheData.data;\n }\n CACHE_DATA_MAP.delete(_key);\n return null;\n }\n}\n\n// 存储缓存队列\nconst cacheStartFlag = new Map();\nconst cachingQueue = new Map();\n\n/**\n * 等上一次请求结果\n * 1. 如果上一次请求成功,直接使用上一次的请求结果\n * 2. 如果上一次请求失败,重启本次请求\n */\nfunction handleCachingStart(ctx, config) {\n const _key = genInnerKey(ctx.key, config.cache.cacheType);\n const caching = cacheStartFlag.get(_key);\n if (caching) {\n return new Promise((resolve) => {\n const queue = cachingQueue.get(_key) || [];\n cachingQueue.set(_key, queue.concat(resolve));\n });\n }\n cacheStartFlag.set(_key, true);\n}\n\n// 有请求成功的\nfunction handleCachingQueueSuccess(ctx, config) {\n // 移除首次缓存 flag\n const _key = genInnerKey(ctx.key, config.cache.cacheType);\n const queue = cachingQueue.get(_key);\n if (queue && queue.length > 0) {\n queue.forEach((resolve) => {\n resolve({\n response: ctx.response\n });\n });\n }\n cachingQueue.delete(_key);\n cacheStartFlag.delete(_key);\n}\n\n// 处理请求失败\nfunction handleCachingQueueError(ctx, config) {\n const _key = genInnerKey(ctx.key, config.cache.cacheType);\n const queue = cachingQueue.get(_key);\n if (queue && queue.length > 0) {\n const firstResolve = queue.shift();\n firstResolve();\n cachingQueue.set(_key, queue);\n } else {\n cachingQueue.delete(_key);\n cacheStartFlag.delete(_key);\n }\n}\n\nexport default async (ctx, next) => {\n const { config } = ctx;\n if (config.cache) {\n const cacheData = getCacheData({ key: ctx.key, cacheType: config.cache.cacheType });\n if (cacheData) {\n ctx.response = {\n data: cacheData\n };\n return;\n }\n const result = await handleCachingStart(ctx, config);\n if (result) {\n Object.keys(result).forEach((key) => {\n ctx[key] = result[key];\n });\n return;\n }\n }\n await next();\n\n if (config.cache) {\n const requestdata = checkHttpRequestHasBody(config.method) ? config.data : config.params;\n if (!ctx.error && ctx.response && canCache(requestdata) && canCache(ctx.response.data)) {\n handleCachingQueueSuccess(ctx, config);\n\n setCacheData({\n key: ctx.key,\n data: ctx.response.data,\n ...config.cache\n });\n } else {\n handleCachingQueueError(ctx, config);\n }\n }\n};"}},{"format":"javascript","foundDate":1638413755665,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-monaco-editor/src/runtime/theme/default.js","start":{"line":2,"column":1,"position":2},"end":{"line":111,"column":2,"position":578},"range":[29,3519],"fragment":"export default {\n register(monaco) {\n monaco.editor.defineTheme('defaultTheme', {\n base: 'vs',\n inherit: true,\n rules: [\n {\n foreground: 'c41a16',\n token: 'string'\n },\n {\n foreground: '1c00cf',\n token: 'constant.numeric'\n },\n {\n foreground: 'aa0d91',\n token: 'keyword'\n },\n {\n foreground: '000000',\n token: 'keyword.operator'\n },\n {\n foreground: 'aa0d91',\n token: 'constant.language'\n },\n {\n foreground: '990000',\n token: 'support.class.exception'\n },\n {\n foreground: '000000',\n token: 'entity.name.function'\n },\n {\n fontStyle: 'bold underline',\n token: 'entity.name.type'\n },\n {\n fontStyle: 'italic',\n token: 'variable.parameter'\n },\n {\n foreground: '007400',\n token: 'comment'\n },\n {\n foreground: 'ff0000',\n token: 'invalid'\n },\n {\n background: 'e71a1100',\n token: 'invalid.deprecated.trailing-whitespace'\n },\n {\n foreground: '000000',\n background: 'fafafafc',\n token: 'text source'\n },\n {\n foreground: 'aa0d91',\n token: 'meta.tag'\n },\n {\n foreground: 'aa0d91',\n token: 'declaration.tag'\n },\n {\n foreground: '000000',\n fontStyle: 'bold',\n token: 'support'\n },\n {\n foreground: 'aa0d91',\n token: 'storage'\n },\n {\n fontStyle: 'bold underline',\n token: 'entity.name.section'\n },\n {\n foreground: '000000',\n fontStyle: 'bold',\n token: 'entity.name.function.frame'\n },\n {\n foreground: '333333',\n token: 'meta.tag.preprocessor.xml'\n },\n {\n foreground: '994500',\n fontStyle: 'italic',\n token: 'entity.other.attribute-name'\n },\n {\n foreground: '881280',\n token: 'entity.name.tag'\n }\n ],\n colors: {\n 'editor.foreground': '#000000',\n 'editor.background': '#FFFFFF',\n 'editor.selectionBackground': '#BAD6FD',\n 'editor.lineHighlightBackground': '#0000001A',\n 'editorCursor.foreground': '#000000',\n 'editorWhitespace.foreground': '#B3B3B3F4'\n }\n });\n }\n};"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-monaco-editor/theme/default.js","start":{"line":2,"column":1,"position":2},"end":{"line":111,"column":2,"position":578},"range":[29,3519],"fragment":"export default {\n register(monaco) {\n monaco.editor.defineTheme('defaultTheme', {\n base: 'vs',\n inherit: true,\n rules: [\n {\n foreground: 'c41a16',\n token: 'string'\n },\n {\n foreground: '1c00cf',\n token: 'constant.numeric'\n },\n {\n foreground: 'aa0d91',\n token: 'keyword'\n },\n {\n foreground: '000000',\n token: 'keyword.operator'\n },\n {\n foreground: 'aa0d91',\n token: 'constant.language'\n },\n {\n foreground: '990000',\n token: 'support.class.exception'\n },\n {\n foreground: '000000',\n token: 'entity.name.function'\n },\n {\n fontStyle: 'bold underline',\n token: 'entity.name.type'\n },\n {\n fontStyle: 'italic',\n token: 'variable.parameter'\n },\n {\n foreground: '007400',\n token: 'comment'\n },\n {\n foreground: 'ff0000',\n token: 'invalid'\n },\n {\n background: 'e71a1100',\n token: 'invalid.deprecated.trailing-whitespace'\n },\n {\n foreground: '000000',\n background: 'fafafafc',\n token: 'text source'\n },\n {\n foreground: 'aa0d91',\n token: 'meta.tag'\n },\n {\n foreground: 'aa0d91',\n token: 'declaration.tag'\n },\n {\n foreground: '000000',\n fontStyle: 'bold',\n token: 'support'\n },\n {\n foreground: 'aa0d91',\n token: 'storage'\n },\n {\n fontStyle: 'bold underline',\n token: 'entity.name.section'\n },\n {\n foreground: '000000',\n fontStyle: 'bold',\n token: 'entity.name.function.frame'\n },\n {\n foreground: '333333',\n token: 'meta.tag.preprocessor.xml'\n },\n {\n foreground: '994500',\n fontStyle: 'italic',\n token: 'entity.other.attribute-name'\n },\n {\n foreground: '881280',\n token: 'entity.name.tag'\n }\n ],\n colors: {\n 'editor.foreground': '#000000',\n 'editor.background': '#FFFFFF',\n 'editor.selectionBackground': '#BAD6FD',\n 'editor.lineHighlightBackground': '#0000001A',\n 'editorCursor.foreground': '#000000',\n 'editorWhitespace.foreground': '#B3B3B3F4'\n }\n });\n }\n};"}},{"format":"markup","foundDate":1638413755668,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-locale/src/runtime/views/SelectLang.vue","start":{"line":1,"column":1,"position":0},"end":{"line":74,"column":2,"position":446},"range":[0,2018],"fragment":"\n\n\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-locale/views/SelectLang.vue","start":{"line":1,"column":1,"position":0},"end":{"line":74,"column":2,"position":446},"range":[0,2018],"fragment":"\n\n\n\n"}},{"format":"markup","foundDate":1638413755674,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-layout/src/runtime/views/MultiTabProvider.vue","start":{"line":17,"column":17,"position":77},"end":{"line":50,"column":10,"position":306},"range":[417,1567],"fragment":"\n \n \n \n \n \n \n \n \n \n\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/MultiTabProvider.vue","start":{"line":121,"column":9,"position":787},"end":{"line":180,"column":2,"position":1090},"range":[4088,5479],"fragment":"};\n const getPageKey = (_route) => {\n const selectedPage = findPage(_route.path);\n if (selectedPage) {\n return selectedPage.key;\n }\n return '';\n };\n const handlerMore = ({ key }) => {\n switch (key) {\n case 'closeOtherPage':\n closeOtherPage();\n break;\n case 'reloadPage':\n reloadPage();\n break;\n default:\n }\n };\n return {\n route,\n pageList,\n getPageKey,\n reloadPage,\n switchPage,\n handlerMore,\n onEdit\n };\n }\n};\n\n"}},{"format":"markup","foundDate":1638413755680,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-layout/src/runtime/views/MenuIcon.vue","start":{"line":1,"column":1,"position":0},"end":{"line":61,"column":2,"position":347},"range":[0,1657],"fragment":"\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/MenuIcon.vue","start":{"line":1,"column":1,"position":0},"end":{"line":61,"column":2,"position":347},"range":[0,1657],"fragment":"\n"}},{"format":"markup","foundDate":1638413755682,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-layout/src/runtime/views/Menu.vue","start":{"line":1,"column":1,"position":0},"end":{"line":106,"column":2,"position":667},"range":[0,3634],"fragment":"\n \n \n\n\n\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/Menu.vue","start":{"line":1,"column":1,"position":0},"end":{"line":106,"column":2,"position":667},"range":[0,3634],"fragment":"\n \n \n\n\n\n\n"}},{"format":"markup","foundDate":1638413755695,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-layout/src/runtime/views/BaseLayout.vue","start":{"line":1,"column":1,"position":0},"end":{"line":378,"column":2,"position":2314},"range":[0,11515],"fragment":"\n\n\n\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/BaseLayout.vue","start":{"line":1,"column":1,"position":0},"end":{"line":378,"column":2,"position":2314},"range":[0,11515],"fragment":"\n\n\n\n\n"}},{"format":"markup","foundDate":1638413755701,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-layout/src/runtime/views/404.vue","start":{"line":1,"column":1,"position":0},"end":{"line":35,"column":2,"position":202},"range":[0,794],"fragment":"\n\n{\n \"layout\": false\n}\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/404.vue","start":{"line":1,"column":1,"position":0},"end":{"line":35,"column":2,"position":202},"range":[0,794],"fragment":"\n\n{\n \"layout\": false\n}\n\n"}},{"format":"markup","foundDate":1638413755702,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-plugin-layout/src/runtime/views/403.vue","start":{"line":1,"column":1,"position":0},"end":{"line":35,"column":2,"position":202},"range":[0,795],"fragment":"\n\n{\n \"layout\": false\n}\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template/src/.fes/plugin-layout/views/403.vue","start":{"line":1,"column":1,"position":0},"end":{"line":35,"column":2,"position":202},"range":[0,794],"fragment":"\n\n{\n \"layout\": false\n}\n\n"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/fes-template-h5/src/.fes/plugin-icon/Icon/Icon.vue","start":{"line":1,"column":1,"position":0},"end":{"line":41,"column":2,"position":278},"range":[0,1225],"fragment":""}},{"format":"json","foundDate":1638413755740,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/create-fes-app/templates/app/h5/tsconfig.json","start":{"line":1,"column":1,"position":0},"end":{"line":37,"column":2,"position":233},"range":[0,893],"fragment":"{\n \"compilerOptions\": {\n \"outDir\": \"build/dist\",\n \"module\": \"esnext\",\n \"target\": \"esnext\",\n \"lib\": [\"esnext\", \"dom\"],\n \"sourceMap\": true,\n \"baseUrl\": \".\",\n \"jsx\": \"preserve\",\n \"allowSyntheticDefaultImports\": true,\n \"moduleResolution\": \"node\",\n \"forceConsistentCasingInFileNames\": true,\n \"noImplicitReturns\": true,\n \"suppressImplicitAnyIndexErrors\": true,\n \"noUnusedLocals\": true,\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"strict\": true,\n \"paths\": {\n \"@/*\": [\"./src/*\"],\n \"@@/*\": [\"./src/.fes/*\"]\n }\n },\n \"include\": [\n \"src/**/*\",\n \"tests/**/*\",\n \"test/**/*\",\n \"__test__/**/*\",\n \"typings/**/*\",\n \"config/**/*\",\n \".eslintrc.js\",\n \".stylelintrc.js\",\n \".prettierrc.js\"\n ],\n \"exclude\": [\"node_modules\", \"build\", \"dist\", \"scripts\", \"src/.fes/*\", \"webpack\", \"jest\"]\n}"},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/create-fes-app/templates/app/pc/tsconfig.json","start":{"line":1,"column":1,"position":0},"end":{"line":37,"column":2,"position":233},"range":[0,893],"fragment":"{\n \"compilerOptions\": {\n \"outDir\": \"build/dist\",\n \"module\": \"esnext\",\n \"target\": \"esnext\",\n \"lib\": [\"esnext\", \"dom\"],\n \"sourceMap\": true,\n \"baseUrl\": \".\",\n \"jsx\": \"preserve\",\n \"allowSyntheticDefaultImports\": true,\n \"moduleResolution\": \"node\",\n \"forceConsistentCasingInFileNames\": true,\n \"noImplicitReturns\": true,\n \"suppressImplicitAnyIndexErrors\": true,\n \"noUnusedLocals\": true,\n \"allowJs\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"strict\": true,\n \"paths\": {\n \"@/*\": [\"./src/*\"],\n \"@@/*\": [\"./src/.fes/*\"]\n }\n },\n \"include\": [\n \"src/**/*\",\n \"tests/**/*\",\n \"test/**/*\",\n \"__test__/**/*\",\n \"typings/**/*\",\n \"config/**/*\",\n \".eslintrc.js\",\n \".stylelintrc.js\",\n \".prettierrc.js\"\n ],\n \"exclude\": [\"node_modules\", \"build\", \"dist\", \"scripts\", \"src/.fes/*\", \"webpack\", \"jest\"]\n}"}},{"format":"json","foundDate":1638413755741,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/packages/create-fes-app/templates/app/h5/package.json","start":{"line":8,"column":3,"position":43},"end":{"line":31,"column":27,"position":148},"range":[152,567],"fragment":"},\n \"keywords\": [\n \"管理端\",\n \"fes\",\n \"fast\",\n \"easy\",\n \"strong\"\n ],\n \"files\": [\n \".eslintrc.js\",\n \".gitignore\",\n \".fes.js\",\n \".fes.prod.js\",\n \"mock.js\",\n \"package.json\",\n \"README.md\",\n \"tsconfig.json\",\n \"/src\",\n \"/config\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/WeBankFinTech/fes.js.git\",\n \"directory\": \"packages/fes-template-h5\""},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/packages/create-fes-app/templates/app/pc/package.json","start":{"line":11,"column":3,"position":64},"end":{"line":34,"column":24,"position":169},"range":[255,667],"fragment":"},\n \"keywords\": [\n \"管理端\",\n \"fes\",\n \"fast\",\n \"easy\",\n \"strong\"\n ],\n \"files\": [\n \".eslintrc.js\",\n \".gitignore\",\n \".fes.js\",\n \".fes.prod.js\",\n \"mock.js\",\n \"package.json\",\n \"README.md\",\n \"tsconfig.json\",\n \"/src\",\n \"/config\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/WeBankFinTech/fes.js.git\",\n \"directory\": \"packages/fes-template\""}},{"format":"javascript","foundDate":1638413755768,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/docs/zh/reference/plugin/plugins/qiankun.md","start":{"line":149,"column":2,"position":405},"end":{"line":229,"column":6,"position":642},"range":[3260,4520],"fragment":"l` 参数,用于指定加载子应用什么路由页面。\n\n ```vue\n\n\n```\n\n## 子应用配置\n\n### 第一步:插件注册\n```js\nexport default {\n qiankun: {\n micro: {},\n }\n};\n```\n\n### 第二步:配置运行时生命周期钩子(可选)\n插件会自动为你创建好 `qiankun` 子应用需要的生命周期钩子,但是如果你想在生命周期期间加一些自定义逻辑,可以在子应用的 `src/app.js` 里导出 `qiankun` 对象,并实现每一个生命周期钩子,其中钩子函数的入参 `props` 由主应用自动注入。\n```js\nexport const qiankun = {\n // 应用加载之前\n async bootstrap(props) {\n console.log('app1 bootstrap', props);\n },\n // 应用 render 之前触发\n async mount(props) {\n console.log('app1 mount', props);\n },\n // 当 props 更新时触发\n async update(props){\n console.log('app1 update', props);\n },\n // 应用卸载之后触发\n async unmount(props) {\n console.log('app1 unmount', props);\n },\n};\n\n```\n\n## 父子应用通讯\n\n有两种方式实现\n\n### 配合 [useModel](./model.md) 使用\n\n确保已经安装了 `@fesjs/plugin-model`:\n```json\n{\n \"dependencies\": {\n \"@fesjs/fes\": \"^2.0.0\",\n \"@fesjs/plugin-model\": \"^2.0.0\"\n },\n}\n```\n\n#### 主应用传递 props\n\n- 如果使用 `MicroApp` 组件模式消费子应用,直接通过 props 传递即可:\n```vue\n\n\n```\n\n#### props\n| 属性 | 说明 | 类型 | 默认值 |\n| ------------- | ------------- | ------------- | ------------- |\n| theme | 编辑器的主题,使用其他主题需要先使用`monaco.editor.defineTheme`定义主题 | string | `defaultTheme` |\n| language | 编辑器的语言 | string | - |\n| height | 编辑器的高度 | string | `100%` |\n| width | 编辑器的宽度 | string | `100%` |\n| modelValue(v-model) | 编辑器的代码 | string | - |\n| readOnly | 是否只读 | boolean | `false` |\n| options | 编辑器的配置对象 | object | `{}` |\n| check | 是否检查代码,如果检查不通过则不更新数据,目前只支持`json` | boolean | `false` |\n\n#### events\n\n| 事件名称 | 说明 | 回调参数 |\n| "},"duplicationB":{"sourceId":"/Users/qlin/code/fes.js/docs/zh/reference/plugin/plugins/editor.md","start":{"line":5,"column":1,"position":4},"end":{"line":120,"column":2,"position":578},"range":[4,3290],"fragment":"esjs/plugin-monaco-editor\n\n\n## 介绍\n我们会遇到需要编辑代码的场景,比如编辑`json`、`javascript`、`python`等等,[Monaco Editor](https://github.com/Microsoft/monaco-editor) 是\b一个好用而且强大的的代码编辑器库,引入`Monaco Editor`有一定的成本,插件实现了胶水代码,提供轻松引入的能力。目前内置的 `Monaco Editor` 版本是 `1.9.1`。\n\n## 启用方式\n在 `package.json` 中引入依赖:\n```json\n{\n \"dependencies\": {\n \"@fesjs/fes\": \"^2.0.0\",\n \"@fesjs/plugin-monaco-editor\": \"^2.0.0\"\n },\n}\n```\n\n## 配置\n\n### 编译时配置\n在执行 `fes dev` 或者 `fes build` 时,通过此配置生成运行时的代码,在配置文件`.fes.js` 中配置:\n```js\nexport default {\n monacoEditor: {\n languages: ['javascript', 'typescript', 'html', 'json']\n }\n}\n```\n我们通过 `monaco-editor-webpack-plugin` 集成 `Monaco Editor` 的 `ESM`版本,所以编辑时其实就是 `monaco-editor-webpack-plugin` 的配置,具体配置项参考[文档](https://github.com/Microsoft/monaco-editor-webpack-plugin)。\n\n\n#### filename\n- **类型**:自定义worker脚本名称\n \n- **默认值**:`'[name].worker.js'`\n\n#### publicPath\n- **类型**:自定义worker脚本的路径\n \n- **默认值**:`''`\n\n#### languages\n- **类型**:需要支持的语言类型\n \n- **默认值**:`['abap', 'apex', 'azcli', 'bat', 'bicep', 'cameligo', 'clojure', 'coffee', 'cpp', 'csharp', 'csp', 'css', 'dart', 'dockerfile', 'ecl', 'elixir', 'fsharp', 'go', 'graphql', 'handlebars', 'hcl', 'html', 'ini', 'java', 'javascript', 'json', 'julia', 'kotlin', 'less', 'lexon', 'liquid', 'lua', 'm3', 'markdown', 'mips', 'msdax', 'mysql', 'objective-c', 'pascal', 'pascaligo', 'perl', 'pgsql', 'php', 'postiats', 'powerquery', 'powershell', 'pug', 'python', 'qsharp', 'r', 'razor', 'redis', 'redshift', 'restructuredtext', 'ruby', 'rust', 'sb', 'scala', 'scheme', 'scss', 'shell', 'solidity', 'sophia', 'sparql', 'sql', 'st', 'swift', 'systemverilog', 'tcl', 'twig', 'typescript', 'vb', 'xml', 'yaml']`\n\n- **详情**:默认是全部,但是编译后包体积会非常大,建议用到什么语言则配置什么语言。特别某些语言依赖其他语言,例如`javascript`依赖`typescript`,需要使用`javascript`时需要配置为:\n```js\nexport default {\n monacoEditor: {\n languages: ['javascript', 'typescript']\n }\n}\n```\n\n## API\n\n### monaco\n编辑器的全局对象,提供扩展语言,自定义主题等等API,具体用法请查看[monaco](https://microsoft.github.io/monaco-editor/)官方文档。\n```js\nimport { monaco } from '@fesjs/fes';\n\nmonaco.editor.defineTheme('myCoolTheme', {\n\tbase: 'vs',\n\tinherit: false,\n\trules: [\n\t\t{ token: 'custom-info', foreground: '808080' },\n\t\t{ token: 'custom-error', foreground: 'ff0000', fontStyle: 'bold' },\n\t\t{ token: 'custom-notice', foreground: 'FFA500' },\n\t\t{ token: 'custom-date', foreground: '008800' },\n\t]\n});\n\n```\n\n### 组件 MonacoEditor\n\n```vue\n\n\n```\n\n#### props\n| 属性 | 说明 | 类型 | 默认值 |\n| ------------- | ------------- | ------------- | ------------- |\n| theme | 编辑器的主题,使用其他主题需要先使用`monaco.editor.defineTheme`定义主题 | string | `defaultTheme` |\n| language | 编辑器的语言 | string | - |\n| height | 编辑器的高度 | string | `100%` |\n| width | 编辑器的宽度 | string | `100%` |\n| modelValue(v-model) | 编辑器的代码 | string | - |\n| readOnly | 是否只读 | boolean | `false` |\n| options | 编辑器的配置对象 | object | `{}` |\n| check | 是否检查代码,如果检查不通过则不更新数据,目前只支持`json` | boolean | `false` |\n\n#### events\n\n| 事件名称 | 说明 | 回调参数 |\n| "}},{"format":"javascript","foundDate":1638413756459,"duplicationA":{"sourceId":"/Users/qlin/code/fes.js/docs/reference/plugin/plugins/access.md","start":{"line":18,"column":2,"position":76},"end":{"line":280,"column":1,"position":1042},"range":[382,4871],"fragment":"cess2 \n\n\n```\n\n\n### 匹配规则\n\n#### 全等匹配\n资源的匹配规则默认是使用全等匹配,比如页面 `pages/a.vue` 对应路由 `path` 是 `/a`,则 `/a` 就是页面的资源ID。如果我们设置:\n```js\naccess.setAccess(['/a'])\n```\n由于权限列表中包含`/a`,则表示拥有此页面权限。\n\n#### 模糊匹配\n页面`@id.vue`会映射为动态路由`/:id`,想匹配此页面有两种办法:\n- **access.setAccess(['/:id'])**\n- **access.setAccess(['/*'])**\n\n第二种是模糊匹配,`*`表示任意路径。比如角色`admin`需要全部权限,则可以:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"*\"]\n }\n }\n}\n```\n\n\n### 角色\n通常我们会用角色来控制权限,相应的Fes.js 用角色定义一组资源。当访问 Fes.js 应用时,使用插件提供的 API 设置用户的角色,角色对应的资源才可见,非角色对应的资源不可见。\n\n\n当然有时候业务比较复杂,角色对应的权限是动态的。不要怕!插件提供粒度更细的 API 来设置当前用户能访问的资源。\n\n\n## 启用方式\n在 `package.json` 中引入依赖:\n```json\n{\n \"dependencies\": {\n \"@fesjs/fes\": \"^2.0.0\",\n \"@fesjs/plugin-access\": \"^2.0.0\"\n },\n}\n```\n\n## 配置\n\n### 编译时配置\n在执行 `fes dev` 或者 `fes build` 时,通过此配置生成运行时的代码,在配置文件`.fes.js` 中配置:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"/\", \"/onepiece\", '/store']\n }\n }\n}\n```\n\n#### roles\n- **类型**:对象\n \n- **默认值**:`{}`\n\n- **详情**: \n \n 角色预定义列表。`key` 是角色 Id ,`value`是角色 Id 对应的资源列表。\n\n\n### 运行时配置\n在 `app.js` 中配置\n\n#### unAccessHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用 `unAccessHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n unAccessHandler({ to, next }) {\n const accesssIds = accessApi.getAccess();\n if (to.path === '/404') {\n accessApi.setAccess(accesssIds.concat(['/404']));\n return next('/404');\n }\n if (!accesssIds.includes('/403')) {\n accessApi.setAccess(accesssIds.concat(['/403']));\n }\n next('/403');\n }\n};\n\n```\n\n#### noFoundHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不存在,则会调用 `noFoundHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n noFoundHandler({ next }) {\n const accesssIds = accessApi.getAccess();\n if (!accesssIds.includes('/404')) {\n accessApi.setAccess(accesssIds.concat(['/404']));\n }\n next('/404');\n }\n};\n\n```\n\n## API\n\n### access\n插件 API 通过 `@fesjs/fes` 导出:\n```js\nimport { access } from '@fesjs/fes'\n```\n\n#### access.hasAccess\n- **类型**:函数\n \n- **详情**: 判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:Boolean\n\n#### access.isDataReady\n- **类型**:函数\n \n- **详情**:可以用异步数据来设置权限,`isDataReady` 用来判断异步数据是否已经加载完毕。\n- **参数**:null\n- **返回值**:Boolean\n```js\nimport { access } from '@fesjs/fes';\nconsole.log(access.isDataReady())\n```\n\n#### access.setRole\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - roleId,角色Id,有两种类型:\n - String,对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应对应着 `roles` 配置对象中的 `key`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setRole(['admin'])\n```\n\n#### access.setAccess\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - accessIds,资源Id数组,有两种类型:\n - Array,数组项对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应该是`Array`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setAccess(['/a', '/b', '/c'])\n```\n\n#### access.getAccess\n- **类型**:函数\n \n- **详情**:返回当前可见的资源列表。\n- **参数**:null\n\n```js\nimport { access } from '@fesjs/fes';\naccess.getAccess();\n```\n\n### useAccess\n- **类型**:[composition]((https://v3.cn.vuejs.org/guide/composition-api-introduction.html)) 函数\n \n- **详情**:判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:`ref`\n \n```vue\n\n\n```\n### v-access\n在指令 `v-access` 中传入 `accessId`,则当 `accessId` 拥有权限时显示DOM,当没有权限时隐藏此DOM。\n```vue\n\n\n```\n\n\n### 匹配规则\n\n#### 全等匹配\n资源的匹配规则默认是使用全等匹配,比如页面 `pages/a.vue` 对应路由 `path` 是 `/a`,则 `/a` 就是页面的资源ID。如果我们设置:\n```js\naccess.setAccess(['/a'])\n```\n由于权限列表中包含`/a`,则表示拥有此页面权限。\n\n#### 模糊匹配\n页面`@id.vue`会映射为动态路由`/:id`,想匹配此页面有两种办法:\n- **access.setAccess(['/:id'])**\n- **access.setAccess(['/*'])**\n\n第二种是模糊匹配,`*`表示任意路径。比如角色`admin`需要全部权限,则可以:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"*\"]\n }\n }\n}\n```\n\n\n### 角色\n通常我们会用角色来控制权限,相应的Fes.js 用角色定义一组资源。当访问 Fes.js 应用时,使用插件提供的 API 设置用户的角色,角色对应的资源才可见,非角色对应的资源不可见。\n\n\n当然有时候业务比较复杂,角色对应的权限是动态的。不要怕!插件提供粒度更细的 API 来设置当前用户能访问的资源。\n\n\n## 启用方式\n在 `package.json` 中引入依赖:\n```json\n{\n \"dependencies\": {\n \"@fesjs/fes\": \"^2.0.0\",\n \"@fesjs/plugin-access\": \"^2.0.0\"\n },\n}\n```\n\n## 配置\n\n### 编译时配置\n在执行 `fes dev` 或者 `fes build` 时,通过此配置生成运行时的代码,在配置文件`.fes.js` 中配置:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"/\", \"/onepiece\", '/store']\n }\n }\n}\n```\n\n#### roles\n- **类型**:对象\n \n- **默认值**:`{}`\n\n- **详情**: \n \n 角色预定义列表。`key` 是角色 Id ,`value`是角色 Id 对应的资源列表。\n\n\n### 运行时配置\n在 `app.js` 中配置\n\n#### unAccessHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用 `unAccessHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n unAccessHandler({ to, next }) {\n const accesssIds = accessApi.getAccess();\n if (to.path === '/404') {\n accessApi.setAccess(accesssIds.concat(['/404']));\n return next('/404');\n }\n if (!accesssIds.includes('/403')) {\n accessApi.setAccess(accesssIds.concat(['/403']));\n }\n next('/403');\n }\n};\n\n```\n\n#### noFoundHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不存在,则会调用 `noFoundHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n noFoundHandler({ next }) {\n const accesssIds = accessApi.getAccess();\n if (!accesssIds.includes('/404')) {\n accessApi.setAccess(accesssIds.concat(['/404']));\n }\n next('/404');\n }\n};\n\n```\n\n## API\n\n### access\n插件 API 通过 `@fesjs/fes` 导出:\n```js\nimport { access } from '@fesjs/fes'\n```\n\n#### access.hasAccess\n- **类型**:函数\n \n- **详情**: 判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:Boolean\n\n#### access.isDataReady\n- **类型**:函数\n \n- **详情**:可以用异步数据来设置权限,`isDataReady` 用来判断异步数据是否已经加载完毕。\n- **参数**:null\n- **返回值**:Boolean\n```js\nimport { access } from '@fesjs/fes';\nconsole.log(access.isDataReady())\n```\n\n#### access.setRole\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - roleId,角色Id,有两种类型:\n - String,对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应对应着 `roles` 配置对象中的 `key`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setRole(['admin'])\n```\n\n#### access.setAccess\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - accessIds,资源Id数组,有两种类型:\n - Array,数组项对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应该是`Array`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setAccess(['/a', '/b', '/c'])\n```\n\n#### access.getAccess\n- **类型**:函数\n \n- **详情**:返回当前可见的资源列表。\n- **参数**:null\n\n```js\nimport { access } from '@fesjs/fes';\naccess.getAccess();\n```\n\n### useAccess\n- **类型**:[composition]((https://v3.cn.vuejs.org/guide/composition-api-introduction.html)) 函数\n \n- **详情**:判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:`ref`\n \n```vue\n\n\n```\n### v-access\n在指令 `v-access` 中传入 `accessId`,则当 `accessId` 拥有权限时显示DOM,当没有权限时隐藏此DOM。\n```vue\n\n\n```\n\n\n### 匹配规则\n\n#### 全等匹配\n资源的匹配规则默认是使用全等匹配,比如页面 `pages/a.vue` 对应路由 `path` 是 `/a`,则 `/a` 就是页面的资源ID。如果我们设置:\n```js\naccess.setAccess(['/a'])\n```\n由于权限列表中包含`/a`,则表示拥有此页面权限。\n\n#### 模糊匹配\n页面`@id.vue`会映射为动态路由`/:id`,想匹配此页面有两种办法:\n- **access.setAccess(['/:id'])**\n- **access.setAccess(['/*'])**\n\n第二种是模糊匹配,`*`表示任意路径。比如角色`admin`需要全部权限,则可以:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"*\"]\n }\n }\n}\n```\n\n\n### 角色\n通常我们会用角色来控制权限,相应的Fes.js 用角色定义一组资源。当访问 Fes.js 应用时,使用插件提供的 API 设置用户的角色,角色对应的资源才可见,非角色对应的资源不可见。\n\n\n当然有时候业务比较复杂,角色对应的权限是动态的。不要怕!插件提供粒度更细的 API 来设置当前用户能访问的资源。\n\n\n## 启用方式\n在 `package.json` 中引入依赖:\n```json\n{\n \"dependencies\": {\n \"@fesjs/fes\": \"^2.0.0\",\n \"@fesjs/plugin-access\": \"^2.0.0\"\n },\n}\n```\n\n## 配置\n\n### 编译时配置\n在执行 `fes dev` 或者 `fes build` 时,通过此配置生成运行时的代码,在配置文件`.fes.js` 中配置:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"/\", \"/onepiece\", '/store']\n }\n }\n}\n```\n\n#### roles\n- **类型**:对象\n \n- **默认值**:`{}`\n\n- **详情**: \n \n 角色预定义列表。`key` 是角色 Id ,`value`是角色 Id 对应的资源列表。\n\n\n### 运行时配置\n在 `app.js` 中配置\n\n#### unAccessHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用 `unAccessHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n unAccessHandler({ to, next }) {\n const accesssIds = accessApi.getAccess();\n if (to.path === '/404') {\n accessApi.setAccess(accesssIds.concat(['/404']));\n return next('/404');\n }\n if (!accesssIds.includes('/403')) {\n accessApi.setAccess(accesssIds.concat(['/403']));\n }\n next('/403');\n }\n};\n\n```\n\n#### noFoundHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不存在,则会调用 `noFoundHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n noFoundHandler({ next }) {\n const accesssIds = accessApi.getAccess();\n if (!accesssIds.includes('/404')) {\n accessApi.setAccess(accesssIds.concat(['/404']));\n }\n next('/404');\n }\n};\n\n```\n\n## API\n\n### access\n插件 API 通过 `@fesjs/fes` 导出:\n```js\nimport { access } from '@fesjs/fes'\n```\n\n#### access.hasAccess\n- **类型**:函数\n \n- **详情**: 判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:Boolean\n\n#### access.isDataReady\n- **类型**:函数\n \n- **详情**:可以用异步数据来设置权限,`isDataReady` 用来判断异步数据是否已经加载完毕。\n- **参数**:null\n- **返回值**:Boolean\n```js\nimport { access } from '@fesjs/fes';\nconsole.log(access.isDataReady())\n```\n\n#### access.setRole\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - roleId,角色Id,有两种类型:\n - String,对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应对应着 `roles` 配置对象中的 `key`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setRole(['admin'])\n```\n\n#### access.setAccess\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - accessIds,资源Id数组,有两种类型:\n - Array,数组项对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应该是`Array`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setAccess(['/a', '/b', '/c'])\n```\n\n#### access.getAccess\n- **类型**:函数\n \n- **详情**:返回当前可见的资源列表。\n- **参数**:null\n\n```js\nimport { access } from '@fesjs/fes';\naccess.getAccess();\n```\n\n### useAccess\n- **类型**:[composition]((https://v3.cn.vuejs.org/guide/composition-api-introduction.html)) 函数\n \n- **详情**:判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:`ref`\n \n```vue\n\n\n```\n### v-access\n在指令 `v-access` 中传入 `accessId`,则当 `accessId` 拥有权限时显示DOM,当没有权限时隐藏此DOM。\n```vue\n\n\n```\n\n\n### 匹配规则\n\n#### 全等匹配\n资源的匹配规则默认是使用全等匹配,比如页面 `pages/a.vue` 对应路由 `path` 是 `/a`,则 `/a` 就是页面的资源ID。如果我们设置:\n```js\naccess.setAccess(['/a'])\n```\n由于权限列表中包含`/a`,则表示拥有此页面权限。\n\n#### 模糊匹配\n页面`@id.vue`会映射为动态路由`/:id`,想匹配此页面有两种办法:\n- **access.setAccess(['/:id'])**\n- **access.setAccess(['/*'])**\n\n第二种是模糊匹配,`*`表示任意路径。比如角色`admin`需要全部权限,则可以:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"*\"]\n }\n }\n}\n```\n\n\n### 角色\n通常我们会用角色来控制权限,相应的Fes.js 用角色定义一组资源。当访问 Fes.js 应用时,使用插件提供的 API 设置用户的角色,角色对应的资源才可见,非角色对应的资源不可见。\n\n\n当然有时候业务比较复杂,角色对应的权限是动态的。不要怕!插件提供粒度更细的 API 来设置当前用户能访问的资源。\n\n\n## 启用方式\n在 `package.json` 中引入依赖:\n```json\n{\n \"dependencies\": {\n \"@fesjs/fes\": \"^2.0.0\",\n \"@fesjs/plugin-access\": \"^2.0.0\"\n },\n}\n```\n\n## 配置\n\n### 编译时配置\n在执行 `fes dev` 或者 `fes build` 时,通过此配置生成运行时的代码,在配置文件`.fes.js` 中配置:\n```js\nexport default {\n access: {\n roles: {\n admin: [\"/\", \"/onepiece\", '/store']\n }\n }\n}\n```\n\n#### roles\n- **类型**:对象\n \n- **默认值**:`{}`\n\n- **详情**: \n \n 角色预定义列表。`key` 是角色 Id ,`value`是角色 Id 对应的资源列表。\n\n\n### 运行时配置\n在 `app.js` 中配置\n\n#### unAccessHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用 `unAccessHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n unAccessHandler({ to, next }) {\n const accesssIds = accessApi.getAccess();\n if (to.path === '/404') {\n accessApi.setAccess(accesssIds.concat(['/404']));\n return next('/404');\n }\n if (!accesssIds.includes('/403')) {\n accessApi.setAccess(accesssIds.concat(['/403']));\n }\n next('/403');\n }\n};\n\n```\n\n#### noFoundHandler\n- **类型**:`Function`\n \n- **默认值**:`null`\n\n- **详情**: \n \n 当进入某个路由时,如果路由对应的页面不存在,则会调用 `noFoundHandler` 函数。\n- **参数**\n - router:createRouter 创建的路由实例\n - to: 准备进入的路由\n - from:离开的路由\n - next: [next函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)\n\n比如:\n```js\nexport const access = {\n noFoundHandler({ next }) {\n const accesssIds = accessApi.getAccess();\n if (!accesssIds.includes('/404')) {\n accessApi.setAccess(accesssIds.concat(['/404']));\n }\n next('/404');\n }\n};\n\n```\n\n## API\n\n### access\n插件 API 通过 `@fesjs/fes` 导出:\n```js\nimport { access } from '@fesjs/fes'\n```\n\n#### access.hasAccess\n- **类型**:函数\n \n- **详情**: 判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:Boolean\n\n#### access.isDataReady\n- **类型**:函数\n \n- **详情**:可以用异步数据来设置权限,`isDataReady` 用来判断异步数据是否已经加载完毕。\n- **参数**:null\n- **返回值**:Boolean\n```js\nimport { access } from '@fesjs/fes';\nconsole.log(access.isDataReady())\n```\n\n#### access.setRole\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - roleId,角色Id,有两种类型:\n - String,对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应对应着 `roles` 配置对象中的 `key`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setRole(['admin'])\n```\n\n#### access.setAccess\n- **类型**:函数\n \n- **详情**:设置当前的角色。\n- **参数**:\n - accessIds,资源Id数组,有两种类型:\n - Array,数组项对应着 `roles` 配置对象中的 `key`。\n - Promise,Promise resolve 的结果应该是`Array`。\n```js\nimport { access } from '@fesjs/fes';\naccess.setAccess(['/a', '/b', '/c'])\n```\n\n#### access.getAccess\n- **类型**:函数\n \n- **详情**:返回当前可见的资源列表。\n- **参数**:null\n\n```js\nimport { access } from '@fesjs/fes';\naccess.getAccess();\n```\n\n### useAccess\n- **类型**:[composition]((https://v3.cn.vuejs.org/guide/composition-api-introduction.html)) 函数\n \n- **详情**:判断某个资源是否可见。\n- **参数**:\n - accessId,资源Id\n- **返回值**:`ref`\n \n```vue\n\n\n```\n### v-access\n在指令 `v-access` 中传入 `accessId`,则当 `accessId` 拥有权限时显示DOM,当没有权限时隐藏此DOM。\n```vue\n\n