diff --git a/packages/libs/lib-server/src/basic/crud-controller.ts b/packages/libs/lib-server/src/basic/crud-controller.ts index e9474df6..11f9f829 100644 --- a/packages/libs/lib-server/src/basic/crud-controller.ts +++ b/packages/libs/lib-server/src/basic/crud-controller.ts @@ -49,4 +49,10 @@ export abstract class CrudController extends BaseController { await this.getService().delete([id]); return this.ok(null); } + + @Post('/deleteByIds') + async deleteByIds(@Body('ids') ids: number[]) { + await this.getService().delete(ids); + return this.ok(null); + } } diff --git a/packages/ui/certd-client/src/router/source/modules/certd.ts b/packages/ui/certd-client/src/router/source/modules/certd.ts index f19639b1..25d596ae 100644 --- a/packages/ui/certd-client/src/router/source/modules/certd.ts +++ b/packages/ui/certd-client/src/router/source/modules/certd.ts @@ -80,6 +80,16 @@ export const certdResources = [ auth: true } }, + { + title: "套餐购买", + name: "SuiteProductBuy", + path: "/certd/suite/buy", + component: "/certd/suite/buy.vue", + meta: { + icon: "mdi:format-list-group", + auth: true + } + }, // { // title: "邮箱设置", // name: "EmailSetting", diff --git a/packages/ui/certd-client/src/views/certd/suite/api.ts b/packages/ui/certd-client/src/views/certd/suite/api.ts new file mode 100644 index 00000000..a1dca698 --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/suite/api.ts @@ -0,0 +1,24 @@ +import { request } from "/@/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export 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 } + ] +}); + +export async function ProductList() { + return await request({ + url: "/suite/product/list", + method: "POST" + }); +} diff --git a/packages/ui/certd-client/src/views/certd/suite/buy.vue b/packages/ui/certd-client/src/views/certd/suite/buy.vue new file mode 100644 index 00000000..a7f8de5a --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/suite/buy.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/packages/ui/certd-client/src/views/certd/suite/card.vue b/packages/ui/certd-client/src/views/certd/suite/card.vue new file mode 100644 index 00000000..3a6cce8d --- /dev/null +++ b/packages/ui/certd-client/src/views/certd/suite/card.vue @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/packages/ui/certd-client/src/views/sys/suite/product/api.ts b/packages/ui/certd-client/src/views/sys/suite/product/api.ts index e28c3434..b9aa22db 100644 --- a/packages/ui/certd-client/src/views/sys/suite/product/api.ts +++ b/packages/ui/certd-client/src/views/sys/suite/product/api.ts @@ -1,6 +1,9 @@ import { request } from "/src/api/service"; - const apiPrefix = "/sys/suite/product"; +export type PriceItem = { + duration: number; + price: number; +}; export async function GetList(query: any) { return await request({ diff --git a/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx b/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx index afcc1e6e..6416ee04 100644 --- a/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx +++ b/packages/ui/certd-client/src/views/sys/suite/product/crud.tsx @@ -7,6 +7,7 @@ import { useUserStore } from "/@/store/modules/user"; import { useSettingStore } from "/@/store/modules/settings"; import SuiteValue from "./suite-value.vue"; import SuiteValueEdit from "./suite-value-edit.vue"; +import PriceEdit from "./price-edit.vue"; export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { const router = useRouter(); @@ -24,9 +25,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat }; const addRequest = async ({ form }: AddReq) => { - form.content = JSON.stringify({ - title: form.title - }); const res = await api.AddObj(form); return res; }; @@ -69,11 +67,15 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat groups: { base: { header: "基础信息", - columns: ["title", "type", "price", "originPrice", "duration", "isBootstrap", "intro"] + columns: ["title", "type", "isBootstrap", "disabled", "order", "intro"] }, content: { header: "套餐内容", - columns: ["maxDomainCount", "maxPipelineCount", "maxDeployCount", "siteMonitor"] + columns: ["content.maxDomainCount", "content.maxPipelineCount", "content.maxDeployCount", "content.siteMonitor"] + }, + price: { + header: "价格", + columns: ["durationPrices"] } } } @@ -96,6 +98,9 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat search: { show: true }, + form: { + rules: [{ required: true, message: "此项必填" }] + }, column: { width: 200 } @@ -114,19 +119,41 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat { label: "加量包", value: "addon" } ] }), + form: { + rules: [{ required: true, message: "此项必填" }] + }, column: { width: 100 + }, + valueBuilder: ({ row }) => { + if (row.content) { + row.content = JSON.parse(row.content); + } + if (row.durationPrices) { + row.durationPrices = JSON.parse(row.durationPrices); + } + }, + valueResolve: ({ form }) => { + debugger; + if (form.content) { + form.content = JSON.stringify(form.content); + } + if (form.durationPrices) { + form.durationPrices = JSON.stringify(form.durationPrices); + } } }, - maxDomainCount: { + "content.maxDomainCount": { title: "域名数量", type: "number", form: { + key: ["content", "maxDomainCount"], component: { name: SuiteValueEdit, vModel: "modelValue", unit: "个" - } + }, + rules: [{ required: true, message: "此项必填" }] }, column: { width: 100, @@ -135,15 +162,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } } }, - maxPipelineCount: { + "content.maxPipelineCount": { title: "流水线数量", type: "number", form: { + key: ["content", "maxPipelineCount"], component: { name: SuiteValueEdit, vModel: "modelValue", unit: "条" - } + }, + rules: [{ required: true, message: "此项必填" }] }, column: { width: 100, @@ -152,15 +181,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } } }, - maxDeployCount: { + "content.maxDeployCount": { title: "部署次数", type: "number", form: { + key: ["content", "maxDeployCount"], component: { name: SuiteValueEdit, vModel: "modelValue", unit: "次" - } + }, + rules: [{ required: true, message: "此项必填" }] }, column: { width: 100, @@ -169,7 +200,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat } } }, - siteMonitor: { + "content.siteMonitor": { title: "支持证书监控", type: "dict-switch", dict: dict({ @@ -178,10 +209,40 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat { label: "否", value: false, color: "error" } ] }), + form: { + key: ["content", "siteMonitor"], + value: false + }, column: { width: 120 } }, + durationPrices: { + title: "时长及价格", + type: "text", + form: { + title: "选择时长", + component: { + name: PriceEdit, + vModel: "modelValue", + edit: true, + style: { + minHeight: "120px" + } + }, + col: { + span: 24 + }, + rules: [{ required: true, message: "此项必填" }] + }, + column: { + component: { + name: PriceEdit, + vModel: "modelValue", + edit: false + } + } + }, isBootstrap: { title: "是否初始套餐", type: "dict-switch", @@ -191,27 +252,36 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat { label: "否", value: false, color: "error" } ] }), + form: { + value: false + }, column: { width: 120 } }, - price: { - title: "单价", - type: "number", + disabled: { + title: "上下架", + type: "dict-radio", + dict: dict({ + data: [ + { value: false, label: "上架" }, + { value: true, label: "下架" } + ] + }), + form: { + value: false + }, column: { width: 100 } }, - originPrice: { - title: "原价", + order: { + title: "排序", type: "number", - column: { - width: 100 - } - }, - duration: { - title: "有效时长", - type: "dict-select", + form: { + helper: "越小越靠前", + value: 0 + }, column: { width: 100 } @@ -223,16 +293,6 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat width: 200 } }, - order: { - title: "排序", - type: "number", - form: { - show: false - }, - column: { - width: 100 - } - }, createTime: { title: "创建时间", type: "datetime", diff --git a/packages/ui/certd-client/src/views/sys/suite/product/duration-prices.vue b/packages/ui/certd-client/src/views/sys/suite/product/duration-prices.vue deleted file mode 100644 index 7fe616ec..00000000 --- a/packages/ui/certd-client/src/views/sys/suite/product/duration-prices.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - diff --git a/packages/ui/certd-client/src/views/sys/suite/product/price-edit.vue b/packages/ui/certd-client/src/views/sys/suite/product/price-edit.vue new file mode 100644 index 00000000..d03a931f --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/suite/product/price-edit.vue @@ -0,0 +1,94 @@ + + + + diff --git a/packages/ui/certd-client/src/views/sys/suite/product/price-input.vue b/packages/ui/certd-client/src/views/sys/suite/product/price-input.vue new file mode 100644 index 00000000..2d8187d4 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/suite/product/price-input.vue @@ -0,0 +1,35 @@ + + + diff --git a/packages/ui/certd-client/src/views/sys/suite/product/suite-value-edit.vue b/packages/ui/certd-client/src/views/sys/suite/product/suite-value-edit.vue index d84ce694..223352c7 100644 --- a/packages/ui/certd-client/src/views/sys/suite/product/suite-value-edit.vue +++ b/packages/ui/certd-client/src/views/sys/suite/product/suite-value-edit.vue @@ -2,7 +2,7 @@
无限制
- +
diff --git a/packages/ui/certd-client/src/views/sys/suite/order/api.ts b/packages/ui/certd-client/src/views/sys/suite/trade/api.ts similarity index 97% rename from packages/ui/certd-client/src/views/sys/suite/order/api.ts rename to packages/ui/certd-client/src/views/sys/suite/trade/api.ts index e4bca0f1..44a31e99 100644 --- a/packages/ui/certd-client/src/views/sys/suite/order/api.ts +++ b/packages/ui/certd-client/src/views/sys/suite/trade/api.ts @@ -1,6 +1,6 @@ import { request } from "/src/api/service"; -const apiPrefix = "/sys/suite/order"; +const apiPrefix = "/sys/suite/trade"; export async function GetList(query: any) { return await request({ diff --git a/packages/ui/certd-client/src/views/sys/suite/order/crud.tsx b/packages/ui/certd-client/src/views/sys/suite/trade/crud.tsx similarity index 100% rename from packages/ui/certd-client/src/views/sys/suite/order/crud.tsx rename to packages/ui/certd-client/src/views/sys/suite/trade/crud.tsx diff --git a/packages/ui/certd-client/src/views/sys/suite/order/index.vue b/packages/ui/certd-client/src/views/sys/suite/trade/index.vue similarity index 100% rename from packages/ui/certd-client/src/views/sys/suite/order/index.vue rename to packages/ui/certd-client/src/views/sys/suite/trade/index.vue diff --git a/packages/ui/certd-server/src/controller/sys/cname/cname-provider-controller.ts b/packages/ui/certd-server/src/controller/sys/cname/cname-provider-controller.ts index e4778616..2559045f 100644 --- a/packages/ui/certd-server/src/controller/sys/cname/cname-provider-controller.ts +++ b/packages/ui/certd-server/src/controller/sys/cname/cname-provider-controller.ts @@ -55,8 +55,8 @@ export class CnameRecordController extends CrudController } @Post('/deleteByIds', { summary: 'sys:settings:edit' }) - async deleteByIds(@Body(ALL) body: { ids: number[] }) { - const res = await this.service.delete(body.ids); + async deleteByIds(@Body('ids') ids: number[]) { + const res = await this.service.delete(ids); return this.ok(res); } diff --git a/packages/ui/certd-server/src/controller/sys/plugin/plugin-controller.ts b/packages/ui/certd-server/src/controller/sys/plugin/plugin-controller.ts index ac620c3b..9db5d29f 100644 --- a/packages/ui/certd-server/src/controller/sys/plugin/plugin-controller.ts +++ b/packages/ui/certd-server/src/controller/sys/plugin/plugin-controller.ts @@ -57,8 +57,8 @@ export class PluginController extends CrudController { } @Post('/deleteByIds', { summary: 'sys:settings:edit' }) - async deleteByIds(@Body(ALL) body: { ids: number[] }) { - const res = await this.service.delete(body.ids); + async deleteByIds(@Body('ids') ids: number[]) { + const res = await this.service.delete(ids); return this.ok(res); }