226 lines
7.3 KiB
Vue
226 lines
7.3 KiB
Vue
|
|
<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>
|