mirror of https://github.com/certd/certd
				
				
				
			chore: code-editor
							parent
							
								
									2e0c067cd2
								
							
						
					
					
						commit
						9475f2e56c
					
				| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <AConfigProvider :locale="locale" :theme="tokenTheme">
 | 
			
		||||
    <fs-form-provider>
 | 
			
		||||
    <FsFormProvider>
 | 
			
		||||
      <contextHolder />
 | 
			
		||||
      <router-view />
 | 
			
		||||
    </fs-form-provider>
 | 
			
		||||
    </FsFormProvider>
 | 
			
		||||
  </AConfigProvider>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
export async function importJsYaml() {
 | 
			
		||||
  return await import("js-yaml");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function importYamlContribution() {
 | 
			
		||||
  await import("monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function importJsonContribution() {
 | 
			
		||||
  await import("monaco-editor/esm/vs/language/json/monaco.contribution");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function importJavascriptContribution() {
 | 
			
		||||
  await import("monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function importMonacoYaml() {
 | 
			
		||||
  return await import("monaco-yaml");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function importWorks() {
 | 
			
		||||
  const editorWorker = await import("monaco-editor/esm/vs/editor/editor.worker?worker");
 | 
			
		||||
  const jsonWorker = await import("monaco-editor/esm/vs/language/json/json.worker?worker");
 | 
			
		||||
  const cssWorker = await import("monaco-editor/esm/vs/language/css/css.worker?worker");
 | 
			
		||||
  const htmlWorker = await import("monaco-editor/esm/vs/language/html/html.worker?worker");
 | 
			
		||||
  const tsWorker = await import("monaco-editor/esm/vs/language/typescript/ts.worker?worker");
 | 
			
		||||
  const yamlWorker = await import("./yaml.worker?worker");
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    editorWorker,
 | 
			
		||||
    jsonWorker,
 | 
			
		||||
    cssWorker,
 | 
			
		||||
    htmlWorker,
 | 
			
		||||
    tsWorker,
 | 
			
		||||
    yamlWorker,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
// const editorWorker = await import("monaco-editor/esm/vs/editor/editor.worker?worker");
 | 
			
		||||
// const jsonWorker = await import("monaco-editor/esm/vs/language/json/json.worker?worker");
 | 
			
		||||
// const cssWorker = await import("monaco-editor/esm/vs/language/css/css.worker?worker");
 | 
			
		||||
// const htmlWorker = await import("monaco-editor/esm/vs/language/html/html.worker?worker");
 | 
			
		||||
// const tsWorker = await import("monaco-editor/esm/vs/language/typescript/ts.worker?worker");
 | 
			
		||||
// const yamlWorker = await import("monaco-yaml/yaml.worker.js?worker");
 | 
			
		||||
 | 
			
		||||
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
 | 
			
		||||
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
 | 
			
		||||
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
 | 
			
		||||
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
 | 
			
		||||
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
 | 
			
		||||
import yamlWorker from "./yaml.worker?worker";
 | 
			
		||||
 | 
			
		||||
const WorkerBucket: any = {};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 注册自定义worker
 | 
			
		||||
 * @param name
 | 
			
		||||
 * @param worker
 | 
			
		||||
 */
 | 
			
		||||
export function registerWorker(name: string, worker: any) {
 | 
			
		||||
  WorkerBucket[name] = worker;
 | 
			
		||||
}
 | 
			
		||||
//@ts-ignore
 | 
			
		||||
window.MonacoEnvironment = {
 | 
			
		||||
  //@ts-ignore
 | 
			
		||||
  getWorker(_, label) {
 | 
			
		||||
    debugger;
 | 
			
		||||
    const custom = WorkerBucket[label];
 | 
			
		||||
    if (custom) {
 | 
			
		||||
      return new custom();
 | 
			
		||||
    }
 | 
			
		||||
    if (label === "json") {
 | 
			
		||||
      return new jsonWorker();
 | 
			
		||||
    } else if (label === "css" || label === "scss" || label === "less") {
 | 
			
		||||
      return new cssWorker();
 | 
			
		||||
    } else if (label === "html" || label === "handlebars" || label === "razor") {
 | 
			
		||||
      return new htmlWorker();
 | 
			
		||||
    } else if (label === "typescript" || label === "javascript") {
 | 
			
		||||
      return new tsWorker();
 | 
			
		||||
    } else if (label === "yaml" || label === "yml") {
 | 
			
		||||
      //@ts-ignore
 | 
			
		||||
      return new yamlWorker();
 | 
			
		||||
    }
 | 
			
		||||
    return new editorWorker();
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,247 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <div ref="monacoRef" class="fs-editor-code"></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import * as monaco from "monaco-editor";
 | 
			
		||||
// import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
 | 
			
		||||
import { onMounted, onUnmounted, ref, watch } from "vue";
 | 
			
		||||
import { cloneDeep, debounce as lodashDebounce } from "lodash-es";
 | 
			
		||||
import { initWorkers } from "./workers";
 | 
			
		||||
import { importJavascriptContribution, importJsonContribution, importMonacoYaml, importYamlContribution } from "./async-import";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * config:
 | 
			
		||||
 *   value: '', // 编辑器初始文本
 | 
			
		||||
 *   language: 'javascript', // 语言
 | 
			
		||||
 *   theme: 'vs', // 主题
 | 
			
		||||
 *   readOnly: false, // 是否只读
 | 
			
		||||
 *   minimap: { enabled: false }, // 是否启用小地图
 | 
			
		||||
 *   fontSize: 14, // 字体大小
 | 
			
		||||
 *   tabSize: 2, // tab缩进长度
 | 
			
		||||
 *   automaticLayout: true, // 自动布局
 | 
			
		||||
 *   lineNumbers: 'off', // 是否启用行号
 | 
			
		||||
 *   contextmenu: true, // 是否启用上下文菜单
 | 
			
		||||
 *   folding: true, // 是否启用代码折叠
 | 
			
		||||
 *   foldingStrategy: 'auto', // 代码折叠策略
 | 
			
		||||
 *   wordWrap: 'on', // 自动换行设置
 | 
			
		||||
 *   wrappingIndent: 'indent', // 换行缩进
 | 
			
		||||
 *   formatOnPaste: true, // 粘贴时是否自动格式化
 | 
			
		||||
 *   formatOnType: true, // 输入时是否自动格式化
 | 
			
		||||
 *   dragAndDrop: true, // 是否允许拖放
 | 
			
		||||
 *   cursorStyle: 'line', // 光标样式
 | 
			
		||||
 *   cursorBlinking: 'blink', // 光标闪烁方式
 | 
			
		||||
 *   scrollbar: {
 | 
			
		||||
 *     vertical: 'auto', // 垂直滚动条的显示方式
 | 
			
		||||
 *     horizontal: 'auto', // 水平滚动条的显示方式
 | 
			
		||||
 *     verticalScrollbarSize: 2, // 垂直滚动条的宽
 | 
			
		||||
 *     horizontalScrollbarSize: 2, // 水平滚动条的高度
 | 
			
		||||
 *   }
 | 
			
		||||
 */
 | 
			
		||||
const props = defineProps<{
 | 
			
		||||
  language?: string;
 | 
			
		||||
  modelValue?: string;
 | 
			
		||||
  config?: any;
 | 
			
		||||
  schema?: any;
 | 
			
		||||
  debounce?: number;
 | 
			
		||||
  init?: any;
 | 
			
		||||
  readonly?: boolean;
 | 
			
		||||
  disabled?: boolean;
 | 
			
		||||
  id?: string;
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
export type EditorCodeCtx = {
 | 
			
		||||
  // monaco对象
 | 
			
		||||
  monaco: any;
 | 
			
		||||
  //语言
 | 
			
		||||
  language: string;
 | 
			
		||||
  //配置
 | 
			
		||||
  config: any;
 | 
			
		||||
  //editor实例对象
 | 
			
		||||
  instance?: any;
 | 
			
		||||
 | 
			
		||||
  schema?: any;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const monacoRef = ref();
 | 
			
		||||
 | 
			
		||||
let instanceRef: any = null;
 | 
			
		||||
 | 
			
		||||
function disposeEditor() {
 | 
			
		||||
  // if (instanceRef.value) {
 | 
			
		||||
  //   instanceRef.value.dispose(); //使用完成销毁实例
 | 
			
		||||
  // }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  disposeEditor();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emits = defineEmits(["update:modelValue", "change", "ready"]);
 | 
			
		||||
 | 
			
		||||
const emitValue = lodashDebounce((value: any) => {
 | 
			
		||||
  emits("update:modelValue", value);
 | 
			
		||||
}, 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) {
 | 
			
		||||
  disposeEditor();
 | 
			
		||||
  const instance = monaco.editor.create(monacoRef.value, {
 | 
			
		||||
    automaticLayout: true,
 | 
			
		||||
    value: props.modelValue,
 | 
			
		||||
    language: ctx.language,
 | 
			
		||||
    theme: "vs-dark",
 | 
			
		||||
    minimap: { enabled: false },
 | 
			
		||||
    readOnly: props.readonly || props.disabled,
 | 
			
		||||
    hover: {
 | 
			
		||||
      enabled: true,
 | 
			
		||||
    },
 | 
			
		||||
    ...ctx.config,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // @event `change`
 | 
			
		||||
  instance.onDidChangeModelContent(event => {
 | 
			
		||||
    const value = instance.getValue();
 | 
			
		||||
    if (props.modelValue !== value) {
 | 
			
		||||
      emits("change", value);
 | 
			
		||||
      emitValue(value);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  instanceRef = instance;
 | 
			
		||||
  ctx.instance = instance;
 | 
			
		||||
  emits("ready", ctx);
 | 
			
		||||
  return instance;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function initJavascript(ctx: EditorCodeCtx) {
 | 
			
		||||
  await importJavascriptContribution();
 | 
			
		||||
  monaco.languages.register({ id: "javascript" });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function initJson(ctx: EditorCodeCtx) {
 | 
			
		||||
  await importJsonContribution();
 | 
			
		||||
  monaco.languages.register({ id: "json" });
 | 
			
		||||
 | 
			
		||||
  const schemas = [];
 | 
			
		||||
  if (ctx.schema) {
 | 
			
		||||
    schemas.push({
 | 
			
		||||
      // uri: "http://myserver/foo-schema.json", // id of the first schema
 | 
			
		||||
      fileMatch: ["*"], // associate with our model
 | 
			
		||||
      schema: {
 | 
			
		||||
        ...ctx.schema,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
 | 
			
		||||
    validate: true,
 | 
			
		||||
    enableSchemaRequest: false,
 | 
			
		||||
    schemas,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function initYaml(ctx: EditorCodeCtx) {
 | 
			
		||||
  await importYamlContribution();
 | 
			
		||||
  const { configureMonacoYaml } = await importMonacoYaml();
 | 
			
		||||
  monaco.languages.register({ id: "yaml" });
 | 
			
		||||
 | 
			
		||||
  const schemas = [];
 | 
			
		||||
  if (ctx.schema) {
 | 
			
		||||
    schemas.push({
 | 
			
		||||
      fileMatch: ["*"], // associate with our model
 | 
			
		||||
      schema: {
 | 
			
		||||
        ...ctx.schema,
 | 
			
		||||
      },
 | 
			
		||||
      uri: "http://myserver/foo-schema.json",
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  configureMonacoYaml(monaco, {
 | 
			
		||||
    schemas,
 | 
			
		||||
    format: true,
 | 
			
		||||
    hover: true,
 | 
			
		||||
    completion: true,
 | 
			
		||||
    validate: true,
 | 
			
		||||
    isKubernetes: false,
 | 
			
		||||
    enableSchemaRequest: false,
 | 
			
		||||
  });
 | 
			
		||||
  const uri = monaco.Uri.parse(`fs-editor-code-yaml-${props.id || ""}.yaml`);
 | 
			
		||||
  const oldModel = monaco.editor.getModel(uri);
 | 
			
		||||
  if (oldModel) {
 | 
			
		||||
    oldModel.dispose();
 | 
			
		||||
  }
 | 
			
		||||
  ctx.config.model = monaco.editor.createModel(props.modelValue, "yaml", uri);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function doInit() {
 | 
			
		||||
  await initWorkers();
 | 
			
		||||
  const ctx: EditorCodeCtx = {
 | 
			
		||||
    monaco,
 | 
			
		||||
    language: props.language || "javascript",
 | 
			
		||||
    config: cloneDeep(props.config || {}),
 | 
			
		||||
    schema: props.schema,
 | 
			
		||||
  };
 | 
			
		||||
  if (ctx.language === "javascript") {
 | 
			
		||||
    await initJavascript(ctx);
 | 
			
		||||
  } else if (ctx.language === "yaml") {
 | 
			
		||||
    await initYaml(ctx);
 | 
			
		||||
  } else if (ctx.language === "json") {
 | 
			
		||||
    await initJson(ctx);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  await createEditor(ctx);
 | 
			
		||||
}
 | 
			
		||||
// watch(
 | 
			
		||||
//   () => {
 | 
			
		||||
//     return {
 | 
			
		||||
//       language: props.language,
 | 
			
		||||
//       config: props.config,
 | 
			
		||||
//     };
 | 
			
		||||
//   },
 | 
			
		||||
//   (value: any) => {
 | 
			
		||||
//     doInit();
 | 
			
		||||
//   }
 | 
			
		||||
// );
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
  () => {
 | 
			
		||||
    return props.modelValue;
 | 
			
		||||
  },
 | 
			
		||||
  newValue => {
 | 
			
		||||
    if (instanceRef) {
 | 
			
		||||
      const editor = instanceRef;
 | 
			
		||||
      if (newValue !== editor.getValue()) {
 | 
			
		||||
        editor.setValue(newValue);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  await doInit();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="less">
 | 
			
		||||
.fs-editor-code {
 | 
			
		||||
  min-height: 100px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  border: 1px solid #eee;
 | 
			
		||||
  border-radius: 5px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.monaco-editor .hover-content {
 | 
			
		||||
  z-index: 1000 !important;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
import { importJsYaml } from "./async-import";
 | 
			
		||||
 | 
			
		||||
const jsonRule = {
 | 
			
		||||
  validator: async (rule: any, value: any) => {
 | 
			
		||||
    //校验value json的有效性
 | 
			
		||||
    if (value) {
 | 
			
		||||
      try {
 | 
			
		||||
        JSON.parse(value);
 | 
			
		||||
      } catch (e: any) {
 | 
			
		||||
        console.error(e);
 | 
			
		||||
        throw new Error("json格式错误:" + e.message);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  message: "json格式错误",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const yamlRule = {
 | 
			
		||||
  validator: async (rule: any, value: any) => {
 | 
			
		||||
    //校验value yaml的有效性
 | 
			
		||||
    if (value) {
 | 
			
		||||
      try {
 | 
			
		||||
        const yaml = await importJsYaml();
 | 
			
		||||
        yaml.load(value, { schema: yaml.JSON_SCHEMA });
 | 
			
		||||
      } catch (e: any) {
 | 
			
		||||
        console.error(e);
 | 
			
		||||
        throw new Error("yaml格式错误:" + e.message);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  message: "yaml格式错误",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const FsEditorCodeValidators = {
 | 
			
		||||
  jsonRule,
 | 
			
		||||
  yamlRule,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
import { importWorks } from "./async-import";
 | 
			
		||||
 | 
			
		||||
const WorkerBucket: any = {};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 注册自定义worker
 | 
			
		||||
 * @param name
 | 
			
		||||
 * @param worker
 | 
			
		||||
 */
 | 
			
		||||
export function registerWorker(name: string, worker: any) {
 | 
			
		||||
  WorkerBucket[name] = worker;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function initWorkers() {
 | 
			
		||||
  if (window.MonacoEnvironment) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // const { editorWorker, jsonWorker, cssWorker, htmlWorker, tsWorker } = await importWorks();
 | 
			
		||||
  //
 | 
			
		||||
  // // const editorWorker = new Worker(new URL("monaco-editor/esm/vs/editor/editor.worker.js", import.meta.url));
 | 
			
		||||
  // // const jsonWorker = new Worker(new URL("monaco-editor/esm/vs/language/json/json.worker.js", import.meta.url));
 | 
			
		||||
  // // const cssWorker = new Worker(new URL("monaco-editor/esm/vs/language/css/css.worker.js", import.meta.url));
 | 
			
		||||
  // // const htmlWorker = new Worker(new URL("monaco-editor/esm/vs/language/html/html.worker.js", import.meta.url));
 | 
			
		||||
  // // const tsWorker = new Worker(new URL("monaco-editor/esm/vs/language/typescript/ts.worker.js", import.meta.url));
 | 
			
		||||
  // // const yamlWorker = new Worker(new URL("./yaml.worker.js", import.meta.url));
 | 
			
		||||
 | 
			
		||||
  const editorWorker = await import("monaco-editor/esm/vs/editor/editor.worker?worker");
 | 
			
		||||
  const jsonWorker = await import("monaco-editor/esm/vs/language/json/json.worker?worker");
 | 
			
		||||
  const cssWorker = await import("monaco-editor/esm/vs/language/css/css.worker?worker");
 | 
			
		||||
  const htmlWorker = await import("monaco-editor/esm/vs/language/html/html.worker?worker");
 | 
			
		||||
  const tsWorker = await import("monaco-editor/esm/vs/language/typescript/ts.worker?worker");
 | 
			
		||||
  const yamlWorker = await import("./yaml.worker?worker");
 | 
			
		||||
 | 
			
		||||
  //@ts-ignore
 | 
			
		||||
  window.MonacoEnvironment = {
 | 
			
		||||
    //@ts-ignore
 | 
			
		||||
    getWorker(_, label) {
 | 
			
		||||
      const custom = WorkerBucket[label];
 | 
			
		||||
      if (custom) {
 | 
			
		||||
        return new custom();
 | 
			
		||||
      }
 | 
			
		||||
      if (label === "json") {
 | 
			
		||||
        return new jsonWorker.default();
 | 
			
		||||
      } else if (label === "css" || label === "scss" || label === "less") {
 | 
			
		||||
        return new cssWorker.default();
 | 
			
		||||
      } else if (label === "html" || label === "handlebars" || label === "razor") {
 | 
			
		||||
        return new htmlWorker.default();
 | 
			
		||||
      } else if (label === "typescript" || label === "javascript") {
 | 
			
		||||
        return new tsWorker.default();
 | 
			
		||||
      } else if (label === "yaml" || label === "yml") {
 | 
			
		||||
        debugger;
 | 
			
		||||
        //@ts-ignore
 | 
			
		||||
        return new yamlWorker.default();
 | 
			
		||||
      }
 | 
			
		||||
      return new editorWorker.default();
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
export * from "monaco-yaml/yaml.worker.js";
 | 
			
		||||
| 
						 | 
				
			
			@ -12,12 +12,18 @@ import IconSelect from "./icon-select.vue";
 | 
			
		|||
import ExpiresTimeText from "./expires-time-text.vue";
 | 
			
		||||
import FileInput from "./file-input.vue";
 | 
			
		||||
import PemInput from "./pem-input.vue";
 | 
			
		||||
import { defineAsyncComponent } from "vue";
 | 
			
		||||
export default {
 | 
			
		||||
  install(app: any) {
 | 
			
		||||
    app.component(
 | 
			
		||||
      "CodeEditor",
 | 
			
		||||
      defineAsyncComponent(() => import("./code-editor/index.vue"))
 | 
			
		||||
    );
 | 
			
		||||
    app.component("PiContainer", PiContainer);
 | 
			
		||||
    app.component("TextEditable", TextEditable);
 | 
			
		||||
    app.component("FileInput", FileInput);
 | 
			
		||||
    app.component("PemInput", PemInput);
 | 
			
		||||
    // app.component("CodeEditor", CodeEditor);
 | 
			
		||||
 | 
			
		||||
    app.component("CronLight", CronLight);
 | 
			
		||||
    app.component("CronEditor", CronEditor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import plugin from "./plugin/";
 | 
			
		|||
import { setupVben } from "./vben";
 | 
			
		||||
import { util } from "/@/utils";
 | 
			
		||||
import { initPreferences } from "/@/vben/preferences";
 | 
			
		||||
// import "./components/code-editor/import-works";
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
async function bootstrap() {
 | 
			
		||||
  const app = createApp(App);
 | 
			
		||||
| 
						 | 
				
			
			@ -33,9 +34,9 @@ async function bootstrap() {
 | 
			
		|||
    namespace,
 | 
			
		||||
    overrides: {
 | 
			
		||||
      app: {
 | 
			
		||||
        name: import.meta.env.VITE_APP_TITLE
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
        name: import.meta.env.VITE_APP_TITLE,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  app.mount("#app");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ import { LocalStorage } from "/@/utils/util.storage";
 | 
			
		|||
import { useUserStore } from "/@/store/modules/user";
 | 
			
		||||
 | 
			
		||||
defineOptions({
 | 
			
		||||
  name: "PipelineDetail"
 | 
			
		||||
  name: "PipelineDetail",
 | 
			
		||||
});
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const pipelineId: Ref = ref(route.query.id);
 | 
			
		||||
| 
						 | 
				
			
			@ -33,8 +33,8 @@ const pipelineOptions: PipelineOptions = {
 | 
			
		|||
        userId: detail.pipeline.userId,
 | 
			
		||||
        stages: [],
 | 
			
		||||
        triggers: [],
 | 
			
		||||
        ...JSON.parse(detail.pipeline.content || "{}")
 | 
			
		||||
      }
 | 
			
		||||
        ...JSON.parse(detail.pipeline.content || "{}"),
 | 
			
		||||
      },
 | 
			
		||||
    } as PipelineDetail;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,13 +56,13 @@ const pipelineOptions: PipelineOptions = {
 | 
			
		|||
  async doSave(pipelineConfig: any) {
 | 
			
		||||
    await api.Save({
 | 
			
		||||
      id: pipelineConfig.id,
 | 
			
		||||
      content: JSON.stringify(pipelineConfig)
 | 
			
		||||
      content: JSON.stringify(pipelineConfig),
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  async doTrigger(options: { pipelineId: number; stepId?: string }) {
 | 
			
		||||
    const { pipelineId, stepId } = options;
 | 
			
		||||
    await api.Trigger(pipelineId, stepId);
 | 
			
		||||
  }
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const pipelineOptionsRef: Ref<PipelineOptions> = ref(pipelineOptions);
 | 
			
		||||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ function useTour() {
 | 
			
		|||
    onFinish: () => {
 | 
			
		||||
      tour.value.open = false;
 | 
			
		||||
      LocalStorage.set("tour-off", true, 999999999);
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const tourHandleOpen = (val: boolean): void => {
 | 
			
		||||
| 
						 | 
				
			
			@ -99,28 +99,28 @@ function useTour() {
 | 
			
		|||
        description: "这里就是我们刚创建的证书任务,点击可以修改证书申请参数",
 | 
			
		||||
        target: () => {
 | 
			
		||||
          return document.querySelector(".pipeline .stages .stage_0 .task");
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "添加部署证书任务",
 | 
			
		||||
        description: "证书申请成功之后还需要部署证书,点击这里可以添加证书部署任务",
 | 
			
		||||
        target: () => {
 | 
			
		||||
          return document.querySelector(".pipeline .stages .last-stage .tasks .task");
 | 
			
		||||
        }
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "手动运行流水线",
 | 
			
		||||
        description: "点击此处可以手动运行流水线",
 | 
			
		||||
        target: () => {
 | 
			
		||||
          return document.querySelector(".pipeline .stages .first-stage .tasks .task");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    tour,
 | 
			
		||||
    tourHandleOpen
 | 
			
		||||
    tourHandleOpen,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,8 +25,11 @@
 | 
			
		|||
              <a-form-item label="必填">
 | 
			
		||||
                <a-switch v-model:checked="item.required" />
 | 
			
		||||
              </a-form-item>
 | 
			
		||||
              <a-form-item label="组件配置">
 | 
			
		||||
                <fs-editor-code v-model:model-value="item.component" language="yaml" />
 | 
			
		||||
              <a-form-item label="组件名称">
 | 
			
		||||
                <a-input v-model:value="item.component.name" />
 | 
			
		||||
              </a-form-item>
 | 
			
		||||
              <a-form-item label="组件vModel">
 | 
			
		||||
                <a-input v-model:value="item.component.vModel" />
 | 
			
		||||
              </a-form-item>
 | 
			
		||||
            </a-form>
 | 
			
		||||
          </a-collapse-panel>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +42,7 @@
 | 
			
		|||
<script lang="ts" setup>
 | 
			
		||||
import { ref, Ref, inject, toRef } from "vue";
 | 
			
		||||
import { useFormWrapper } from "@fast-crud/fast-crud";
 | 
			
		||||
 | 
			
		||||
import yaml from "js-yaml";
 | 
			
		||||
const activeKey = ref([]);
 | 
			
		||||
 | 
			
		||||
const getPlugin: any = inject("get:plugin");
 | 
			
		||||
| 
						 | 
				
			
			@ -49,52 +52,63 @@ if (!inputs.value) {
 | 
			
		|||
  inputs.value = {};
 | 
			
		||||
}
 | 
			
		||||
function addNewField() {
 | 
			
		||||
  const { openCrudFormDialog } = useFormWrapper();
 | 
			
		||||
 | 
			
		||||
  openCrudFormDialog({
 | 
			
		||||
    crudOptions: {
 | 
			
		||||
      form: {
 | 
			
		||||
        labelCol: { style: { width: "80px" } },
 | 
			
		||||
        wrapperCol: { span: 18 },
 | 
			
		||||
        wrapper: {
 | 
			
		||||
          title: "添加输入",
 | 
			
		||||
        },
 | 
			
		||||
        doSubmit({ form }: any) {
 | 
			
		||||
          debugger;
 | 
			
		||||
          const key = form.key;
 | 
			
		||||
          const title = form.title;
 | 
			
		||||
          inputs.value[key] = {
 | 
			
		||||
            key,
 | 
			
		||||
            title,
 | 
			
		||||
            component: `
 | 
			
		||||
  name: a-input
 | 
			
		||||
    
 | 
			
		||||
    `,
 | 
			
		||||
            helper: "",
 | 
			
		||||
            value: undefined,
 | 
			
		||||
            required: false,
 | 
			
		||||
          };
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      columns: {
 | 
			
		||||
        key: {
 | 
			
		||||
          title: "字段名称",
 | 
			
		||||
          type: "text",
 | 
			
		||||
          form: {
 | 
			
		||||
            helper: "英文字段名称",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        title: {
 | 
			
		||||
          title: "字段标题",
 | 
			
		||||
          type: "text",
 | 
			
		||||
          form: {
 | 
			
		||||
            helper: "字段标题",
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  inputs.value.push({
 | 
			
		||||
    key: "newKey",
 | 
			
		||||
    title: "字段名",
 | 
			
		||||
  });
 | 
			
		||||
  // const { openCrudFormDialog } = useFormWrapper();
 | 
			
		||||
  //
 | 
			
		||||
  // openCrudFormDialog({
 | 
			
		||||
  //   crudOptions: {
 | 
			
		||||
  //     form: {
 | 
			
		||||
  //       labelCol: { style: { width: "80px" } },
 | 
			
		||||
  //       wrapperCol: { span: 18 },
 | 
			
		||||
  //       wrapper: {
 | 
			
		||||
  //         title: "添加输入",
 | 
			
		||||
  //       },
 | 
			
		||||
  //       doSubmit({ form }: any) {
 | 
			
		||||
  //         const key = form.key;
 | 
			
		||||
  //         const title = form.title;
 | 
			
		||||
  //         inputs.value[key] = {
 | 
			
		||||
  //           key,
 | 
			
		||||
  //           title,
 | 
			
		||||
  //           component: {
 | 
			
		||||
  //             name: "a-input",
 | 
			
		||||
  //             vModel: "value",
 | 
			
		||||
  //           },
 | 
			
		||||
  //           helper: "",
 | 
			
		||||
  //           value: undefined,
 | 
			
		||||
  //           required: false,
 | 
			
		||||
  //         };
 | 
			
		||||
  //       },
 | 
			
		||||
  //     },
 | 
			
		||||
  //     columns: {
 | 
			
		||||
  //       key: {
 | 
			
		||||
  //         title: "字段名称",
 | 
			
		||||
  //         type: "text",
 | 
			
		||||
  //         form: {
 | 
			
		||||
  //           helper: "英文字段名称",
 | 
			
		||||
  //         },
 | 
			
		||||
  //       },
 | 
			
		||||
  //       title: {
 | 
			
		||||
  //         title: "字段标题",
 | 
			
		||||
  //         type: "text",
 | 
			
		||||
  //         form: {
 | 
			
		||||
  //           helper: "字段标题",
 | 
			
		||||
  //         },
 | 
			
		||||
  //       },
 | 
			
		||||
  //     },
 | 
			
		||||
  //   },
 | 
			
		||||
  // });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// function onComponentChange(item: any, value: any) {
 | 
			
		||||
//   if (!item) {
 | 
			
		||||
//     item.component = {};
 | 
			
		||||
//     return;
 | 
			
		||||
//   }
 | 
			
		||||
//   item.component = yaml.load(value);
 | 
			
		||||
// }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="less">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,44 +7,35 @@
 | 
			
		|||
          <span class="name">{{ plugin.title }} 【{{ plugin.author }}/{{ plugin.name }}】 </span>
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="more">
 | 
			
		||||
        <a-button type="primary" :loading="saveLoading" @click="doSave">保存</a-button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <div class="pi-plugin-editor">
 | 
			
		||||
      <div class="metadata">
 | 
			
		||||
        <a-tabs v-model:active-key="metadataActive" type="card">
 | 
			
		||||
        <a-tabs type="card">
 | 
			
		||||
          <a-tab-pane key="editor" tab="元数据"> </a-tab-pane>
 | 
			
		||||
          <a-tab-pane key="source" tab="yaml"> </a-tab-pane>
 | 
			
		||||
        </a-tabs>
 | 
			
		||||
        <div class="metadata-body">
 | 
			
		||||
          <a-tabs v-if="metadataActive === 'editor'" class="metadata-editor" tab-position="left" type="card">
 | 
			
		||||
            <a-tab-pane key="input" tab="输入">
 | 
			
		||||
              <plugin-input></plugin-input>
 | 
			
		||||
            </a-tab-pane>
 | 
			
		||||
            <a-tab-pane key="output" tab="输出"></a-tab-pane>
 | 
			
		||||
            <a-tab-pane key="dependLibs" tab="第三方依赖"></a-tab-pane>
 | 
			
		||||
            <a-tab-pane key="dependPlugins" tab="插件依赖"></a-tab-pane>
 | 
			
		||||
          </a-tabs>
 | 
			
		||||
 | 
			
		||||
          <div v-if="metadataActive === 'source'" class="metadata-source">
 | 
			
		||||
            <fs-editor-code :model-value="metadataStr" language="yaml" @update:model-value="onMetadataStrUpdate"></fs-editor-code>
 | 
			
		||||
          </div>
 | 
			
		||||
          <code-editor id="metadata" v-model:model-value="plugin.metadata" language="yaml"></code-editor>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="script">
 | 
			
		||||
        <a-tabs type="card">
 | 
			
		||||
          <a-tab-pane key="script" tab="脚本"> </a-tab-pane>
 | 
			
		||||
        </a-tabs>
 | 
			
		||||
        <fs-editor-code v-model="plugin.content" language="javascript"></fs-editor-code>
 | 
			
		||||
        <code-editor id="content" v-model:model-value="plugin.content" language="javascript"></code-editor>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </fs-page>
 | 
			
		||||
</template>
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { onMounted, ref, watch, provide } from "vue";
 | 
			
		||||
import { onMounted, provide, ref } from "vue";
 | 
			
		||||
import { useRoute } from "vue-router";
 | 
			
		||||
import * as api from "./api";
 | 
			
		||||
import yaml from "js-yaml";
 | 
			
		||||
import PluginInput from "/@/views/sys/plugin/components/plugin-input.vue";
 | 
			
		||||
import { merge } from "lodash-es";
 | 
			
		||||
 | 
			
		||||
const CertApplyPluginNames = ["CertApply", "CertApplyLego", "CertApplyUpload"];
 | 
			
		||||
defineOptions({
 | 
			
		||||
  name: "SysPluginEdit",
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -52,30 +43,44 @@ const route = useRoute();
 | 
			
		|||
 | 
			
		||||
const plugin = ref<any>({});
 | 
			
		||||
 | 
			
		||||
const metadataStr = ref("");
 | 
			
		||||
function onMetadataStrUpdate(value: string) {
 | 
			
		||||
  metadataStr.value = value;
 | 
			
		||||
}
 | 
			
		||||
const metadataActive = ref("editor");
 | 
			
		||||
async function getPlugin() {
 | 
			
		||||
  const id = route.query.id;
 | 
			
		||||
  const pluginObj = await api.GetObj(id);
 | 
			
		||||
  if (!pluginObj.metadata) {
 | 
			
		||||
    pluginObj.metadata = {
 | 
			
		||||
      input: {},
 | 
			
		||||
      output: {},
 | 
			
		||||
    };
 | 
			
		||||
    pluginObj.metadata = yaml.dump({
 | 
			
		||||
      input: [
 | 
			
		||||
        {
 | 
			
		||||
          key: "cert",
 | 
			
		||||
          title: "前置任务生成的证书",
 | 
			
		||||
          component: {
 | 
			
		||||
            name: "output-selector",
 | 
			
		||||
            from: [...CertApplyPluginNames],
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
      output: [],
 | 
			
		||||
    });
 | 
			
		||||
  } else {
 | 
			
		||||
    pluginObj.metadata = "";
 | 
			
		||||
  }
 | 
			
		||||
  plugin.value = pluginObj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  await getPlugin();
 | 
			
		||||
});
 | 
			
		||||
getPlugin();
 | 
			
		||||
onMounted(async () => {});
 | 
			
		||||
 | 
			
		||||
provide("get:plugin", () => {
 | 
			
		||||
  return plugin;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const saveLoading = ref(false);
 | 
			
		||||
function doSave() {
 | 
			
		||||
  saveLoading.value = true;
 | 
			
		||||
  try {
 | 
			
		||||
    // api.Save(plugin.value);
 | 
			
		||||
  } finally {
 | 
			
		||||
    saveLoading.value = false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="less">
 | 
			
		||||
| 
						 | 
				
			
			@ -89,11 +94,11 @@ provide("get:plugin", () => {
 | 
			
		|||
    .fs-editor-code {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      flex: 1;
 | 
			
		||||
      overflow-y: hidden;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .metadata {
 | 
			
		||||
      width: 500px;
 | 
			
		||||
      width: 600px;
 | 
			
		||||
      max-width: 50%;
 | 
			
		||||
      margin-right: 20px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
| 
						 | 
				
			
			@ -101,13 +106,11 @@ provide("get:plugin", () => {
 | 
			
		|||
      .metadata-body {
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        overflow-y: hidden;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .metadata-editor {
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        overflow-y: hidden;
 | 
			
		||||
        .ant-tabs-content {
 | 
			
		||||
          height: 100%;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue