mirror of https://github.com/certd/certd
perf: 用户创建证书流水线没有购买套餐或者超限时提前报错
parent
f5ec9870fd
commit
472f06c2d1
|
@ -34,6 +34,8 @@ services:
|
|||
# #↓↓↓↓ ----------------------------- 如果忘记管理员密码,可以设置为true,重启之后,管理员密码将改成123456,然后请及时修改回false
|
||||
- certd_system_resetAdminPasswd=false
|
||||
# 默认使用sqlite文件数据库,如果需要使用其他数据库,请设置以下环境变量
|
||||
# 注意: 选定使用一种数据库之后,不支持更换数据库。
|
||||
# 数据库迁移方法:1、使用新数据库重新部署一套,然后将旧数据同步过去,注意flyway_history表的数据不要同步
|
||||
# #↓↓↓↓ ----------------------------- 使用postgresql数据库,需要提前创建数据库
|
||||
# - certd_flyway_scriptDir=./db/migration-pg # 升级脚本目录
|
||||
# - certd_typeorm_dataSource_default_type=postgres # 数据库类型
|
||||
|
|
|
@ -146,6 +146,10 @@ export class RunnableCollection {
|
|||
|
||||
static initPipelineRunnableType(pipeline: Pipeline) {
|
||||
pipeline.runnableType = "pipeline";
|
||||
if (pipeline.stages === undefined) {
|
||||
pipeline.stages = [];
|
||||
return;
|
||||
}
|
||||
pipeline.stages.forEach((stage) => {
|
||||
stage.runnableType = "stage";
|
||||
stage.tasks.forEach((task) => {
|
||||
|
|
|
@ -4,10 +4,13 @@ import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, Edi
|
|||
import { siteInfoApi } from "./api";
|
||||
import dayjs from "dayjs";
|
||||
import { notification } from "ant-design-vue";
|
||||
import { useSettingStore } from "/@/store/modules/settings";
|
||||
import { mySuiteApi } from "/@/views/certd/suite/mine/api";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const { t } = useI18n();
|
||||
const api = siteInfoApi;
|
||||
const { crudBinding } = crudExpose;
|
||||
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
|
||||
return await api.GetList(query);
|
||||
};
|
||||
|
@ -28,6 +31,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
return res;
|
||||
};
|
||||
|
||||
const settingsStore = useSettingStore();
|
||||
|
||||
return {
|
||||
crudOptions: {
|
||||
request: {
|
||||
|
@ -51,6 +56,37 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
width: 600
|
||||
}
|
||||
},
|
||||
actionbar: {
|
||||
buttons: {
|
||||
add: {
|
||||
async click() {
|
||||
if (!settingsStore.isPlus) {
|
||||
//非plus
|
||||
if (crudBinding.value.data.length >= 1) {
|
||||
notification.error({
|
||||
message: "基础版只能添加一个监控站点"
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//检查是否监控站点数量超出限制
|
||||
if (settingsStore.isComm && settingsStore.suiteSetting.enabled) {
|
||||
//检查数量是否超限
|
||||
const suiteDetail = await mySuiteApi.SuiteDetailGet();
|
||||
const max = suiteDetail.monitorCount.max;
|
||||
if (max != -1 && max <= suiteDetail.monitorCount.used) {
|
||||
notification.error({
|
||||
message: `对不起,您最多只能创建条${max}监控记录,请购买或升级套餐`
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
await crudExpose.openAdd({});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
rowHandle: {
|
||||
fixed: "right",
|
||||
width: 240,
|
||||
|
@ -111,6 +147,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
form: {
|
||||
rules: [
|
||||
{ required: true, message: "请输入域名" },
|
||||
//@ts-ignore
|
||||
{ type: "domains", message: "请输入正确的域名" }
|
||||
]
|
||||
},
|
||||
|
|
|
@ -15,6 +15,7 @@ import { useModal } from "/@/use/use-modal";
|
|||
import CertView from "./cert-view.vue";
|
||||
import { eachStages } from "./utils";
|
||||
import { createNotificationApi as createNotificationApi } from "../notification/api";
|
||||
import { mySuiteApi } from "/@/views/certd/suite/mine/api";
|
||||
export default function ({ crudExpose, context: { certdFormRef, groupDictRef, selectedRowKeys } }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
@ -94,7 +95,23 @@ export default function ({ crudExpose, context: { certdFormRef, groupDictRef, se
|
|||
lastResRef.value = res;
|
||||
return res;
|
||||
};
|
||||
function addCertdPipeline() {
|
||||
|
||||
const settingsStore = useSettingStore();
|
||||
async function addCertdPipeline() {
|
||||
//检查是否流水线数量超出限制
|
||||
if (settingsStore.isComm && settingsStore.suiteSetting.enabled) {
|
||||
//检查数量是否超限
|
||||
|
||||
const suiteDetail = await mySuiteApi.SuiteDetailGet();
|
||||
const max = suiteDetail.pipelineCount.max;
|
||||
if (max != -1 && max <= suiteDetail.pipelineCount.used) {
|
||||
notification.error({
|
||||
message: `对不起,您最多只能创建${max}条流水线,请购买或升级套餐`
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
certdFormRef.value.open(async ({ form }: any) => {
|
||||
// 添加certd pipeline
|
||||
const triggers = [];
|
||||
|
|
|
@ -16,7 +16,7 @@ export type SuiteDetail = {
|
|||
monitorCount?: SuiteValue;
|
||||
};
|
||||
|
||||
export default {
|
||||
export const mySuiteApi = {
|
||||
async GetList(query: any) {
|
||||
return await request({
|
||||
url: apiPrefix + "/page",
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||
import api from "./api";
|
||||
import { mySuiteApi as api } from "./api";
|
||||
import { useRouter } from "vue-router";
|
||||
import SuiteValueEdit from "/@/views/sys/suite/product/suite-value-edit.vue";
|
||||
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
|
||||
import DurationValue from "/@/views/sys/suite/product/duration-value.vue";
|
||||
import dayjs from "dayjs";
|
||||
import UserSuiteStatus from "/@/views/certd/suite/mine/user-suite-status.vue";
|
||||
|
||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
import { computed, onActivated, onMounted, ref } from "vue";
|
||||
import { useFs } from "@fast-crud/fast-crud";
|
||||
import createCrudOptions from "./crud";
|
||||
import api, { SuiteDetail } from "/@/views/certd/suite/mine/api";
|
||||
import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api";
|
||||
import SuiteCard from "/@/views/framework/home/dashboard/suite-card.vue";
|
||||
|
||||
defineOptions({
|
||||
|
@ -35,7 +35,7 @@ const currentSuite = computed(() => {
|
|||
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { detail, currentSuite } });
|
||||
|
||||
async function loadSuiteDetail() {
|
||||
detail.value = await api.SuiteDetailGet();
|
||||
detail.value = await mySuiteApi.SuiteDetailGet();
|
||||
}
|
||||
|
||||
// 页面打开后获取列表数据
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
|
||||
import { ref } from "vue";
|
||||
import ExpiresTimeText from "/@/components/expires-time-text.vue";
|
||||
import api, { SuiteDetail } from "/@/views/certd/suite/mine/api";
|
||||
import { mySuiteApi, SuiteDetail } from "/@/views/certd/suite/mine/api";
|
||||
import { FsIcon } from "@fast-crud/fast-crud";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
|
@ -60,7 +60,7 @@ defineOptions({
|
|||
const detail = ref<SuiteDetail>({});
|
||||
|
||||
async function loadSuiteDetail() {
|
||||
detail.value = await api.SuiteDetailGet();
|
||||
detail.value = await mySuiteApi.SuiteDetailGet();
|
||||
}
|
||||
|
||||
loadSuiteDetail();
|
||||
|
|
|
@ -166,6 +166,11 @@ export default defineComponent({
|
|||
{
|
||||
required: true,
|
||||
message: "请输入图片验证码"
|
||||
},
|
||||
{
|
||||
min: 4,
|
||||
max: 4,
|
||||
message: "请输入4位图片验证码"
|
||||
}
|
||||
],
|
||||
smsCode: [
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<div style="height: 400px">
|
||||
<ProductManager @refreshed="onTableRefresh"></ProductManager>
|
||||
</div>
|
||||
<div class="helper">不建议设置免费套餐,可以在下方配置注册赠送套餐</div>
|
||||
<div class="helper">不建议设置免费套餐,可以在下方配置注册赠送套餐,或者在用户套餐管理中手动赠送套餐</div>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="注册赠送套餐" name="registerGift">
|
||||
|
|
|
@ -139,17 +139,27 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
|||
type: "dict-select",
|
||||
column: { show: false },
|
||||
addForm: {
|
||||
show: true,
|
||||
component: {
|
||||
name: SuiteDurationSelector,
|
||||
vModel: "modelValue"
|
||||
},
|
||||
rules: [{ required: true, message: "请选择套餐" }]
|
||||
rules: [
|
||||
{
|
||||
validator: async (rule, value) => {
|
||||
if (value && value.productId) {
|
||||
return true;
|
||||
}
|
||||
throw new Error("请选择套餐");
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
valueResolve({ form, value }) {
|
||||
if (value) {
|
||||
const arr = value.splict("_");
|
||||
form.productId = parseInt(arr[0]);
|
||||
form.duration = parseInt(arr[1]);
|
||||
debugger;
|
||||
if (value && value.productId) {
|
||||
form.productId = value.productId;
|
||||
form.duration = value.duration;
|
||||
}
|
||||
},
|
||||
form: { show: false }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Provide } from '@midwayjs/core';
|
||||
import { IWebMiddleware, IMidwayKoaContext, NextFunction } from '@midwayjs/koa';
|
||||
import { IMidwayKoaContext, IWebMiddleware, NextFunction } from '@midwayjs/koa';
|
||||
import { logger } from '@certd/basic';
|
||||
import { BaseException, Result } from '@certd/lib-server';
|
||||
import { Result } from '@certd/lib-server';
|
||||
|
||||
@Provide()
|
||||
export class GlobalExceptionMiddleware implements IWebMiddleware {
|
||||
|
@ -14,11 +14,7 @@ export class GlobalExceptionMiddleware implements IWebMiddleware {
|
|||
await next();
|
||||
logger.info('请求完成:', url, Date.now() - startTime + 'ms');
|
||||
} catch (err) {
|
||||
logger.error('请求异常:', url, Date.now() - startTime + 'ms', err.message);
|
||||
if (!(err instanceof BaseException)) {
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
logger.error('请求异常:', url, Date.now() - startTime + 'ms', err);
|
||||
ctx.status = 200;
|
||||
if (err.code == null || typeof err.code !== 'number') {
|
||||
err.code = 1;
|
||||
|
|
|
@ -30,6 +30,19 @@ export class QywxNotification extends BaseNotification {
|
|||
})
|
||||
mentionedList!: string[];
|
||||
|
||||
@NotificationInput({
|
||||
title: '提醒指定手机号成员',
|
||||
component: {
|
||||
name: 'a-select',
|
||||
vModel: 'value',
|
||||
mode: 'tags',
|
||||
open: false,
|
||||
},
|
||||
required: false,
|
||||
helper: '填写成员手机号,@all 为提醒所有人',
|
||||
})
|
||||
mentionedMobileList!: string[];
|
||||
|
||||
async send(body: NotificationBody) {
|
||||
if (!this.webhook) {
|
||||
throw new Error('webhook地址不能为空');
|
||||
|
@ -47,10 +60,11 @@ export class QywxNotification extends BaseNotification {
|
|||
url: this.webhook,
|
||||
method: 'POST',
|
||||
data: {
|
||||
msgtype: 'markdown',
|
||||
markdown: {
|
||||
content: `# ${body.title}\n\n${body.content}\n\n[查看详情](${body.url})`,
|
||||
msgtype: 'text',
|
||||
text: {
|
||||
content: `· ${body.title}\n· ${body.content}\n· 查看详情: ${body.url}`,
|
||||
mentioned_list: this.mentionedList,
|
||||
mentioned_mobile_list: this.mentionedMobileList,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue