Files
bdrp-app/src/pages/promote.vue

226 lines
7.3 KiB
Vue
Raw Normal View History

2026-04-20 16:42:28 +08:00
<script setup>
import PriceInputPopup from '@/components/PriceInputPopup.vue'
import VipBanner from '@/components/VipBanner.vue'
definePage({ layout: 'default' })
const showPricePicker = ref(false)
const pickerProductConfig = ref(null)
const productConfig = ref(null)
const linkIdentifier = ref('')
const showQRcode = ref(false)
const promotionForm = ref(null)
const loadingConfig = ref(false)
const generating = ref(false)
const formData = ref({
productType: '',
clientPrice: null,
})
const availableReportTypes = computed(() => {
if (!productConfig.value?.length)
return []
return productConfig.value
.map(item => ({
id: item.product_id,
label: item.product_name || `产品${item.product_id}`,
value: item.product_en || '',
}))
.filter(item => !!item.value)
})
const costPrice = computed(() => {
if (!pickerProductConfig.value)
return '0.00'
let platformPricing = 0
platformPricing += pickerProductConfig.value.cost_price
if (formData.value.clientPrice > pickerProductConfig.value.p_pricing_standard) {
platformPricing += (formData.value.clientPrice - pickerProductConfig.value.p_pricing_standard) * pickerProductConfig.value.p_overpricing_ratio
}
if (pickerProductConfig.value.a_pricing_standard > platformPricing && pickerProductConfig.value.a_pricing_end > platformPricing && pickerProductConfig.value.a_overpricing_ratio > 0) {
if (formData.value.clientPrice > pickerProductConfig.value.a_pricing_standard) {
if (formData.value.clientPrice > pickerProductConfig.value.a_pricing_end) {
platformPricing += (pickerProductConfig.value.a_pricing_end - pickerProductConfig.value.a_pricing_standard) * pickerProductConfig.value.a_overpricing_ratio
}
else {
platformPricing += (formData.value.clientPrice - pickerProductConfig.value.a_pricing_standard) * pickerProductConfig.value.a_overpricing_ratio
}
}
}
return safeTruncate(platformPricing)
})
const promotionRevenue = computed(() => {
return safeTruncate(formData.value.clientPrice - costPrice.value)
})
function safeTruncate(num, decimals = 2) {
if (Number.isNaN(num) || !Number.isFinite(num))
return '0.00'
const factor = 10 ** decimals
const scaled = Math.trunc(num * factor)
return (scaled / factor).toFixed(decimals)
}
function selectProductType(reportTypeValue) {
const reportType = availableReportTypes.value.find(item => item.id === reportTypeValue || item.value === reportTypeValue)
if (!reportType)
return
formData.value.productType = reportType.value
const matchedConfig = productConfig.value?.find(item => item.product_id === reportType.id)
if (!matchedConfig) {
pickerProductConfig.value = null
formData.value.clientPrice = null
uni.showToast({ title: '该报告暂不可推广', icon: 'none' })
return
}
pickerProductConfig.value = matchedConfig
formData.value.clientPrice = matchedConfig.cost_price
}
function onConfirmType(e) {
const nextValue = e?.value?.[0] ?? e?.selectedOptions?.[0]?.value
if (nextValue)
selectProductType(nextValue)
}
function onPriceChange(price) {
formData.value.clientPrice = price
}
function getPricePayload() {
return safeTruncate(Number(formData.value.clientPrice))
}
function openPricePicker() {
if (!pickerProductConfig.value) {
uni.showToast({ title: '请先选择报告类型', icon: 'none' })
return
}
showPricePicker.value = true
}
async function getPromoteConfig() {
loadingConfig.value = true
try {
const { data, error } = await useApiFetch('/agent/product_config').get().json()
if (data.value && !error.value && data.value.code === 200) {
const list = data.value.data.AgentProductConfig || []
productConfig.value = list
const availableType = availableReportTypes.value[0]
if (availableType) {
selectProductType(availableType.value)
}
else {
pickerProductConfig.value = null
formData.value.productType = ''
formData.value.clientPrice = null
uni.showToast({ title: '暂无可推广产品', icon: 'none' })
}
return
}
uni.showToast({ title: data.value?.msg || '获取配置失败', icon: 'none' })
}
catch {
uni.showToast({ title: '获取配置失败', icon: 'none' })
}
finally {
loadingConfig.value = false
}
}
async function generatePromotionCode() {
if (generating.value)
return
try {
await promotionForm.value.validate()
}
catch {
return
}
generating.value = true
try {
const { data, error } = await useApiFetch('/agent/generating_link')
.post({ product: formData.value.productType, price: getPricePayload() })
.json()
if (data.value && !error.value && data.value.code === 200) {
linkIdentifier.value = data.value.data.link_identifier
showQRcode.value = true
}
else {
uni.showToast({ title: data.value?.msg || '生成推广码失败', icon: 'none' })
}
}
catch {
uni.showToast({ title: '生成推广码失败', icon: 'none' })
}
finally {
generating.value = false
}
}
onMounted(() => {
getPromoteConfig()
})
</script>
<template>
<view class="promote min-h-screen p-4">
<view class="card mb-4 from-orange-200 to-orange-200/80 !bg-gradient-to-b">
<view class="text-lg text-orange-500 font-bold">
直推用户查询
</view>
<view class="mt-1 text-orange-400 font-bold">
自定义价格赚取差价
</view>
<view class="mt-6 rounded-xl bg-orange-100 px-4 py-2 text-gray-600">
在下方 自定义价格 处选择报告类型设置客户查询价即可立即推广
</view>
</view>
<VipBanner />
<view class="card mb-4">
<view class="mb-2 text-xl font-semibold">
生成推广码
</view>
<wd-form ref="promotionForm" :model="formData">
<wd-cell-group border>
<wd-picker v-model="formData.productType" label="报告类型" label-width="100px" title="选择报告类型"
:columns="[availableReportTypes]" prop="productType" placeholder="请选择报告类型"
:rules="[{ required: true, message: '请选择报告类型' }]" @confirm="onConfirmType" />
<wd-input v-model="formData.clientPrice" label="客户查询价" label-width="100px" placeholder="请输入价格"
prop="clientPrice" clickable readonly suffix-icon="arrow-right"
:rules="[{ required: true, message: '请输入客户查询价' }]" @click="openPricePicker" />
</wd-cell-group>
<view class="my-2 flex items-center justify-between text-sm text-gray-500">
<view>
推广收益为 <text class="text-orange-500">
{{ promotionRevenue }}
</text>
</view>
<view>
我的成本为 <text class="text-orange-500">
{{ costPrice }}
</text>
</view>
</view>
</wd-form>
<wd-button type="primary" block :loading="generating || loadingConfig"
:disabled="loadingConfig || !pickerProductConfig" @click="generatePromotionCode">
点击立即推广
</wd-button>
</view>
<PriceInputPopup v-model:show="showPricePicker" :default-price="formData.clientPrice"
:product-config="pickerProductConfig" @change="onPriceChange" />
<QRcode v-model:show="showQRcode" :link-identifier="linkIdentifier" />
</view>
</template>
<style scoped></style>