diff --git a/packages/core/basic/src/utils/util.env.ts b/packages/core/basic/src/utils/util.env.ts index f92f5fc9..4454fff7 100644 --- a/packages/core/basic/src/utils/util.env.ts +++ b/packages/core/basic/src/utils/util.env.ts @@ -1,4 +1,4 @@ export function isDev() { const nodeEnv = process.env.NODE_ENV || ''; - return nodeEnv === 'development' || nodeEnv.indexOf('local') >= 0 || nodeEnv.includes('dev'); + return nodeEnv === 'development' || nodeEnv.includes('local') || nodeEnv.startsWith('dev'); } diff --git a/packages/libs/lib-server/src/basic/base-service.ts b/packages/libs/lib-server/src/basic/base-service.ts index 20c3a88c..01e749c5 100644 --- a/packages/libs/lib-server/src/basic/base-service.ts +++ b/packages/libs/lib-server/src/basic/base-service.ts @@ -3,6 +3,7 @@ import { In, Repository, SelectQueryBuilder } from 'typeorm'; import { Inject } from '@midwayjs/core'; import { TypeORMDataSourceManager } from '@midwayjs/typeorm'; import { EntityManager } from 'typeorm/entity-manager/EntityManager.js'; +import { FindManyOptions } from 'typeorm'; export type PageReq = { page?: { offset: number; limit: number }; @@ -15,6 +16,7 @@ export type ListReq = { asc: boolean; }; buildQuery?: (bq: SelectQueryBuilder) => void; + select?: any; }; /** @@ -53,7 +55,7 @@ export abstract class BaseService { * 非分页查询 * @param options */ - async find(options) { + async find(options: FindManyOptions) { return await this.getRepository().find(options); } diff --git a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts index 4128830d..6807028c 100644 --- a/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts +++ b/packages/plugins/plugin-cert/src/plugin/cert-plugin/cert-reader.ts @@ -84,6 +84,10 @@ export class CertReader { } getCrtDetail(crt: string = this.cert.crt) { + return CertReader.readCertDetail(crt); + } + + static readCertDetail(crt: string) { const detail = crypto.readCertificateInfo(crt.toString()); const expires = detail.notAfter; return { detail, expires }; diff --git a/packages/ui/certd-client/src/router/source/modules/certd.ts b/packages/ui/certd-client/src/router/source/modules/certd.ts index 38a6a4b2..6e7dee96 100644 --- a/packages/ui/certd-client/src/router/source/modules/certd.ts +++ b/packages/ui/certd-client/src/router/source/modules/certd.ts @@ -41,7 +41,7 @@ export const certdResources = [ } }, { - title: "证书监控", + title: "站点证书监控", name: "SiteCertMonitor", path: "/certd/monitor/site", component: "/certd/monitor/site/index.vue", diff --git a/packages/ui/certd-client/src/router/source/modules/sys.ts b/packages/ui/certd-client/src/router/source/modules/sys.ts index a04fe25b..010ae6ad 100644 --- a/packages/ui/certd-client/src/router/source/modules/sys.ts +++ b/packages/ui/certd-client/src/router/source/modules/sys.ts @@ -170,33 +170,63 @@ export const sysResources = [ permission: "sys:auth:user:view" } }, + { - title: "套餐设置", - name: "SuiteSetting", - path: "/sys/suite/setting", - component: "/sys/suite/setting/index.vue", + title: "套餐管理", + name: "SuiteManager", + path: "/sys/suite", meta: { + icon: "ion:cart-outline", + permission: "sys:settings:edit", show: () => { const settingStore = useSettingStore(); return settingStore.isComm; + } + }, + children: [ + { + title: "套餐设置", + name: "SuiteSetting", + path: "/sys/suite/setting", + component: "/sys/suite/setting/index.vue", + meta: { + show: () => { + const settingStore = useSettingStore(); + return settingStore.isComm; + }, + icon: "ion:cart", + permission: "sys:settings:edit" + } }, - icon: "ion:cart", - permission: "sys:settings:edit" - } - }, - { - title: "订单管理", - name: "OrderManager", - path: "/sys/suite/trade", - component: "/sys/suite/trade/index.vue", - meta: { - show: () => { - const settingStore = useSettingStore(); - return settingStore.isComm; + { + title: "订单管理", + name: "OrderManager", + path: "/sys/suite/trade", + component: "/sys/suite/trade/index.vue", + meta: { + show: () => { + const settingStore = useSettingStore(); + return settingStore.isComm; + }, + icon: "ion:bag-check", + permission: "sys:settings:edit" + } }, - icon: "ion:bag-check", - permission: "sys:settings:edit" - } + { + title: "用户套餐", + name: "UserSuites", + path: "/sys/suite/user-suite", + component: "/certd/suite/user-suite/index.vue", + meta: { + show: () => { + const settingStore = useSettingStore(); + return settingStore.isComm; + }, + icon: "ion:gift-outline", + auth: true + } + } + ] } ] } diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/api.ts b/packages/ui/certd-client/src/views/certd/monitor/site/api.ts index 35b71fd5..d8ae199e 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/api.ts +++ b/packages/ui/certd-client/src/views/certd/monitor/site/api.ts @@ -1,54 +1,58 @@ import { request } from "/src/api/service"; -export function createApi() { - const apiPrefix = "/monitor/site"; - return { - async GetList(query: any) { - return await request({ - url: apiPrefix + "/page", - method: "post", - data: query - }); - }, +const apiPrefix = "/monitor/site"; - async AddObj(obj: any) { - return await request({ - url: apiPrefix + "/add", - method: "post", - data: obj - }); - }, +export const siteInfoApi = { + async GetList(query: any) { + return await request({ + url: apiPrefix + "/page", + method: "post", + data: query + }); + }, - async UpdateObj(obj: any) { - return await request({ - url: apiPrefix + "/update", - method: "post", - data: obj - }); - }, + async AddObj(obj: any) { + return await request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); + }, - async DelObj(id: number) { - return await request({ - url: apiPrefix + "/delete", - method: "post", - params: { id } - }); - }, + async UpdateObj(obj: any) { + return await request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); + }, - async GetObj(id: number) { - return await request({ - url: apiPrefix + "/info", - method: "post", - params: { id } - }); - }, - async ListAll() { - return await request({ - url: apiPrefix + "/all", - method: "post" - }); - } - }; -} + async DelObj(id: number) { + return await request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); + }, -export const pipelineGroupApi = createApi(); + async GetObj(id: number) { + return await request({ + url: apiPrefix + "/info", + method: "post", + params: { id } + }); + }, + async DoCheck(id: number) { + return await request({ + url: apiPrefix + "/check", + method: "post", + data: { id } + }); + }, + async CheckAll() { + return await request({ + url: apiPrefix + "/checkAll", + method: "post" + }); + } +}; diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx index 3d80dffa..a3df8c23 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx @@ -1,12 +1,13 @@ // @ts-ignore import { useI18n } from "vue-i18n"; -import { ref } from "vue"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -import { pipelineGroupApi } from "./api"; +import { siteInfoApi } from "./api"; +import dayjs from "dayjs"; +import { notification } from "ant-design-vue"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { const { t } = useI18n(); - const api = pipelineGroupApi; + const api = siteInfoApi; const pageRequest = async (query: UserPageQuery): Promise => { return await api.GetList(query); }; @@ -51,7 +52,24 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } }, rowHandle: { - width: 200 + fixed: "right", + width: 240, + buttons: { + check: { + order: 0, + type: "link", + text: null, + title: "立即检查", + icon: "ion:play-sharp", + click: async ({ row }) => { + await api.DoCheck(row.id); + await crudExpose.doRefresh(); + notification.success({ + message: "检查完成" + }); + } + } + } }, columns: { id: { @@ -62,44 +80,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat show: false }, column: { - width: 100, - editable: { - disabled: true - } + width: 80, + align: "center" }, form: { show: false } }, - - domain: { - title: "网站域名", - search: { - show: true - }, - type: "text", - form: { - rules: [{ required: true, message: "请输入域名" }] - }, - column: { - width: 200, - sorter: true - } - }, - port: { - title: "HTTPS端口", - search: { - show: false - }, - type: "number", - form: { - value: 443, - rules: [{ required: true, message: "请输入端口" }] - }, - column: { - width: 100 - } - }, name: { title: "站点名称", search: { @@ -110,11 +97,40 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat rules: [{ required: true, message: "请输入站点名称" }] }, column: { - width: 200 + width: 160 } }, - domains: { - title: "其他域名", + domain: { + title: "网站域名", + search: { + show: true + }, + type: "text", + form: { + rules: [{ required: true, message: "请输入域名" }] + }, + column: { + width: 160, + sorter: true + } + }, + httpsPort: { + title: "HTTPS端口", + search: { + show: false + }, + type: "number", + form: { + value: 443, + rules: [{ required: true, message: "请输入端口" }] + }, + column: { + align: "center", + width: 100 + } + }, + certDomains: { + title: "证书域名", search: { show: false }, @@ -123,13 +139,13 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat show: false }, column: { - width: 300, + width: 200, sorter: true, - show: false + show: true } }, - certInfo: { - title: "证书详情", + certProvider: { + title: "证书颁发者", search: { show: false }, @@ -138,8 +154,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat show: false }, column: { - width: 100, - show: false + width: 200, + sorter: true } }, certStatus: { @@ -147,13 +163,20 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat search: { show: true }, - type: "text", + type: "dict-select", + dict: dict({ + data: [ + { label: "正常", value: "ok", color: "green" }, + { label: "过期", value: "expired", color: "red" } + ] + }), form: { show: false }, column: { width: 100, - sorter: true + sorter: true, + show: false } }, certExpiresTime: { @@ -166,7 +189,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat show: false }, column: { - sorter: true + sorter: true, + cellRender({ value }) { + if (!value) { + return "-"; + } + const expireDate = dayjs(value).format("YYYY-MM-DD"); + const leftDays = dayjs(value).diff(dayjs(), "day"); + const color = leftDays < 20 ? "red" : "#389e0d"; + const percent = (leftDays / 90) * 100; + return `${leftDays}天`} />; + } } }, lastCheckTime: { @@ -187,12 +220,33 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat search: { show: false }, - type: "text", + type: "dict-select", + dict: dict({ + data: [ + { label: "正常", value: "ok", color: "green" }, + { label: "异常", value: "error", color: "red" } + ] + }), form: { show: false }, column: { width: 100, + align: "center", + sorter: true + } + }, + error: { + title: "错误信息", + search: { + show: false + }, + type: "text", + form: { + show: false + }, + column: { + width: 200, sorter: true } }, @@ -205,7 +259,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat type: "number", column: { width: 200, - sorter: true + sorter: true, + show: false } }, certInfoId: { @@ -234,7 +289,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat ] }), form: { - value: true + value: false }, column: { width: 100, diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/index.vue b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue index cd6c353d..6798af7d 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue @@ -3,7 +3,10 @@ @@ -11,15 +14,30 @@