From a019956698acaf2c4beb620b5ad8c18918ead6a1 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 22 Dec 2024 14:00:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=A8=E6=88=B7=E5=A5=97=E9=A4=90?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E6=88=B7=E6=94=AF=E4=BB=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 13 +- packages/core/basic/package.json | 1 + packages/core/basic/src/utils/index.ts | 5 + packages/core/basic/src/utils/util.hash.ts | 5 +- packages/core/basic/src/utils/util.lock.ts | 51 ++++ packages/core/basic/src/utils/util.mitter.ts | 2 + .../libs/lib-server/src/basic/base-service.ts | 6 +- .../libs/lib-server/src/basic/constants.ts | 4 + .../src/basic/exception/vip-exception.ts | 6 + packages/libs/lib-server/src/index.ts | 4 +- .../src/system/settings/service/models.ts | 32 +++ .../src/user/access}/entity/access.ts | 0 .../libs/lib-server/src/user/access/index.ts | 5 + .../src/user/access}/service/access-getter.ts | 0 .../user/access}/service/access-service.ts | 3 +- .../user/access}/service/access-sys-getter.ts | 0 .../user/access}/service/encrypt-service.ts | 3 +- packages/libs/lib-server/src/user/index.ts | 1 + .../src/components/expires-time-text.vue | 33 +++ .../ui/certd-client/src/components/index.ts | 3 +- .../src/components/vip-button/index.vue | 4 +- .../src/router/source/modules/certd.ts | 43 +++- .../src/router/source/modules/sys.ts | 56 ++--- .../payment => certd/monitor/cert}/api.ts | 34 +-- .../src/views/certd/monitor/cert/crud.tsx | 178 ++++++++++++++ .../src/views/certd/monitor/cert/index.vue | 30 +++ .../src/views/certd/monitor/site/api.ts | 54 +++++ .../src/views/certd/monitor/site/crud.tsx | 228 ++++++++++++++++++ .../src/views/certd/monitor/site/index.vue | 30 +++ .../src/views/certd/payment/api.ts | 11 + .../src/views/certd/payment/return.vue | 50 ++++ .../src/views/certd/pipeline/group/index.vue | 2 +- .../certd-client/src/views/certd/suite/api.ts | 14 ++ .../src/views/certd/suite/buy.vue | 22 +- .../src/views/certd/suite/card.vue | 3 - .../src/views/certd/suite/order-modal.vue | 31 ++- .../src/views/certd/suite/product-info.vue | 50 +++- .../certd-client/src/views/certd/trade/api.ts | 75 ++++++ .../src/views/certd/trade/crud.tsx | 194 +++++++++++++++ .../src/views/certd/trade/index.vue | 51 ++++ .../views/framework/home/dashboard/index.vue | 25 +- .../framework/home/dashboard/suite-card.vue | 77 ++++++ .../src/views/sys/settings/index.vue | 4 + .../src/views/sys/settings/tabs/payment.vue | 91 +++++++ .../src/views/sys/suite/payment/common.tsx | 194 --------------- .../src/views/sys/suite/payment/crud.tsx | 54 ----- .../src/views/sys/suite/payment/index.vue | 41 ---- .../src/views/sys/suite/payment/selector.vue | 163 ------------- .../src/views/sys/suite/product/crud.tsx | 133 +++++----- .../suite/product/duration-price-value.vue | 36 +++ .../sys/suite/product/duration-value.vue | 11 + .../src/views/sys/suite/product/index.vue | 41 +--- .../views/sys/suite/product/price-input.vue | 2 +- .../views/sys/suite/product/suite-value.vue | 12 +- .../src/views/sys/suite/setting/index.vue | 110 +++++++++ .../suite/setting/suite-duration-selector.vue | 85 +++++++ .../db/migration/v10018__suite.sql | 84 +++++-- packages/ui/certd-server/package.json | 1 + .../monitor/cert-info-controller.ts | 73 ++++++ .../monitor/site-info-controller.ts | 74 ++++++ .../controller/pipeline/access-controller.ts | 2 +- .../controller/pipeline/handle-controller.ts | 3 +- .../sys/access/access-controller.ts | 2 +- .../src/modules/basic/service/code-service.ts | 4 +- .../cname/service/cname-record-service.ts | 2 +- .../src/modules/pipeline/entity/pipeline.ts | 8 + .../pipeline/service/pipeline-service.ts | 106 +++++--- .../modules/suite/service/my-count-service.ts | 31 +++ .../sys/authority/service/user-service.ts | 3 + 69 files changed, 2071 insertions(+), 738 deletions(-) create mode 100644 packages/core/basic/src/utils/util.lock.ts create mode 100644 packages/core/basic/src/utils/util.mitter.ts rename packages/{ui/certd-server/src/modules/pipeline => libs/lib-server/src/user/access}/entity/access.ts (100%) create mode 100644 packages/libs/lib-server/src/user/access/index.ts rename packages/{ui/certd-server/src/modules/pipeline => libs/lib-server/src/user/access}/service/access-getter.ts (100%) rename packages/{ui/certd-server/src/modules/pipeline => libs/lib-server/src/user/access}/service/access-service.ts (98%) rename packages/{ui/certd-server/src/modules/pipeline => libs/lib-server/src/user/access}/service/access-sys-getter.ts (100%) rename packages/{ui/certd-server/src/modules/pipeline => libs/lib-server/src/user/access}/service/encrypt-service.ts (92%) create mode 100644 packages/libs/lib-server/src/user/index.ts create mode 100644 packages/ui/certd-client/src/components/expires-time-text.vue rename packages/ui/certd-client/src/views/{sys/suite/payment => certd/monitor/cert}/api.ts (58%) create mode 100644 packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx create mode 100644 packages/ui/certd-client/src/views/certd/monitor/cert/index.vue create mode 100644 packages/ui/certd-client/src/views/certd/monitor/site/api.ts create mode 100644 packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx create mode 100644 packages/ui/certd-client/src/views/certd/monitor/site/index.vue create mode 100644 packages/ui/certd-client/src/views/certd/payment/api.ts create mode 100644 packages/ui/certd-client/src/views/certd/payment/return.vue delete mode 100644 packages/ui/certd-client/src/views/certd/suite/card.vue create mode 100644 packages/ui/certd-client/src/views/certd/trade/api.ts create mode 100644 packages/ui/certd-client/src/views/certd/trade/crud.tsx create mode 100644 packages/ui/certd-client/src/views/certd/trade/index.vue create mode 100644 packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue create mode 100644 packages/ui/certd-client/src/views/sys/settings/tabs/payment.vue delete mode 100644 packages/ui/certd-client/src/views/sys/suite/payment/common.tsx delete mode 100644 packages/ui/certd-client/src/views/sys/suite/payment/crud.tsx delete mode 100644 packages/ui/certd-client/src/views/sys/suite/payment/index.vue delete mode 100644 packages/ui/certd-client/src/views/sys/suite/payment/selector.vue create mode 100644 packages/ui/certd-client/src/views/sys/suite/product/duration-price-value.vue create mode 100644 packages/ui/certd-client/src/views/sys/suite/product/duration-value.vue create mode 100644 packages/ui/certd-client/src/views/sys/suite/setting/index.vue create mode 100644 packages/ui/certd-client/src/views/sys/suite/setting/suite-duration-selector.vue create mode 100644 packages/ui/certd-server/src/controller/monitor/cert-info-controller.ts create mode 100644 packages/ui/certd-server/src/controller/monitor/site-info-controller.ts create mode 100644 packages/ui/certd-server/src/modules/suite/service/my-count-service.ts diff --git a/README.md b/README.md index 0a3ad1bf..cecb6b14 100644 --- a/README.md +++ b/README.md @@ -202,12 +202,13 @@ https://afdian.com/a/greper 专业版特权对比 -| 功能 | 免费版 | 专业版 | -|---------|-------------------|-----------------------| -| 免费证书申请 | 免费无限制 | 免费无限制 | -| 自动部署插件 | 阿里云、腾讯云、七牛云、主机部署等 | 支持群晖、宝塔、1Panel等,持续开发中 | -| 发邮件功能 | 需要配置 | 免配置 | -| 证书流水线条数 | 10条 | 无限制 | +| 功能 | 基础版 | 专业版 | +|---------|-----------------|-------------------| +| 免费证书申请 | 免费无限制 | 无限制 | +| 证书流水线条数 | 免费无限制 | 无限制 | +| 站点证书监控 | 1条 | 无限制 | +| 自动部署插件 | 阿里云、腾讯云、七牛云、SSH | 支持群晖、宝塔、1Panel等,持续开发中 | +| 通知 | 邮件、webhook | server酱、企微、anpush、钉钉等 | ************************ diff --git a/packages/core/basic/package.json b/packages/core/basic/package.json index d1bad95c..9bec4e31 100644 --- a/packages/core/basic/package.json +++ b/packages/core/basic/package.json @@ -23,6 +23,7 @@ "lodash-es": "^4.17.21", "log4js": "^6.9.1", "lru-cache": "^10.0.0", + "mitt": "^3.0.1", "nanoid": "^5.0.7", "node-forge": "^1.3.1", "nodemailer": "^6.9.3" diff --git a/packages/core/basic/src/utils/index.ts b/packages/core/basic/src/utils/index.ts index 43a0d321..0a7dac22 100644 --- a/packages/core/basic/src/utils/index.ts +++ b/packages/core/basic/src/utils/index.ts @@ -8,6 +8,7 @@ export * from './util.hash.js'; export * from './util.merge.js'; export * from './util.cache.js'; export * from './util.string.js'; +export * from './util.lock.js'; import { stringUtils } from './util.string.js'; import sleep from './util.sleep.js'; import { http, download } from './util.request.js'; @@ -24,6 +25,8 @@ import { domainUtils } from './util.domain.js'; import { optionsUtils } from './util.options.js'; import { nanoid } from 'nanoid'; import * as id from './util.id.js'; +import { locker } from './util.lock.js'; +import { mitter } from './util.mitter.js'; export const utils = { sleep, http, @@ -41,4 +44,6 @@ export const utils = { domain: domainUtils, options: optionsUtils, string: stringUtils, + locker, + mitter, }; diff --git a/packages/core/basic/src/utils/util.hash.ts b/packages/core/basic/src/utils/util.hash.ts index 44d2f97d..8727c436 100644 --- a/packages/core/basic/src/utils/util.hash.ts +++ b/packages/core/basic/src/utils/util.hash.ts @@ -3,7 +3,10 @@ import crypto from 'crypto'; function md5(data: string) { return crypto.createHash('md5').update(data).digest('hex'); } - +function sha256(data: string) { + return crypto.createHash('sha256').update(data).digest('hex'); +} export const hashUtils = { md5, + sha256, }; diff --git a/packages/core/basic/src/utils/util.lock.ts b/packages/core/basic/src/utils/util.lock.ts new file mode 100644 index 00000000..04aa9afd --- /dev/null +++ b/packages/core/basic/src/utils/util.lock.ts @@ -0,0 +1,51 @@ +import { logger, utils } from './index.js'; + +export class Locker { + locked: Record = {}; + + async execute(lockStr: string, callback: any) { + await this.lock(lockStr); + const timeoutId = setTimeout(() => { + logger.warn('Lock timeout,自动解锁', lockStr); + this.unlock(lockStr); + }, 20000); + try { + return await callback(); + } finally { + clearTimeout(timeoutId); + this.unlock(lockStr); + } + } + + async lock(str: string) { + const isLocked = this.isLocked(str); + if (isLocked) { + let count = 0; + while (true) { + await utils.sleep(100); + if (!this.isLocked(str)) { + break; + } + count++; + if (count > 20) { + throw new Error('Lock timeout'); + } + } + } + this.locked[str] = true; + } + + unlock(str: string) { + const isLocked = this.locked[str]; + if (isLocked != null) { + return; + } + delete this.locked[str]; + } + + isLocked(str: string) { + return this.locked[str] ?? false; + } +} + +export const locker = new Locker(); diff --git a/packages/core/basic/src/utils/util.mitter.ts b/packages/core/basic/src/utils/util.mitter.ts new file mode 100644 index 00000000..3ffb07a9 --- /dev/null +++ b/packages/core/basic/src/utils/util.mitter.ts @@ -0,0 +1,2 @@ +import mitt from 'mitt'; +export const mitter = mitt(); diff --git a/packages/libs/lib-server/src/basic/base-service.ts b/packages/libs/lib-server/src/basic/base-service.ts index f4963c9a..5e393259 100644 --- a/packages/libs/lib-server/src/basic/base-service.ts +++ b/packages/libs/lib-server/src/basic/base-service.ts @@ -99,7 +99,7 @@ export abstract class BaseService { * 新增|修改 * @param param 数据 */ - async addOrUpdate(param) { + async addOrUpdate(param: any) { await this.getRepository().save(param); } @@ -107,7 +107,7 @@ export abstract class BaseService { * 新增 * @param param 数据 */ - async add(param) { + async add(param: any) { const now = new Date(); param.createTime = now; param.updateTime = now; @@ -122,7 +122,7 @@ export abstract class BaseService { * 修改 * @param param 数据 */ - async update(param) { + async update(param: any) { if (!param.id) throw new ValidateException('id 不能为空'); param.updateTime = new Date(); await this.addOrUpdate(param); diff --git a/packages/libs/lib-server/src/basic/constants.ts b/packages/libs/lib-server/src/basic/constants.ts index 598004a1..aba37e77 100644 --- a/packages/libs/lib-server/src/basic/constants.ts +++ b/packages/libs/lib-server/src/basic/constants.ts @@ -36,6 +36,10 @@ export const Constants = { code: 88, message: '需要VIP', }, + needsuite: { + code: 89, + message: '需要购买或升级套餐', + }, loginError: { code: 2, message: '登录失败', diff --git a/packages/libs/lib-server/src/basic/exception/vip-exception.ts b/packages/libs/lib-server/src/basic/exception/vip-exception.ts index e791f1ab..86f65f69 100644 --- a/packages/libs/lib-server/src/basic/exception/vip-exception.ts +++ b/packages/libs/lib-server/src/basic/exception/vip-exception.ts @@ -8,3 +8,9 @@ export class NeedVIPException extends BaseException { super('NeedVIPException', Constants.res.needvip.code, message ? message : Constants.res.needvip.message); } } + +export class NeedSuiteException extends BaseException { + constructor(message) { + super('NeedSuiteException', Constants.res.needsuite.code, message ? message : Constants.res.needsuite.message); + } +} diff --git a/packages/libs/lib-server/src/index.ts b/packages/libs/lib-server/src/index.ts index 72c93823..a6d3f603 100644 --- a/packages/libs/lib-server/src/index.ts +++ b/packages/libs/lib-server/src/index.ts @@ -1,6 +1,8 @@ import { SysSettingsEntity } from './system/index.js'; +import { AccessEntity } from './user/access/entity/access.js'; export * from './basic/index.js'; export * from './system/index.js'; +export * from './user/index.js'; export { LibServerConfiguration as Configuration } from './configuration.js'; -export const libServerEntities = [SysSettingsEntity]; +export const libServerEntities = [SysSettingsEntity, AccessEntity]; diff --git a/packages/libs/lib-server/src/system/settings/service/models.ts b/packages/libs/lib-server/src/system/settings/service/models.ts index 05daa08a..67d346e5 100644 --- a/packages/libs/lib-server/src/system/settings/service/models.ts +++ b/packages/libs/lib-server/src/system/settings/service/models.ts @@ -136,3 +136,35 @@ export class SysHeaderMenus extends BaseSettings { menus: MenuItem[]; } + +export type PaymentItem = { + enabled: boolean; + accessId?: number; +}; + +export class SysPaymentSetting extends BaseSettings { + static __title__ = '支付设置'; + static __key__ = 'sys.payment'; + static __access__ = 'private'; + + yizhifu?: PaymentItem = { enabled: false }; + + alipay?: PaymentItem = { enabled: false }; + + wxpay?: PaymentItem = { enabled: false }; +} + +export class SysSuiteSetting extends BaseSettings { + static __title__ = '套餐设置'; + static __key__ = 'sys.suite'; + static __access__ = 'private'; + + enabled = false; + + registerGift?: { + productId: number; + duration: number; + }; + + intro?: string; +} diff --git a/packages/ui/certd-server/src/modules/pipeline/entity/access.ts b/packages/libs/lib-server/src/user/access/entity/access.ts similarity index 100% rename from packages/ui/certd-server/src/modules/pipeline/entity/access.ts rename to packages/libs/lib-server/src/user/access/entity/access.ts diff --git a/packages/libs/lib-server/src/user/access/index.ts b/packages/libs/lib-server/src/user/access/index.ts new file mode 100644 index 00000000..7c711f6b --- /dev/null +++ b/packages/libs/lib-server/src/user/access/index.ts @@ -0,0 +1,5 @@ +export * from './entity/access.js'; +export * from './service/access-service.js'; +export * from './service/access-sys-getter.js'; +export * from './service/access-getter.js'; +export * from './service/encrypt-service.js'; diff --git a/packages/ui/certd-server/src/modules/pipeline/service/access-getter.ts b/packages/libs/lib-server/src/user/access/service/access-getter.ts similarity index 100% rename from packages/ui/certd-server/src/modules/pipeline/service/access-getter.ts rename to packages/libs/lib-server/src/user/access/service/access-getter.ts diff --git a/packages/ui/certd-server/src/modules/pipeline/service/access-service.ts b/packages/libs/lib-server/src/user/access/service/access-service.ts similarity index 98% rename from packages/ui/certd-server/src/modules/pipeline/service/access-service.ts rename to packages/libs/lib-server/src/user/access/service/access-service.ts index dffeb23f..1b38c81b 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/access-service.ts +++ b/packages/libs/lib-server/src/user/access/service/access-service.ts @@ -1,7 +1,7 @@ import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { Repository } from 'typeorm'; -import { BaseService, PageReq, PermissionException, ValidateException } from '@certd/lib-server'; +import { BaseService, PageReq, PermissionException, ValidateException } from '../../../index.js'; import { AccessEntity } from '../entity/access.js'; import { AccessDefine, accessRegistry, newAccess } from '@certd/pipeline'; import { EncryptService } from './encrypt-service.js'; @@ -18,6 +18,7 @@ export class AccessService extends BaseService { @Inject() encryptService: EncryptService; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment //@ts-ignore getRepository() { return this.repository; diff --git a/packages/ui/certd-server/src/modules/pipeline/service/access-sys-getter.ts b/packages/libs/lib-server/src/user/access/service/access-sys-getter.ts similarity index 100% rename from packages/ui/certd-server/src/modules/pipeline/service/access-sys-getter.ts rename to packages/libs/lib-server/src/user/access/service/access-sys-getter.ts diff --git a/packages/ui/certd-server/src/modules/pipeline/service/encrypt-service.ts b/packages/libs/lib-server/src/user/access/service/encrypt-service.ts similarity index 92% rename from packages/ui/certd-server/src/modules/pipeline/service/encrypt-service.ts rename to packages/libs/lib-server/src/user/access/service/encrypt-service.ts index 9fc1e2a5..5e787ec2 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/encrypt-service.ts +++ b/packages/libs/lib-server/src/user/access/service/encrypt-service.ts @@ -1,7 +1,6 @@ import { Init, Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; import crypto from 'crypto'; -import { SysSettingsService } from '@certd/lib-server'; -import { SysPrivateSettings } from '@certd/lib-server'; +import { SysPrivateSettings, SysSettingsService } from '../../../system/index.js'; /** * 授权 diff --git a/packages/libs/lib-server/src/user/index.ts b/packages/libs/lib-server/src/user/index.ts new file mode 100644 index 00000000..17e3af2c --- /dev/null +++ b/packages/libs/lib-server/src/user/index.ts @@ -0,0 +1 @@ +export * from './access/index.js'; diff --git a/packages/ui/certd-client/src/components/expires-time-text.vue b/packages/ui/certd-client/src/components/expires-time-text.vue new file mode 100644 index 00000000..55a72b6d --- /dev/null +++ b/packages/ui/certd-client/src/components/expires-time-text.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/ui/certd-client/src/components/index.ts b/packages/ui/certd-client/src/components/index.ts index 93d39517..9a075756 100644 --- a/packages/ui/certd-client/src/components/index.ts +++ b/packages/ui/certd-client/src/components/index.ts @@ -9,6 +9,7 @@ import "@vue-js-cron/light/dist/light.css"; import Plugins from "./plugins/index"; import LoadingButton from "./loading-button.vue"; import IconSelect from "./icon-select.vue"; +import ExpiresTimeText from "./expires-time-text.vue"; export default { install(app: any) { app.component("PiContainer", PiContainer); @@ -25,7 +26,7 @@ export default { app.component("LoadingButton", LoadingButton); app.component("IconSelect", IconSelect); - + app.component("ExpiresTimeText", ExpiresTimeText); app.use(vip); app.use(Plugins); } diff --git a/packages/ui/certd-client/src/components/vip-button/index.vue b/packages/ui/certd-client/src/components/vip-button/index.vue index 5d79acda..5ac458b3 100644 --- a/packages/ui/certd-client/src/components/vip-button/index.vue +++ b/packages/ui/certd-client/src/components/vip-button/index.vue @@ -231,13 +231,13 @@ function openUpgrade() { title: "基础版", desc: "免费使用", type: "free", - privilege: ["证书申请功能无限制", "证书流水线数量10条", "常用的主机、cdn等部署插件"] + privilege: ["证书申请功能无限制", "证书流水线数量无限制", "常用的主机、云平台、cdn等部署插件"] }, plus: { title: "专业版", desc: "功能增强,适用于个人企业内部使用", type: "plus", - privilege: ["可加VIP群,需求优先实现", "证书流水线数量无限制", "免配置发邮件功能", "支持宝塔、易盾、群晖、1Panel、cdnfly等部署插件"], + privilege: ["可加VIP群,需求优先实现", "宝塔、群晖、1Panel、易盾等部署插件", "站点证书监控", "更多通知种类"], trial: { title: "7天试用", click: () => { 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 25d596ae..60f01b3b 100644 --- a/packages/ui/certd-client/src/router/source/modules/certd.ts +++ b/packages/ui/certd-client/src/router/source/modules/certd.ts @@ -71,7 +71,7 @@ export const certdResources = [ } }, { - title: "分组管理", + title: "流水线分组管理", name: "PipelineGroupManager", path: "/certd/pipeline/group", component: "/certd/pipeline/group/index.vue", @@ -90,6 +90,47 @@ export const certdResources = [ auth: true } }, + { + title: "我的订单", + name: "MyTrade", + path: "/certd/trade", + component: "/certd/trade/index.vue", + meta: { + icon: "ion:person-outline", + auth: true + } + }, + { + title: "支付返回", + name: "PaymentReturn", + path: "/certd/payment/return/:type", + component: "/certd/payment/return.vue", + meta: { + icon: "ion:person-outline", + auth: false, + isMenu: false + } + }, + { + title: "站点证书监控", + name: "SiteCertMonitor", + path: "/certd/monitor/site", + component: "/certd/monitor/site/index.vue", + meta: { + icon: "ion:person-outline", + auth: true + } + }, + { + title: "证书仓库", + name: "CertStore", + path: "/certd/monitor/cert", + component: "/certd/monitor/cert/index.vue", + meta: { + icon: "ion:person-outline", + auth: true + } + }, // { // title: "邮箱设置", // name: "EmailSetting", 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 414bab91..37b936ba 100644 --- a/packages/ui/certd-client/src/router/source/modules/sys.ts +++ b/packages/ui/certd-client/src/router/source/modules/sys.ts @@ -171,46 +171,24 @@ export const sysResources = [ } }, { - title: "套餐支付", - name: "SuiteManager", - path: "/sys/suite", - redirect: "/sys/suite/product", + title: "套餐设置", + name: "SuiteSetting", + path: "/sys/suite/setting", + component: "/sys/suite/setting/index.vue", meta: { - icon: "ion:golf-outline", - permission: "sys:settings:view" - }, - children: [ - { - title: "套餐管理", - name: "ProductManager", - path: "/sys/suite/product", - component: "/sys/suite/product/index.vue", - meta: { - icon: "ion:person-outline", - permission: "sys:settings:edit" - } - }, - { - title: "支付管理", - name: "PaymentManager", - path: "/sys/suite/payment", - component: "/sys/suite/payment/index.vue", - meta: { - icon: "ion:person-outline", - permission: "sys:settings:edit" - } - }, - { - title: "订单管理", - name: "OrderManager", - path: "/sys/suite/order", - component: "/sys/suite/order/index.vue", - meta: { - icon: "ion:person-outline", - permission: "sys:settings:edit" - } - } - ] + icon: "ion:person-outline", + permission: "sys:settings:edit" + } + }, + { + title: "订单管理", + name: "OrderManager", + path: "/sys/suite/trade", + component: "/sys/suite/trade/index.vue", + meta: { + icon: "ion:person-outline", + permission: "sys:settings:edit" + } } // { diff --git a/packages/ui/certd-client/src/views/sys/suite/payment/api.ts b/packages/ui/certd-client/src/views/certd/monitor/cert/api.ts similarity index 58% rename from packages/ui/certd-client/src/views/sys/suite/payment/api.ts rename to packages/ui/certd-client/src/views/certd/monitor/cert/api.ts index b2acd428..39df0db2 100644 --- a/packages/ui/certd-client/src/views/sys/suite/payment/api.ts +++ b/packages/ui/certd-client/src/views/certd/monitor/cert/api.ts @@ -1,7 +1,7 @@ import { request } from "/src/api/service"; -export function createPaymentApi() { - const apiPrefix = "/sys/suite/payment"; +export function createApi() { + const apiPrefix = "/pi/pipeline/group"; return { async GetList(query: any) { return await request({ @@ -42,35 +42,13 @@ export function createPaymentApi() { params: { id } }); }, - - async GetOptions(id: number) { + async ListAll() { return await request({ - url: apiPrefix + "/options", + url: apiPrefix + "/all", method: "post" }); - }, - - async GetSimpleInfo(id: number) { - return await request({ - url: apiPrefix + "/simpleInfo", - method: "post", - params: { id } - }); - }, - - async GetDefineTypes() { - return await request({ - url: apiPrefix + "/getTypeDict", - method: "post" - }); - }, - - async GetProviderDefine(type: string) { - return await request({ - url: apiPrefix + "/define", - method: "post", - params: { type } - }); } }; } + +export const pipelineGroupApi = createApi(); diff --git a/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx b/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx new file mode 100644 index 00000000..a20f49b5 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/monitor/cert/crud.tsx @@ -0,0 +1,178 @@ +// @ts-ignore +import { useI18n } from "vue-i18n"; +import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; +import { pipelineGroupApi } from "./api"; + +export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const { t } = useI18n(); + const api = pipelineGroupApi; + const pageRequest = async (query: UserPageQuery): Promise => { + return await api.GetList(query); + }; + const editRequest = async (req: EditReq) => { + const { form, row } = req; + form.id = row.id; + const res = await api.UpdateObj(form); + return res; + }; + const delRequest = async (req: DelReq) => { + const { row } = req; + return await api.DelObj(row.id); + }; + + const addRequest = async (req: AddReq) => { + const { form } = req; + const res = await api.AddObj(form); + return res; + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + labelCol: { + //固定label宽度 + span: null, + style: { + width: "100px" + } + }, + col: { + span: 22 + }, + wrapper: { + width: 600 + } + }, + rowHandle: { + width: 200 + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + search: { + show: false + }, + column: { + width: 100, + editable: { + disabled: true + } + }, + form: { + show: false + } + }, + domain: { + title: "主域名", + search: { + show: true + }, + type: "text", + form: { + show: false + }, + column: { + width: 100, + sorter: true + } + }, + domains: { + title: "全部域名", + search: { + show: false + }, + type: "text", + form: { + rules: [{ required: true, message: "请输入域名" }] + }, + column: { + width: 300, + sorter: true + } + }, + domainCount: { + title: "域名数量", + type: "number", + form: { + show: false + }, + column: { + width: 120, + sorter: true + } + }, + pipelineId: { + title: "已关联流水线", + search: { show: false }, + type: "text", + form: { + show: false + }, + column: { + width: 200, + sorter: true + } + }, + applyTime: { + title: "申请时间", + search: { + show: false + }, + type: "datetime", + form: { + show: false + }, + column: { + sorter: true + } + }, + expiresTime: { + title: "过期时间", + search: { + show: true + }, + type: "date", + form: { + show: false + }, + column: { + sorter: true + } + }, + fromType: { + title: "来源", + search: { + show: true + }, + type: "text", + form: { show: false }, + column: { + width: 100, + sorter: true + } + }, + certProvider: { + title: "证书颁发机构", + search: { + show: true + }, + type: "text", + form: { + show: false + }, + column: { + width: 400 + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue b/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue new file mode 100644 index 00000000..653b9597 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/monitor/cert/index.vue @@ -0,0 +1,30 @@ + + + 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 new file mode 100644 index 00000000..39df0db2 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/monitor/site/api.ts @@ -0,0 +1,54 @@ +import { request } from "/src/api/service"; + +export function createApi() { + const apiPrefix = "/pi/pipeline/group"; + return { + async GetList(query: any) { + return await request({ + url: apiPrefix + "/page", + method: "post", + data: query + }); + }, + + async AddObj(obj: any) { + return await request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); + }, + + async UpdateObj(obj: any) { + return await request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); + }, + + async DelObj(id: number) { + return await request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); + }, + + async GetObj(id: number) { + return await request({ + url: apiPrefix + "/info", + method: "post", + params: { id } + }); + }, + async ListAll() { + return await request({ + url: apiPrefix + "/all", + method: "post" + }); + } + }; +} + +export const pipelineGroupApi = createApi(); 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 new file mode 100644 index 00000000..da5a047a --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/monitor/site/crud.tsx @@ -0,0 +1,228 @@ +// @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"; + +export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { + const { t } = useI18n(); + const api = pipelineGroupApi; + const pageRequest = async (query: UserPageQuery): Promise => { + return await api.GetList(query); + }; + const editRequest = async (req: EditReq) => { + const { form, row } = req; + form.id = row.id; + const res = await api.UpdateObj(form); + return res; + }; + const delRequest = async (req: DelReq) => { + const { row } = req; + return await api.DelObj(row.id); + }; + + const addRequest = async (req: AddReq) => { + const { form } = req; + const res = await api.AddObj(form); + return res; + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + labelCol: { + //固定label宽度 + span: null, + style: { + width: "100px" + } + }, + col: { + span: 22 + }, + wrapper: { + width: 600 + } + }, + rowHandle: { + width: 200 + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + search: { + show: false + }, + column: { + width: 100, + editable: { + disabled: true + } + }, + form: { + show: false + } + }, + + name: { + title: "站点名称", + search: { + show: true + }, + type: "text", + form: { + rules: [{ required: true, message: "请输入站点名称" }] + }, + column: { + width: 100 + } + }, + domain: { + title: "主域名", + search: { + show: true + }, + type: "text", + form: { + rules: [{ required: true, message: "请输入域名" }] + }, + column: { + width: 100, + sorter: true + } + }, + domains: { + title: "其他域名", + search: { + show: true + }, + type: "text", + form: { + rules: [{ required: true, message: "请输入其他域名" }] + }, + column: { + width: 300, + sorter: true + } + }, + certInfo: { + title: "证书详情", + search: { + show: false + }, + type: "text", + form: { + show: false + }, + column: { + width: 100 + } + }, + certStatus: { + title: "证书状态", + search: { + show: true + }, + type: "text", + form: { + show: false + }, + column: { + width: 100, + sorter: true + } + }, + certExpiresTime: { + title: "证书到期时间", + search: { + show: false + }, + type: "date", + form: { + show: false + }, + column: { + sorter: true + } + }, + lastCheckTime: { + title: "上次检查时间", + search: { + show: false + }, + type: "datetime", + form: { + show: false + }, + column: { + sorter: true + } + }, + checkStatus: { + title: "检查状态", + search: { + show: false + }, + type: "text", + form: { + show: false + }, + column: { + width: 100, + sorter: true + } + }, + pipelineId: { + title: "关联流水线id", + search: { + show: false + }, + type: "number", + column: { + width: 200, + sorter: true + } + }, + certInfoId: { + title: "证书id", + search: { + show: false + }, + type: "number", + form: {}, + column: { + width: 100, + sorter: true, + show: false + } + }, + disabled: { + title: "禁用启用", + search: { + show: false + }, + type: "dict-switch", + dict: dict({ + data: [ + { label: "禁用", value: true, color: "red" }, + { label: "启用", value: false, color: "green" } + ] + }), + form: {}, + column: { + width: 100, + sorter: true + } + } + } + } + }; +} 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 new file mode 100644 index 00000000..f174e35c --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/monitor/site/index.vue @@ -0,0 +1,30 @@ + + + diff --git a/packages/ui/certd-client/src/views/certd/payment/api.ts b/packages/ui/certd-client/src/views/certd/payment/api.ts new file mode 100644 index 00000000..a0b5dcf1 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/payment/api.ts @@ -0,0 +1,11 @@ +import { request } from "/src/api/service"; + +const apiPrefix = "/pay"; +export async function Notify(type: string, query: any) { + return await request({ + url: apiPrefix + `/notify/${type}`, + method: "post", + data: query, + returnResponse: true + }); +} diff --git a/packages/ui/certd-client/src/views/certd/payment/return.vue b/packages/ui/certd-client/src/views/certd/payment/return.vue new file mode 100644 index 00000000..5a0f3b5d --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/payment/return.vue @@ -0,0 +1,50 @@ + + + diff --git a/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue b/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue index 2b1fbbbf..9e3ffee6 100644 --- a/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue +++ b/packages/ui/certd-client/src/views/certd/pipeline/group/index.vue @@ -2,7 +2,7 @@ diff --git a/packages/ui/certd-client/src/views/certd/suite/api.ts b/packages/ui/certd-client/src/views/certd/suite/api.ts index f17408a1..a2e27f68 100644 --- a/packages/ui/certd-client/src/views/certd/suite/api.ts +++ b/packages/ui/certd-client/src/views/certd/suite/api.ts @@ -51,3 +51,17 @@ export async function TradeCreate(form: TradeCreateReq) { data: form }); } + +export async function GetPaymentTypes() { + return await request({ + url: "/suite/trade/payments", + method: "POST" + }); +} + +export async function GetSuiteSetting() { + return await request({ + url: "/suite/settings/get", + method: "POST" + }); +} diff --git a/packages/ui/certd-client/src/views/certd/suite/buy.vue b/packages/ui/certd-client/src/views/certd/suite/buy.vue index 756feeb9..2c318cb8 100644 --- a/packages/ui/certd-client/src/views/certd/suite/buy.vue +++ b/packages/ui/certd-client/src/views/certd/suite/buy.vue @@ -4,8 +4,14 @@
套餐购买
- - +
+ +
套餐说明:多个套餐内的数量可以叠加
+
+
+
+ + @@ -34,6 +40,13 @@ async function doOrder(req: any) { ...req }); } + +const suiteIntro = ref(""); +async function loadSuiteIntro() { + const res = await api.GetSuiteSetting(); + suiteIntro.value = res.intro; +} +loadSuiteIntro(); diff --git a/packages/ui/certd-client/src/views/certd/suite/card.vue b/packages/ui/certd-client/src/views/certd/suite/card.vue deleted file mode 100644 index 3a6cce8d..00000000 --- a/packages/ui/certd-client/src/views/certd/suite/card.vue +++ /dev/null @@ -1,3 +0,0 @@ -
- -
\ No newline at end of file diff --git a/packages/ui/certd-client/src/views/certd/suite/order-modal.vue b/packages/ui/certd-client/src/views/certd/suite/order-modal.vue index 7699c28d..8d8d93a6 100644 --- a/packages/ui/certd-client/src/views/certd/suite/order-modal.vue +++ b/packages/ui/certd-client/src/views/certd/suite/order-modal.vue @@ -12,17 +12,13 @@
时长: - {{ durationDict.dataMap[formRef.duration]?.label }} +
价格:
支付方式: - - 易支付 - 支付宝 - 微信支付 - +
@@ -30,11 +26,13 @@ + diff --git a/packages/ui/certd-client/src/views/framework/home/dashboard/index.vue b/packages/ui/certd-client/src/views/framework/home/dashboard/index.vue index 1ddbea9a..c5d7c06e 100644 --- a/packages/ui/certd-client/src/views/framework/home/dashboard/index.vue +++ b/packages/ui/certd-client/src/views/framework/home/dashboard/index.vue @@ -12,14 +12,19 @@
您好,{{ userInfo.nickName || userInfo.username }}, 欢迎使用 【{{ siteInfo.title }}】
-
- {{ now }} - - - - v{{ version }} - - +
+ {{ now }} + + +
@@ -82,7 +87,7 @@
@@ -118,7 +123,7 @@ import TutorialButton from "/@/components/tutorial/index.vue"; import DayCount from "./charts/day-count.vue"; import PieCount from "./charts/pie-count.vue"; import ExpiringList from "./charts/expiring-list.vue"; - +import SuiteCard from "./suite-card.vue"; import { useSettingStore } from "/@/store/modules/settings"; import { SiteInfo } from "/@/api/modules/api.basic"; import { UserInfoRes } from "/@/api/modules/api.user"; 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 new file mode 100644 index 00000000..ea85acee --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/home/dashboard/suite-card.vue @@ -0,0 +1,77 @@ + + + diff --git a/packages/ui/certd-client/src/views/sys/settings/index.vue b/packages/ui/certd-client/src/views/sys/settings/index.vue index c0b44d90..e91e7644 100644 --- a/packages/ui/certd-client/src/views/sys/settings/index.vue +++ b/packages/ui/certd-client/src/views/sys/settings/index.vue @@ -11,6 +11,9 @@ + + +
@@ -19,6 +22,7 @@ + diff --git a/packages/ui/certd-client/src/views/sys/suite/payment/common.tsx b/packages/ui/certd-client/src/views/sys/suite/payment/common.tsx deleted file mode 100644 index 3bf18feb..00000000 --- a/packages/ui/certd-client/src/views/sys/suite/payment/common.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import { ColumnCompositionProps, compute, dict } from "@fast-crud/fast-crud"; -import { computed, provide, ref, toRef } from "vue"; -import { useReference } from "/@/use/use-refrence"; -import { forEach, get, merge, set } from "lodash-es"; -import { Modal } from "ant-design-vue"; -import * as api from "/@/views/sys/cname/provider/api"; -import { mitter } from "/@/utils/util.mitt"; - -export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) { - const notificationTypeDictRef = dict({ - url: "/sys/suite/payment/getList" - }); - const defaultPluginConfig = { - component: { - name: "a-input", - vModel: "value" - } - }; - - function buildDefineFields(define: any, form: any, mode: string) { - const formWrapperRef = crudExpose.getFormWrapperRef(); - const columnsRef = toRef(formWrapperRef.formOptions, "columns"); - - for (const key in columnsRef.value) { - if (key.indexOf(".") >= 0) { - delete columnsRef.value[key]; - } - } - console.log('crudBinding.value[mode + "Form"].columns', columnsRef.value); - forEach(define.input, (value: any, mapKey: any) => { - const key = "body." + mapKey; - const field = { - ...value, - key - }; - const column = merge({ title: key }, defaultPluginConfig, field); - //eval - useReference(column); - - if (column.required) { - if (!column.rules) { - column.rules = []; - } - column.rules.push({ required: true, message: "此项必填" }); - } - - //设置默认值 - if (column.value != null && get(form, key) == null) { - set(form, key, column.value); - } - //字段配置赋值 - columnsRef.value[key] = column; - console.log("form", columnsRef.value, form); - }); - } - - const currentDefine = ref(); - - return { - id: { - title: "ID", - key: "id", - type: "number", - column: { - width: 100 - }, - form: { - show: false - } - }, - type: { - title: "支付类型", - type: "dict-select", - dict: notificationTypeDictRef, - search: { - show: false - }, - column: { - width: 200, - component: { - color: "auto" - } - }, - editForm: { - component: { - disabled: false - } - }, - form: { - component: { - disabled: false, - showSearch: true, - filterOption: (input: string, option: any) => { - input = input?.toLowerCase(); - return option.value.toLowerCase().indexOf(input) >= 0 || option.label.toLowerCase().indexOf(input) >= 0; - }, - renderLabel(item: any) { - return ( - - {item.label} - {item.needPlus && } - - ); - } - }, - rules: [{ required: true, message: "请选择通知类型" }], - valueChange: { - immediate: true, - async handle({ value, mode, form, immediate }) { - if (value == null) { - return; - } - const lastTitle = currentDefine.value?.title; - const define = await api.GetProviderDefine(value); - currentDefine.value = define; - console.log("define", define); - - if (!immediate) { - form.body = {}; - if (define.needPlus) { - mitter.emit("openVipModal"); - } - } - - if (!form.name || form.name === lastTitle) { - form.name = define.title; - } - buildDefineFields(define, form, mode); - } - }, - helper: computed(() => { - const define = currentDefine.value; - if (define == null) { - return ""; - } - return define.desc; - }) - } - } as ColumnCompositionProps, - name: { - title: "通知名称", - search: { - show: true - }, - type: ["text"], - form: { - rules: [{ required: true, message: "请填写名称" }], - helper: "随便填,当多个相同类型的通知时,便于区分" - }, - column: { - width: 200 - } - }, - test: { - title: "测试", - form: { - show: compute(({ form }) => { - return !!form.type; - }), - component: { - name: "api-test", - action: "TestRequest" - }, - order: 990, - col: { - span: 24 - } - }, - column: { - show: false - } - }, - setting: { - column: { show: false }, - form: { - show: false, - valueBuilder({ value, form }) { - form.body = {}; - if (!value) { - return; - } - const setting = JSON.parse(value); - for (const key in setting) { - form.body[key] = setting[key]; - } - }, - valueResolve({ form }) { - const setting = form.body; - form.setting = JSON.stringify(setting); - } - } - } as ColumnCompositionProps - }; -} diff --git a/packages/ui/certd-client/src/views/sys/suite/payment/crud.tsx b/packages/ui/certd-client/src/views/sys/suite/payment/crud.tsx deleted file mode 100644 index ae2d1d27..00000000 --- a/packages/ui/certd-client/src/views/sys/suite/payment/crud.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { ref } from "vue"; -import { getCommonColumnDefine } from "./common"; -import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -import { createNotificationApi } from "/@/views/certd/notification/api"; -const api = createNotificationApi(); -export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { - const pageRequest = async (query: UserPageQuery): Promise => { - return await api.GetList(query); - }; - const editRequest = async (req: EditReq) => { - const { form, row } = req; - form.id = row.id; - const res = await api.UpdateObj(form); - return res; - }; - const delRequest = async (req: DelReq) => { - const { row } = req; - return await api.DelObj(row.id); - }; - - const addRequest = async (req: AddReq) => { - const { form } = req; - const res = await api.AddObj(form); - return res; - }; - - const typeRef = ref(); - const commonColumnsDefine = getCommonColumnDefine(crudExpose, typeRef, api); - return { - crudOptions: { - request: { - pageRequest, - addRequest, - editRequest, - delRequest - }, - form: { - labelCol: { - //固定label宽度 - span: null, - style: { - width: "145px" - } - } - }, - rowHandle: { - width: 200 - }, - columns: { - ...commonColumnsDefine - } - } - }; -} diff --git a/packages/ui/certd-client/src/views/sys/suite/payment/index.vue b/packages/ui/certd-client/src/views/sys/suite/payment/index.vue deleted file mode 100644 index 3ac0d220..00000000 --- a/packages/ui/certd-client/src/views/sys/suite/payment/index.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/packages/ui/certd-client/src/views/sys/suite/payment/selector.vue b/packages/ui/certd-client/src/views/sys/suite/payment/selector.vue deleted file mode 100644 index e851b86a..00000000 --- a/packages/ui/certd-client/src/views/sys/suite/payment/selector.vue +++ /dev/null @@ -1,163 +0,0 @@ - - - - diff --git a/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx b/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx index d9ba0778..736fb202 100644 --- a/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx +++ b/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx @@ -1,17 +1,12 @@ import * as api from "./api"; -import { useI18n } from "vue-i18n"; -import { Ref, ref } from "vue"; -import { useRouter } from "vue-router"; import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; -import { useUserStore } from "/@/store/modules/user"; -import { useSettingStore } from "/@/store/modules/settings"; import SuiteValue from "./suite-value.vue"; import SuiteValueEdit from "./suite-value-edit.vue"; import PriceEdit from "./price-edit.vue"; +import DurationPriceValue from "/@/views/sys/suite/product/duration-price-value.vue"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { - const router = useRouter(); - const { t } = useI18n(); + const emit = context.emit; const pageRequest = async (query: UserPageQuery): Promise => { return await api.GetList(query); }; @@ -29,35 +24,26 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat return res; }; - const userStore = useUserStore(); - const settingStore = useSettingStore(); - const selectedRowKeys: Ref = ref([]); - context.selectedRowKeys = selectedRowKeys; - return { crudOptions: { - settings: { - plugins: { - //这里使用行选择插件,生成行选择crudOptions配置,最终会与crudOptions合并 - rowSelection: { - enabled: true, - order: -2, - before: true, - // handle: (pluginProps,useCrudProps)=>CrudOptions, - props: { - multiple: true, - crossPage: true, - selectedRowKeys - } - } + table: { + onRefreshed: () => { + emit("refreshed"); } }, + search: { + show: false + }, request: { pageRequest, addRequest, editRequest, delRequest }, + pagination: { + show: false, + pageSize: 999999 + }, rowHandle: { minWidth: 200, fixed: "right" @@ -71,7 +57,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, content: { header: "套餐内容", - columns: ["content.maxDomainCount", "content.maxPipelineCount", "content.maxDeployCount", "content.siteMonitor"] + columns: ["content.maxDomainCount", "content.maxPipelineCount", "content.maxDeployCount", "content.maxMonitorCount"] }, price: { header: "价格", @@ -81,17 +67,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } }, columns: { - id: { - title: "ID", - key: "id", - type: "number", - column: { - width: 100 - }, - form: { - show: false - } - }, + // id: { + // title: "ID", + // key: "id", + // type: "number", + // column: { + // width: 100 + // }, + // form: { + // show: false + // } + // }, title: { title: "套餐名称", type: "text", @@ -123,7 +109,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat rules: [{ required: true, message: "此项必填" }] }, column: { - width: 100 + width: 80, + align: "center" }, valueBuilder: ({ row }) => { if (row.content) { @@ -205,37 +192,25 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } } }, - "content.siteMonitor": { - title: "支持证书监控", - type: "dict-switch", - dict: dict({ - data: [ - { label: "是", value: true, color: "success" }, - { label: "否", value: false, color: "error" } - ] - }), + "content.maxMonitorCount": { + title: "证书监控数量", + type: "text", form: { - key: ["content", "siteMonitor"], - value: false + key: ["content", "maxMonitorCount"], + component: { + name: SuiteValueEdit, + vModel: "modelValue", + unit: "个" + }, + rules: [{ required: true, message: "此项必填" }] }, column: { - width: 120 - } - }, - isBootstrap: { - title: "是否初始套餐", - type: "dict-switch", - dict: dict({ - data: [ - { label: "是", value: true, color: "success" }, - { label: "否", value: false, color: "gray" } - ] - }), - form: { - value: false - }, - column: { - width: 120 + width: 120, + component: { + name: SuiteValue, + vModel: "modelValue", + unit: "个" + } } }, durationPrices: { @@ -258,10 +233,26 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }, column: { component: { - name: PriceEdit, - vModel: "modelValue", - edit: false - } + name: DurationPriceValue, + vModel: "modelValue" + }, + width: 350 + } + }, + supportBuy: { + title: "支持购买", + type: "dict-switch", + dict: dict({ + data: [ + { label: "是", value: true, color: "success" }, + { label: "否", value: false, color: "gray" } + ] + }), + form: { + value: false + }, + column: { + width: 120 } }, disabled: { diff --git a/packages/ui/certd-client/src/views/sys/suite/product/duration-price-value.vue b/packages/ui/certd-client/src/views/sys/suite/product/duration-price-value.vue new file mode 100644 index 00000000..16c7f83d --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/suite/product/duration-price-value.vue @@ -0,0 +1,36 @@ + + + + diff --git a/packages/ui/certd-client/src/views/sys/suite/product/duration-value.vue b/packages/ui/certd-client/src/views/sys/suite/product/duration-value.vue new file mode 100644 index 00000000..671a0e62 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/suite/product/duration-value.vue @@ -0,0 +1,11 @@ + + + diff --git a/packages/ui/certd-client/src/views/sys/suite/product/index.vue b/packages/ui/certd-client/src/views/sys/suite/product/index.vue index 3b8a14e9..add0870a 100644 --- a/packages/ui/certd-client/src/views/sys/suite/product/index.vue +++ b/packages/ui/certd-client/src/views/sys/suite/product/index.vue @@ -1,50 +1,19 @@ + + diff --git a/packages/ui/certd-client/src/views/sys/suite/setting/suite-duration-selector.vue b/packages/ui/certd-client/src/views/sys/suite/setting/suite-duration-selector.vue new file mode 100644 index 00000000..271bfe6c --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/suite/setting/suite-duration-selector.vue @@ -0,0 +1,85 @@ + + + + diff --git a/packages/ui/certd-server/db/migration/v10018__suite.sql b/packages/ui/certd-server/db/migration/v10018__suite.sql index eda42b83..4450d0c1 100644 --- a/packages/ui/certd-server/db/migration/v10018__suite.sql +++ b/packages/ui/certd-server/db/migration/v10018__suite.sql @@ -10,27 +10,12 @@ CREATE TABLE "cd_product" "price" integer, "intro" varchar(10240), "order" integer, - "is_bootstrap" boolean, + "support_buy" boolean, "disabled" boolean NOT NULL DEFAULT (false), "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP) ); - - -CREATE TABLE "cd_payment" -( - "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, - "type" varchar(100), - "title" varchar(100), - "setting" text, - "order" integer, - "disabled" boolean NOT NULL DEFAULT (false), - "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), - "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP) -); - - CREATE TABLE "cd_trade" ( "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -55,7 +40,7 @@ CREATE TABLE "cd_trade" CREATE INDEX "index_trade_user_id" ON "cd_trade" ("user_id"); CREATE UNIQUE INDEX "index_trade_trade_no" ON "cd_trade" ("trade_no"); -CREATE INDEX "index_trade_pay_no" ON "cd_trade" ("pay_type","pay_no"); +CREATE INDEX "index_trade_pay_no" ON "cd_trade" ("pay_type", "pay_no"); CREATE TABLE "cd_user_suite" @@ -68,7 +53,10 @@ CREATE TABLE "cd_user_suite" "title" varchar(100), "content" text, "duration" integer, - "used_deploy_count" integer, + "deploy_count_used" integer, + "is_present" boolean, + "is_bootstrap" boolean, + "disabled" boolean NOT NULL DEFAULT (false), "active_time" integer, "expires_time" integer, "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), @@ -84,3 +72,63 @@ DROP TABLE IF EXISTS "cd_cert_issuer"; DROP TABLE IF EXISTS "cd_task"; DROP TABLE IF EXISTS "cd_task_history"; + + +CREATE TABLE "cd_cert_info" +( + "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, + "user_id" integer, + "domain" varchar(100), + "domains" varchar(10240), + "domain_count" integer, + "pipeline_id" integer, + "apply_time" integer, + "from_type" varchar(100), + "cert_provider" varchar(100), + "expires_time" integer, + "cert_info" text, + "cert_file" varchar(100), + "disabled" boolean NOT NULL DEFAULT (false), + "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), + "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP) +); + +CREATE INDEX "index_cert_info_user_id" ON "cd_cert_info" ("user_id"); +CREATE INDEX "index_cert_info_domain" ON "cd_cert_info" ("domain"); +CREATE INDEX "index_cert_info_domains" ON "cd_cert_info" ("domains"); +CREATE INDEX "index_cert_info_pipeline" ON "cd_cert_info" ("pipeline_id"); + + +CREATE TABLE "cd_site_info" +( + "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, + "user_id" integer, + + "name" varchar(100), + "domain" varchar(100), + "domains" varchar(10240), + "cert_info" varchar(10240), + + "cert_provider" varchar(100), + "cert_status" varchar(100), + "cert_expires_time" integer, + "last_check_time" integer, + "check_status" varchar(100), + "pipeline_id" integer, + "cert_info_id" integer, + "disabled" boolean NOT NULL DEFAULT (false), + + "create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP), + "update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP) +); + +CREATE INDEX "index_site_info_user_id" ON "cd_site_info" ("user_id"); +CREATE INDEX "index_site_info_domain" ON "cd_site_info" ("domain"); +CREATE INDEX "index_site_info_domains" ON "cd_site_info" ("domains"); +CREATE INDEX "index_site_info_pipeline" ON "cd_site_info" ("pipeline_id"); + + +ALTER TABLE pi_pipeline + ADD COLUMN "type" varchar(50); +ALTER TABLE pi_pipeline + ADD COLUMN "from" varchar(50); diff --git a/packages/ui/certd-server/package.json b/packages/ui/certd-server/package.json index 35befd37..e9673b21 100644 --- a/packages/ui/certd-server/package.json +++ b/packages/ui/certd-server/package.json @@ -82,6 +82,7 @@ "lodash-es": "^4.17.21", "log4js": "^6.7.1", "lru-cache": "^11.0.1", + "mitt": "^3.0.1", "mwts": "^1.3.0", "mwtsc": "^1.4.0", "mysql": "^2.18.1", diff --git a/packages/ui/certd-server/src/controller/monitor/cert-info-controller.ts b/packages/ui/certd-server/src/controller/monitor/cert-info-controller.ts new file mode 100644 index 00000000..a3ddbb4d --- /dev/null +++ b/packages/ui/certd-server/src/controller/monitor/cert-info-controller.ts @@ -0,0 +1,73 @@ +import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; +import { Constants, CrudController } from '@certd/lib-server'; +import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; +import { SiteInfoService } from '../../modules/monitor/service/site-info-service.js'; + +/** + * 通知 + */ +@Provide() +@Controller('/api/monitor/site') +export class SiteInfoController extends CrudController { + @Inject() + service: SiteInfoService; + @Inject() + authService: AuthService; + + getService(): SiteInfoService { + return this.service; + } + + @Post('/page', { summary: Constants.per.authOnly }) + async page(@Body(ALL) body: any) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + const res = await this.service.page({ + query: body.query, + page: body.page, + sort: body.sort, + }); + return this.ok(res); + } + + @Post('/list', { summary: Constants.per.authOnly }) + async list(@Body(ALL) body: any) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + return await super.list(body); + } + + @Post('/add', { summary: Constants.per.authOnly }) + async add(@Body(ALL) bean: any) { + bean.userId = this.getUserId(); + return await super.add(bean); + } + + @Post('/update', { summary: Constants.per.authOnly }) + async update(@Body(ALL) bean) { + await this.service.checkUserId(bean.id, this.getUserId()); + delete bean.userId; + return await super.update(bean); + } + @Post('/info', { summary: Constants.per.authOnly }) + async info(@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + return await super.info(id); + } + + @Post('/delete', { summary: Constants.per.authOnly }) + async delete(@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + return await super.delete(id); + } + + @Post('/all', { summary: Constants.per.authOnly }) + async all() { + const list: any = await this.service.find({ + where: { + userId: this.getUserId(), + }, + }); + return this.ok(list); + } +} diff --git a/packages/ui/certd-server/src/controller/monitor/site-info-controller.ts b/packages/ui/certd-server/src/controller/monitor/site-info-controller.ts new file mode 100644 index 00000000..d22a5616 --- /dev/null +++ b/packages/ui/certd-server/src/controller/monitor/site-info-controller.ts @@ -0,0 +1,74 @@ +import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; +import { Constants, CrudController } from '@certd/lib-server'; +import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; +import { CertInfoService } from '../../modules/monitor/service/cert-info-service.js'; + +/** + * 通知 + */ +@Provide() +@Controller('/api/monitor/cert') +export class CertInfoController extends CrudController { + @Inject() + service: CertInfoService; + @Inject() + authService: AuthService; + + getService(): CertInfoService { + return this.service; + } + + @Post('/page', { summary: Constants.per.authOnly }) + async page(@Body(ALL) body: any) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + + const res = await this.service.page({ + query: body.query, + page: body.page, + sort: body.sort, + }); + return this.ok(res); + } + + @Post('/list', { summary: Constants.per.authOnly }) + async list(@Body(ALL) body: any) { + body.query = body.query ?? {}; + body.query.userId = this.getUserId(); + return await super.list(body); + } + + @Post('/add', { summary: Constants.per.authOnly }) + async add(@Body(ALL) bean: any) { + bean.userId = this.getUserId(); + return await super.add(bean); + } + + @Post('/update', { summary: Constants.per.authOnly }) + async update(@Body(ALL) bean) { + await this.service.checkUserId(bean.id, this.getUserId()); + delete bean.userId; + return await super.update(bean); + } + @Post('/info', { summary: Constants.per.authOnly }) + async info(@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + return await super.info(id); + } + + @Post('/delete', { summary: Constants.per.authOnly }) + async delete(@Query('id') id: number) { + await this.service.checkUserId(id, this.getUserId()); + return await super.delete(id); + } + + @Post('/all', { summary: Constants.per.authOnly }) + async all() { + const list: any = await this.service.find({ + where: { + userId: this.getUserId(), + }, + }); + return this.ok(list); + } +} diff --git a/packages/ui/certd-server/src/controller/pipeline/access-controller.ts b/packages/ui/certd-server/src/controller/pipeline/access-controller.ts index 8abbb536..ce2ff661 100644 --- a/packages/ui/certd-server/src/controller/pipeline/access-controller.ts +++ b/packages/ui/certd-server/src/controller/pipeline/access-controller.ts @@ -1,6 +1,6 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; import { Constants, CrudController } from '@certd/lib-server'; -import { AccessService } from '../../modules/pipeline/service/access-service.js'; +import { AccessService } from '@certd/lib-server'; import { AuthService } from '../../modules/sys/authority/service/auth-service.js'; import { AccessDefine } from '@certd/pipeline'; diff --git a/packages/ui/certd-server/src/controller/pipeline/handle-controller.ts b/packages/ui/certd-server/src/controller/pipeline/handle-controller.ts index 288a8fd6..6bbd31e6 100644 --- a/packages/ui/certd-server/src/controller/pipeline/handle-controller.ts +++ b/packages/ui/certd-server/src/controller/pipeline/handle-controller.ts @@ -10,9 +10,8 @@ import { PluginRequestHandleReq, TaskInstanceContext, } from '@certd/pipeline'; -import { AccessService } from '../../modules/pipeline/service/access-service.js'; +import { AccessService, AccessGetter } from '@certd/lib-server'; import { EmailService } from '../../modules/basic/service/email-service.js'; -import { AccessGetter } from '../../modules/pipeline/service/access-getter.js'; import { http, HttpRequestConfig, logger, mergeUtils, utils } from '@certd/basic'; import { NotificationService } from '../../modules/pipeline/service/notification-service.js'; diff --git a/packages/ui/certd-server/src/controller/sys/access/access-controller.ts b/packages/ui/certd-server/src/controller/sys/access/access-controller.ts index 20fa47c6..03ed3108 100644 --- a/packages/ui/certd-server/src/controller/sys/access/access-controller.ts +++ b/packages/ui/certd-server/src/controller/sys/access/access-controller.ts @@ -1,5 +1,5 @@ import { ALL, Body, Controller, Inject, Post, Provide, Query } from '@midwayjs/core'; -import { AccessService } from '../../../modules/pipeline/service/access-service.js'; +import { AccessService } from '@certd/lib-server'; import { AccessController } from '../../pipeline/access-controller.js'; import { checkComm } from '@certd/plus-core'; diff --git a/packages/ui/certd-server/src/modules/basic/service/code-service.ts b/packages/ui/certd-server/src/modules/basic/service/code-service.ts index c589cbb4..65a9daaa 100644 --- a/packages/ui/certd-server/src/modules/basic/service/code-service.ts +++ b/packages/ui/certd-server/src/modules/basic/service/code-service.ts @@ -5,8 +5,8 @@ import { SmsServiceFactory } from '../sms/factory.js'; import { ISmsService } from '../sms/api.js'; import { CodeErrorException } from '@certd/lib-server/dist/basic/exception/code-error-exception.js'; import { EmailService } from './email-service.js'; -import { AccessService } from '../../pipeline/service/access-service.js'; -import { AccessSysGetter } from '../../pipeline/service/access-sys-getter.js'; +import { AccessService } from '@certd/lib-server'; +import { AccessSysGetter } from '@certd/lib-server'; import { isComm } from '@certd/plus-core'; // {data: '', text: 'abcd'} diff --git a/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts b/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts index fbfb7fb3..616ca19a 100644 --- a/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts +++ b/packages/ui/certd-server/src/modules/cname/service/cname-record-service.ts @@ -7,7 +7,7 @@ import { createDnsProvider, IDnsProvider, parseDomain } from '@certd/plugin-cert import { CnameProvider, CnameRecord } from '@certd/pipeline'; import { cache, http, logger, utils } from '@certd/basic'; -import { AccessService } from '../../pipeline/service/access-service.js'; +import { AccessService } from '@certd/lib-server'; import { isDev } from '@certd/basic'; import { walkTxtRecord } from '@certd/acme-client'; import { CnameProviderService } from './cname-provider-service.js'; diff --git a/packages/ui/certd-server/src/modules/pipeline/entity/pipeline.ts b/packages/ui/certd-server/src/modules/pipeline/entity/pipeline.ts index 145f922c..a88da45a 100644 --- a/packages/ui/certd-server/src/modules/pipeline/entity/pipeline.ts +++ b/packages/ui/certd-server/src/modules/pipeline/entity/pipeline.ts @@ -29,6 +29,14 @@ export class PipelineEntity { @Column({ comment: '启用/禁用', nullable: true, default: false }) disabled: boolean; + // cert: 证书; backup: 备份; custom:自定义; + @Column({ comment: '类型', nullable: true, default: 'cert' }) + type: string; + + // custom: 自定义; monitor: 监控; + @Column({ comment: '来源', nullable: true, default: 'custom' }) + from: string; + @Column({ name: 'last_history_time', comment: '最后一次执行时间', diff --git a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts index c437fbcc..c947c303 100644 --- a/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts +++ b/packages/ui/certd-server/src/modules/pipeline/service/pipeline-service.ts @@ -1,11 +1,20 @@ import { Config, Inject, Provide, Scope, ScopeEnum, sleep } from '@midwayjs/core'; import { InjectEntityModel } from '@midwayjs/typeorm'; import { In, MoreThan, Repository } from 'typeorm'; -import { BaseService, NeedVIPException, PageReq, SysPublicSettings, SysSettingsService, SysSiteInfo } from '@certd/lib-server'; +import { + AccessGetter, + AccessService, + BaseService, + NeedSuiteException, + NeedVIPException, + PageReq, + SysPublicSettings, + SysSettingsService, + SysSiteInfo, +} from '@certd/lib-server'; import { PipelineEntity } from '../entity/pipeline.js'; import { PipelineDetail } from '../entity/vo/pipeline-detail.js'; -import { Executor, Pipeline, ResultType, RunHistory, SysInfo, UserInfo } from '@certd/pipeline'; -import { AccessService } from './access-service.js'; +import { Executor, Pipeline, ResultType, RunHistory, RunnableCollection, SysInfo, UserInfo } from '@certd/pipeline'; import { DbStorage } from './db-storage.js'; import { StorageService } from './storage-service.js'; import { Cron } from '../../cron/cron.js'; @@ -15,26 +24,26 @@ import { HistoryLogEntity } from '../entity/history-log.js'; import { HistoryLogService } from './history-log-service.js'; import { EmailService } from '../../basic/service/email-service.js'; import { UserService } from '../../sys/authority/service/user-service.js'; -import { AccessGetter } from './access-getter.js'; import { CnameRecordService } from '../../cname/service/cname-record-service.js'; import { CnameProxyService } from './cname-proxy-service.js'; import { PluginConfigGetter } from '../../plugin/service/plugin-config-getter.js'; import dayjs from 'dayjs'; import { DbAdapter } from '../../db/index.js'; -import { isComm, isPlus } from '@certd/plus-core'; +import { isComm } from '@certd/plus-core'; import { logger } from '@certd/basic'; import { UrlService } from './url-service.js'; import { NotificationService } from './notification-service.js'; import { NotificationGetter } from './notification-getter.js'; +import { UserSuiteService } from '@certd/commercial-core'; +import { CertInfoService } from '../../monitor/service/cert-info-service.js'; const runningTasks: Map = new Map(); -const freeCount = 10; /** * 证书申请 */ @Provide() -@Scope(ScopeEnum.Singleton) +@Scope(ScopeEnum.Request, { allowDowngrade: true }) export class PipelineService extends BaseService { @InjectEntityModel(PipelineEntity) repository: Repository; @@ -60,6 +69,9 @@ export class PipelineService extends BaseService { @Inject() userService: UserService; + @Inject() + userSuiteService: UserSuiteService; + @Inject() cron: Cron; @@ -75,6 +87,9 @@ export class PipelineService extends BaseService { @Inject() dbAdapter: DbAdapter; + @Inject() + certInfoService: CertInfoService; + //@ts-ignore getRepository() { return this.repository; @@ -144,26 +159,19 @@ export class PipelineService extends BaseService { //修改 old = await this.info(bean.id); } + const pipeline = JSON.parse(bean.content || '{}'); const isUpdate = bean.id > 0 && old != null; + + let domains = []; + RunnableCollection.each(pipeline.stages, (runnable: any) => { + if (runnable.runnableType === 'step' && runnable.type.startsWith('CertApply')) { + domains = runnable.input.domains || []; + } + }); + if (!isUpdate) { //如果是添加,校验数量 - if (!isPlus()) { - const count = await this.repository.count(); - if (count >= freeCount) { - throw new NeedVIPException(`基础版最多只能创建${freeCount}条流水线`); - } - } - const userId = bean.userId; - const userIsAdmin = await this.userService.isAdmin(userId); - if (!userIsAdmin) { - //非管理员用户,限制pipeline数量 - const count = await this.repository.count({ where: { userId } }); - const sysPublic = await this.sysSettingsService.getSetting(SysPublicSettings); - const limitUserPipelineCount = sysPublic.limitUserPipelineCount; - if (limitUserPipelineCount && limitUserPipelineCount > 0 && count >= limitUserPipelineCount) { - throw new NeedVIPException(`您最多只能创建${limitUserPipelineCount}条流水线`); - } - } + await this.checkMaxPipelineCount(bean, pipeline, domains); } if (!isUpdate) { @@ -171,19 +179,51 @@ export class PipelineService extends BaseService { await this.addOrUpdate(bean); } await this.clearTriggers(bean.id); - if (bean.content) { - const pipeline = JSON.parse(bean.content); - if (pipeline.title) { - bean.title = pipeline.title; - } - pipeline.id = bean.id; - bean.content = JSON.stringify(pipeline); + if (pipeline.title) { + bean.title = pipeline.title; } + pipeline.id = bean.id; + bean.content = JSON.stringify(pipeline); await this.addOrUpdate(bean); await this.registerTriggerById(bean.id); + + //保存域名信息到certInfo表 + await this.certInfoService.updateDomains(pipeline.id, domains); return bean; } + private async checkMaxPipelineCount(bean: PipelineEntity, pipeline: Pipeline, domains: string[]) { + // if (!isPlus()) { + // const count = await this.repository.count(); + // if (count >= freeCount) { + // throw new NeedVIPException(`基础版最多只能创建${freeCount}条流水线`); + // } + // } + if (isComm()) { + //校验pipelineCount + const userSuite = await this.userSuiteService.getMySuiteDetail(bean.userId); + if (userSuite?.pipelineCount.used + 1 > userSuite?.pipelineCount.max) { + throw new NeedSuiteException(`对不起,您最多只能创建${userSuite?.pipelineCount.max}条流水线,请购买或升级套餐`); + } + + if (userSuite.domainCount.used + domains.length > userSuite.domainCount.max) { + throw new NeedSuiteException(`对不起,您最多只能添加${userSuite.domainCount.max}个域名,请购买或升级套餐`); + } + } + + const userId = bean.userId; + const userIsAdmin = await this.userService.isAdmin(userId); + if (!userIsAdmin) { + //非管理员用户,限制pipeline数量 + const count = await this.repository.count({ where: { userId } }); + const sysPublic = await this.sysSettingsService.getSetting(SysPublicSettings); + const limitUserPipelineCount = sysPublic.limitUserPipelineCount; + if (limitUserPipelineCount && limitUserPipelineCount > 0 && count >= limitUserPipelineCount) { + throw new NeedVIPException(`您最多只能创建${limitUserPipelineCount}条流水线`); + } + } + } + async foreachPipeline(callback: (pipeline: PipelineEntity) => void) { const idEntityList = await this.repository.find({ select: { @@ -578,4 +618,8 @@ export class PipelineService extends BaseService { { groupId } ); } + + async getUserPipelineCount(userId) { + return await this.repository.count({ where: { userId } }); + } } diff --git a/packages/ui/certd-server/src/modules/suite/service/my-count-service.ts b/packages/ui/certd-server/src/modules/suite/service/my-count-service.ts new file mode 100644 index 00000000..9faa2f14 --- /dev/null +++ b/packages/ui/certd-server/src/modules/suite/service/my-count-service.ts @@ -0,0 +1,31 @@ +import { Inject, Provide, Scope, ScopeEnum } from '@midwayjs/core'; +import { PipelineService } from '../../pipeline/service/pipeline-service.js'; +import { CertInfoService } from '../../monitor/service/cert-info-service.js'; +import { IUsedCountService } from '@certd/commercial-core'; +import { SiteInfoService } from '../../monitor/service/site-info-service.js'; + +@Provide('myCountService') +@Scope(ScopeEnum.Request, { allowDowngrade: true }) +export class MyCountService implements IUsedCountService { + @Inject() + pipelineService: PipelineService; + + @Inject() + certInfoService: CertInfoService; + @Inject() + siteInfoService: SiteInfoService; + + async getUsedCount(userId: number) { + if (!userId) { + throw new Error('userId is required'); + } + const pipelineCountUsed = await this.pipelineService.getUserPipelineCount(userId); + const domainCountUsed = await this.certInfoService.getUserDomainCount(userId); + const monitorCountUsed = await this.siteInfoService.getUserMonitorCount(userId); + return { + pipelineCountUsed, + domainCountUsed, + monitorCountUsed, + }; + } +} diff --git a/packages/ui/certd-server/src/modules/sys/authority/service/user-service.ts b/packages/ui/certd-server/src/modules/sys/authority/service/user-service.ts index 212ae86c..5a0e49f8 100644 --- a/packages/ui/certd-server/src/modules/sys/authority/service/user-service.ts +++ b/packages/ui/certd-server/src/modules/sys/authority/service/user-service.ts @@ -206,6 +206,9 @@ export class UserService extends BaseService { }); delete newUser.password; + + utils.mitter.emit('register', { userId: newUser.id }); + return newUser; }