180 lines
5.7 KiB
Vue
180 lines
5.7 KiB
Vue
|
<template>
|
|||
|
<wd-popup v-model="show" position="bottom" round close-on-click-modal destroy-on-close>
|
|||
|
<div class="min-h-[500px] bg-gray-50 text-gray-600">
|
|||
|
<div class="h-10 bg-white flex items-center justify-center font-semibold text-lg">设置客户查询价
|
|||
|
</div>
|
|||
|
<div class="card m-4">
|
|||
|
<div class="flex items-center justify-between">
|
|||
|
<div class="text-lg">
|
|||
|
客户查询价 (元)</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="border-b border-gray-200">
|
|||
|
<wd-input v-model="price" type="number" label="¥" label-width="28px" size="large"
|
|||
|
:placeholder="`${productConfig.price_range_min} - ${productConfig.price_range_max}`"
|
|||
|
@blur="onBlurPrice" custom-class="wd-input" />
|
|||
|
</div>
|
|||
|
<div class="flex items-center justify-between mt-2">
|
|||
|
<div>推广收益为<span class="text-orange-500"> {{ promotionRevenue }} </span>元</div>
|
|||
|
<div>我的成本为<span class="text-orange-500"> {{ costPrice }} </span>元</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<div class="card m-4">
|
|||
|
<div class="text-lg mb-2">收益与成本说明</div>
|
|||
|
|
|||
|
<div>推广收益 = 客户查询价 - 我的成本</div>
|
|||
|
<div>我的成本 = 提价成本 + 底价成本</div>
|
|||
|
<div class="mt-1">提价成本:超过平台标准定价部分,平台会收取部分成本价</div>
|
|||
|
<div class="">设定范围:<span class="text-orange-500">{{
|
|||
|
productConfig.price_range_min }}</span>元 - <span class="text-orange-500">{{
|
|||
|
productConfig.price_range_max }}</span>元</div>
|
|||
|
</div>
|
|||
|
<div class="px-4 pb-4">
|
|||
|
<wd-button class="w-full" round type="primary" size="large" @click="onConfirm">确认</wd-button>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</wd-popup>
|
|||
|
<wd-toast />
|
|||
|
</template>
|
|||
|
|
|||
|
<script setup>
|
|||
|
import { ref, computed, watch, toRefs } from 'vue'
|
|||
|
import { useToast } from 'wot-design-uni'
|
|||
|
const props = defineProps({
|
|||
|
defaultPrice: {
|
|||
|
type: Number,
|
|||
|
required: true
|
|||
|
},
|
|||
|
productConfig: {
|
|||
|
type: Object,
|
|||
|
required: true
|
|||
|
}
|
|||
|
})
|
|||
|
const { defaultPrice, productConfig } = toRefs(props)
|
|||
|
const emit = defineEmits(["change"])
|
|||
|
const show = defineModel("show")
|
|||
|
const price = ref(null)
|
|||
|
const toast = useToast()
|
|||
|
|
|||
|
watch(show, () => {
|
|||
|
price.value = defaultPrice.value
|
|||
|
})
|
|||
|
|
|||
|
const costPrice = computed(() => {
|
|||
|
if (!productConfig.value) return 0.00
|
|||
|
// 平台定价成本
|
|||
|
let platformPricing = 0
|
|||
|
platformPricing += productConfig.value.cost_price
|
|||
|
if (price.value > productConfig.value.p_pricing_standard) {
|
|||
|
platformPricing += (price.value - productConfig.value.p_pricing_standard) * productConfig.value.p_overpricing_ratio
|
|||
|
}
|
|||
|
|
|||
|
if (productConfig.value.a_pricing_standard > platformPricing && productConfig.value.a_pricing_end > platformPricing && productConfig.value.a_overpricing_ratio > 0) {
|
|||
|
if (price.value > productConfig.value.a_pricing_standard) {
|
|||
|
if (price.value > productConfig.value.a_pricing_end) {
|
|||
|
platformPricing += (productConfig.value.a_pricing_end - productConfig.value.a_pricing_standard) * productConfig.value.a_overpricing_ratio
|
|||
|
} else {
|
|||
|
platformPricing += (price.value - productConfig.value.a_pricing_standard) * productConfig.value.a_overpricing_ratio
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return safeTruncate(platformPricing)
|
|||
|
})
|
|||
|
|
|||
|
const promotionRevenue = computed(() => {
|
|||
|
return safeTruncate(price.value - costPrice.value)
|
|||
|
});
|
|||
|
|
|||
|
// 价格校验与修正逻辑
|
|||
|
const validatePrice = (currentPrice) => {
|
|||
|
const min = productConfig.value.price_range_min;
|
|||
|
const max = productConfig.value.price_range_max;
|
|||
|
let newPrice = Number(currentPrice);
|
|||
|
let message = '';
|
|||
|
|
|||
|
// 处理无效输入
|
|||
|
if (isNaN(newPrice)) {
|
|||
|
newPrice = defaultPrice.value;
|
|||
|
return { newPrice, message: '输入无效,请输入价格' };
|
|||
|
}
|
|||
|
|
|||
|
// 处理小数位数(兼容科学计数法)
|
|||
|
try {
|
|||
|
const priceString = newPrice.toString()
|
|||
|
const [_, decimalPart = ""] = priceString.split('.');
|
|||
|
console.log(priceString, decimalPart)
|
|||
|
// 当小数位数超过2位时处理
|
|||
|
if (decimalPart.length > 2) {
|
|||
|
newPrice = parseFloat(safeTruncate(newPrice));
|
|||
|
message = '价格已自动格式化为两位小数';
|
|||
|
}
|
|||
|
} catch (e) {
|
|||
|
console.error('价格格式化异常:', e);
|
|||
|
}
|
|||
|
|
|||
|
// 范围校验(基于可能格式化后的值)
|
|||
|
if (newPrice < min) {
|
|||
|
message = `价格不能低于 ${min} 元`;
|
|||
|
newPrice = min;
|
|||
|
} else if (newPrice > max) {
|
|||
|
message = `价格不能高于 ${max} 元`;
|
|||
|
newPrice = max;
|
|||
|
}
|
|||
|
console.log(newPrice, message)
|
|||
|
return { newPrice, message };
|
|||
|
}
|
|||
|
function safeTruncate(num, decimals = 2) {
|
|||
|
if (isNaN(num) || !isFinite(num)) return "0.00";
|
|||
|
|
|||
|
const factor = 10 ** decimals;
|
|||
|
const scaled = Math.trunc(num * factor);
|
|||
|
const truncated = scaled / factor;
|
|||
|
|
|||
|
return truncated.toFixed(decimals);
|
|||
|
}
|
|||
|
const isManualConfirm = ref(false)
|
|||
|
const onConfirm = () => {
|
|||
|
if (isManualConfirm.value) return
|
|||
|
const { newPrice, message } = validatePrice(price.value)
|
|||
|
if (message) {
|
|||
|
price.value = newPrice
|
|||
|
toast.show(message)
|
|||
|
} else {
|
|||
|
emit("change", price.value)
|
|||
|
show.value = false
|
|||
|
}
|
|||
|
}
|
|||
|
const onBlurPrice = () => {
|
|||
|
const { newPrice, message } = validatePrice(price.value)
|
|||
|
if (message) {
|
|||
|
isManualConfirm.value = true
|
|||
|
price.value = newPrice
|
|||
|
toast.show(message)
|
|||
|
}
|
|||
|
setTimeout(() => {
|
|||
|
isManualConfirm.value = false
|
|||
|
}, 0)
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
<style lang="scss" scoped>
|
|||
|
.wd-input {
|
|||
|
display: flex !important;
|
|||
|
align-items: center !important;
|
|||
|
justify-content: center !important;
|
|||
|
:deep(.wd-input__label-inner) {
|
|||
|
font-size: 24px !important; /* 增大label字体 */
|
|||
|
}
|
|||
|
|
|||
|
:deep(.wd-input__inner) {
|
|||
|
font-size: 24px !important; /* 增大输入框内字体 */
|
|||
|
}
|
|||
|
|
|||
|
:deep(.wd-input) {
|
|||
|
height: auto !important; /* 确保高度自适应 */
|
|||
|
padding: 8px 0 !important; /* 增加垂直内边距 */
|
|||
|
}
|
|||
|
}
|
|||
|
</style>
|