first commit
This commit is contained in:
181
src/components/PriceInputPopup.vue
Normal file
181
src/components/PriceInputPopup.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<van-popup v-model:show="show" destroy-on-close round position="bottom">
|
||||
<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">
|
||||
<van-field v-model="price" type="number" label="¥" label-width="28"
|
||||
:placeholder="`${productConfig.price_range_min} - ${productConfig.price_range_max}`"
|
||||
@blur="onBlurPrice" class="!text-3xl" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-2">
|
||||
<div>推广收益为<span class="text-orange-500"> {{ promotionRevenue }} </span>元</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-2">
|
||||
<div>底价成本为<span class="text-orange-500"> {{ baseCost }} </span>元</div>
|
||||
<div>提价成本为<span class="text-orange-500"> {{ raiseCost }} </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">
|
||||
<van-button class="w-full" round type="primary" size="large" @click="onConfirm">确认</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</van-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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)
|
||||
|
||||
|
||||
watch(show, () => {
|
||||
price.value = defaultPrice.value
|
||||
})
|
||||
|
||||
|
||||
const costPrice = computed(() => {
|
||||
if (!productConfig.value) return 0.00
|
||||
|
||||
// 新代理系统:成本价 = 实际底价(actual_base_price)+ 提价成本
|
||||
const actualBasePrice = Number(productConfig.value.actual_base_price) || 0;
|
||||
const priceNum = Number(price.value) || 0;
|
||||
const priceThreshold = Number(productConfig.value.price_threshold) || 0;
|
||||
const priceFeeRate = Number(productConfig.value.price_fee_rate) || 0;
|
||||
|
||||
// 计算提价成本
|
||||
let priceCost = 0;
|
||||
if (priceNum > priceThreshold) {
|
||||
priceCost = (priceNum - priceThreshold) * priceFeeRate;
|
||||
}
|
||||
|
||||
// 总成本 = 实际底价 + 提价成本
|
||||
const totalCost = actualBasePrice + priceCost;
|
||||
|
||||
return safeTruncate(totalCost);
|
||||
})
|
||||
|
||||
const baseCost = computed(() => {
|
||||
if (!productConfig.value) return "0.00";
|
||||
const actualBasePrice = Number(productConfig.value.actual_base_price) || 0;
|
||||
return safeTruncate(actualBasePrice);
|
||||
})
|
||||
|
||||
const raiseCost = computed(() => {
|
||||
if (!productConfig.value) return "0.00";
|
||||
const priceNum = Number(price.value) || 0;
|
||||
const priceThreshold = Number(productConfig.value.price_threshold) || 0;
|
||||
const priceFeeRate = Number(productConfig.value.price_fee_rate) || 0;
|
||||
let priceCost = 0;
|
||||
if (priceNum > priceThreshold) {
|
||||
priceCost = (priceNum - priceThreshold) * priceFeeRate;
|
||||
}
|
||||
return safeTruncate(priceCost);
|
||||
})
|
||||
|
||||
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
|
||||
showToast({ 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
|
||||
showToast({ message });
|
||||
}
|
||||
setTimeout(() => {
|
||||
isManualConfirm.value = false
|
||||
}, 0)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
Reference in New Issue
Block a user