chore: 插件编辑与运行测试beta

pull/370/head
xiaojunnuo 2025-04-08 22:56:38 +08:00
parent c021dd03d3
commit a0eeb17d73
17 changed files with 169 additions and 122 deletions

View File

@ -3,14 +3,23 @@ import { AbstractTaskPlugin } from "./api.js";
import { pluginGroups } from "./group.js"; import { pluginGroups } from "./group.js";
const onRegister = ({ key, value }: OnRegisterContext<AbstractTaskPlugin>) => { const onRegister = ({ key, value }: OnRegisterContext<AbstractTaskPlugin>) => {
//如果有相同名字的先移除
for (const group of Object.values(pluginGroups)) {
const index = group.plugins.findIndex(plugin => plugin.name === key);
if (index > -1) {
group.plugins.splice(index, 1);
}
}
const group = value?.define?.group as string; const group = value?.define?.group as string;
if (group) { if (group) {
if (pluginGroups.hasOwnProperty(group)) { if (pluginGroups.hasOwnProperty(group)) {
// @ts-ignore // @ts-ignore
pluginGroups[group].plugins.push(value.define); pluginGroups[group].plugins.push(value.define);
} else { return;
pluginGroups.other.plugins.push(value.define);
} }
} }
pluginGroups.other.plugins.push(value.define);
}; };
export const pluginRegistry = createRegistry<AbstractTaskPlugin>("plugin", onRegister); export const pluginRegistry = createRegistry<AbstractTaskPlugin>("plugin", onRegister);

View File

@ -26,7 +26,6 @@ export function registerWorker(name: string, worker: any) {
window.MonacoEnvironment = { window.MonacoEnvironment = {
//@ts-ignore //@ts-ignore
getWorker(_, label) { getWorker(_, label) {
debugger;
const custom = WorkerBucket[label]; const custom = WorkerBucket[label];
if (custom) { if (custom) {
return new custom(); return new custom();

View File

@ -83,17 +83,6 @@ const emitValue = lodashDebounce((value: any) => {
emits("update:modelValue", value); emits("update:modelValue", value);
}, props.debounce || 500); }, props.debounce || 500);
// watch(
// () => {
// return props.modelValue;
// },
// (value: string) => {
// if (instanceRef.value && value !== instanceRef.value.getValue()) {
// // instanceRef.value.setValue(value);
// }
// }
// );
async function createEditor(ctx: EditorCodeCtx) { async function createEditor(ctx: EditorCodeCtx) {
disposeEditor(); disposeEditor();
const instance = monaco.editor.create(monacoRef.value, { const instance = monaco.editor.create(monacoRef.value, {
@ -121,6 +110,9 @@ async function createEditor(ctx: EditorCodeCtx) {
instanceRef = instance; instanceRef = instance;
ctx.instance = instance; ctx.instance = instance;
emits("ready", ctx); emits("ready", ctx);
if (props.modelValue) {
instanceRef.setValue(props.modelValue);
}
return instance; return instance;
} }
@ -224,6 +216,9 @@ watch(
editor.setValue(newValue); editor.setValue(newValue);
} }
} }
},
{
immediate: true,
} }
); );

View File

@ -49,7 +49,6 @@ export async function initWorkers() {
} else if (label === "typescript" || label === "javascript") { } else if (label === "typescript" || label === "javascript") {
return new tsWorker.default(); return new tsWorker.default();
} else if (label === "yaml" || label === "yml") { } else if (label === "yaml" || label === "yml") {
debugger;
//@ts-ignore //@ts-ignore
return new yamlWorker.default(); return new yamlWorker.default();
} }

View File

@ -65,7 +65,7 @@ export default router;
// // 多页控制 打开新的页面 // // 多页控制 打开新的页面
// const pageStore = usePageStore(); // const pageStore = usePageStore();
// // for (const item of to.matched) { // // for (const item of to.matched) {
// // pageStore.keepAlivePush(item.name); // // pageStore.cachePush(item.name);
// // } // // }
// pageStore.open(to); // pageStore.open(to);
// // 更改标题 // // 更改标题

View File

@ -58,7 +58,7 @@ function transformOneResource(resource: any, parent: any) {
} }
return { return {
menu, menu,
route route,
}; };
} }
@ -79,7 +79,7 @@ export const buildMenusAndRouters = (resources: any, parent: any = null) => {
setIndex(menus); setIndex(menus);
return { return {
routes, routes,
menus menus,
}; };
}; };

View File

@ -47,6 +47,7 @@ export const sysResources = [
meta: { meta: {
icon: "ion:earth-outline", icon: "ion:earth-outline",
permission: "sys:settings:view", permission: "sys:settings:view",
cache: true,
}, },
}, },
{ {
@ -110,6 +111,7 @@ export const sysResources = [
meta: { meta: {
icon: "ion:extension-puzzle-outline", icon: "ion:extension-puzzle-outline",
permission: "sys:settings:view", permission: "sys:settings:view",
cache: true,
}, },
}, },
{ {
@ -121,6 +123,7 @@ export const sysResources = [
isMenu: false, isMenu: false,
icon: "ion:extension-puzzle", icon: "ion:extension-puzzle",
permission: "sys:settings:view", permission: "sys:settings:view",
cache: true,
}, },
}, },
{ {
@ -145,6 +148,7 @@ export const sysResources = [
meta: { meta: {
icon: "ion:golf-outline", icon: "ion:golf-outline",
permission: "sys:settings:view", permission: "sys:settings:view",
cache: true,
}, },
}, },
{ {

View File

@ -88,7 +88,7 @@ function wrapperMenus(menus: MenuRecordRaw[], deep: boolean = true) {
? mapTree(menus, (item: any) => { ? mapTree(menus, (item: any) => {
return { ...cloneDeep(item), name: $t(item.name) }; return { ...cloneDeep(item), name: $t(item.name) };
}) })
: menus.map((item) => { : menus.map(item => {
return { ...cloneDeep(item), name: $t(item.name) }; return { ...cloneDeep(item), name: $t(item.name) };
}); });
} }
@ -96,8 +96,8 @@ function wrapperMenus(menus: MenuRecordRaw[], deep: boolean = true) {
function toggleSidebar() { function toggleSidebar() {
updatePreferences({ updatePreferences({
sidebar: { sidebar: {
hidden: !preferences.sidebar.hidden hidden: !preferences.sidebar.hidden,
} },
}); });
} }
@ -107,12 +107,12 @@ function clearPreferencesAndLogout() {
watch( watch(
() => preferences.app.layout, () => preferences.app.layout,
async (val) => { async val => {
if (val === "sidebar-mixed-nav" && preferences.sidebar.hidden) { if (val === "sidebar-mixed-nav" && preferences.sidebar.hidden) {
updatePreferences({ updatePreferences({
sidebar: { sidebar: {
hidden: false hidden: false,
} },
}); });
} }
} }
@ -124,7 +124,7 @@ watch(i18n.global.locale, refresh, { flush: "post" });
const slots: SetupContext["slots"] = useSlots(); const slots: SetupContext["slots"] = useSlots();
const headerSlots = computed(() => { const headerSlots = computed(() => {
return Object.keys(slots).filter((key) => key.startsWith("header-")); return Object.keys(slots).filter(key => key.startsWith("header-"));
}); });
</script> </script>

View File

@ -20,14 +20,14 @@ const defaultPreferences: Preferences = {
loginExpiredMode: "page", loginExpiredMode: "page",
name: "", name: "",
preferencesButtonPosition: "auto", preferencesButtonPosition: "auto",
watermark: false watermark: false,
}, },
breadcrumb: { breadcrumb: {
enable: true, enable: true,
hideOnlyOne: false, hideOnlyOne: false,
showHome: false, showHome: false,
showIcon: true, showIcon: true,
styleType: "normal" styleType: "normal",
}, },
copyright: { copyright: {
companyName: "greper", companyName: "greper",
@ -36,33 +36,33 @@ const defaultPreferences: Preferences = {
enable: false, enable: false,
icp: "", icp: "",
icpLink: "", icpLink: "",
settingShow: false settingShow: false,
}, },
footer: { footer: {
enable: true, enable: true,
fixed: false fixed: false,
}, },
header: { header: {
enable: true, enable: true,
hidden: false, hidden: false,
menuAlign: "start", menuAlign: "start",
mode: "fixed" mode: "fixed",
}, },
logo: { logo: {
enable: true, enable: true,
source: "./static/images/logo/logo.svg" source: "./static/images/logo/logo.svg",
}, },
navigation: { navigation: {
accordion: true, accordion: true,
split: true, split: true,
styleType: "rounded" styleType: "rounded",
}, },
shortcutKeys: { shortcutKeys: {
enable: true, enable: true,
globalLockScreen: true, globalLockScreen: true,
globalLogout: true, globalLogout: true,
globalPreferences: true, globalPreferences: true,
globalSearch: true globalSearch: true,
}, },
sidebar: { sidebar: {
autoActivateChild: true, autoActivateChild: true,
@ -72,7 +72,7 @@ const defaultPreferences: Preferences = {
expandOnHover: true, expandOnHover: true,
extraCollapse: false, extraCollapse: false,
hidden: false, hidden: false,
width: 224 width: 224,
}, },
tabbar: { tabbar: {
draggable: true, draggable: true,
@ -86,7 +86,7 @@ const defaultPreferences: Preferences = {
showMaximize: true, showMaximize: true,
showMore: true, showMore: true,
styleType: "chrome", styleType: "chrome",
wheelable: true wheelable: true,
}, },
theme: { theme: {
builtinType: "default", builtinType: "default",
@ -97,13 +97,13 @@ const defaultPreferences: Preferences = {
mode: "light", mode: "light",
radius: "0.5", radius: "0.5",
semiDarkHeader: false, semiDarkHeader: false,
semiDarkSidebar: false semiDarkSidebar: false,
}, },
transition: { transition: {
enable: true, enable: true,
loading: false, loading: false,
name: "fade-slide", name: "fade-slide",
progress: true progress: true,
}, },
widget: { widget: {
fullscreen: true, fullscreen: true,
@ -113,8 +113,8 @@ const defaultPreferences: Preferences = {
notification: false, notification: false,
refresh: true, refresh: true,
sidebarToggle: true, sidebarToggle: true,
themeToggle: true themeToggle: true,
} },
}; };
export { defaultPreferences }; export { defaultPreferences };

View File

@ -45,7 +45,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* Close tabs in bulk * Close tabs in bulk
*/ */
async _bulkCloseByPaths(paths: string[]) { async _bulkCloseByPaths(paths: string[]) {
this.tabs = this.tabs.filter((item) => { this.tabs = this.tabs.filter(item => {
return !paths.includes(getTabPath(item)); return !paths.includes(getTabPath(item));
}); });
@ -60,7 +60,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
if (isAffixTab(tab)) { if (isAffixTab(tab)) {
return; return;
} }
const index = this.tabs.findIndex((item) => item.fullPath === fullPath); const index = this.tabs.findIndex(item => item.fullPath === fullPath);
index !== -1 && this.tabs.splice(index, 1); index !== -1 && this.tabs.splice(index, 1);
}, },
/** /**
@ -85,7 +85,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
const toParams = { const toParams = {
params: params || {}, params: params || {},
path, path,
query: query || {} query: query || {},
}; };
await router.replace(toParams); await router.replace(toParams);
}, },
@ -99,7 +99,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
return; return;
} }
const tabIndex = this.tabs.findIndex((tab) => { const tabIndex = this.tabs.findIndex(tab => {
return getTabPath(tab) === getTabPath(routeTab); return getTabPath(tab) === getTabPath(routeTab);
}); });
@ -109,13 +109,13 @@ export const useTabbarStore = defineStore("core-tabbar", {
const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ?? -1) as number; const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ?? -1) as number;
// 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了 // 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了
// 获取到已经打开的动态路由数, 判断是否大于某一个值 // 获取到已经打开的动态路由数, 判断是否大于某一个值
if (maxNumOfOpenTab > 0 && this.tabs.filter((tab) => tab.name === routeTab.name).length >= maxNumOfOpenTab) { if (maxNumOfOpenTab > 0 && this.tabs.filter(tab => tab.name === routeTab.name).length >= maxNumOfOpenTab) {
// 关闭第一个 // 关闭第一个
const index = this.tabs.findIndex((item) => item.name === routeTab.name); const index = this.tabs.findIndex(item => item.name === routeTab.name);
index !== -1 && this.tabs.splice(index, 1); index !== -1 && this.tabs.splice(index, 1);
} else if (maxCount > 0 && this.tabs.length >= maxCount) { } else if (maxCount > 0 && this.tabs.length >= maxCount) {
// 关闭第一个 // 关闭第一个
const index = this.tabs.findIndex((item) => !Reflect.has(item.meta, "affixTab") || !item.meta.affixTab); const index = this.tabs.findIndex(item => !Reflect.has(item.meta, "affixTab") || !item.meta.affixTab);
index !== -1 && this.tabs.splice(index, 1); index !== -1 && this.tabs.splice(index, 1);
} }
this.tabs.push(tab); this.tabs.push(tab);
@ -125,7 +125,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
const mergedTab = { const mergedTab = {
...currentTab, ...currentTab,
...tab, ...tab,
meta: { ...currentTab?.meta, ...tab.meta } meta: { ...currentTab?.meta, ...tab.meta },
}; };
if (currentTab) { if (currentTab) {
const curMeta = currentTab.meta; const curMeta = currentTab.meta;
@ -145,7 +145,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @zh_CN * @zh_CN
*/ */
async closeAllTabs(router: Router) { async closeAllTabs(router: Router) {
const newTabs = this.tabs.filter((tab) => isAffixTab(tab)); const newTabs = this.tabs.filter(tab => isAffixTab(tab));
this.tabs = newTabs.length > 0 ? newTabs : [...this.tabs].splice(0, 1); this.tabs = newTabs.length > 0 ? newTabs : [...this.tabs].splice(0, 1);
await this._goToDefaultTab(router); await this._goToDefaultTab(router);
this.updateCacheTabs(); this.updateCacheTabs();
@ -155,7 +155,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param tab * @param tab
*/ */
async closeLeftTabs(tab: TabDefinition) { async closeLeftTabs(tab: TabDefinition) {
const index = this.tabs.findIndex((item) => getTabPath(item) === getTabPath(tab)); const index = this.tabs.findIndex(item => getTabPath(item) === getTabPath(tab));
if (index < 1) { if (index < 1) {
return; return;
@ -176,13 +176,13 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param tab * @param tab
*/ */
async closeOtherTabs(tab: TabDefinition) { async closeOtherTabs(tab: TabDefinition) {
const closePaths = this.tabs.map((item) => getTabPath(item)); const closePaths = this.tabs.map(item => getTabPath(item));
const paths: string[] = []; const paths: string[] = [];
for (const path of closePaths) { for (const path of closePaths) {
if (path !== tab.fullPath) { if (path !== tab.fullPath) {
const closeTab = this.tabs.find((item) => getTabPath(item) === path); const closeTab = this.tabs.find(item => getTabPath(item) === path);
if (!closeTab) { if (!closeTab) {
continue; continue;
} }
@ -198,7 +198,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param tab * @param tab
*/ */
async closeRightTabs(tab: TabDefinition) { async closeRightTabs(tab: TabDefinition) {
const index = this.tabs.findIndex((item) => getTabPath(item) === getTabPath(tab)); const index = this.tabs.findIndex(item => getTabPath(item) === getTabPath(tab));
if (index !== -1 && index < this.tabs.length - 1) { if (index !== -1 && index < this.tabs.length - 1) {
const rightTabs = this.tabs.slice(index + 1); const rightTabs = this.tabs.slice(index + 1);
@ -227,7 +227,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
this.updateCacheTabs(); this.updateCacheTabs();
return; return;
} }
const index = this.getTabs.findIndex((item) => getTabPath(item) === getTabPath(currentRoute.value)); const index = this.getTabs.findIndex(item => getTabPath(item) === getTabPath(currentRoute.value));
const before = this.getTabs[index - 1]; const before = this.getTabs[index - 1];
const after = this.getTabs[index + 1]; const after = this.getTabs[index + 1];
@ -252,7 +252,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
*/ */
async closeTabByKey(key: string, router: Router) { async closeTabByKey(key: string, router: Router) {
const originKey = decodeURIComponent(key); const originKey = decodeURIComponent(key);
const index = this.tabs.findIndex((item) => getTabPath(item) === originKey); const index = this.tabs.findIndex(item => getTabPath(item) === originKey);
if (index === -1) { if (index === -1) {
return; return;
} }
@ -268,7 +268,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param path * @param path
*/ */
getTabByPath(path: string) { getTabByPath(path: string) {
return this.getTabs.find((item) => getTabPath(item) === path) as TabDefinition; return this.getTabs.find(item => getTabPath(item) === path) as TabDefinition;
}, },
/** /**
* @zh_CN * @zh_CN
@ -283,7 +283,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param tab * @param tab
*/ */
async pinTab(tab: TabDefinition) { async pinTab(tab: TabDefinition) {
const index = this.tabs.findIndex((item) => getTabPath(item) === getTabPath(tab)); const index = this.tabs.findIndex(item => getTabPath(item) === getTabPath(tab));
if (index !== -1) { if (index !== -1) {
const oldTab = this.tabs[index]; const oldTab = this.tabs[index];
tab.meta.affixTab = true; tab.meta.affixTab = true;
@ -292,9 +292,9 @@ export const useTabbarStore = defineStore("core-tabbar", {
this.tabs.splice(index, 1, tab); this.tabs.splice(index, 1, tab);
} }
// 过滤固定tabs后面更改affixTabOrder的值的话可能会有问题目前行464排序affixTabs没有设置值 // 过滤固定tabs后面更改affixTabOrder的值的话可能会有问题目前行464排序affixTabs没有设置值
const affixTabs = this.tabs.filter((tab) => isAffixTab(tab)); const affixTabs = this.tabs.filter(tab => isAffixTab(tab));
// 获得固定tabs的index // 获得固定tabs的index
const newIndex = affixTabs.findIndex((item) => getTabPath(item) === getTabPath(tab)); const newIndex = affixTabs.findIndex(item => getTabPath(item) === getTabPath(tab));
// 交换位置重新排序 // 交换位置重新排序
await this.sortTabs(index, newIndex); await this.sortTabs(index, newIndex);
}, },
@ -310,7 +310,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
this.renderRouteView = false; this.renderRouteView = false;
startProgress(); startProgress();
await new Promise((resolve) => setTimeout(resolve, 200)); await new Promise(resolve => setTimeout(resolve, 200));
this.excludeCachedTabs.delete(name as string); this.excludeCachedTabs.delete(name as string);
this.renderRouteView = true; this.renderRouteView = true;
@ -324,7 +324,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
if (tab?.meta?.newTabTitle) { if (tab?.meta?.newTabTitle) {
return; return;
} }
const findTab = this.tabs.find((item) => getTabPath(item) === getTabPath(tab)); const findTab = this.tabs.find(item => getTabPath(item) === getTabPath(tab));
if (findTab) { if (findTab) {
findTab.meta.newTabTitle = undefined; findTab.meta.newTabTitle = undefined;
await this.updateCacheTabs(); await this.updateCacheTabs();
@ -348,7 +348,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param title * @param title
*/ */
async setTabTitle(tab: TabDefinition, title: string) { async setTabTitle(tab: TabDefinition, title: string) {
const findTab = this.tabs.find((item) => getTabPath(item) === getTabPath(tab)); const findTab = this.tabs.find(item => getTabPath(item) === getTabPath(tab));
if (findTab) { if (findTab) {
findTab.meta.newTabTitle = title; findTab.meta.newTabTitle = title;
@ -389,7 +389,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
* @param tab * @param tab
*/ */
async unpinTab(tab: TabDefinition) { async unpinTab(tab: TabDefinition) {
const index = this.tabs.findIndex((item) => getTabPath(item) === getTabPath(tab)); const index = this.tabs.findIndex(item => getTabPath(item) === getTabPath(tab));
if (index !== -1) { if (index !== -1) {
const oldTab = this.tabs[index]; const oldTab = this.tabs[index];
@ -399,7 +399,7 @@ export const useTabbarStore = defineStore("core-tabbar", {
this.tabs.splice(index, 1, tab); this.tabs.splice(index, 1, tab);
} }
// 过滤固定tabs后面更改affixTabOrder的值的话可能会有问题目前行464排序affixTabs没有设置值 // 过滤固定tabs后面更改affixTabOrder的值的话可能会有问题目前行464排序affixTabs没有设置值
const affixTabs = this.tabs.filter((tab) => isAffixTab(tab)); const affixTabs = this.tabs.filter(tab => isAffixTab(tab));
// 获得固定tabs的index,使用固定tabs的下一个位置也就是活动tabs的第一个位置 // 获得固定tabs的index,使用固定tabs的下一个位置也就是活动tabs的第一个位置
const newIndex = affixTabs.length; const newIndex = affixTabs.length;
// 交换位置重新排序 // 交换位置重新排序
@ -428,11 +428,11 @@ export const useTabbarStore = defineStore("core-tabbar", {
cacheMap.add(name); cacheMap.add(name);
} }
this.cachedTabs = cacheMap; this.cachedTabs = cacheMap;
} },
}, },
getters: { getters: {
affixTabs(): TabDefinition[] { affixTabs(): TabDefinition[] {
const affixTabs = this.tabs.filter((tab) => isAffixTab(tab)); const affixTabs = this.tabs.filter(tab => isAffixTab(tab));
return affixTabs.sort((a, b) => { return affixTabs.sort((a, b) => {
const orderA = (a.meta?.affixTabOrder ?? 0) as number; const orderA = (a.meta?.affixTabOrder ?? 0) as number;
@ -447,16 +447,16 @@ export const useTabbarStore = defineStore("core-tabbar", {
return [...this.excludeCachedTabs]; return [...this.excludeCachedTabs];
}, },
getTabs(): TabDefinition[] { getTabs(): TabDefinition[] {
const normalTabs = this.tabs.filter((tab) => !isAffixTab(tab)); const normalTabs = this.tabs.filter(tab => !isAffixTab(tab));
return [...this.affixTabs, ...normalTabs].filter(Boolean); return [...this.affixTabs, ...normalTabs].filter(Boolean);
} },
}, },
persist: [ persist: [
// tabs不需要保存在localStorage // tabs不需要保存在localStorage
{ {
pick: ["tabs"], pick: ["tabs"],
storage: sessionStorage storage: sessionStorage,
} },
], ],
state: (): TabbarState => ({ state: (): TabbarState => ({
cachedTabs: new Set(), cachedTabs: new Set(),
@ -464,8 +464,8 @@ export const useTabbarStore = defineStore("core-tabbar", {
excludeCachedTabs: new Set(), excludeCachedTabs: new Set(),
renderRouteView: true, renderRouteView: true,
tabs: [], tabs: [],
updateTime: Date.now() updateTime: Date.now(),
}) }),
}); });
// 解决热更新问题 // 解决热更新问题
@ -486,16 +486,16 @@ function cloneTab(route: TabDefinition): TabDefinition {
return { return {
...opt, ...opt,
matched: (matched matched: (matched
? matched.map((item) => ({ ? matched.map(item => ({
meta: item.meta, meta: item.meta,
name: item.name, name: item.name,
path: item.path path: item.path,
})) }))
: undefined) as RouteRecordNormalized[], : undefined) as RouteRecordNormalized[],
meta: { meta: {
...meta, ...meta,
newTabTitle: meta.newTabTitle newTabTitle: meta.newTabTitle,
} },
}; };
} }
@ -513,7 +513,7 @@ function isAffixTab(tab: TabDefinition) {
*/ */
function isTabShown(tab: TabDefinition) { function isTabShown(tab: TabDefinition) {
const matched = tab?.matched ?? []; const matched = tab?.matched ?? [];
return !tab.meta.hideInTab && matched.every((item) => !item.meta.hideInTab); return !tab.meta.hideInTab && matched.every(item => !item.meta.hideInTab);
} }
/** /**
@ -528,6 +528,6 @@ function routeToTab(route: RouteRecordNormalized) {
return { return {
meta: route.meta, meta: route.meta,
name: route.name, name: route.name,
path: route.path path: route.path,
} as TabDefinition; } as TabDefinition;
} }

View File

@ -37,7 +37,6 @@ const domain = computed(() => {
}); });
function onUpdated(res: { uploadCert: any }) { function onUpdated(res: { uploadCert: any }) {
debugger;
emit("update:modelValue", res.uploadCert); emit("update:modelValue", res.uploadCert);
const domains = getAllDomainsFromCrt(res.uploadCert.crt); const domains = getAllDomainsFromCrt(res.uploadCert.crt);
emit("updated", { domains }); emit("updated", { domains });
@ -45,7 +44,6 @@ function onUpdated(res: { uploadCert: any }) {
const pipeline: any = inject("pipeline"); const pipeline: any = inject("pipeline");
function onUploadClick() { function onUploadClick() {
debugger;
openUpdateCertDialog({ openUpdateCertDialog({
onSubmit: onUpdated, onSubmit: onUpdated,
}); });

View File

@ -30,20 +30,20 @@ import { Modal, notification } from "ant-design-vue";
import * as api from "./api"; import * as api from "./api";
defineOptions({ defineOptions({
name: "PipelineManager" name: "PipelineManager",
}); });
const certdFormRef = ref(); const certdFormRef = ref();
const groupDictRef = dict({ const groupDictRef = dict({
url: "/pi/pipeline/group/all", url: "/pi/pipeline/group/all",
value: "id", value: "id",
label: "name" label: "name",
}); });
const selectedRowKeys = ref([]); const selectedRowKeys = ref([]);
const context: any = { const context: any = {
certdFormRef, certdFormRef,
groupDictRef, groupDictRef,
selectedRowKeys selectedRowKeys,
}; };
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context }); const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
@ -70,7 +70,7 @@ function batchDelete() {
notification.success({ message: "删除成功" }); notification.success({ message: "删除成功" });
await crudExpose.doRefresh(); await crudExpose.doRefresh();
selectedRowKeys.value = []; selectedRowKeys.value = [];
} },
}); });
} }
</script> </script>

View File

@ -101,3 +101,11 @@ export async function SaveCommPluginConfigs(data: CommPluginConfig): Promise<voi
data, data,
}); });
} }
export async function DoTest(req: { id: number; input: any }): Promise<void> {
return await request({
url: apiPrefix + "/doTest",
method: "post",
data: req,
});
}

View File

@ -8,7 +8,8 @@
</span> </span>
</div> </div>
<div class="more"> <div class="more">
<a-button type="primary" :loading="saveLoading" @click="doSave"></a-button> <a-button class="mr-1" type="primary" :loading="saveLoading" @click="doSave"></a-button>
<a-button type="primary" @click="doTest"></a-button>
</div> </div>
</template> </template>
<div class="pi-plugin-editor"> <div class="pi-plugin-editor">
@ -34,6 +35,7 @@ import { onMounted, provide, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import * as api from "./api"; import * as api from "./api";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { notification } from "ant-design-vue";
const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"]; const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"];
defineOptions({ defineOptions({
@ -48,39 +50,53 @@ async function getPlugin() {
const pluginObj = await api.GetObj(id); const pluginObj = await api.GetObj(id);
if (!pluginObj.metadata) { if (!pluginObj.metadata) {
pluginObj.metadata = yaml.dump({ pluginObj.metadata = yaml.dump({
input: [ input: {
{ cert: {
key: "cert",
title: "前置任务生成的证书", title: "前置任务生成的证书",
component: { component: {
name: "output-selector", name: "output-selector",
from: [...CertApplyPluginNames], from: [...CertApplyPluginNames],
}, },
}, },
], },
output: [], output: {},
}); });
} else {
pluginObj.metadata = "";
} }
plugin.value = pluginObj; plugin.value = pluginObj;
} }
getPlugin();
onMounted(async () => {}); onMounted(async () => {
getPlugin();
});
provide("get:plugin", () => { provide("get:plugin", () => {
return plugin; return plugin;
}); });
const saveLoading = ref(false); const saveLoading = ref(false);
function doSave() { async function doSave() {
saveLoading.value = true; saveLoading.value = true;
try { try {
// api.Save(plugin.value); await api.UpdateObj(plugin.value);
notification.success({
message: "保存成功",
});
} finally { } finally {
saveLoading.value = false; saveLoading.value = false;
} }
} }
async function doTest() {
await doSave();
const result = await api.DoTest({
id: plugin.value.id,
input: {},
});
notification.success({
message: "测试已开始",
description: result,
});
}
</script> </script>
<style lang="less"> <style lang="less">

View File

@ -21,7 +21,7 @@ import { message, Modal } from "ant-design-vue";
import { DeleteBatch } from "./api"; import { DeleteBatch } from "./api";
defineOptions({ defineOptions({
name: "SysPlugin" name: "SysPlugin",
}); });
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions }); const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
@ -36,7 +36,7 @@ const handleBatchDelete = () => {
message.info("删除成功"); message.info("删除成功");
crudExpose.doRefresh(); crudExpose.doRefresh();
selectedRowKeys.value = []; selectedRowKeys.value = [];
} },
}); });
} else { } else {
message.error("请先勾选记录"); message.error("请先勾选记录");

View File

@ -42,7 +42,12 @@ export class PluginController extends CrudController<PluginService> {
@Post('/update', { summary: 'sys:settings:edit' }) @Post('/update', { summary: 'sys:settings:edit' })
async update(@Body(ALL) bean: any) { async update(@Body(ALL) bean: any) {
return super.update(bean);
const res = await super.update(bean);
// 更新插件配置
const info = await this.service.info(bean.id)
await this.service.registerPlugin(info)
return res
} }
@Post('/info', { summary: 'sys:settings:view' }) @Post('/info', { summary: 'sys:settings:view' })

View File

@ -9,7 +9,7 @@ import { merge } from "lodash-es";
import { accessRegistry, pluginRegistry } from "@certd/pipeline"; import { accessRegistry, pluginRegistry } from "@certd/pipeline";
import { dnsProviderRegistry } from "@certd/plugin-cert"; import { dnsProviderRegistry } from "@certd/plugin-cert";
import { logger } from "@certd/basic"; import { logger } from "@certd/basic";
import yaml from 'js-yaml'
@Provide() @Provide()
@Scope(ScopeEnum.Request, { allowDowngrade: true }) @Scope(ScopeEnum.Request, { allowDowngrade: true })
export class PluginService extends BaseService<PluginEntity> { export class PluginService extends BaseService<PluginEntity> {
@ -158,12 +158,14 @@ export class PluginService extends BaseService<PluginEntity> {
author: author author: author
} }
}); });
if (info.length > 0) { if (info&&info.length > 0) {
const plugin = info[0]; const plugin = info[0];
const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor; const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
const getPluginClass = new AsyncFunction(plugin.content); const getPluginClass = new AsyncFunction(plugin.content);
return await getPluginClass(); const pluginClass = await getPluginClass({logger: logger});
return new pluginClass()
} }
throw new Error(`插件${pluginName}不存在`);
} }
/** /**
* *
@ -177,28 +179,40 @@ export class PluginService extends BaseService<PluginEntity> {
}) })
}); });
for (const item of res) { for (const item of res) {
const pluginName = item.author ? item.author +"/"+ item.name : item.name; await this.registerPlugin(item);
let registry = null
if(item.pluginType === 'access'){
registry = accessRegistry;
}else if (item.pluginType === 'plugin'){
registry = pluginRegistry;
}else if (item.pluginType === 'dnsProvider'){
registry = dnsProviderRegistry
}else {
logger.warn(`插件${pluginName}类型错误:${item.pluginType}`)
continue
}
registry.register(pluginName, {
define:item,
target: ()=>{
return this.getPluginTarget(pluginName);
}
});
} }
} }
async registerPlugin(plugin:PluginEntity){
const metadata = yaml.load(plugin.metadata);
const item = {
...plugin,
...metadata
}
delete item.metadata;
delete item.content;
if(item.author){
item.name = item.author +"/"+ item.name;
}
let registry = null
if(item.pluginType === 'access'){
registry = accessRegistry;
}else if (item.pluginType === 'plugin'){
registry = pluginRegistry;
}else if (item.pluginType === 'dnsProvider'){
registry = dnsProviderRegistry
}else {
logger.warn(`插件${item.name}类型错误:${item.pluginType}`)
return
}
registry.register(item.name, {
define:item,
target: ()=>{
return this.getPluginTarget(item.name);
}
});
}
} }