Merge branch 'v2-dev' into v2-invite

This commit is contained in:
xiaojunnuo
2026-05-25 22:36:40 +08:00
40 changed files with 325 additions and 77 deletions
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Performance Improvements
* 商业版套餐只支持设置为可叠加 ([5e72f75](https://github.com/certd/certd/commit/5e72f75395fb632a30e80c07d35d8ba40ef631fa))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.40.3",
"version": "1.40.4",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -106,8 +106,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.40.3",
"@certd/pipeline": "^1.40.3",
"@certd/lib-iframe": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",
@@ -8,7 +8,7 @@
<a-col :span="24">
<a-card>
<div class="suite-intro-box">
<div>说明 同一时间只有最新购买的一个套餐生效 可以购买多个加量包加量包立即生效 套餐和加量包内的数量可以叠加</div>
<div>{{ buyHelperText }}</div>
<div v-if="suiteIntro" v-html="suiteIntro"></div>
</div>
</a-card>
@@ -31,7 +31,7 @@
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { computed, ref } from "vue";
import * as api from "./api";
import ProductInfo from "/@/views/certd/suite/product-info.vue";
import OrderModal from "/@/views/certd/suite/order-modal.vue";
@@ -55,9 +55,17 @@ async function doOrder(req: any) {
}
const suiteIntro = ref("");
const allowSuiteStack = ref(false);
const buyHelperText = computed(() => {
if (allowSuiteStack.value) {
return "说明:可以购买多个套餐和加量包,套餐和加量包内的数量可以叠加";
}
return "说明:① 同一时间只有最新购买的一个套餐生效;② 可以购买多个加量包,加量包立即生效;③ 套餐和加量包内的数量可以叠加";
});
async function loadSuiteIntro() {
const res = await api.GetSuiteSetting();
suiteIntro.value = res.intro;
allowSuiteStack.value = !!res.allowSuiteStack;
}
loadSuiteIntro();
</script>
@@ -4,8 +4,14 @@
<a-popover>
<template #content>
<div style="width: 300px">
<div v-if="detail.addonList.length > 0" class="flex flex-wrap">
<a-tag v-for="(item, index) of detail.addonList" :key="index" color="green" class="pointer flex-o m-1">
<div v-if="hiddenSuiteList.length > 0 || detail.addonList.length > 0" class="flex flex-wrap">
<a-tag v-for="(item, index) of hiddenSuiteList" :key="`suite-${index}`" color="green" class="pointer flex-o m-1">
<span class="mr-5">
{{ item.title }}
</span>
<span>(<expires-time-text :value="item.expiresTime" />)</span>
</a-tag>
<a-tag v-for="(item, index) of detail.addonList" :key="`addon-${index}`" color="green" class="pointer flex-o m-1">
<span class="mr-5">
{{ item.title }}
</span>
@@ -43,13 +49,13 @@
</template>
<div class="flex-o">
<fs-icon icon="ant-design:gift-outlined" class="color-green mr-5" />
<a-tag v-for="(item, index) of detail.suiteList" :key="index" color="green" class="pointer flex-o">
<a-tag v-if="currentSuite" color="green" class="pointer flex-o">
<span class="mr-5">
{{ item.title }}
{{ currentSuite.title }}
</span>
<span>(<expires-time-text :value="item.expiresTime" />)</span>
<span>(<expires-time-text :value="currentSuite.expiresTime" />)</span>
<span v-if="hiddenCount > 0" class="ml-5">+{{ hiddenCount }}</span>
</a-tag>
<a-tag v-if="detail.addonList.length > 0" color="green" class="pointer flex-o">加量包+{{ detail.addonList.length }}</a-tag>
<div v-if="detail.suites?.length === 0" class="flex-o ml-5">暂无套餐 <a-button class="ml-5" type="primary" size="small" @click="goBuy">去购买</a-button></div>
</div>
</a-popover>
@@ -59,7 +65,7 @@
<script lang="ts" setup>
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
import { ref } from "vue";
import { computed, ref } from "vue";
import ExpiresTimeText from "/@/components/expires-time-text.vue";
import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api";
import { FsIcon } from "@fast-crud/fast-crud";
@@ -71,6 +77,10 @@ defineOptions({
const detail = ref<SuiteDetail>({});
const currentSuite = computed(() => detail.value.suiteList?.[0]);
const hiddenSuiteList = computed(() => detail.value.suiteList?.slice(1) || []);
const hiddenCount = computed(() => hiddenSuiteList.value.length + (detail.value.addonList?.length || 0));
async function loadSuiteDetail() {
detail.value = await mySuiteApi.SuiteDetailGet();
const suites = detail.value.suites.filter(item => item.productType === "suite");
@@ -21,6 +21,11 @@
<div class="helper">不建议设置免费套餐可以在下方配置注册赠送套餐或者在用户套餐管理中手动赠送套餐</div>
</a-form-item>
<a-form-item label="套餐支持叠加" name="allowSuiteStack">
<a-switch v-model:checked="formState.allowSuiteStack" />
<div class="helper">默认只有一个套餐生效开启此开关可以让多个套餐可以叠加加量包无论是否开启此开关都可以叠加</div>
</a-form-item>
<a-form-item label="注册赠送套餐" name="registerGift">
<suite-duration-selector ref="suiteDurationSelectedRef" v-model="formState.registerGift"></suite-duration-selector>
<div class="helper">添加套餐后再选择</div>
@@ -73,6 +78,7 @@ const formRef = ref<any>(null);
const formState = reactive<
Partial<{
enabled: boolean;
allowSuiteStack: boolean;
registerGift?: {
productId?: number;
duration?: number;
+10
View File
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.40.4](https://github.com/certd/certd/compare/v1.40.3...v1.40.4) (2026-05-24)
### Bug Fixes
* **pipeline-service:** 修复流水线运行时超过套餐部署次数仍然能够正常运行的bug ([5e59651](https://github.com/certd/certd/commit/5e59651d45bc91919629e35995ff1b3cff6b87ea))
### Performance Improvements
* 新增阿里云直播证书部署插件 ([8edb6f8](https://github.com/certd/certd/commit/8edb6f8727bd148f106801bef25567880fd35e9e))
## [1.40.3](https://github.com/certd/certd/compare/v1.40.2...v1.40.3) (2026-05-21)
### Bug Fixes
@@ -0,0 +1,96 @@
showRunStrategy: false
default:
strategy:
runStrategy: 1
name: DeployCertToAliyunLive
title: 阿里云-部署至直播(Live
icon: svg:icon-aliyun
group: aliyun
desc: 部署证书到阿里云视频直播(Live)域名
needPlus: false
input:
cert:
title: 域名证书
helper: 请选择前置任务输出的域名证书
component:
name: output-selector
from:
- ':cert:'
- uploadCertToAliyun
template: false
required: true
order: 0
certDomains:
title: 当前证书域名
component:
name: cert-domains-getter
mergeScript: |2-
return {
component:{
inputKey: ctx.compute(({form})=>{
return form.cert
}),
}
}
template: false
required: false
order: 0
accessId:
title: Access授权
helper: 阿里云授权AccessKeyId、AccessKeySecret
component:
name: access-selector
type: aliyun
required: true
order: 0
endpoint:
title: 证书服务接入点
helper: 不会选就按默认
value: cas.aliyuncs.com
component:
name: a-select
options:
- value: cas.aliyuncs.com
label: 中国大陆
- value: cas.ap-southeast-1.aliyuncs.com
label: 新加坡
- value: cas.eu-central-1.aliyuncs.com
label: 德国(法兰克福)
required: true
order: 0
domainList:
title: 直播域名
component:
name: remote-select
vModel: value
mode: tags
type: plugin
typeName: DeployCertToAliyunLive
action: onGetDomainList
search: true
pager: true
multi: true
watches:
- certDomains
- accessId
- certDomains
- accessId
required: true
mergeScript: |2-
return {
component:{
form: ctx.compute(({form})=>{
return form
})
},
}
helper: 请选择要部署证书的直播域名
order: 0
output: {}
pluginType: deploy
type: builtIn
scriptFilePath: /plugins/plugin-aliyun/plugin/deploy-to-live/index.js
+14 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-server",
"version": "1.40.3",
"version": "1.40.4",
"description": "fast-server base midway",
"private": true,
"type": "module",
@@ -53,20 +53,20 @@
"@aws-sdk/client-sts": "^3.990.0",
"@azure/arm-dns": "^5.1.0",
"@azure/identity": "^4.13.1",
"@certd/acme-client": "^1.40.3",
"@certd/basic": "^1.40.3",
"@certd/commercial-core": "^1.40.3",
"@certd/acme-client": "^1.40.4",
"@certd/basic": "^1.40.4",
"@certd/commercial-core": "^1.40.4",
"@certd/cv4pve-api-javascript": "^8.4.2",
"@certd/jdcloud": "^1.40.3",
"@certd/lib-huawei": "^1.40.3",
"@certd/lib-k8s": "^1.40.3",
"@certd/lib-server": "^1.40.3",
"@certd/midway-flyway-js": "^1.40.3",
"@certd/pipeline": "^1.40.3",
"@certd/plugin-cert": "^1.40.3",
"@certd/plugin-lib": "^1.40.3",
"@certd/plugin-plus": "^1.40.3",
"@certd/plus-core": "^1.40.3",
"@certd/jdcloud": "^1.40.4",
"@certd/lib-huawei": "^1.40.4",
"@certd/lib-k8s": "^1.40.4",
"@certd/lib-server": "^1.40.4",
"@certd/midway-flyway-js": "^1.40.4",
"@certd/pipeline": "^1.40.4",
"@certd/plugin-cert": "^1.40.4",
"@certd/plugin-lib": "^1.40.4",
"@certd/plugin-plus": "^1.40.4",
"@certd/plus-core": "^1.40.4",
"@google-cloud/dns": "^5.3.1",
"@google-cloud/publicca": "^1.3.0",
"@huaweicloud/huaweicloud-sdk-cdn": "3.1.185",
@@ -0,0 +1,38 @@
import assert from "assert";
import { PipelineEntity } from "../entity/pipeline.js";
import { PipelineService } from "./pipeline-service.js";
describe("PipelineService", () => {
it("does not start a pipeline run when beforeCheck fails", async () => {
const service = new PipelineService();
let historyStarted = false;
service.beforeCheck = async () => {
throw new Error("部署次数不足");
};
service.userService = {
async isAdmin() {
return false;
},
} as any;
service.historyService = {
async start() {
historyStarted = true;
throw new Error("history should not start");
},
} as any;
const entity = new PipelineEntity();
entity.id = 1;
entity.userId = 1;
entity.projectId = 0;
entity.content = JSON.stringify({
stages: [{ id: "stage1", tasks: [] }],
triggers: [],
});
await service.doRun(entity, null, "ALL");
assert.equal(historyStarted, false);
});
});
@@ -659,6 +659,7 @@ export class PipelineService extends BaseService<PipelineEntity> {
suite = res.suite
} catch (e) {
logger.error(`流水线${entity.id}触发失败(${triggerId}):${e.message}`);
return;
}
const id = entity.id;