mirror of https://github.com/certd/certd
chore: suite
parent
8057586dc1
commit
1c8e25beb3
|
@ -280,3 +280,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||||
.fs-16{
|
.fs-16{
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.w-50\%{
|
||||||
|
width: 50%;
|
||||||
|
}
|
|
@ -14,12 +14,12 @@ export async function GetLatestVersion() {
|
||||||
return latest;
|
return latest;
|
||||||
}
|
}
|
||||||
const res = await request({
|
const res = await request({
|
||||||
url: "https://registry.npmmirror.com/@certd/pipeline",
|
url: "/app/latest",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
unpack: false
|
unpack: true
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
const latest = res["dist-tags"].latest;
|
const latest = res;
|
||||||
LocalStorage.set("latestVersion", latest, 60 * 60 * 24);
|
LocalStorage.set("latestVersion", latest, 60 * 60 * 24);
|
||||||
return latest;
|
return latest;
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { computed, Ref, ref } from "vue";
|
import { Ref, ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes, utils } from "@fast-crud/fast-crud";
|
import { AddReq, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
|
||||||
import { useUserStore } from "/@/store/modules/user";
|
import { useUserStore } from "/@/store/modules/user";
|
||||||
import { useSettingStore } from "/@/store/modules/settings";
|
import { useSettingStore } from "/@/store/modules/settings";
|
||||||
import { Modal } from "ant-design-vue";
|
import SuiteValue from "./suite-value.vue";
|
||||||
|
import SuiteValueEdit from "./suite-value-edit.vue";
|
||||||
|
|
||||||
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -63,6 +64,20 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
minWidth: 200,
|
minWidth: 200,
|
||||||
fixed: "right"
|
fixed: "right"
|
||||||
},
|
},
|
||||||
|
form: {
|
||||||
|
group: {
|
||||||
|
groups: {
|
||||||
|
base: {
|
||||||
|
header: "基础信息",
|
||||||
|
columns: ["title", "type", "price", "originPrice", "duration", "isBootstrap", "intro"]
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
header: "套餐内容",
|
||||||
|
columns: ["maxDomainCount", "maxPipelineCount", "maxDeployCount", "siteMonitor"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
columns: {
|
columns: {
|
||||||
id: {
|
id: {
|
||||||
title: "ID",
|
title: "ID",
|
||||||
|
@ -78,11 +93,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
title: {
|
title: {
|
||||||
title: "套餐名称",
|
title: "套餐名称",
|
||||||
type: "text",
|
type: "text",
|
||||||
editForm: {
|
|
||||||
component: {
|
|
||||||
disabled: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
search: {
|
search: {
|
||||||
show: true
|
show: true
|
||||||
},
|
},
|
||||||
|
@ -93,77 +103,134 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
|
||||||
type: {
|
type: {
|
||||||
title: "类型",
|
title: "类型",
|
||||||
type: "dict-select",
|
type: "dict-select",
|
||||||
|
editForm: {
|
||||||
|
component: {
|
||||||
|
disabled: true
|
||||||
|
}
|
||||||
|
},
|
||||||
dict: dict({
|
dict: dict({
|
||||||
data: [
|
data: [
|
||||||
{ label: "套餐", value: "suite" },
|
{ label: "套餐", value: "suite" },
|
||||||
{ label: "加量包", value: "addon" }
|
{ label: "加量包", value: "addon" }
|
||||||
]
|
]
|
||||||
})
|
}),
|
||||||
|
column: {
|
||||||
|
width: 100
|
||||||
|
}
|
||||||
},
|
},
|
||||||
maxDomainCount: {
|
maxDomainCount: {
|
||||||
title: "域名数量",
|
title: "域名数量",
|
||||||
type: "number"
|
type: "number",
|
||||||
|
form: {
|
||||||
|
component: {
|
||||||
|
name: SuiteValueEdit,
|
||||||
|
vModel: "modelValue",
|
||||||
|
unit: "个"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 100,
|
||||||
|
component: {
|
||||||
|
name: SuiteValue
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
maxPipelineCount: {
|
maxPipelineCount: {
|
||||||
title: "流水线数量",
|
title: "流水线数量",
|
||||||
type: "number"
|
type: "number",
|
||||||
|
form: {
|
||||||
|
component: {
|
||||||
|
name: SuiteValueEdit,
|
||||||
|
vModel: "modelValue",
|
||||||
|
unit: "条"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 100,
|
||||||
|
component: {
|
||||||
|
name: SuiteValue
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
maxDeployCount: {
|
maxDeployCount: {
|
||||||
title: "部署次数",
|
title: "部署次数",
|
||||||
type: "number"
|
type: "number",
|
||||||
|
form: {
|
||||||
|
component: {
|
||||||
|
name: SuiteValueEdit,
|
||||||
|
vModel: "modelValue",
|
||||||
|
unit: "次"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 100,
|
||||||
|
component: {
|
||||||
|
name: SuiteValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
siteMonitor: {
|
||||||
|
title: "支持证书监控",
|
||||||
|
type: "dict-switch",
|
||||||
|
dict: dict({
|
||||||
|
data: [
|
||||||
|
{ label: "是", value: true, color: "success" },
|
||||||
|
{ label: "否", value: false, color: "error" }
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
column: {
|
||||||
|
width: 120
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isBootstrap: {
|
||||||
|
title: "是否初始套餐",
|
||||||
|
type: "dict-switch",
|
||||||
|
dict: dict({
|
||||||
|
data: [
|
||||||
|
{ label: "是", value: true, color: "success" },
|
||||||
|
{ label: "否", value: false, color: "error" }
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
column: {
|
||||||
|
width: 120
|
||||||
|
}
|
||||||
},
|
},
|
||||||
price: {
|
price: {
|
||||||
title: "单价",
|
title: "单价",
|
||||||
type: "number"
|
type: "number",
|
||||||
|
column: {
|
||||||
|
width: 100
|
||||||
|
}
|
||||||
},
|
},
|
||||||
originPrice: {
|
originPrice: {
|
||||||
title: "原价",
|
title: "原价",
|
||||||
type: "number"
|
type: "number",
|
||||||
|
column: {
|
||||||
|
width: 100
|
||||||
|
}
|
||||||
},
|
},
|
||||||
duration: {
|
duration: {
|
||||||
title: "有效时长",
|
title: "有效时长",
|
||||||
type: "number"
|
type: "dict-select",
|
||||||
|
column: {
|
||||||
|
width: 100
|
||||||
|
}
|
||||||
},
|
},
|
||||||
intro: {
|
intro: {
|
||||||
title: "说明",
|
title: "说明",
|
||||||
type: "textarea"
|
type: "textarea",
|
||||||
|
column: {
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
title: "排序",
|
title: "排序",
|
||||||
type: "number",
|
type: "number",
|
||||||
form: {
|
form: {
|
||||||
show: false
|
show: false
|
||||||
}
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
title: "禁用/启用",
|
|
||||||
type: "dict-switch",
|
|
||||||
dict: dict({
|
|
||||||
data: [
|
|
||||||
{ label: "启用", value: false, color: "success" },
|
|
||||||
{ label: "禁用", value: true, color: "error" }
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
form: {
|
|
||||||
value: false
|
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
width: 100,
|
width: 100
|
||||||
component: {
|
|
||||||
title: "点击可禁用/启用",
|
|
||||||
on: {
|
|
||||||
async click({ value, row }) {
|
|
||||||
Modal.confirm({
|
|
||||||
title: "提示",
|
|
||||||
content: `确定要${!value ? "禁用" : "启用"}吗?`,
|
|
||||||
onOk: async () => {
|
|
||||||
await api.SetDisabled(row.id, !value);
|
|
||||||
await crudExpose.doRefresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createTime: {
|
createTime: {
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<template>
|
||||||
|
<div class="cd-suite-value-edit flex-o">
|
||||||
|
<div class="flex- 1"><a-checkbox :checked="modelValue === -1" @update:checked="onCheckedChange">无限制</a-checkbox><span class="ml-5"></span></div>
|
||||||
|
<div class="ml-10 w-50%">
|
||||||
|
<a-input-number v-if="modelValue >= 0" :value="modelValue" class="ml-5" @update:value="onValueChange">
|
||||||
|
<template v-if="unit" #addonAfter>{{ unit }}</template>
|
||||||
|
</a-input-number>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Form } from "ant-design-vue";
|
||||||
|
import { dict } from "@fast-crud/fast-crud";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue?: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const durationDict = dict({
|
||||||
|
data: [
|
||||||
|
{ label: "1年", value: 365 },
|
||||||
|
{ label: "2年", value: 730 },
|
||||||
|
{ label: "3年", value: 1095 },
|
||||||
|
{ label: "4年", value: 1460 },
|
||||||
|
{ label: "5年", value: 1825 },
|
||||||
|
{ label: "6年", value: 2190 },
|
||||||
|
{ label: "7年", value: 2555 },
|
||||||
|
{ label: "8年", value: 2920 },
|
||||||
|
{ label: "9年", value: 3285 },
|
||||||
|
{ label: "10年", value: 3650 },
|
||||||
|
{ label: "永久", value: -1 }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const formItemContext = Form.useInjectFormItemContext();
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
|
const onCheckedChange = (checked: boolean) => {
|
||||||
|
const value = checked ? -1 : 1;
|
||||||
|
onValueChange(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onValueChange(value: number) {
|
||||||
|
emit("update:modelValue", value);
|
||||||
|
formItemContext.onFieldChange();
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -2,11 +2,8 @@
|
||||||
<fs-page class="page-cert">
|
<fs-page class="page-cert">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
CNAME服务配置
|
套餐管理
|
||||||
<span class="sub">
|
<span class="sub"> 必须设置一个初始套餐 </span>
|
||||||
此处配置的域名作为其他域名校验的代理,当别的域名需要申请证书时,通过CNAME映射到此域名上来验证所有权。好处是任何域名都可以通过此方式申请证书,也无需填写AccessSecret。
|
|
||||||
<a href="https://certd.docmirror.cn/guide/feature/cname/" target="_blank">CNAME功能原理及使用说明</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<fs-crud ref="crudRef" v-bind="crudBinding">
|
<fs-crud ref="crudRef" v-bind="crudBinding">
|
||||||
|
@ -27,7 +24,7 @@ import { message, Modal } from "ant-design-vue";
|
||||||
import { DeleteBatch } from "./api";
|
import { DeleteBatch } from "./api";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "CnameProvider"
|
name: "ProductManager"
|
||||||
});
|
});
|
||||||
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
|
const { crudBinding, crudRef, crudExpose, context } = useFs({ createCrudOptions });
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<div class="cd-suite-value-edit flex-o">
|
||||||
|
<div class="flex- 1"><a-checkbox :checked="modelValue === -1" @update:checked="onCheckedChange">无限制</a-checkbox><span class="ml-5"></span></div>
|
||||||
|
<div class="ml-10 w-50%">
|
||||||
|
<a-input-number v-if="modelValue >= 0" :value="modelValue" class="ml-5" @update:value="onValueChange">
|
||||||
|
<template v-if="unit" #addonAfter>{{ unit }}</template>
|
||||||
|
</a-input-number>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Form } from "ant-design-vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue?: number;
|
||||||
|
unit?: string;
|
||||||
|
}>();
|
||||||
|
const formItemContext = Form.useInjectFormItemContext();
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
|
const onCheckedChange = (checked: boolean) => {
|
||||||
|
const value = checked ? -1 : 1;
|
||||||
|
onValueChange(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
function onValueChange(value: number) {
|
||||||
|
emit("update:modelValue", value);
|
||||||
|
formItemContext.onFieldChange();
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="target" class="cd-suite-value">
|
||||||
|
<a-tag :color="target.color">{{ target.label }}</a-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const target = computed(() => {
|
||||||
|
if (!props.modelValue) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (props.modelValue === -1) {
|
||||||
|
return {
|
||||||
|
value: -1,
|
||||||
|
label: "无限制",
|
||||||
|
color: "green"
|
||||||
|
};
|
||||||
|
} else if (props.modelValue === 0) {
|
||||||
|
return {
|
||||||
|
value: 0,
|
||||||
|
label: "-",
|
||||||
|
color: "red"
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
value: props.modelValue,
|
||||||
|
label: props.modelValue,
|
||||||
|
color: "blue"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -9,11 +9,12 @@ CREATE TABLE "cd_product"
|
||||||
"max_deploy_count" integer,
|
"max_deploy_count" integer,
|
||||||
"deploy_count_period" varchar(100),
|
"deploy_count_period" varchar(100),
|
||||||
"site_monitor" boolean,
|
"site_monitor" boolean,
|
||||||
"expires_time" integer,
|
"duration" integer,
|
||||||
"price" integer,
|
"price" integer,
|
||||||
"origin_price" integer,
|
"origin_price" integer,
|
||||||
"intro" varchar(2048),
|
"intro" varchar(2048),
|
||||||
"order" integer,
|
"order" integer,
|
||||||
|
"is_bootstrap" boolean,
|
||||||
"disabled" boolean NOT NULL DEFAULT (false),
|
"disabled" boolean NOT NULL DEFAULT (false),
|
||||||
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||||
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
|
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
|
||||||
|
@ -65,10 +66,12 @@ CREATE TABLE "cd_user_suite"
|
||||||
"max_domain_count" integer,
|
"max_domain_count" integer,
|
||||||
"max_pipeline_count" integer,
|
"max_pipeline_count" integer,
|
||||||
"max_deploy_count" integer,
|
"max_deploy_count" integer,
|
||||||
"used_deploy_count" integer,
|
"deploy_count_period" varchar(100),
|
||||||
"site_monitor" boolean,
|
"site_monitor" boolean,
|
||||||
|
"duration" integer,
|
||||||
|
"used_deploy_count" integer,
|
||||||
|
"active_time" integer,
|
||||||
"expires_time" integer,
|
"expires_time" integer,
|
||||||
"disabled" boolean NOT NULL DEFAULT (false),
|
|
||||||
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
"create_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
||||||
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
|
"update_time" datetime NOT NULL DEFAULT (CURRENT_TIMESTAMP)
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,6 +18,7 @@ export class AppController extends BaseController {
|
||||||
const res = await http.request({
|
const res = await http.request({
|
||||||
url: 'https://registry.npmmirror.com/@certd/pipeline',
|
url: 'https://registry.npmmirror.com/@certd/pipeline',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
logRes: false,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
const latest = res['dist-tags'].latest;
|
const latest = res['dist-tags'].latest;
|
||||||
|
|
Loading…
Reference in New Issue