mirror of https://github.com/certd/certd
perf: 同一时间只允许一个套餐生效
parent
7f596ed315
commit
8ebf95a222
|
@ -102,6 +102,7 @@ export class Executor {
|
|||
await this.notification("success");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (e: any) {
|
||||
await this.notification("error", e);
|
||||
this.logger.error("pipeline 执行失败", e);
|
||||
|
|
|
@ -8,14 +8,21 @@
|
|||
<a-col :span="24">
|
||||
<a-card>
|
||||
<div class="suite-intro-box">
|
||||
<div>套餐说明:多个套餐内的数量可以叠加</div>
|
||||
<div>说明:① 同一时间只有最新购买的一个套餐生效;② 可以购买多个加量包,加量包立即生效;③ 套餐和加量包内的数量可以叠加</div>
|
||||
<div v-if="suiteIntro" v-html="suiteIntro"></div>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<h3>套餐</h3>
|
||||
<a-row :gutter="8" class="mt-10">
|
||||
<a-col v-for="item of products" :key="item.id" class="mb-10 suite-card-col">
|
||||
<a-col v-for="item of suites" :key="item.id" class="mb-10 suite-card-col">
|
||||
<product-info :product="item" @order="doOrder" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<h3>加量包</h3>
|
||||
<a-row :gutter="8" class="mt-10">
|
||||
<a-col v-for="item of addons" :key="item.id" class="mb-10 suite-card-col">
|
||||
<product-info :product="item" @order="doOrder" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
@ -31,10 +38,13 @@ import * as api from "./api";
|
|||
import ProductInfo from "/@/views/certd/suite/product-info.vue";
|
||||
import OrderModal from "/@/views/certd/suite/order-modal.vue";
|
||||
|
||||
const products = ref([]);
|
||||
const suites = ref([]);
|
||||
const addons = ref([]);
|
||||
|
||||
async function loadProducts() {
|
||||
products.value = await api.ProductList();
|
||||
const list = await api.ProductList();
|
||||
suites.value = list.filter((x: any) => x.type === "suite");
|
||||
addons.value = list.filter((x: any) => x.type === "addone");
|
||||
}
|
||||
|
||||
loadProducts();
|
||||
|
|
|
@ -1,54 +1,71 @@
|
|||
import { request } from "/src/api/service";
|
||||
|
||||
export function createApi() {
|
||||
const apiPrefix = "/mine/suite";
|
||||
return {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
});
|
||||
},
|
||||
const apiPrefix = "/mine/suite";
|
||||
|
||||
async AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
export type SuiteValue = {
|
||||
max: number;
|
||||
used: number;
|
||||
};
|
||||
export type SuiteDetail = {
|
||||
enabled?: boolean;
|
||||
suites?: any[];
|
||||
expiresTime?: number;
|
||||
pipelineCount?: SuiteValue;
|
||||
domainCount?: SuiteValue;
|
||||
deployCount?: SuiteValue;
|
||||
monitorCount?: SuiteValue;
|
||||
};
|
||||
|
||||
async UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
export default {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
method: "post",
|
||||
data: query
|
||||
});
|
||||
},
|
||||
|
||||
async DelObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/delete",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
async AddObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/add",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
|
||||
async GetObj(id: number) {
|
||||
return await request({
|
||||
url: apiPrefix + "/info",
|
||||
method: "post",
|
||||
params: { id }
|
||||
});
|
||||
},
|
||||
async ListAll() {
|
||||
return await request({
|
||||
url: apiPrefix + "/all",
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
async UpdateObj(obj: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/update",
|
||||
method: "post",
|
||||
data: obj
|
||||
});
|
||||
},
|
||||
|
||||
export const pipelineGroupApi = createApi();
|
||||
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"
|
||||
});
|
||||
},
|
||||
async SuiteDetailGet() {
|
||||
return await request({
|
||||
url: `${apiPrefix}/detail`,
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import { pipelineGroupApi } from "./api";
|
||||
import 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";
|
||||
|
@ -7,7 +7,6 @@ import DurationValue from "/@/views/sys/suite/product/duration-value.vue";
|
|||
import dayjs from "dayjs";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const api = pipelineGroupApi;
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
|
@ -274,6 +273,15 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
if (now < row.activeTime) {
|
||||
return <a-tag color="blue">待生效</a-tag>;
|
||||
}
|
||||
|
||||
//是否是当前套餐
|
||||
const suites = context.detail.value.suites;
|
||||
if (suites && suites.length > 0) {
|
||||
const suite = suites[0];
|
||||
if (suite.productType === "suite" && suite.id === row.id) {
|
||||
return <a-tag color="success">当前套餐</a-tag>;
|
||||
}
|
||||
}
|
||||
// 是否在激活时间和过期时间之间
|
||||
if (now > row.activeTime && (row.expiresTime == -1 || now < row.expiresTime)) {
|
||||
return <a-tag color="success">生效中</a-tag>;
|
||||
|
|
|
@ -11,18 +11,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent, onActivated, onMounted } from "vue";
|
||||
import { onActivated, onMounted, ref } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import { createApi } from "./api";
|
||||
import api, { SuiteDetail } from "/@/views/certd/suite/mine/api";
|
||||
|
||||
defineOptions({
|
||||
name: "MySuites"
|
||||
});
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: {} });
|
||||
const detail = ref<SuiteDetail>({});
|
||||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { detail } });
|
||||
|
||||
async function loadSuiteDetail() {
|
||||
detail.value = await api.SuiteDetailGet();
|
||||
}
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
onMounted(() => {
|
||||
crudExpose.doRefresh();
|
||||
onMounted(async () => {
|
||||
await loadSuiteDetail();
|
||||
await crudExpose.doRefresh();
|
||||
});
|
||||
onActivated(() => {
|
||||
crudExpose.doRefresh();
|
||||
|
|
|
@ -38,38 +38,16 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { request } from "/@/api/service";
|
||||
import dayjs from "dayjs";
|
||||
import { ref } from "vue";
|
||||
import ExpiresTimeText from "/@/components/expires-time-text.vue";
|
||||
import api, { SuiteDetail } from "/@/views/certd/suite/mine/api";
|
||||
|
||||
defineOptions({
|
||||
name: "SuiteCard"
|
||||
});
|
||||
|
||||
type SuiteValue = {
|
||||
max: number;
|
||||
used: number;
|
||||
};
|
||||
type SuiteDetail = {
|
||||
enabled?: boolean;
|
||||
suites?: any[];
|
||||
expiresTime?: number;
|
||||
pipelineCount?: SuiteValue;
|
||||
domainCount?: SuiteValue;
|
||||
deployCount?: SuiteValue;
|
||||
monitorCount?: SuiteValue;
|
||||
};
|
||||
const detail = ref<SuiteDetail>({});
|
||||
|
||||
const api = {
|
||||
async SuiteDetailGet() {
|
||||
return await request({
|
||||
url: "/mine/suite/detail",
|
||||
method: "post"
|
||||
});
|
||||
}
|
||||
};
|
||||
async function loadSuiteDetail() {
|
||||
detail.value = await api.SuiteDetailGet();
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
form: {
|
||||
value: "suite",
|
||||
rules: [{ required: true, message: "此项必填" }],
|
||||
helper: "目前没区别,重复购买可叠加数量"
|
||||
helper: "套餐:同一时间只有最新购买的一个生效\n加量包:可购买多个,购买后立即生效,不影响套餐\n套餐和加量包数量可叠加"
|
||||
},
|
||||
column: {
|
||||
width: 80,
|
||||
|
|
|
@ -57,6 +57,7 @@ CREATE TABLE "cd_user_suite"
|
|||
"deploy_count_used" integer,
|
||||
"is_present" boolean,
|
||||
"is_bootstrap" boolean,
|
||||
"is_empty" boolean,
|
||||
"disabled" boolean NOT NULL DEFAULT (false),
|
||||
"active_time" integer,
|
||||
"expires_time" integer,
|
||||
|
|
|
@ -72,7 +72,7 @@ const development = {
|
|||
type: 'better-sqlite3',
|
||||
database: './data/db.sqlite',
|
||||
synchronize: false, // 如果第一次使用,不存在表,有同步的需求可以写 true
|
||||
logging: false,
|
||||
logging: true,
|
||||
highlightSql: false,
|
||||
|
||||
// 配置实体模型 或者 entities: '/entity',
|
||||
|
|
|
@ -34,7 +34,7 @@ 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 { UserSuiteEntity, UserSuiteService } from '@certd/commercial-core';
|
||||
import { CertInfoService } from '../../monitor/service/cert-info-service.js';
|
||||
|
||||
const runningTasks: Map<string | number, Executor> = new Map();
|
||||
|
@ -391,6 +391,11 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||
async run(id: number, triggerId: string, stepId?: string) {
|
||||
const entity: PipelineEntity = await this.info(id);
|
||||
|
||||
let suite: UserSuiteEntity = null;
|
||||
if (isComm()) {
|
||||
suite = await this.userSuiteService.checkHasDeployCount(entity.userId);
|
||||
}
|
||||
|
||||
const pipeline = JSON.parse(entity.content);
|
||||
if (!pipeline.id) {
|
||||
pipeline.id = id;
|
||||
|
@ -464,7 +469,14 @@ export class PipelineService extends BaseService<PipelineEntity> {
|
|||
// 清除该step的状态
|
||||
executor.clearLastStatus(stepId);
|
||||
}
|
||||
await executor.run(historyId, triggerType);
|
||||
const result = await executor.run(historyId, triggerType);
|
||||
|
||||
if (result === ResultType.success) {
|
||||
if (isComm()) {
|
||||
// 消耗成功次数
|
||||
await this.userSuiteService.consumeDeployCount(suite, 1);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('执行失败:', e);
|
||||
// throw e;
|
||||
|
|
Loading…
Reference in New Issue