pull/330/head
xiaojunnuo 2024-12-19 22:37:27 +08:00
parent 45839f227a
commit 08111f1418
4 changed files with 120 additions and 59 deletions

View File

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

View File

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

View File

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

View File

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