From 472f06c2d190d0ae48e8b53c18bc278437656a1c Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Wed, 25 Dec 2024 23:20:07 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E7=94=A8=E6=88=B7=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=AF=81=E4=B9=A6=E6=B5=81=E6=B0=B4=E7=BA=BF=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E8=B4=AD=E4=B9=B0=E5=A5=97=E9=A4=90=E6=88=96=E8=80=85=E8=B6=85?= =?UTF-8?q?=E9=99=90=E6=97=B6=E6=8F=90=E5=89=8D=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/run/docker-compose.yaml | 2 + .../core/pipeline/src/core/run-history.ts | 4 ++ .../src/views/certd/monitor/site/crud.tsx | 37 +++++++++++++++++++ .../src/views/certd/pipeline/crud.tsx | 19 +++++++++- .../src/views/certd/suite/mine/api.ts | 2 +- .../src/views/certd/suite/mine/crud.tsx | 3 +- .../src/views/certd/suite/mine/index.vue | 4 +- .../framework/home/dashboard/suite-card.vue | 4 +- .../src/views/framework/register/index.vue | 5 +++ .../src/views/sys/suite/setting/index.vue | 2 +- .../src/views/sys/suite/user-suite/crud.tsx | 20 +++++++--- .../src/middleware/global-exception.ts | 10 ++--- .../plugins/plugin-notification/qywx/index.ts | 20 ++++++++-- 13 files changed, 108 insertions(+), 24 deletions(-) diff --git a/docker/run/docker-compose.yaml b/docker/run/docker-compose.yaml index e9ce4db9..436b158f 100644 --- a/docker/run/docker-compose.yaml +++ b/docker/run/docker-compose.yaml @@ -34,6 +34,8 @@ services: # #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false - certd_system_resetAdminPasswd=false # 默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量 +# 注意: 选定使用一种数据库之后,不支持更换数据库。 +# 数据库迁移方法:1、使用新数据库重新部署一套,然后将旧数据同步过去,注意flyway_history表的数据不要同步 # #↓↓↓↓ ----------------------------- 使用postgresql数据库,需要提前创建数据库 # - certd_flyway_scriptDir=./db/migration-pg # 升级脚本目录 # - certd_typeorm_dataSource_default_type=postgres # 数据库类型 diff --git a/packages/core/pipeline/src/core/run-history.ts b/packages/core/pipeline/src/core/run-history.ts index aa48ac3b..9c472ee6 100644 --- a/packages/core/pipeline/src/core/run-history.ts +++ b/packages/core/pipeline/src/core/run-history.ts @@ -146,6 +146,10 @@ export class RunnableCollection { static initPipelineRunnableType(pipeline: Pipeline) { pipeline.runnableType = "pipeline"; + if (pipeline.stages === undefined) { + pipeline.stages = []; + return; + } pipeline.stages.forEach((stage) => { stage.runnableType = "stage"; stage.tasks.forEach((task) => { 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 c29aec9d..2f795af7 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 @@ -4,10 +4,13 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi import { siteInfoApi } from "./api"; import dayjs from "dayjs"; import { notification } from "ant-design-vue"; +import { useSettingStore } from "/@/store/modules/settings"; +import { mySuiteApi } from "/@/views/certd/suite/mine/api"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { const { t } = useI18n(); const api = siteInfoApi; + const { crudBinding } = crudExpose; const pageRequest = async (query: UserPageQuery): Promise => { return await api.GetList(query); }; @@ -28,6 +31,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat return res; }; + const settingsStore = useSettingStore(); + return { crudOptions: { request: { @@ -51,6 +56,37 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat width: 600 } }, + actionbar: { + buttons: { + add: { + async click() { + if (!settingsStore.isPlus) { + //非plus + if (crudBinding.value.data.length >= 1) { + notification.error({ + message: "基础版只能添加一个监控站点" + }); + return; + } + } + + //检查是否监控站点数量超出限制 + if (settingsStore.isComm && settingsStore.suiteSetting.enabled) { + //检查数量是否超限 + const suiteDetail = await mySuiteApi.SuiteDetailGet(); + const max = suiteDetail.monitorCount.max; + if (max != -1 && max <= suiteDetail.monitorCount.used) { + notification.error({ + message: `对不起,您最多只能创建条${max}监控记录,请购买或升级套餐` + }); + return; + } + } + await crudExpose.openAdd({}); + } + } + } + }, rowHandle: { fixed: "right", width: 240, @@ -111,6 +147,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat form: { rules: [ { required: true, message: "请输入域名" }, + //@ts-ignore { type: "domains", message: "请输入正确的域名" } ] }, diff --git a/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx b/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx index 27beb506..953a8150 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/pipeline/crud.tsx @@ -15,6 +15,7 @@ import { useModal } from "/@/use/use-modal"; import CertView from "./cert-view.vue"; import { eachStages } from "./utils"; import { createNotificationApi as createNotificationApi } from "../notification/api"; +import { mySuiteApi } from "/@/views/certd/suite/mine/api"; export default function ({ crudExpose, context: { certdFormRef, groupDictRef, selectedRowKeys } }: CreateCrudOptionsProps): CreateCrudOptionsRet { const router = useRouter(); const { t } = useI18n(); @@ -94,7 +95,23 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se lastResRef.value = res; return res; }; - function addCertdPipeline() { + + const settingsStore = useSettingStore(); + async function addCertdPipeline() { + //检查是否流水线数量超出限制 + if (settingsStore.isComm && settingsStore.suiteSetting.enabled) { + //检查数量是否超限 + + const suiteDetail = await mySuiteApi.SuiteDetailGet(); + const max = suiteDetail.pipelineCount.max; + if (max != -1 && max <= suiteDetail.pipelineCount.used) { + notification.error({ + message: `对不起,您最多只能创建${max}条流水线,请购买或升级套餐` + }); + return; + } + } + certdFormRef.value.open(async ({ form }: any) => { // 添加certd pipeline const triggers = []; diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/api.ts b/packages/ui/certd-client/src/views/certd/suite/mine/api.ts index 16afd46a..d890d2ad 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/api.ts +++ b/packages/ui/certd-client/src/views/certd/suite/mine/api.ts @@ -16,7 +16,7 @@ export type SuiteDetail = { monitorCount?: SuiteValue; }; -export default { +export const mySuiteApi = { async GetList(query: any) { return await request({ url: apiPrefix + "/page", diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/crud.tsx b/packages/ui/certd-client/src/views/certd/suite/mine/crud.tsx index 8f4cb242..06efebe5 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/crud.tsx +++ b/packages/ui/certd-client/src/views/certd/suite/mine/crud.tsx @@ -1,10 +1,9 @@ import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -import api from "./api"; +import { mySuiteApi as api } from "./api"; import { useRouter } from "vue-router"; import SuiteValueEdit from "/@/views/sys/suite/product/suite-value-edit.vue"; import SuiteValue from "/@/views/sys/suite/product/suite-value.vue"; import DurationValue from "/@/views/sys/suite/product/duration-value.vue"; -import dayjs from "dayjs"; import UserSuiteStatus from "/@/views/certd/suite/mine/user-suite-status.vue"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { diff --git a/packages/ui/certd-client/src/views/certd/suite/mine/index.vue b/packages/ui/certd-client/src/views/certd/suite/mine/index.vue index 0a36aa01..d9b86129 100644 --- a/packages/ui/certd-client/src/views/certd/suite/mine/index.vue +++ b/packages/ui/certd-client/src/views/certd/suite/mine/index.vue @@ -18,7 +18,7 @@ import { computed, onActivated, onMounted, ref } from "vue"; import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; -import api, { SuiteDetail } from "/@/views/certd/suite/mine/api"; +import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api"; import SuiteCard from "/@/views/framework/home/dashboard/suite-card.vue"; defineOptions({ @@ -35,7 +35,7 @@ const currentSuite = computed(() => { const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { detail, currentSuite } }); async function loadSuiteDetail() { - detail.value = await api.SuiteDetailGet(); + detail.value = await mySuiteApi.SuiteDetailGet(); } // 页面打开后获取列表数据 diff --git a/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue b/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue index e6f62472..8c00fd25 100644 --- a/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue +++ b/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue @@ -49,7 +49,7 @@ import SuiteValue from "/@/views/sys/suite/product/suite-value.vue"; import { ref } from "vue"; import ExpiresTimeText from "/@/components/expires-time-text.vue"; -import api, { SuiteDetail } from "/@/views/certd/suite/mine/api"; +import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api"; import { FsIcon } from "@fast-crud/fast-crud"; import { useRouter } from "vue-router"; @@ -60,7 +60,7 @@ defineOptions({ const detail = ref({}); async function loadSuiteDetail() { - detail.value = await api.SuiteDetailGet(); + detail.value = await mySuiteApi.SuiteDetailGet(); } loadSuiteDetail(); diff --git a/packages/ui/certd-client/src/views/framework/register/index.vue b/packages/ui/certd-client/src/views/framework/register/index.vue index 2c983185..55ada601 100644 --- a/packages/ui/certd-client/src/views/framework/register/index.vue +++ b/packages/ui/certd-client/src/views/framework/register/index.vue @@ -166,6 +166,11 @@ export default defineComponent({ { required: true, message: "请输入图片验证码" + }, + { + min: 4, + max: 4, + message: "请输入4位图片验证码" } ], smsCode: [ diff --git a/packages/ui/certd-client/src/views/sys/suite/setting/index.vue b/packages/ui/certd-client/src/views/sys/suite/setting/index.vue index d193724d..cdfda989 100644 --- a/packages/ui/certd-client/src/views/sys/suite/setting/index.vue +++ b/packages/ui/certd-client/src/views/sys/suite/setting/index.vue @@ -17,7 +17,7 @@
-
不建议设置免费套餐,可以在下方配置注册赠送套餐
+
不建议设置免费套餐,可以在下方配置注册赠送套餐,或者在用户套餐管理中手动赠送套餐
diff --git a/packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx b/packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx index 55fe5a4c..62333995 100644 --- a/packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx +++ b/packages/ui/certd-client/src/views/sys/suite/user-suite/crud.tsx @@ -139,17 +139,27 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat type: "dict-select", column: { show: false }, addForm: { + show: true, component: { name: SuiteDurationSelector, vModel: "modelValue" }, - rules: [{ required: true, message: "请选择套餐" }] + rules: [ + { + validator: async (rule, value) => { + if (value && value.productId) { + return true; + } + throw new Error("请选择套餐"); + } + } + ] }, valueResolve({ form, value }) { - if (value) { - const arr = value.splict("_"); - form.productId = parseInt(arr[0]); - form.duration = parseInt(arr[1]); + debugger; + if (value && value.productId) { + form.productId = value.productId; + form.duration = value.duration; } }, form: { show: false } diff --git a/packages/ui/certd-server/src/middleware/global-exception.ts b/packages/ui/certd-server/src/middleware/global-exception.ts index 5a6ec009..7e8b684a 100644 --- a/packages/ui/certd-server/src/middleware/global-exception.ts +++ b/packages/ui/certd-server/src/middleware/global-exception.ts @@ -1,7 +1,7 @@ import { Provide } from '@midwayjs/core'; -import { IWebMiddleware, IMidwayKoaContext, NextFunction } from '@midwayjs/koa'; +import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa'; import { logger } from '@certd/basic'; -import { BaseException, Result } from '@certd/lib-server'; +import { Result } from '@certd/lib-server'; @Provide() export class GlobalExceptionMiddleware implements IWebMiddleware { @@ -14,11 +14,7 @@ export class GlobalExceptionMiddleware implements IWebMiddleware { await next(); logger.info('请求完成:', url, Date.now() - startTime + 'ms'); } catch (err) { - logger.error('请求异常:', url, Date.now() - startTime + 'ms', err.message); - if (!(err instanceof BaseException)) { - logger.error(err); - } - + logger.error('请求异常:', url, Date.now() - startTime + 'ms', err); ctx.status = 200; if (err.code == null || typeof err.code !== 'number') { err.code = 1; diff --git a/packages/ui/certd-server/src/plugins/plugin-notification/qywx/index.ts b/packages/ui/certd-server/src/plugins/plugin-notification/qywx/index.ts index abb22415..b67ff03d 100644 --- a/packages/ui/certd-server/src/plugins/plugin-notification/qywx/index.ts +++ b/packages/ui/certd-server/src/plugins/plugin-notification/qywx/index.ts @@ -30,6 +30,19 @@ export class QywxNotification extends BaseNotification { }) mentionedList!: string[]; + @NotificationInput({ + title: '提醒指定手机号成员', + component: { + name: 'a-select', + vModel: 'value', + mode: 'tags', + open: false, + }, + required: false, + helper: '填写成员手机号,@all 为提醒所有人', + }) + mentionedMobileList!: string[]; + async send(body: NotificationBody) { if (!this.webhook) { throw new Error('webhook地址不能为空'); @@ -47,10 +60,11 @@ export class QywxNotification extends BaseNotification { url: this.webhook, method: 'POST', data: { - msgtype: 'markdown', - markdown: { - content: `# ${body.title}\n\n${body.content}\n\n[查看详情](${body.url})`, + msgtype: 'text', + text: { + content: `· ${body.title}\n· ${body.content}\n· 查看详情: ${body.url}`, mentioned_list: this.mentionedList, + mentioned_mobile_list: this.mentionedMobileList, }, }, });