mirror of
https://github.com/certd/certd.git
synced 2026-04-24 04:17:25 +08:00
chore: 模版创建流水线
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
defineOptions({
|
||||
name: "LayoutFooter"
|
||||
name: "LayoutFooter",
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -37,6 +37,11 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
editRequest,
|
||||
delRequest,
|
||||
},
|
||||
addForm: {
|
||||
onSuccess: ({ res }) => {
|
||||
router.push({ path: "/certd/pipeline/template/edit", query: { templateId: res.id, editMode: "true" } });
|
||||
},
|
||||
},
|
||||
form: {
|
||||
labelCol: {
|
||||
//固定label宽度
|
||||
@@ -95,7 +100,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
show: true,
|
||||
},
|
||||
column: {
|
||||
width: 200,
|
||||
width: 400,
|
||||
sorter: true,
|
||||
cellRender({ row, value }) {
|
||||
return <router-link to={{ path: "/certd/pipeline/template/edit", query: { templateId: row.id } }}>{value}</router-link>;
|
||||
@@ -117,8 +122,12 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||
editForm: {
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
column: {
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
show: true,
|
||||
helper: "复制该流水线配置作为模版来源",
|
||||
component: {
|
||||
valuesFormat: {
|
||||
labelFormatter: (item: any) => {
|
||||
|
||||
@@ -7,18 +7,33 @@
|
||||
</div>
|
||||
|
||||
<div class="more flex items-center flex-1 justify-end">
|
||||
<loading-button type="primary" @click="doSave">保存</loading-button>
|
||||
<loading-button type="primary" @click="doSave">保存模版</loading-button>
|
||||
<loading-button class="ml-10" type="primary" @click="useTemplateCreate">使用模版</loading-button>
|
||||
<loading-button class="ml-10" type="primary" danger @click="doDelete">删除模版</loading-button>
|
||||
</div>
|
||||
</template>
|
||||
<div class="page-template-edit">
|
||||
<div class="base"></div>
|
||||
<div class="props flex p-10">
|
||||
<div class="task-list w-50%">
|
||||
<div class="block-title">
|
||||
原始任务参数
|
||||
<div class="helper">点击加号,将字段作为模版变量</div>
|
||||
<div class="block-title flex flex-between">
|
||||
<div>
|
||||
模版流水线参数
|
||||
<div class="helper">点击加号,将字段作为模版变量</div>
|
||||
</div>
|
||||
<div class="more">
|
||||
<router-link
|
||||
v-if="detail?.template?.pipelineId > 0"
|
||||
:to="{
|
||||
path: '/certd/pipeline/detail',
|
||||
query: { id: detail?.template?.pipelineId, editMode: true },
|
||||
}"
|
||||
>
|
||||
修改模版流水线
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<a-collapse v-model:active-key="activeKey">
|
||||
<a-collapse v-if="detail?.template?.pipelineId > 0" v-model:active-key="activeKey">
|
||||
<a-collapse-panel v-for="(step, stepId) in steps" :key="stepId" class="step-item" :header="step.title">
|
||||
<div class="step-inputs flex flex-wrap">
|
||||
<div v-for="(input, key) of step.input" :key="key" class="hover:bg-gray-100 p-5 w-full xl:w-[50%]">
|
||||
@@ -36,6 +51,17 @@
|
||||
</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
|
||||
<div v-else-if="detail?.template?.pipelineId === 0">
|
||||
<div class="p-20 flex flex-col flex-center text-sm">
|
||||
<div class="mb-10">还未绑定模版流水线</div>
|
||||
<div>
|
||||
<a-button type="primary" @click="bindPipelineByCreate">创建新流水线作为模版</a-button>
|
||||
或
|
||||
<a-button type="primary" @click="bindPipelineByCopy">从已有流水线复制</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="template-props w-50%">
|
||||
@@ -60,7 +86,9 @@ import { templateApi } from "./api";
|
||||
import { usePluginStore } from "/@/store/plugin";
|
||||
import { useStepHelper } from "./utils";
|
||||
import TemplateForm from "./form.vue";
|
||||
|
||||
import { Modal, notification } from "ant-design-vue";
|
||||
import { useTabbarStore } from "/@/vben/stores";
|
||||
import { useTemplate } from "./use";
|
||||
const route = useRoute();
|
||||
const templateId = route.query.templateId as string;
|
||||
|
||||
@@ -79,6 +107,9 @@ const templateProps: Ref = ref({
|
||||
});
|
||||
const detail: Ref<TemplateDetail> = ref();
|
||||
async function getTemplateDetail() {
|
||||
if (!templateId) {
|
||||
return;
|
||||
}
|
||||
const res = await templateApi.GetDetail(parseInt(templateId));
|
||||
detail.value = res;
|
||||
templateProps.value = JSON.parse(res.template.content ?? "{input:{}}");
|
||||
@@ -100,7 +131,7 @@ onMounted(async () => {
|
||||
|
||||
const { getStepsMap } = useStepHelper(pluginStore);
|
||||
const steps = computed(() => {
|
||||
if (!detail.value) {
|
||||
if (!detail.value || !detail.value.pipeline) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -126,5 +157,36 @@ async function doSave() {
|
||||
title: detail.value.template.title,
|
||||
content: JSON.stringify(templateProps.value),
|
||||
});
|
||||
notification.success({
|
||||
message: "保存成功",
|
||||
});
|
||||
}
|
||||
|
||||
const tabbar = useTabbarStore();
|
||||
async function doDelete() {
|
||||
Modal.confirm({
|
||||
title: "确定删除模版?",
|
||||
content: "删除后,该模版流水线将不能再使用",
|
||||
onOk() {
|
||||
templateApi.DelObj(detail.value.template.id);
|
||||
notification.success({
|
||||
message: "删除成功",
|
||||
});
|
||||
tabbar.closeTab({ fullPath: route.fullPath } as any, router);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function bindPipelineByCreate() {
|
||||
//
|
||||
// openAddCertdPipelineDialog({ templateId: detail.value.template.id });
|
||||
}
|
||||
|
||||
async function bindPipelineByCopy() {}
|
||||
|
||||
const { openCreateFromTemplateDialog } = useTemplate();
|
||||
|
||||
async function useTemplateCreate() {
|
||||
openCreateFromTemplateDialog({ templateId: detail.value.template.id });
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-form ref="templateFormRef" class="template-form" :model="templateForm" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<a-form ref="templateFormRef" class="template-form w-full" :model="templateForm" :label-col="labelCol" :wrapper-col="wrapperCol">
|
||||
<template v-for="(item, key) in templateFormColumns" :key="key">
|
||||
<fs-form-item v-if="item.show !== false" :model-value="get(templateForm, key)" :item="item" :get-context-fn="getScopeFunc(key)" @update:model-value="set(templateForm, key, $event)" />
|
||||
</template>
|
||||
@@ -28,7 +28,12 @@ const steps = computed(() => {
|
||||
return getStepsMap(props.pipeline);
|
||||
});
|
||||
|
||||
const labelCol = ref({ span: 6 });
|
||||
const labelCol = ref({
|
||||
span: null,
|
||||
style: {
|
||||
width: "145px",
|
||||
},
|
||||
});
|
||||
const wrapperCol = ref({ span: 16 });
|
||||
const templateForm: any = reactive({});
|
||||
const templateFormColumns = computed(() => {
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
import { dict, useFormWrapper } from "@fast-crud/fast-crud";
|
||||
import { checkPipelineLimit } from "/@/views/certd/pipeline/utils";
|
||||
import { templateApi } from "/@/views/certd/pipeline/template/api";
|
||||
import TemplateForm from "./form.vue";
|
||||
import NotificationSelector from "/@/views/certd/notification/notification-selector/index.vue";
|
||||
import GroupSelector from "/@/views/certd/pipeline/group/group-selector.vue";
|
||||
import { ref } from "vue";
|
||||
|
||||
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;
|
||||
|
||||
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 crudOptions = {
|
||||
form: {
|
||||
wrapper: {
|
||||
title: `从模版<${detail.template.title}>创建流水线`,
|
||||
width: 1100,
|
||||
slots: {
|
||||
"form-body-top": () => {
|
||||
return (
|
||||
<div class={"w-full flex"}>
|
||||
<TemplateForm input={templateProps.input} pipeline={pipeline} />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
triggerCron: {
|
||||
title: "定时触发",
|
||||
type: "text",
|
||||
form: {
|
||||
value: `0 ${randomMin} ${randomHour} * * *`,
|
||||
component: {
|
||||
name: "cron-editor",
|
||||
vModel: "modelValue",
|
||||
placeholder: "0 0 4 * * *",
|
||||
},
|
||||
helper: "点击上面的按钮,选择每天几点定时执行。\n建议设置为每天触发一次,证书未到期之前任务会跳过,不会重复执行",
|
||||
order: 100,
|
||||
},
|
||||
},
|
||||
notification: {
|
||||
title: "失败通知",
|
||||
type: "text",
|
||||
form: {
|
||||
value: 0,
|
||||
component: {
|
||||
name: NotificationSelector,
|
||||
vModel: "modelValue",
|
||||
on: {
|
||||
selectedChange(opts: any) {
|
||||
opts.form.notificationTarget = opts.$event;
|
||||
},
|
||||
},
|
||||
},
|
||||
order: 101,
|
||||
helper: "任务执行失败实时提醒",
|
||||
},
|
||||
},
|
||||
groupId: {
|
||||
title: "流水线分组",
|
||||
type: "dict-select",
|
||||
dict: groupDictRef,
|
||||
form: {
|
||||
component: {
|
||||
name: GroupSelector,
|
||||
vModel: "modelValue",
|
||||
},
|
||||
order: 9999,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = await openCrudFormDialog({ crudOptions });
|
||||
wrapperRef.value = wrapper;
|
||||
}
|
||||
|
||||
return {
|
||||
openCreateFromTemplateDialog,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user