chore: suite

v2
xiaojunnuo 2024-12-18 09:07:52 +08:00
parent 8057586dc1
commit 1c8e25beb3
9 changed files with 270 additions and 80 deletions

View File

@ -280,3 +280,7 @@ h1, h2, h3, h4, h5, h6 {
.fs-16{ .fs-16{
font-size: 16px; font-size: 16px;
} }
.w-50\%{
width: 50%;
}

View File

@ -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) {

View File

@ -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: {

View File

@ -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>

View File

@ -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 });

View File

@ -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>

View File

@ -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>

View File

@ -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)
@ -23,34 +24,34 @@ CREATE TABLE "cd_product"
CREATE TABLE "cd_payment" CREATE TABLE "cd_payment"
( (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"type" varchar(100), "type" varchar(100),
"title" varchar(100), "title" varchar(100),
"setting" text, "setting" text,
"order" integer, "order" integer,
"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)
); );
CREATE TABLE "cd_order" CREATE TABLE "cd_order"
( (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"user_id" integer, "user_id" integer,
"product_id" integer, "product_id" integer,
"title" varchar(100), "title" varchar(100),
"count" integer, "count" integer,
"price" integer, "price" integer,
"amount" integer, "amount" integer,
"remark" varchar(100), "remark" varchar(100),
"status" varchar(100), "status" varchar(100),
"pay_id" integer, "pay_id" integer,
"pay_time" integer, "pay_time" integer,
"pay_type" varchar(100), "pay_type" varchar(100),
"pay_no" varchar(100), "pay_no" varchar(100),
"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)
); );

View File

@ -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;