fix: 免费套餐支持购买

v2
xiaojunnuo 2024-12-25 17:05:24 +08:00
parent fe4786e168
commit f5ec9870fd
14 changed files with 158 additions and 92 deletions

View File

@ -122,12 +122,11 @@ export const useSettingStore = defineStore({
}; };
return vipLabelMap[this.plusInfo?.vipType || "free"]; return vipLabelMap[this.plusInfo?.vipType || "free"];
}, },
// @ts-ignore getHeaderMenus(): { menus: any[] } {
getHeaderMenus() {
// @ts-ignore // @ts-ignore
return this.headerMenus?.menus || { menus: [] }; return this.headerMenus?.menus || { menus: [] };
}, },
isSuiteEnabled() { isSuiteEnabled(): boolean {
// @ts-ignore // @ts-ignore
return this.suiteSetting?.enabled === true; return this.suiteSetting?.enabled === true;
} }

View File

@ -52,6 +52,14 @@ export async function TradeCreate(form: TradeCreateReq) {
}); });
} }
export async function TradeCreateFree(form: TradeCreateReq) {
return await request({
url: "/suite/trade/createFree",
method: "POST",
data: form
});
}
export async function GetPaymentTypes() { export async function GetPaymentTypes() {
return await request({ return await request({
url: "/suite/trade/payments", url: "/suite/trade/payments",

View File

@ -35,6 +35,7 @@ import { ref } from "vue";
import * as api from "./api"; import * as api from "./api";
import ProductInfo from "/@/views/certd/suite/product-info.vue"; import ProductInfo from "/@/views/certd/suite/product-info.vue";
import OrderModal from "/@/views/certd/suite/order-modal.vue"; import OrderModal from "/@/views/certd/suite/order-modal.vue";
import { notification } from "ant-design-vue";
const suites = ref([]); const suites = ref([]);
const addons = ref([]); const addons = ref([]);
@ -48,6 +49,20 @@ async function loadProducts() {
loadProducts(); loadProducts();
const orderModalRef = ref<any>(null); const orderModalRef = ref<any>(null);
async function doOrder(req: any) { async function doOrder(req: any) {
if (req.price === 0) {
//0
await api.TradeCreateFree({
productId: req.productId,
duration: req.duration,
num: 1,
payType: "free"
});
notification.success({
message: "套餐购买成功"
});
return;
}
await orderModalRef.value.open({ await orderModalRef.value.open({
...req ...req
}); });

View File

@ -263,7 +263,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
userSuite: compute(({ row }) => { userSuite: compute(({ row }) => {
return row; return row;
}), }),
currentSuite: context.detail currentSuite: context.currentSuite
}, },
conditionalRender: { conditionalRender: {
match() { match() {

View File

@ -15,7 +15,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onActivated, onMounted, ref } from "vue"; import { computed, onActivated, onMounted, ref } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import api, { SuiteDetail } from "/@/views/certd/suite/mine/api"; import api, { SuiteDetail } from "/@/views/certd/suite/mine/api";
@ -25,7 +25,14 @@ defineOptions({
name: "MySuites" name: "MySuites"
}); });
const detail = ref<SuiteDetail>({}); const detail = ref<SuiteDetail>({});
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { detail } }); const currentSuite = computed(() => {
if (detail.value?.suites && detail.value.suites.length > 0) {
return detail.value.suites[0];
}
return null;
});
const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions, context: { detail, currentSuite } });
async function loadSuiteDetail() { async function loadSuiteDetail() {
detail.value = await api.SuiteDetailGet(); detail.value = await api.SuiteDetailGet();

View File

@ -80,7 +80,7 @@ const productTypeDictRef = dict({
const emit = defineEmits(["order"]); const emit = defineEmits(["order"]);
async function doOrder() { async function doOrder() {
emit("order", { product: props.product, productId: props.product.id, duration: selected.value.duration }); emit("order", { product: props.product, productId: props.product.id, duration: selected.value.duration, price: selected.value.price });
} }
</script> </script>

View File

@ -162,7 +162,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
] ]
}), }),
column: { column: {
width: 100 width: 100,
align: "center"
} }
}, },
payType: { payType: {
@ -173,14 +174,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
data: [ data: [
{ label: "聚合支付", value: "yizhifu" }, { label: "聚合支付", value: "yizhifu" },
{ label: "支付宝", value: "alipay" }, { label: "支付宝", value: "alipay" },
{ label: "微信", value: "wxpay" } { label: "微信", value: "wxpay" },
{ label: "免费", value: "free" }
] ]
}), }),
column: { column: {
width: 100, width: 100,
component: { component: {
color: "auto" color: "auto"
} },
align: "center"
} }
}, },
payTime: { payTime: {

View File

@ -36,8 +36,8 @@
</span> </span>
<span>(<expires-time-text :value="item.expiresTime" />)</span> <span>(<expires-time-text :value="item.expiresTime" />)</span>
</a-tag> </a-tag>
<div class="flex-o ml-5"> <div v-if="detail.suites?.length === 0" class="flex-o ml-5">
暂无套餐 <a-button v-if="detail.suites?.length === 0" class="ml-5" type="primary" size="small" @click="goBuy"></a-button> 暂无套餐 <a-button class="ml-5" type="primary" size="small" @click="goBuy"></a-button>
</div> </div>
</div> </div>
</a-popover> </a-popover>

View File

@ -17,6 +17,7 @@
<div style="height: 400px"> <div style="height: 400px">
<ProductManager @refreshed="onTableRefresh"></ProductManager> <ProductManager @refreshed="onTableRefresh"></ProductManager>
</div> </div>
<div class="helper">不建议设置免费套餐可以在下方配置注册赠送套餐</div>
</a-form-item> </a-form-item>
<a-form-item label="注册赠送套餐" name="registerGift"> <a-form-item label="注册赠送套餐" name="registerGift">

View File

@ -7,6 +7,10 @@ import { ref, watch } from "vue";
import { dict } from "@fast-crud/fast-crud"; import { dict } from "@fast-crud/fast-crud";
import { request } from "/@/api/service"; import { request } from "/@/api/service";
defineOptions({
name: "SuiteDurationSelector"
});
const props = defineProps<{ const props = defineProps<{
modelValue?: { modelValue?: {
productId?: number; productId?: number;

View File

@ -155,7 +155,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
component: { component: {
name: DurationValue, name: DurationValue,
vModel: "modelValue" vModel: "modelValue"
} },
align: "center"
} }
}, },
amount: { amount: {
@ -182,7 +183,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
] ]
}), }),
column: { column: {
width: 100 width: 100,
align: "center"
} }
}, },
payType: { payType: {
@ -193,14 +195,16 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
data: [ data: [
{ label: "聚合支付", value: "yizhifu" }, { label: "聚合支付", value: "yizhifu" },
{ label: "支付宝", value: "alipay" }, { label: "支付宝", value: "alipay" },
{ label: "微信", value: "wxpay" } { label: "微信", value: "wxpay" },
{ label: "免费", value: "free" }
] ]
}), }),
column: { column: {
width: 100, width: 100,
component: { component: {
color: "auto" color: "auto"
} },
align: "center"
} }
}, },
payTime: { payTime: {

View File

@ -1,8 +1,7 @@
import { request } from "/src/api/service"; import { request } from "/src/api/service";
export function createApi() { const apiPrefix = "/sys/suite/user-suite";
const apiPrefix = "/sys/suite/user-suite"; export const sysUserSuiteApi = {
return {
async GetList(query: any) { async GetList(query: any) {
return await request({ return await request({
url: apiPrefix + "/page", url: apiPrefix + "/page",
@ -55,8 +54,12 @@ export function createApi() {
method: "post", method: "post",
data: { ids } data: { ids }
}); });
},
async PresentSuite(form: any) {
return await request({
url: apiPrefix + "/presentSuite",
method: "post",
data: form
});
} }
}; };
}
export const pipelineGroupApi = createApi();

View File

@ -1,15 +1,14 @@
import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud"; import { AddReq, compute, CreateCrudOptionsProps, CreateCrudOptionsRet, DelReq, dict, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import { pipelineGroupApi } from "./api"; import { sysUserSuiteApi } from "./api";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import SuiteValueEdit from "/@/views/sys/suite/product/suite-value-edit.vue"; import SuiteValueEdit from "/@/views/sys/suite/product/suite-value-edit.vue";
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue"; import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
import DurationValue from "/@/views/sys/suite/product/duration-value.vue"; import DurationValue from "/@/views/sys/suite/product/duration-value.vue";
import dayjs from "dayjs";
import createCrudOptionsUser from "/@/views/sys/authority/user/crud"; import createCrudOptionsUser from "/@/views/sys/authority/user/crud";
import UserSuiteStatus from "/@/views/certd/suite/mine/user-suite-status.vue"; import UserSuiteStatus from "/@/views/certd/suite/mine/user-suite-status.vue";
import SuiteDurationSelector from "../setting/suite-duration-selector.vue";
export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet { export default function ({ crudExpose, context }: CreateCrudOptionsProps): CreateCrudOptionsRet {
const api = pipelineGroupApi; const api = sysUserSuiteApi;
const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => { const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
return await api.GetList(query); return await api.GetList(query);
}; };
@ -26,7 +25,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
const addRequest = async (req: AddReq) => { const addRequest = async (req: AddReq) => {
const { form } = req; const { form } = req;
const res = await api.AddObj(form); const res = await api.PresentSuite(form);
return res; return res;
}; };
@ -57,16 +56,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
}, },
actionbar: { actionbar: {
buttons: { buttons: {
add: { show: false } add: { text: "赠送套餐" }
// buy: {
// text: "购买",
// type: "primary",
// click() {
// router.push({
// path: "/certd/suite/buy"
// });
// }
// }
} }
}, },
toolbar: { show: false }, toolbar: { show: false },
@ -112,7 +102,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
show: true show: true
}, },
form: { form: {
rules: [{ required: true, message: "此项必填" }] show: false
}, },
column: { column: {
width: 200 width: 200
@ -143,6 +133,27 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
} }
} }
}, },
//赠送
presentSuiteId: {
title: "赠送套餐",
type: "dict-select",
column: { show: false },
addForm: {
component: {
name: SuiteDurationSelector,
vModel: "modelValue"
},
rules: [{ required: true, message: "请选择套餐" }]
},
valueResolve({ form, value }) {
if (value) {
const arr = value.splict("_");
form.productId = parseInt(arr[0]);
form.duration = parseInt(arr[1]);
}
},
form: { show: false }
},
productType: { productType: {
title: "类型", title: "类型",
type: "dict-select", type: "dict-select",
@ -158,7 +169,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
] ]
}), }),
form: { form: {
rules: [{ required: true, message: "此项必填" }] show: false
}, },
column: { column: {
width: 80, width: 80,
@ -179,6 +190,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
title: "域名数量", title: "域名数量",
type: "text", type: "text",
form: { form: {
show: false,
key: ["content", "maxDomainCount"], key: ["content", "maxDomainCount"],
component: { component: {
name: SuiteValueEdit, name: SuiteValueEdit,
@ -201,6 +213,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
title: "流水线数量", title: "流水线数量",
type: "text", type: "text",
form: { form: {
show: false,
key: ["content", "maxPipelineCount"], key: ["content", "maxPipelineCount"],
component: { component: {
name: SuiteValueEdit, name: SuiteValueEdit,
@ -223,6 +236,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
title: "部署次数", title: "部署次数",
type: "text", type: "text",
form: { form: {
show: false,
key: ["content", "maxDeployCount"], key: ["content", "maxDeployCount"],
component: { component: {
name: SuiteValueEdit, name: SuiteValueEdit,
@ -248,6 +262,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
title: "证书监控数量", title: "证书监控数量",
type: "text", type: "text",
form: { form: {
show: false,
key: ["content", "maxMonitorCount"], key: ["content", "maxMonitorCount"],
component: { component: {
name: SuiteValueEdit, name: SuiteValueEdit,
@ -269,7 +284,7 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
duration: { duration: {
title: "时长", title: "时长",
type: "text", type: "text",
form: {}, form: { show: false },
column: { column: {
component: { component: {
name: DurationValue, name: DurationValue,
@ -304,11 +319,17 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
type: "date", type: "date",
column: { column: {
width: 150 width: 150
},
form: {
show: false
} }
}, },
expiresTime: { expiresTime: {
title: "过期时间", title: "过期时间",
type: "date", type: "date",
form: {
show: false
},
column: { column: {
width: 150, width: 150,
component: { component: {
@ -328,7 +349,8 @@ export default function ({ crudExpose, context }: CreateCrudOptionsProps): Creat
] ]
}), }),
form: { form: {
value: true value: true,
show: false
}, },
column: { column: {
width: 100, width: 100,

View File

@ -11,10 +11,10 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineComponent, onActivated, onMounted } from "vue"; import { onActivated, onMounted } from "vue";
import { useFs } from "@fast-crud/fast-crud"; import { useFs } from "@fast-crud/fast-crud";
import createCrudOptions from "./crud"; import createCrudOptions from "./crud";
import { createApi } from "./api";
defineOptions({ defineOptions({
name: "UserSuites" name: "UserSuites"
}); });