mirror of https://github.com/certd/certd
chore:
parent
45839f227a
commit
08111f1418
|
@ -16,9 +16,37 @@ export const durationDict = dict({
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type OrderModalOpenReq = {
|
||||||
|
productId: number;
|
||||||
|
duration: number;
|
||||||
|
num?: number;
|
||||||
|
};
|
||||||
|
|
||||||
export async function ProductList() {
|
export async function ProductList() {
|
||||||
return await request({
|
return await request({
|
||||||
url: "/suite/product/list",
|
url: "/suite/product/list",
|
||||||
method: "POST"
|
method: "POST"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function ProductInfo(productId: number) {
|
||||||
|
return await request({
|
||||||
|
url: "/suite/product/info",
|
||||||
|
method: "POST",
|
||||||
|
data: { id: productId }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TradeCreateReq = {
|
||||||
|
productId: number;
|
||||||
|
duration: number;
|
||||||
|
num: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function TradeCreate(form: TradeCreateReq) {
|
||||||
|
return await request({
|
||||||
|
url: "/suite/trade/create",
|
||||||
|
method: "POST",
|
||||||
|
data: form
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -5,52 +5,8 @@
|
||||||
</template>
|
</template>
|
||||||
<div class="suite-buy-content">
|
<div class="suite-buy-content">
|
||||||
<a-row :gutter="12">
|
<a-row :gutter="12">
|
||||||
<a-col v-for="item of suites" :key="item.id" class="mb-10" :xs="12" :sm="12" :md="8" :lg="6" :xl="6" :xxl="4">
|
<a-col v-for="item of products" :key="item.id" class="mb-10" :xs="12" :sm="12" :md="8" :lg="6" :xl="6" :xxl="4">
|
||||||
<a-card :title="item.title">
|
<product-info product="item"></product-info>
|
||||||
<template #extra>
|
|
||||||
<a-tag>{{ item.type }}</a-tag>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div>{{ item.intro }}</div>
|
|
||||||
<div class="hr">
|
|
||||||
<div class="flex-between mt-5">流水线条数:<suite-value :model-value="item.content.maxPipelineCount" /></div>
|
|
||||||
<div class="flex-between mt-5">域名数量: <suite-value :model-value="item.content.maxDomainCount" /></div>
|
|
||||||
<div class="flex-between mt-5">部署次数: <suite-value :model-value="item.content.maxDeployCount" /></div>
|
|
||||||
<div class="flex-between mt-5">
|
|
||||||
证书监控:
|
|
||||||
<span v-if="item.content.siteMonitor">支持</span>
|
|
||||||
<span v-else>不支持</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="duration flex-between mt-5 hr">
|
|
||||||
<div class="flex-o">时长</div>
|
|
||||||
<div class="duration-list">
|
|
||||||
<div
|
|
||||||
v-for="dp of item.durationPrices"
|
|
||||||
:key="dp.duration"
|
|
||||||
class="duration-item"
|
|
||||||
:class="{ active: item._selected.duration === dp.duration }"
|
|
||||||
@click="item._selected = dp"
|
|
||||||
>
|
|
||||||
{{ durationDict.dataMap[dp.duration]?.label }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="price flex-between mt-5 hr">
|
|
||||||
<div class="flex-o">价格</div>
|
|
||||||
<div class="flex-o price-text">
|
|
||||||
<price-input style="font-size: 18px; color: red" :model-value="item._selected?.price" :edit="false" />
|
|
||||||
<span class="ml-5" style="font-size: 12px"> / {{ durationDict.dataMap[item._selected.duration]?.label }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template #actions>
|
|
||||||
<setting-outlined key="setting" />
|
|
||||||
<a-button type="primary">立即购买</a-button>
|
|
||||||
</template>
|
|
||||||
</a-card>
|
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</div>
|
</div>
|
||||||
|
@ -60,22 +16,12 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import * as api from "./api";
|
import * as api from "./api";
|
||||||
import { durationDict } from "./api";
|
import ProductInfo from "/@/views/certd/suite/product-info.vue";
|
||||||
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
|
|
||||||
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
|
|
||||||
import { dict } from "@fast-crud/fast-crud";
|
|
||||||
const suites = ref([]);
|
|
||||||
|
|
||||||
const optionsDict = dict({
|
const products = ref([]);
|
||||||
data: []
|
|
||||||
});
|
|
||||||
|
|
||||||
async function loadSuites() {
|
async function loadSuites() {
|
||||||
suites.value = await api.ProductList();
|
products.value = await api.ProductList();
|
||||||
|
|
||||||
for (const item of suites.value) {
|
|
||||||
item._selected = item.durationPrices[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSuites();
|
loadSuites();
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<template>
|
||||||
|
<a-modal class="order-modal">
|
||||||
|
<div class="order-box"></div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { OrderModalOpenReq } from "/@/views/certd/suite/api";
|
||||||
|
|
||||||
|
const openRef = ref(false);
|
||||||
|
|
||||||
|
async function open(opts: OrderModalOpenReq) {
|
||||||
|
openRef.value = true;
|
||||||
|
|
||||||
|
const productDetail = api.ProductInfo(opts.productId);
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<a-card :title="product.title">
|
||||||
|
<template #extra>
|
||||||
|
<a-tag>{{ product.type }}</a-tag>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div>{{ product.intro }}</div>
|
||||||
|
<div class="hr">
|
||||||
|
<div class="flex-between mt-5">流水线条数:<suite-value :model-value="product.content.maxPipelineCount" /></div>
|
||||||
|
<div class="flex-between mt-5">域名数量: <suite-value :model-value="product.content.maxDomainCount" /></div>
|
||||||
|
<div class="flex-between mt-5">部署次数: <suite-value :model-value="product.content.maxDeployCount" /></div>
|
||||||
|
<div class="flex-between mt-5">
|
||||||
|
证书监控:
|
||||||
|
<span v-if="product.content.sproductonitor">支持</span>
|
||||||
|
<span v-else>不支持</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="duration flex-between mt-5 hr">
|
||||||
|
<div class="flex-o">时长</div>
|
||||||
|
<div class="duration-list">
|
||||||
|
<div
|
||||||
|
v-for="dp of product.durationPrices"
|
||||||
|
:key="dp.duration"
|
||||||
|
class="duration-product"
|
||||||
|
:class="{ active: selected.duration === dp.duration }"
|
||||||
|
@click="selected = dp"
|
||||||
|
>
|
||||||
|
{{ durationDict.dataMap[dp.duration]?.label }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="price flex-between mt-5 hr">
|
||||||
|
<div class="flex-o">价格</div>
|
||||||
|
<div class="flex-o price-text">
|
||||||
|
<price-input style="font-size: 18px; color: red" :model-value="selected?.price" :edit="false" />
|
||||||
|
<span class="ml-5" style="font-size: 12px"> / {{ durationDict.dataMap[selected.duration]?.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #actions>
|
||||||
|
<setting-outlined key="setting" />
|
||||||
|
<a-button type="primary" @click="doOrder">立即购买</a-button>
|
||||||
|
</template>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { durationDict } from "/@/views/certd/suite/api";
|
||||||
|
import SuiteValue from "/@/views/sys/suite/product/suite-value.vue";
|
||||||
|
import PriceInput from "/@/views/sys/suite/product/price-input.vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import * as api from "./api";
|
||||||
|
const props = defineProps<{
|
||||||
|
product: any;
|
||||||
|
}>();
|
||||||
|
const selected = ref(props.product.durationPrices[0]);
|
||||||
|
async function doOrder() {
|
||||||
|
console.log("doOrder", selected.value);
|
||||||
|
const res = await api.OrderCreate({
|
||||||
|
productId: props.product.id,
|
||||||
|
duration: selected.value.duration
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue