certd/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx

553 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import * as api from "./api";
import { useI18n } from "vue-i18n";
import { computed, ref } from "vue";
import { useRouter } from "vue-router";
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, useUi } from "@fast-crud/fast-crud";
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
import { Modal, notification } from "ant-design-vue";
import { useUserStore } from "/@/store/user";
import dayjs from "dayjs";
import { useSettingStore } from "/@/store/settings";
import { cloneDeep } from "lodash-es";
import { eachStages } from "./utils";
import { setRunnableIds, useCertPipelineCreator } from "/@/views/certd/pipeline/certd-form/use";
import { useCertUpload } from "/@/views/certd/pipeline/cert-upload/use";
import GroupSelector from "/@/views/certd/pipeline/group/group-selector.vue";
import { useCertViewer } from "/@/views/certd/pipeline/use";
export default function ({ crudExpose, context: { groupDictRef, selectedRowKeys } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const router = useRouter();
const { t } = useI18n();
const lastResRef = ref();
const { openAddCertdPipelineDialog } = useCertPipelineCreator();
const { openUploadCreateDialog } = useCertUpload();
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query);
};
const editRequest = async ({ form, row }: EditReq) => {
form.id = row.id;
const res = await api.UpdateObj(form);
lastResRef.value = res;
return res;
};
const delRequest = async ({ row }: DelReq) => {
return await api.DelObj(row.id);
};
const addRequest = async ({ form }: AddReq) => {
if (form.content == null) {
form.content = JSON.stringify({
title: form.title,
});
} else {
//复制的流水线
delete form.status;
delete form.lastHistoryTime;
delete form.lastVars;
delete form.createTime;
delete form.id;
let pipeline = JSON.parse(form.content);
pipeline.title = form.title;
pipeline = setRunnableIds(pipeline);
form.content = JSON.stringify(pipeline);
}
const res = await api.AddObj(form);
lastResRef.value = res;
return res;
};
const { viewCert, downloadCert } = useCertViewer();
const userStore = useUserStore();
const settingStore = useSettingStore();
function onDialogOpen(opt: any) {
const searchForm = crudExpose.getSearchValidatedFormData();
opt.initialForm = {
...opt.initialForm,
groupId: searchForm.groupId,
};
}
return {
crudOptions: {
request: {
pageRequest,
addRequest,
editRequest,
delRequest,
},
settings: {
plugins: {
//行选择插件,内置插件
rowSelection: {
//是否启用本插件
enabled: true,
order: -2,
//合并在用户配置crudOptions之前还是之后
before: true,
props: {
multiple: true,
crossPage: false,
selectedRowKeys,
onSelectedChanged(selected) {
console.log("已选择变化:", selected);
},
},
},
},
},
actionbar: {
buttons: {
add: {
order: 5,
icon: "ion:ios-add-circle-outline",
text: "自定义流水线",
},
addCertd: {
order: 1,
text: "创建证书流水线",
type: "primary",
icon: "ion:ios-add-circle-outline",
click() {
const searchForm = crudExpose.getSearchValidatedFormData();
const defaultGroupId = searchForm.groupId;
openAddCertdPipelineDialog({ defaultGroupId });
},
},
uploadCert: {
order: 2,
text: "商用证书托管",
type: "primary",
tooltip: {
slots: {
title() {
return (
<ul>
<li></li>
<li></li>
<li></li>
</ul>
);
},
},
},
icon: "ion:cloud-upload-outline",
click() {
const searchForm = crudExpose.getSearchValidatedFormData();
openUploadCreateDialog({ defaultGroupId: searchForm.groupId });
},
},
},
},
form: {
afterSubmit({ form, res, mode }) {
if (mode === "add") {
router.push({ path: "/certd/pipeline/detail", query: { id: res.id, editMode: "true" } });
}
},
wrapper: {
onOpen: onDialogOpen,
},
},
table: {
scroll: { x: 1500 },
remove: {
confirmTitle: "确定要删除吗?",
confirmMessage: "将删除该流水线相关的所有数据,包括执行历史、证书文件、证书仓库记录等",
},
},
tabs: {
name: "groupId",
show: true,
},
rowHandle: {
width: 200,
fixed: "right",
dropdown: {
show: true,
},
buttons: {
play: {
order: -999,
title: "运行流水线",
tooltip: { title: "运行流水线" },
type: "link",
icon: "ant-design:play-circle-outlined",
click({ row }) {
Modal.confirm({
title: "确认",
content: `确定要触发运行吗?`,
async onOk() {
await api.Trigger(row.id);
notification.success({ message: "管道已经开始运行" });
},
});
},
},
view: {
show: false,
click({ row }) {
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "false" } });
},
},
copy: {
click: async context => {
settingStore.checkPlus();
const { ui } = useUi();
// @ts-ignore
let row = context[ui.tableColumn.row];
row = cloneDeep(row);
row.title = row.title + "_copy";
await crudExpose.openCopy({
row: row,
index: context.index,
});
},
class: "need-plus",
},
config: {
order: 1,
title: "编辑流水线",
type: "link",
dropdown: true,
icon: "ant-design:edit-outlined",
click({ row }) {
router.push({ path: "/certd/pipeline/detail", query: { id: row.id, editMode: "true" } });
},
},
edit: {
order: 2,
title: "修改配置/分组",
icon: "ant-design:setting-outlined",
dropdown: true,
},
viewCert: {
order: 3,
title: "查看证书",
tooltip: { title: "查看证书" },
type: "link",
icon: "ph:certificate",
async click({ row }) {
await viewCert(row.id);
},
},
download: {
order: 4,
type: "link",
title: "下载证书",
tooltip: { title: "下载证书" },
icon: "ant-design:download-outlined",
async click({ row }) {
await downloadCert(row.id);
},
},
remove: {
order: 5,
dropdown: true,
},
},
},
columns: {
id: {
title: "ID",
key: "id",
type: "number",
search: {
show: true,
},
column: {
width: 100,
},
form: {
show: false,
},
},
userId: {
title: "用户Id",
type: "number",
search: {
show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
}),
},
form: {
show: false,
},
column: {
show: computed(() => {
return userStore.isAdmin && settingStore.sysPublic.managerOtherUserPipeline;
}),
width: 100,
},
},
title: {
title: "流水线名称",
type: "link",
search: {
show: true,
title: "关键字",
component: {
name: "a-input",
},
},
form: {
rules: [{ required: true, message: "此项必填" }],
},
column: {
width: 350,
// tooltip: true,
ellipsis: true,
sorter: true,
showTitle: true,
cellRender: ({ row, value }) => {
return <router-link to={{ path: "/certd/pipeline/detail", query: { id: row.id, editMode: false } }}>{value}</router-link>;
},
},
},
content: {
title: "流水线内容",
form: { show: false },
column: {
show: false,
},
valueBuilder({ row }) {
if (row.content) {
row.content = JSON.parse(row.content);
const pipeline = row.content;
let stepCount = 0;
eachStages(pipeline.stages, (item, runnableType) => {
if (runnableType === "step") {
stepCount++;
}
});
row._stepCount = stepCount;
if (pipeline.triggers) {
row._triggerCount = pipeline.triggers?.length > 0 ? pipeline.triggers.length : "-";
}
}
},
valueResolve({ row }) {
if (row.content) {
row.content = JSON.stringify(row.content);
}
},
},
_triggerCount: {
title: "定时任务数",
type: "number",
column: {
align: "center",
width: 100,
},
form: {
show: false,
},
},
_stepCount: {
title: "部署任务数",
type: "number",
form: { show: false },
column: {
align: "center",
width: 100,
},
},
lastVars: {
title: "到期剩余",
type: "number",
form: {
show: false,
},
column: {
cellRender({ row }) {
if (!row.lastVars?.certExpiresTime) {
return "-";
}
const leftDays = dayjs(row.lastVars.certExpiresTime).diff(dayjs(), "day");
const color = leftDays < 20 ? "red" : "#389e0d";
const percent = (leftDays / 90) * 100;
return <a-progress percent={percent} strokeColor={color} format={(percent: number) => `${leftDays}`} />;
},
width: 150,
},
},
"lastVars.certExpiresTime": {
title: "过期时间",
search: {
show: false,
},
type: "datetime",
form: {
show: false,
},
column: {
sorter: false,
width: 150,
align: "center",
},
},
status: {
title: "状态",
type: "dict-select",
search: {
show: true,
},
dict: dict({
data: statusUtil.getOptions(),
}),
form: {
show: false,
},
column: {
sorter: true,
width: 120,
align: "center",
},
},
lastHistoryTime: {
title: "最后运行",
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 150,
align: "center",
},
},
disabled: {
title: "启用",
type: "dict-switch",
dict: dict({
data: [
{ value: false, label: "启用" },
{ value: true, label: "禁用" },
],
}),
form: {
value: false,
show: false,
},
column: {
sorter: true,
width: 80,
align: "center",
component: {
name: "fs-dict-switch",
vModel: "checked",
},
async valueChange({ row, key, value }) {
return await api.UpdateObj({
id: row.id,
disabled: row[key],
});
},
},
},
groupId: {
title: "分组",
type: "dict-select",
search: {
show: true,
},
dict: groupDictRef,
form: {
component: {
name: GroupSelector,
vModel: "modelValue",
},
},
column: {
width: 130,
align: "center",
component: {
color: "auto",
},
sorter: true,
},
},
type: {
title: "类型",
type: "dict-select",
search: {
show: true,
},
dict: dict({
data: [
{ value: "cert", label: "证书申请" },
{ value: "cert_upload", label: "证书上传" },
{ value: "custom", label: "自定义" },
],
}),
form: {
show: false,
value: "custom",
},
column: {
sorter: true,
width: 90,
align: "center",
show: true,
component: {
color: "auto",
},
},
},
order: {
title: "排序号",
type: "number",
column: {
sorter: true,
align: "center",
width: 80,
},
form: {
value: 0,
},
},
keepHistoryCount: {
title: "历史记录保持数",
type: "number",
form: {
value: 20,
helper: "历史记录保持条数,多余的会被删除",
},
column: {
width: 130,
show: false,
sorter: true,
},
},
createTime: {
title: "创建时间",
type: "datetime",
form: {
show: false,
},
column: {
sorter: true,
width: 155,
align: "center",
},
},
updateTime: {
title: "更新时间",
type: "datetime",
form: {
show: false,
},
column: {
width: 125,
show: false,
sorter: true,
},
},
},
},
};
}