mirror of https://github.com/certd/certd
perf: 模版导入流水线
parent
529482a83e
commit
dcc8c56969
|
@ -8,7 +8,7 @@ export const EVENT_CERT_APPLY_SUCCESS = "CertApply.success";
|
|||
|
||||
export abstract class CertApplyBaseConvertPlugin extends AbstractTaskPlugin {
|
||||
@TaskInput({
|
||||
title: "域名",
|
||||
title: "证书域名",
|
||||
component: {
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
|
|
|
@ -19,7 +19,9 @@ defineOptions({
|
|||
});
|
||||
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
const getPluginType: any = inject("get:plugin:type", () => {
|
||||
return "access";
|
||||
});
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
const props = defineProps<{} & ComponentPropsType>();
|
||||
|
||||
|
|
|
@ -27,7 +27,9 @@ const emit = defineEmits<{
|
|||
}>();
|
||||
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
const getPluginType: any = inject("get:plugin:type", () => {
|
||||
return "plugin";
|
||||
});
|
||||
|
||||
const attrs = useAttrs();
|
||||
|
||||
|
|
|
@ -69,9 +69,15 @@ const emit = defineEmits<{
|
|||
|
||||
const attrs = useAttrs();
|
||||
|
||||
const getCurrentPluginDefine: any = inject("getCurrentPluginDefine");
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
const getCurrentPluginDefine: any = inject("getCurrentPluginDefine", () => {
|
||||
return {};
|
||||
});
|
||||
const getScope: any = inject("get:scope", () => {
|
||||
return {};
|
||||
});
|
||||
const getPluginType: any = inject("get:plugin:type", () => {
|
||||
return "plugin";
|
||||
});
|
||||
|
||||
const searchKeyRef = ref("");
|
||||
const optionsRef = ref([]);
|
||||
|
@ -96,7 +102,7 @@ const getOptions = async () => {
|
|||
}
|
||||
const pluginType = getPluginType();
|
||||
const { form } = getScope();
|
||||
const input = pluginType === "plugin" ? form.input : form;
|
||||
const input = (pluginType === "plugin" ? form?.input : form) || {};
|
||||
|
||||
for (let key in define.input) {
|
||||
const inWatches = props.watches.includes(key);
|
||||
|
@ -186,7 +192,7 @@ watch(
|
|||
() => {
|
||||
const pluginType = getPluginType();
|
||||
const { form, key } = getScope();
|
||||
const input = pluginType === "plugin" ? form.input : form;
|
||||
const input = (pluginType === "plugin" ? form?.input : form) || {};
|
||||
const watches = {};
|
||||
for (const key of props.watches) {
|
||||
watches[key] = input[key];
|
||||
|
@ -198,10 +204,11 @@ watch(
|
|||
},
|
||||
async (value, oldValue) => {
|
||||
const { form } = value;
|
||||
const oldForm = oldValue.form;
|
||||
const oldForm: any = oldValue?.form;
|
||||
let changed = oldForm == null || optionsRef.value.length == 0;
|
||||
for (const key of props.watches) {
|
||||
if (form[key] != oldForm[key]) {
|
||||
//@ts-ignore
|
||||
if (oldForm && form[key] != oldForm[key]) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,9 @@ const attrs = useAttrs();
|
|||
|
||||
const otpCodeRef = ref("");
|
||||
const getScope: any = inject("get:scope");
|
||||
const getPluginType: any = inject("get:plugin:type");
|
||||
const getPluginType: any = inject("get:plugin:type", () => {
|
||||
return "access";
|
||||
});
|
||||
|
||||
async function loginWithOTPCode(otpCode: string) {
|
||||
const { form } = getScope();
|
||||
|
|
|
@ -61,6 +61,15 @@ export const certdResources = [
|
|||
isMenu: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "流水线模版批量创建",
|
||||
name: "PipelineTemplateImport",
|
||||
path: "/certd/pipeline/template/import",
|
||||
component: "/certd/pipeline/template/import/index.vue",
|
||||
meta: {
|
||||
isMenu: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "证书仓库",
|
||||
name: "CertStore",
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useRouter } from "vue-router";
|
|||
import { useModal } from "/@/use/use-modal";
|
||||
import createCrudOptionsPipeline from "../crud";
|
||||
import * as pipelineApi from "../api";
|
||||
import { useTemplate } from "/@/views/certd/pipeline/template/use";
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const api = templateApi;
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
|
@ -29,6 +30,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
const router = useRouter();
|
||||
|
||||
const model = useModal();
|
||||
|
||||
const { openCreateFromTemplateDialog } = useTemplate();
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
|
@ -73,6 +77,27 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
buttons: {
|
||||
edit: { show: false },
|
||||
copy: { show: false },
|
||||
use: {
|
||||
text: null,
|
||||
title: "使用此模版创建流水线",
|
||||
icon: "ion:duplicate-outline",
|
||||
click({ row }) {
|
||||
openCreateFromTemplateDialog({
|
||||
templateId: row.id,
|
||||
onCreated: ({ id }) => {
|
||||
router.push({ path: "/certd/pipeline/detail", query: { id, editMode: true } });
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
import: {
|
||||
text: null,
|
||||
title: "批量导入创建",
|
||||
icon: "ion:duplicate",
|
||||
click({ row }) {
|
||||
router.push({ path: "/certd/pipeline/template/import", query: { templateId: row.id } });
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { CreateCrudOptionsProps, CreateCrudOptionsRet, importTable } from "@fast-crud/fast-crud";
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
|
||||
export default function ({ crudExpose }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
return {
|
||||
crudOptions: {
|
||||
mode: {
|
||||
name: "local",
|
||||
isMergeWhenUpdate: true,
|
||||
isAppendWhenAdd: true,
|
||||
},
|
||||
//启用addRow按钮
|
||||
actionbar: {
|
||||
buttons: {
|
||||
//禁用弹框添加
|
||||
add: { show: false },
|
||||
//启用添加行
|
||||
addRow: { show: true },
|
||||
//导入按钮
|
||||
import: {
|
||||
show: false,
|
||||
text: "批量导入",
|
||||
type: "primary",
|
||||
click() {
|
||||
const modal = Modal.info({
|
||||
title: "批量导入",
|
||||
okText: "关闭",
|
||||
content() {
|
||||
async function onChange(e: any) {
|
||||
const file = e.target.files[0];
|
||||
await importTable(crudExpose, { file, append: true });
|
||||
modal.destroy();
|
||||
notification.success({
|
||||
message: "导入成功",
|
||||
});
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
1、<a href={"template-import.csv"}>下载导入模板</a>
|
||||
</p>
|
||||
<p>
|
||||
2、<span>模板填充数据</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>3、导入:</span>
|
||||
<input type={"file"} onInput={onChange}></input>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
table: {
|
||||
remove: {
|
||||
//删除数据后不请求后台
|
||||
refreshTable: false,
|
||||
},
|
||||
editable: {
|
||||
enabled: true,
|
||||
mode: "row",
|
||||
activeTrigger: false,
|
||||
},
|
||||
},
|
||||
search: {
|
||||
show: false,
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
pagination: {
|
||||
show: false,
|
||||
},
|
||||
columns: {},
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import { useColumns } from "@fast-crud/fast-crud";
|
||||
import { createExtraColumns } from "/@/views/certd/pipeline/template/use";
|
||||
import TemplateImportTable from "/@/views/certd/pipeline/template/import/table.vue";
|
||||
import { Ref } from "vue";
|
||||
|
||||
export function createFormOptions(detail: Ref): any {
|
||||
const { buildFormOptions } = useColumns();
|
||||
|
||||
const crudOptions = {
|
||||
columns: {
|
||||
...createExtraColumns(),
|
||||
templateProps: {
|
||||
title: "流水线导入",
|
||||
type: "text",
|
||||
form: {
|
||||
order: 1,
|
||||
component: {
|
||||
name: TemplateImportTable,
|
||||
detail: detail,
|
||||
},
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return buildFormOptions(crudOptions);
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<fs-page class="page-template-import">
|
||||
<template #header>
|
||||
<div class="title flex flex-1 items-center">
|
||||
<fs-button class="back" icon="ion:chevron-back-outline" @click="goBack"></fs-button>
|
||||
<div class="ml-10">从模版{{ detail?.template?.title }}批量创建流水线</div>
|
||||
</div>
|
||||
</template>
|
||||
<fs-form v-if="importFromOptions" ref="formRef" class="mt-10" v-bind="importFromOptions"> </fs-form>
|
||||
<div class="p-10">
|
||||
<a-button class="ml-20" type="primary" @click="doImport">确定导入 </a-button>
|
||||
</div>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { onMounted, ref, Ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { templateApi } from "../api";
|
||||
import { createFormOptions } from "/@/views/certd/pipeline/template/import/form";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { fillPipelineByDefaultForm } from "/@/views/certd/pipeline/certd-form/use";
|
||||
import { eachSteps } from "/@/views/certd/pipeline/utils";
|
||||
|
||||
const route = useRoute();
|
||||
const templateId = route.query.templateId as string;
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
function goBack() {
|
||||
router.back();
|
||||
}
|
||||
|
||||
type TemplateDetail = {
|
||||
template: any;
|
||||
pipeline: any;
|
||||
};
|
||||
|
||||
const detail: Ref<TemplateDetail> = ref();
|
||||
|
||||
async function getTemplateDetail() {
|
||||
if (!templateId) {
|
||||
return;
|
||||
}
|
||||
detail.value = await templateApi.GetDetail(parseInt(templateId));
|
||||
}
|
||||
|
||||
const importFromOptions = ref();
|
||||
onMounted(async () => {
|
||||
await getTemplateDetail();
|
||||
importFromOptions.value = createFormOptions(detail);
|
||||
});
|
||||
|
||||
const formRef = ref();
|
||||
async function doImport() {
|
||||
await formRef.value.validate();
|
||||
|
||||
const form = formRef.value.getFormData();
|
||||
|
||||
const importTableRef = formRef.value.getComponentRef("templateProps");
|
||||
|
||||
const templateList = importTableRef.value.getData();
|
||||
|
||||
for (let i = 0; i < templateList.length; i++) {
|
||||
const tempInputs = templateList[i];
|
||||
const title = tempInputs.title;
|
||||
delete tempInputs.title;
|
||||
|
||||
let newPipeline = cloneDeep(detail.value.pipeline);
|
||||
newPipeline = fillPipelineByDefaultForm(newPipeline, form);
|
||||
//填充模版参数
|
||||
const steps: any = {};
|
||||
eachSteps(newPipeline, (step: any) => {
|
||||
steps[step.id] = step;
|
||||
});
|
||||
|
||||
for (const inputKey in tempInputs) {
|
||||
const [stepId, key] = inputKey.split(".");
|
||||
const step = steps[stepId];
|
||||
if (step) {
|
||||
step.input[key] = tempInputs[inputKey];
|
||||
}
|
||||
}
|
||||
|
||||
newPipeline.title = title;
|
||||
const groupId = form.groupId;
|
||||
|
||||
await templateApi.CreatePipelineByTemplate({
|
||||
title,
|
||||
content: JSON.stringify(newPipeline),
|
||||
keepHistoryCount: 30,
|
||||
groupId,
|
||||
templateId: parseInt(templateId),
|
||||
pipeline: {
|
||||
title: form.title,
|
||||
templateProps: templateList,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.page-template-import {
|
||||
.ant-table-container {
|
||||
.ant-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,115 @@
|
|||
<template>
|
||||
<fs-crud ref="crudRef" class="template-import-table" v-bind="crudBinding">
|
||||
<template #actionbar-right>
|
||||
<div class="helper ml-10">1. 点击添加按钮,添加一行记录; 2.输入流水线参数; 3. 点击右边“确认创建”,批量创建流水线。</div>
|
||||
</template>
|
||||
</fs-crud>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { computed, onMounted, ref, Ref, nextTick, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { templateApi } from "../api";
|
||||
import { usePluginStore } from "/@/store/plugin";
|
||||
import { useStepHelper } from "../utils";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { Form } from "ant-design-vue";
|
||||
|
||||
defineOptions({
|
||||
name: "TemplateImportTable",
|
||||
});
|
||||
|
||||
const formItemContext = Form.useInjectFormItemContext();
|
||||
|
||||
type TemplateDetail = {
|
||||
template: any;
|
||||
pipeline: any;
|
||||
};
|
||||
const templateProps: Ref = ref({
|
||||
input: {},
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
detail: TemplateDetail;
|
||||
}>();
|
||||
|
||||
const pluginStore = usePluginStore();
|
||||
|
||||
const { getStepsMap } = useStepHelper(pluginStore);
|
||||
|
||||
function buildColumns(steps: any) {
|
||||
const columns: any = {
|
||||
title: {
|
||||
title: "流水线标题",
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
placeholder: "请输入流水线标题",
|
||||
},
|
||||
rules: [{ required: true, message: "请输入流水线标题" }],
|
||||
},
|
||||
},
|
||||
};
|
||||
for (const inputKey in templateProps.value.input) {
|
||||
const [stepId, key] = inputKey.split(".");
|
||||
const item = steps[stepId].input[key];
|
||||
columns[inputKey] = {
|
||||
title: item.define.title,
|
||||
type: "text",
|
||||
form: {
|
||||
...item.define,
|
||||
},
|
||||
column: {},
|
||||
};
|
||||
}
|
||||
return {
|
||||
table: {
|
||||
slots: {
|
||||
headerCell({ column }: any) {
|
||||
const col = columns[column.key];
|
||||
if (col && col?.form?.helper) {
|
||||
return (
|
||||
<span class={"flex "}>
|
||||
{col.title}
|
||||
<a-tooltip title={col.form.helper}>
|
||||
<fs-icon class={"ml-5"} icon={"ion:alert-circle-outline"}></fs-icon>
|
||||
</a-tooltip>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
columns,
|
||||
};
|
||||
}
|
||||
|
||||
//启用行编辑模式
|
||||
const { crudBinding, crudRef, crudExpose, appendCrudOptions } = useFs({ createCrudOptions, context: {} });
|
||||
onMounted(async () => {
|
||||
await pluginStore.init();
|
||||
await nextTick();
|
||||
const steps = getStepsMap(props.detail.pipeline);
|
||||
templateProps.value = JSON.parse(props.detail.template?.content ?? "{input:{}}");
|
||||
appendCrudOptions({ ...buildColumns(steps) });
|
||||
crudBinding.value.data = [];
|
||||
await crudExpose.editable.enable({ mode: "row" });
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
getData() {
|
||||
return crudBinding.value.data;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.template-import-table {
|
||||
.ant-table-container {
|
||||
.ant-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -8,102 +8,15 @@ import { ref } from "vue";
|
|||
import { fillPipelineByDefaultForm } from "/@/views/certd/pipeline/certd-form/use";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
|
||||
export function useTemplate() {
|
||||
const { openCrudFormDialog } = useFormWrapper();
|
||||
|
||||
async function openCreateFromTemplateDialog(req: { templateId?: number }) {
|
||||
//检查是否流水线数量超出限制
|
||||
await checkPipelineLimit();
|
||||
const detail = await templateApi.GetDetail(req.templateId);
|
||||
if (!detail) {
|
||||
throw new Error("模板不存在");
|
||||
}
|
||||
if (!detail.template?.pipelineId) {
|
||||
throw new Error("还未绑定模版流水线");
|
||||
}
|
||||
const templateProps = JSON.parse(detail.template.content || "{}");
|
||||
const pipeline = detail.pipeline;
|
||||
|
||||
export function createExtraColumns() {
|
||||
const groupDictRef = dict({
|
||||
url: "/pi/pipeline/group/all",
|
||||
value: "id",
|
||||
label: "name",
|
||||
});
|
||||
|
||||
const wrapperRef = ref();
|
||||
function getFormData() {
|
||||
if (!wrapperRef.value) {
|
||||
return null;
|
||||
}
|
||||
return wrapperRef.value.getFormData();
|
||||
}
|
||||
|
||||
const randomHour = Math.floor(Math.random() * 6);
|
||||
const randomMin = Math.floor(Math.random() * 60);
|
||||
const templateFormRef = ref();
|
||||
|
||||
async function doSubmit(opts: { form: any }) {
|
||||
const form = opts.form;
|
||||
await templateFormRef.value.validate();
|
||||
|
||||
const tempInputs = templateFormRef.value.getForm();
|
||||
|
||||
let newPipeline = cloneDeep(pipeline);
|
||||
newPipeline = fillPipelineByDefaultForm(newPipeline, form);
|
||||
//填充模版参数
|
||||
const steps: any = {};
|
||||
eachSteps(newPipeline, (step: any) => {
|
||||
steps[step.id] = step;
|
||||
});
|
||||
|
||||
for (const inputKey in tempInputs) {
|
||||
const [stepId, key] = inputKey.split(".");
|
||||
const step = steps[stepId];
|
||||
if (step) {
|
||||
step.input[key] = tempInputs[inputKey];
|
||||
}
|
||||
}
|
||||
|
||||
const title = form.title;
|
||||
newPipeline.title = title;
|
||||
const groupId = form.groupId;
|
||||
await templateApi.CreatePipelineByTemplate({
|
||||
title,
|
||||
content: JSON.stringify(newPipeline),
|
||||
keepHistoryCount: 30,
|
||||
groupId,
|
||||
templateId: detail.template.id,
|
||||
});
|
||||
}
|
||||
|
||||
const crudOptions = {
|
||||
form: {
|
||||
doSubmit,
|
||||
wrapper: {
|
||||
title: `从模版<${detail.template.title}>创建流水线`,
|
||||
width: 1100,
|
||||
slots: {
|
||||
"form-body-top": () => {
|
||||
return (
|
||||
<div class={"w-full flex"}>
|
||||
<TemplateForm ref={templateFormRef} input={templateProps.input} pipeline={pipeline} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
title: {
|
||||
title: "流水线标题",
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
placeholder: "请输入流水线标题",
|
||||
},
|
||||
rules: [{ required: true, message: "请输入流水线标题" }],
|
||||
},
|
||||
},
|
||||
return {
|
||||
triggerCron: {
|
||||
title: "定时触发",
|
||||
type: "text",
|
||||
|
@ -114,6 +27,9 @@ export function useTemplate() {
|
|||
vModel: "modelValue",
|
||||
placeholder: "0 0 4 * * *",
|
||||
},
|
||||
col: {
|
||||
span: 24,
|
||||
},
|
||||
helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行",
|
||||
order: 100,
|
||||
},
|
||||
|
@ -145,9 +61,104 @@ export function useTemplate() {
|
|||
name: GroupSelector,
|
||||
vModel: "modelValue",
|
||||
},
|
||||
order: 99,
|
||||
order: 999,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function useTemplate() {
|
||||
const { openCrudFormDialog } = useFormWrapper();
|
||||
|
||||
async function openCreateFromTemplateDialog(req: { templateId?: number; onCreated?: (ctx: any) => void }) {
|
||||
//检查是否流水线数量超出限制
|
||||
await checkPipelineLimit();
|
||||
const detail = await templateApi.GetDetail(req.templateId);
|
||||
if (!detail) {
|
||||
throw new Error("模板不存在");
|
||||
}
|
||||
if (!detail.template?.pipelineId) {
|
||||
throw new Error("还未绑定模版流水线");
|
||||
}
|
||||
const templateProps = JSON.parse(detail.template.content || "{}");
|
||||
const pipeline = detail.pipeline;
|
||||
|
||||
const wrapperRef = ref();
|
||||
function getFormData() {
|
||||
if (!wrapperRef.value) {
|
||||
return null;
|
||||
}
|
||||
return wrapperRef.value.getFormData();
|
||||
}
|
||||
|
||||
const templateFormRef = ref();
|
||||
|
||||
async function doSubmit(opts: { form: any }) {
|
||||
const form = opts.form;
|
||||
await templateFormRef.value.validate();
|
||||
|
||||
const tempInputs = templateFormRef.value.getForm();
|
||||
|
||||
let newPipeline = cloneDeep(pipeline);
|
||||
newPipeline = fillPipelineByDefaultForm(newPipeline, form);
|
||||
//填充模版参数
|
||||
const steps: any = {};
|
||||
eachSteps(newPipeline, (step: any) => {
|
||||
steps[step.id] = step;
|
||||
});
|
||||
|
||||
for (const inputKey in tempInputs) {
|
||||
const [stepId, key] = inputKey.split(".");
|
||||
const step = steps[stepId];
|
||||
if (step) {
|
||||
step.input[key] = tempInputs[inputKey];
|
||||
}
|
||||
}
|
||||
|
||||
const title = form.title;
|
||||
newPipeline.title = title;
|
||||
const groupId = form.groupId;
|
||||
const { id } = await templateApi.CreatePipelineByTemplate({
|
||||
title,
|
||||
content: JSON.stringify(newPipeline),
|
||||
keepHistoryCount: 30,
|
||||
groupId,
|
||||
templateId: detail.template.id,
|
||||
});
|
||||
if (req.onCreated) {
|
||||
req.onCreated({ id });
|
||||
}
|
||||
}
|
||||
|
||||
const crudOptions = {
|
||||
form: {
|
||||
doSubmit,
|
||||
wrapper: {
|
||||
title: `从模版<${detail.template.title}>创建流水线`,
|
||||
width: 1100,
|
||||
slots: {
|
||||
"form-body-top": () => {
|
||||
return (
|
||||
<div class={"w-full flex"}>
|
||||
<TemplateForm ref={templateFormRef} input={templateProps.input} pipeline={pipeline} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
title: {
|
||||
title: "流水线标题",
|
||||
type: "text",
|
||||
form: {
|
||||
component: {
|
||||
placeholder: "请输入流水线标题",
|
||||
},
|
||||
rules: [{ required: true, message: "请输入流水线标题" }],
|
||||
},
|
||||
},
|
||||
...createExtraColumns(),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -48,10 +48,10 @@ export class TemplateService extends BaseService<TemplateEntity> {
|
|||
newPipeline.title = template.title + "模版流水线"
|
||||
newPipeline.templateId = template.id
|
||||
newPipeline.isTemplate = true
|
||||
newPipeline.userId = template.userId
|
||||
|
||||
const pipelineJson: Pipeline = JSON.parse(newPipeline.content)
|
||||
delete pipelineJson.triggers
|
||||
pipelineJson.id = template.id
|
||||
pipelineJson.userId = template.userId
|
||||
pipelineJson.title = newPipeline.title
|
||||
newPipeline.content = JSON.stringify(pipelineJson)
|
||||
|
@ -121,6 +121,8 @@ export class TemplateService extends BaseService<TemplateEntity> {
|
|||
}
|
||||
|
||||
await this.pipelineService.save(newPipeline)
|
||||
|
||||
return newPipeline
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue