mirror of
https://github.com/certd/certd.git
synced 2026-06-10 10:37:34 +08:00
feat: 新增管理员针对用户流水线和证书监控管理功能
1. 新增后台管理页面:用户流水线管理、用户证书监控管理 2. 新增对应前后端接口与控制器 3. 添加多语言国际化配置 4. 修复导入顺序与多余空行问题 5. 补充证书申请类型选项
This commit is contained in:
@@ -45,6 +45,9 @@ export default {
|
||||
permissionManager: "Permission Management",
|
||||
roleManager: "Role Management",
|
||||
userManager: "User Management",
|
||||
userDataManager: "User Data Management",
|
||||
pipelineManager: "User Pipeline Management",
|
||||
siteMonitorManager: "User Certificate Monitor",
|
||||
suiteManager: "Suite Management",
|
||||
suiteSetting: "Suite Settings",
|
||||
orderManager: "Order Management",
|
||||
|
||||
@@ -46,6 +46,9 @@ export default {
|
||||
permissionManager: "权限管理",
|
||||
roleManager: "角色管理",
|
||||
userManager: "用户管理",
|
||||
userDataManager: "用户数据管理",
|
||||
pipelineManager: "用户流水线管理",
|
||||
siteMonitorManager: "用户证书监控管理",
|
||||
suiteManager: "套餐管理",
|
||||
suiteSetting: "套餐设置",
|
||||
orderManager: "订单管理",
|
||||
|
||||
@@ -230,6 +230,44 @@ export const sysResources = [
|
||||
auth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "certd.sysResources.userDataManager",
|
||||
name: "UserDataManager",
|
||||
path: "/sys/user-data",
|
||||
redirect: "/sys/pipeline",
|
||||
meta: {
|
||||
icon: "ion:folder-open-outline",
|
||||
permission: "sys:settings:view",
|
||||
keepAlive: true,
|
||||
auth: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
title: "certd.sysResources.pipelineManager",
|
||||
name: "SysPipelineManager",
|
||||
path: "/sys/pipeline",
|
||||
component: "/sys/pipeline/index.vue",
|
||||
meta: {
|
||||
icon: "ion:analytics-sharp",
|
||||
permission: "sys:settings:view",
|
||||
keepAlive: true,
|
||||
auth: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "certd.sysResources.siteMonitorManager",
|
||||
name: "SysSiteMonitorManager",
|
||||
path: "/sys/monitor/site",
|
||||
component: "/sys/monitor/site/index.vue",
|
||||
meta: {
|
||||
icon: "ion:videocam-outline",
|
||||
permission: "sys:settings:view",
|
||||
keepAlive: true,
|
||||
auth: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "certd.sysResources.suiteManager",
|
||||
name: "SuiteManager",
|
||||
|
||||
@@ -568,6 +568,7 @@ export default function ({ crudExpose, context: { selectedRowKeys, openCertApply
|
||||
{ value: "cert_upload", label: t("certd.types.certUpload") },
|
||||
{ value: "custom", label: t("certd.types.custom") },
|
||||
{ value: "template", label: t("certd.types.template") },
|
||||
{ value: "cert_auto", label: t("certd.types.certApply") },
|
||||
],
|
||||
}),
|
||||
form: {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/sys/monitor/site";
|
||||
|
||||
export const sysSiteMonitorApi = {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query,
|
||||
});
|
||||
},
|
||||
|
||||
async DelObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id },
|
||||
});
|
||||
},
|
||||
|
||||
async BatchDelObj(ids: number[]) {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchDelete",
|
||||
method: "post",
|
||||
data: { ids },
|
||||
});
|
||||
},
|
||||
|
||||
async GetSimpleUserByIds(ids: number[]) {
|
||||
return await request({
|
||||
url: "/sys/authority/user/getSimpleUserByIds",
|
||||
method: "post",
|
||||
data: { ids },
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,379 @@
|
||||
import createCrudOptionsUser from "/@/views/sys/authority/user/crud";
|
||||
import { CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import dayjs from "dayjs";
|
||||
import { ref } from "vue";
|
||||
import { sysSiteMonitorApi } from "./api";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const api = sysSiteMonitorApi;
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
const delRequest = async ({ row }: DelReq) => {
|
||||
return await api.DelObj(row.id);
|
||||
};
|
||||
|
||||
const selectedRowKeys = ref<number[]>([]);
|
||||
const handleBatchDelete = () => {
|
||||
if (!selectedRowKeys.value?.length) {
|
||||
message.error("请先选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: "确认",
|
||||
content: `确认删除选中的 ${selectedRowKeys.value.length} 条站点监控记录?`,
|
||||
async onOk() {
|
||||
await api.BatchDelObj(selectedRowKeys.value);
|
||||
message.success("删除成功");
|
||||
selectedRowKeys.value = [];
|
||||
await crudExpose.doRefresh();
|
||||
},
|
||||
});
|
||||
};
|
||||
context.handleBatchDelete = handleBatchDelete;
|
||||
|
||||
const checkStatusDict = dict({
|
||||
data: [
|
||||
{ label: "正常", value: "ok", color: "green" },
|
||||
{ label: "检查中", value: "checking", color: "blue" },
|
||||
{ label: "异常", value: "error", color: "red" },
|
||||
],
|
||||
});
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
pageRequest,
|
||||
delRequest,
|
||||
},
|
||||
actionbar: {
|
||||
show: false,
|
||||
},
|
||||
toolbar: {
|
||||
buttons: {
|
||||
export: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
export: {
|
||||
dataFrom: "search",
|
||||
},
|
||||
},
|
||||
pagination: {
|
||||
pageSizeOptions: ["10", "20", "50", "100", "200"],
|
||||
},
|
||||
settings: {
|
||||
plugins: {
|
||||
rowSelection: {
|
||||
enabled: true,
|
||||
props: {
|
||||
multiple: true,
|
||||
crossPage: false,
|
||||
selectedRowKeys: () => {
|
||||
return selectedRowKeys;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: "right",
|
||||
width: 100,
|
||||
buttons: {
|
||||
view: { show: false },
|
||||
copy: { show: false },
|
||||
edit: { show: false },
|
||||
remove: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
column: {
|
||||
width: 80,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
userId: {
|
||||
title: "用户",
|
||||
type: "table-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 4,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
async getNodesByValues(ids: number[]) {
|
||||
return await api.GetSimpleUserByIds(ids);
|
||||
},
|
||||
value: "id",
|
||||
label: "nickName",
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
component: {
|
||||
crossPage: true,
|
||||
multiple: false,
|
||||
select: {
|
||||
placeholder: "点击选择用户",
|
||||
},
|
||||
createCrudOptions: createCrudOptionsUser,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 150,
|
||||
},
|
||||
},
|
||||
projectId: {
|
||||
title: "项目ID",
|
||||
type: "number",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
name: {
|
||||
title: "站点名称",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 4,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 160,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
domain: {
|
||||
title: "域名",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 4,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 230,
|
||||
sorter: true,
|
||||
cellRender({ value, row }) {
|
||||
const domainPort = `${value}:${row.httpsPort || 443}`;
|
||||
return (
|
||||
<a-tooltip title={domainPort} placement="left">
|
||||
<fs-copyable modelValue={domainPort} title={domainPort}>
|
||||
<a target="_blank" href={`https://${domainPort}`}>
|
||||
{domainPort}
|
||||
</a>
|
||||
</fs-copyable>
|
||||
</a-tooltip>
|
||||
);
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
certDomains: {
|
||||
title: "证书域名",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 4,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 260,
|
||||
sorter: true,
|
||||
ellipsis: true,
|
||||
cellRender({ value }) {
|
||||
return <a-tooltip title={value}>{value}</a-tooltip>;
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
certProvider: {
|
||||
title: "颁发机构",
|
||||
type: "text",
|
||||
column: {
|
||||
width: 200,
|
||||
sorter: true,
|
||||
ellipsis: true,
|
||||
cellRender({ value }) {
|
||||
return <a-tooltip title={value}>{value}</a-tooltip>;
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
certStatus: {
|
||||
title: "证书状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "正常", value: "ok", color: "green" },
|
||||
{ label: "已过期", value: "expired", color: "red" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
width: 100,
|
||||
sorter: true,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
checkStatus: {
|
||||
title: "检查状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
dict: checkStatusDict,
|
||||
column: {
|
||||
width: 100,
|
||||
sorter: true,
|
||||
align: "center",
|
||||
cellRender({ value, row }) {
|
||||
return (
|
||||
<a-tooltip title={row.error}>
|
||||
<fs-values-format v-model={value} dict={checkStatusDict}></fs-values-format>
|
||||
</a-tooltip>
|
||||
);
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
certExpiresTime: {
|
||||
title: "证书到期时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 155,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
remainingValidity: {
|
||||
title: "剩余有效期",
|
||||
type: "date",
|
||||
column: {
|
||||
width: 120,
|
||||
conditionalRender: false,
|
||||
cellRender({ row }) {
|
||||
if (!row.certExpiresTime) {
|
||||
return "-";
|
||||
}
|
||||
const leftDays = dayjs(row.certExpiresTime).diff(dayjs(), "day");
|
||||
const color = leftDays < 15 ? "red" : "#389e0d";
|
||||
return <span style={{ color }}>{leftDays}天</span>;
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
lastCheckTime: {
|
||||
title: "上次检查时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 155,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "启用", value: false, color: "green" },
|
||||
{ label: "禁用", value: true, color: "red" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
width: 90,
|
||||
sorter: true,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
remark: {
|
||||
title: "备注",
|
||||
type: "textarea",
|
||||
column: {
|
||||
width: 200,
|
||||
sorter: true,
|
||||
ellipsis: true,
|
||||
cellRender({ value }) {
|
||||
return <a-tooltip title={value}>{value}</a-tooltip>;
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
width: 155,
|
||||
sorter: true,
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<fs-page>
|
||||
<template #header>
|
||||
<div class="title">用户证书监控管理</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<template #pagination-left>
|
||||
<a-tooltip title="批量删除">
|
||||
<fs-button icon="DeleteOutlined" @click="handleBatchDelete"></fs-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</fs-crud>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import { onActivated, onMounted } from "vue";
|
||||
import createCrudOptions from "./crud";
|
||||
|
||||
defineOptions({
|
||||
name: "SysSiteMonitorManager",
|
||||
});
|
||||
|
||||
const context: any = {};
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
|
||||
const handleBatchDelete = context.handleBatchDelete;
|
||||
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,37 @@
|
||||
import { request } from "/src/api/service";
|
||||
|
||||
const apiPrefix = "/sys/pipeline";
|
||||
|
||||
export const sysPipelineApi = {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query,
|
||||
});
|
||||
},
|
||||
|
||||
async DelObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id },
|
||||
});
|
||||
},
|
||||
|
||||
async BatchDelObj(ids: number[]) {
|
||||
return await request({
|
||||
url: apiPrefix + "/batchDelete",
|
||||
method: "post",
|
||||
data: { ids },
|
||||
});
|
||||
},
|
||||
|
||||
async GetSimpleUserByIds(ids: number[]) {
|
||||
return await request({
|
||||
url: "/sys/authority/user/getSimpleUserByIds",
|
||||
method: "post",
|
||||
data: { ids },
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,363 @@
|
||||
import createCrudOptionsUser from "/@/views/sys/authority/user/crud";
|
||||
import { CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { message, Modal } from "ant-design-vue";
|
||||
import dayjs from "dayjs";
|
||||
import { ref } from "vue";
|
||||
import { statusUtil } from "/@/views/certd/pipeline/pipeline/utils/util.status";
|
||||
import { sysPipelineApi } from "./api";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const api = sysPipelineApi;
|
||||
const settingStore = useSettingStore();
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
const delRequest = async ({ row }: DelReq) => {
|
||||
return await api.DelObj(row.id);
|
||||
};
|
||||
|
||||
const selectedRowKeys = ref<number[]>([]);
|
||||
const handleBatchDelete = () => {
|
||||
if (!selectedRowKeys.value?.length) {
|
||||
message.error("请先选择要删除的记录");
|
||||
return;
|
||||
}
|
||||
settingStore.checkPlus();
|
||||
Modal.confirm({
|
||||
title: "确认",
|
||||
content: `确认删除选中的 ${selectedRowKeys.value.length} 条用户流水线?删除后会清理对应执行历史、日志和证书仓库记录。`,
|
||||
async onOk() {
|
||||
await api.BatchDelObj(selectedRowKeys.value);
|
||||
message.success("删除成功");
|
||||
selectedRowKeys.value = [];
|
||||
await crudExpose.doRefresh();
|
||||
},
|
||||
});
|
||||
};
|
||||
context.handleBatchDelete = handleBatchDelete;
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
pageRequest,
|
||||
delRequest,
|
||||
},
|
||||
actionbar: {
|
||||
show: false,
|
||||
},
|
||||
toolbar: {
|
||||
buttons: {
|
||||
export: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
export: {
|
||||
dataFrom: "search",
|
||||
},
|
||||
},
|
||||
pagination: {
|
||||
pageSizeOptions: ["10", "20", "50", "100", "200"],
|
||||
},
|
||||
settings: {
|
||||
plugins: {
|
||||
rowSelection: {
|
||||
enabled: true,
|
||||
props: {
|
||||
multiple: true,
|
||||
crossPage: false,
|
||||
selectedRowKeys: () => {
|
||||
return selectedRowKeys;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: "right",
|
||||
width: 100,
|
||||
buttons: {
|
||||
view: { show: false },
|
||||
copy: { show: false },
|
||||
edit: { show: false },
|
||||
remove: {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
columns: {
|
||||
id: {
|
||||
title: "ID",
|
||||
key: "id",
|
||||
type: "number",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 2,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 90,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
userId: {
|
||||
title: "用户",
|
||||
type: "table-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 4,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
async getNodesByValues(ids: number[]) {
|
||||
return await api.GetSimpleUserByIds(ids);
|
||||
},
|
||||
value: "id",
|
||||
label: "nickName",
|
||||
}),
|
||||
form: {
|
||||
show: false,
|
||||
component: {
|
||||
crossPage: true,
|
||||
multiple: false,
|
||||
select: {
|
||||
placeholder: "点击选择用户",
|
||||
},
|
||||
createCrudOptions: createCrudOptionsUser,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 150,
|
||||
},
|
||||
},
|
||||
projectId: {
|
||||
title: "项目ID",
|
||||
type: "number",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 100,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
title: {
|
||||
title: "流水线名称",
|
||||
type: "text",
|
||||
search: {
|
||||
show: true,
|
||||
title: "关键词",
|
||||
component: {
|
||||
name: "a-input",
|
||||
},
|
||||
col: {
|
||||
span: 4,
|
||||
},
|
||||
},
|
||||
column: {
|
||||
width: 320,
|
||||
sorter: true,
|
||||
ellipsis: true,
|
||||
showTitle: true,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
type: {
|
||||
title: "类型",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ value: "cert", label: "证书申请" },
|
||||
{ value: "cert_upload", label: "证书上传" },
|
||||
{ value: "custom", label: "自定义" },
|
||||
{ value: "template", label: "模板" },
|
||||
{ value: "cert_auto", label: "证书申请" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
width: 110,
|
||||
align: "center",
|
||||
sorter: true,
|
||||
component: {
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
status: {
|
||||
title: "运行状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
data: statusUtil.getOptions(),
|
||||
}),
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 120,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
title: "状态",
|
||||
type: "dict-select",
|
||||
search: {
|
||||
show: true,
|
||||
col: {
|
||||
span: 3,
|
||||
},
|
||||
},
|
||||
dict: dict({
|
||||
data: [
|
||||
{ label: "启用", value: false, color: "green" },
|
||||
{ label: "禁用", value: true, color: "red" },
|
||||
],
|
||||
}),
|
||||
column: {
|
||||
width: 90,
|
||||
sorter: true,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
stepCount: {
|
||||
title: "部署任务数",
|
||||
type: "number",
|
||||
column: {
|
||||
align: "center",
|
||||
width: 110,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
triggerCount: {
|
||||
title: "定时任务数",
|
||||
type: "number",
|
||||
column: {
|
||||
align: "center",
|
||||
width: 110,
|
||||
sorter: true,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
lastHistoryTime: {
|
||||
title: "最后执行时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 155,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
nextRunTime: {
|
||||
title: "下次执行时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 155,
|
||||
align: "center",
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
validTime: {
|
||||
title: "有效期",
|
||||
type: "date",
|
||||
column: {
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: "center",
|
||||
cellRender({ value }) {
|
||||
if (!value || value <= 0) {
|
||||
return "-";
|
||||
}
|
||||
if (value < Date.now()) {
|
||||
return <span style={{ color: "red" }}>已过期</span>;
|
||||
}
|
||||
return dayjs(value).format("YYYY-MM-DD");
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
remark: {
|
||||
title: "备注",
|
||||
type: "textarea",
|
||||
column: {
|
||||
width: 200,
|
||||
sorter: true,
|
||||
ellipsis: true,
|
||||
cellRender({ value }) {
|
||||
return <a-tooltip title={value}>{value}</a-tooltip>;
|
||||
},
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
createTime: {
|
||||
title: "创建时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
width: 155,
|
||||
sorter: true,
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
updateTime: {
|
||||
title: "更新时间",
|
||||
type: "datetime",
|
||||
column: {
|
||||
width: 155,
|
||||
sorter: true,
|
||||
show: false,
|
||||
},
|
||||
form: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<fs-page>
|
||||
<template #header>
|
||||
<div class="title flex items-center">用户流水线管理</div>
|
||||
</template>
|
||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||
<template #pagination-left>
|
||||
<a-tooltip title="批量删除">
|
||||
<fs-button icon="DeleteOutlined" class="need-plus" @click="handleBatchDelete"></fs-button>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
</fs-crud>
|
||||
</fs-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import { onActivated, onMounted } from "vue";
|
||||
import createCrudOptions from "./crud";
|
||||
|
||||
defineOptions({
|
||||
name: "SysPipelineManager",
|
||||
});
|
||||
|
||||
const context: any = {};
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context });
|
||||
const handleBatchDelete = context.handleBatchDelete;
|
||||
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
});
|
||||
</script>
|
||||
@@ -134,6 +134,5 @@ export class MainConfiguration {
|
||||
});
|
||||
|
||||
logger.info("当前环境:", this.app.getEnv()); // prod
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import { CrudController } from "@certd/lib-server";
|
||||
import { SiteInfoService } from "../../../modules/monitor/service/site-info-service.js";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
|
||||
@Provide()
|
||||
@Controller("/api/sys/monitor/site")
|
||||
@ApiTags(["sys-monitor"])
|
||||
export class SysSiteInfoController extends CrudController<SiteInfoService> {
|
||||
@Inject()
|
||||
service: SiteInfoService;
|
||||
|
||||
getService(): SiteInfoService {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post("/page", { description: "sys:settings:view", summary: "管理员查询站点监控分页列表" })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
const certDomains = body.query.certDomains;
|
||||
const domain = body.query.domain;
|
||||
const name = body.query.name;
|
||||
delete body.query.certDomains;
|
||||
delete body.query.domain;
|
||||
delete body.query.name;
|
||||
const res = await this.service.page({
|
||||
query: body.query,
|
||||
page: body.page,
|
||||
sort: body.sort,
|
||||
buildQuery: bq => {
|
||||
if (domain) {
|
||||
bq.andWhere("domain like :domain", { domain: `%${domain}%` });
|
||||
}
|
||||
if (certDomains) {
|
||||
bq.andWhere("cert_domains like :cert_domains", { cert_domains: `%${certDomains}%` });
|
||||
}
|
||||
if (name) {
|
||||
bq.andWhere("name like :name", { name: `%${name}%` });
|
||||
}
|
||||
},
|
||||
});
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post("/delete", { description: "sys:settings:edit", summary: "管理员删除站点监控" })
|
||||
async delete(@Query("id") id: number) {
|
||||
return await super.delete(id);
|
||||
}
|
||||
|
||||
@Post("/batchDelete", { description: "sys:settings:edit", summary: "管理员批量删除站点监控" })
|
||||
async batchDelete(@Body("ids") ids: number[]) {
|
||||
await this.service.delete(ids);
|
||||
return this.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { ALL, Body, Controller, Inject, Post, Provide, Query } from "@midwayjs/core";
|
||||
import { CrudController } from "@certd/lib-server";
|
||||
import { ApiTags } from "@midwayjs/swagger";
|
||||
import { PipelineService } from "../../../modules/pipeline/service/pipeline-service.js";
|
||||
import { checkPlus } from "@certd/plus-core";
|
||||
|
||||
@Provide()
|
||||
@Controller("/api/sys/pipeline")
|
||||
@ApiTags(["sys-pipeline"])
|
||||
export class SysPipelineController extends CrudController<PipelineService> {
|
||||
@Inject()
|
||||
service: PipelineService;
|
||||
|
||||
getService(): PipelineService {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Post("/page", { description: "sys:settings:view", summary: "管理员查询用户流水线分页列表" })
|
||||
async page(@Body(ALL) body: any) {
|
||||
body.query = body.query ?? {};
|
||||
const title = body.query.title;
|
||||
delete body.query.title;
|
||||
|
||||
if (!body.sort || !body.sort?.prop) {
|
||||
body.sort = { prop: "order", asc: false };
|
||||
}
|
||||
|
||||
const res = await this.service.page({
|
||||
query: body.query,
|
||||
page: body.page,
|
||||
sort: body.sort,
|
||||
buildQuery: bq => {
|
||||
if (title) {
|
||||
bq.andWhere("(title like :title or content like :content)", { title: `%${title}%`, content: `%${title}%` });
|
||||
}
|
||||
},
|
||||
});
|
||||
return this.ok(res);
|
||||
}
|
||||
|
||||
@Post("/delete", { description: "sys:settings:edit", summary: "管理员删除用户流水线" })
|
||||
async delete(@Query("id") id: number) {
|
||||
await this.service.delete(id);
|
||||
return this.ok();
|
||||
}
|
||||
|
||||
@Post("/batchDelete", { description: "sys:settings:edit", summary: "管理员批量删除用户流水线" })
|
||||
async batchDelete(@Body("ids") ids: number[]) {
|
||||
checkPlus();
|
||||
await this.service.batchDelete(ids);
|
||||
return this.ok();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BaseService, ValidateException } from "@certd/lib-server";
|
||||
import { Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||
import { BaseService, ValidateException } from "@certd/lib-server";
|
||||
import { IsNull, Repository } from "typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { CertApplyTemplateEntity } from "../entity/cert-apply-template.js";
|
||||
import { CertApplyTemplateParams, pickCertApplyCustomParams, pickCertApplyTemplateParams } from "./cert-apply-template-fields.js";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user