This commit is contained in:
2026-04-28 16:37:05 +08:00
parent cd7c4c8d3b
commit 121c7ffcf5
4 changed files with 140 additions and 18 deletions

View File

@@ -7,6 +7,16 @@ export function safeTruncate(num, decimals = 2) {
return (scaled / factor).toFixed(decimals) return (scaled / factor).toFixed(decimals)
} }
function toTruncatedCents(num) {
if (Number.isNaN(num) || !Number.isFinite(num))
return 0
return Math.trunc((num + Number.EPSILON) * 100)
}
function centsToFixed(cents) {
return (cents / 100).toFixed(2)
}
function calculatePlatformOverpricingCost(price, config) { function calculatePlatformOverpricingCost(price, config) {
if (price <= config.p_pricing_standard) if (price <= config.p_pricing_standard)
return 0 return 0
@@ -37,10 +47,12 @@ export function calculatePromotionPricing(priceInput, config) {
const platformOverpricingCost = calculatePlatformOverpricingCost(price, config) const platformOverpricingCost = calculatePlatformOverpricingCost(price, config)
const superiorOverpricingCost = calculateSuperiorOverpricingCost(price, config) const superiorOverpricingCost = calculateSuperiorOverpricingCost(price, config)
const totalCost = baseCost + platformOverpricingCost + superiorOverpricingCost const totalCost = baseCost + platformOverpricingCost + superiorOverpricingCost
const revenue = price - totalCost const priceCents = toTruncatedCents(price)
const costCents = toTruncatedCents(totalCost)
const revenueCents = priceCents - costCents
return { return {
costPrice: safeTruncate(totalCost), costPrice: centsToFixed(costCents),
promotionRevenue: safeTruncate(revenue), promotionRevenue: centsToFixed(revenueCents),
} }
} }

View File

@@ -17,7 +17,8 @@
待结账金额¥ {{ (data?.frozen_balance || 0).toFixed(2) }} 待结账金额¥ {{ (data?.frozen_balance || 0).toFixed(2) }}
<van-popover v-model:show="showTooltip" placement="bottom-start" :offset="10"> <van-popover v-model:show="showTooltip" placement="bottom-start" :offset="10">
<template #reference> <template #reference>
<van-icon name="question-o" class="ml-2 cursor-help" @mouseenter="showTooltip = true" @mouseleave="showTooltip = false" /> <van-icon name="question-o" class="ml-2 cursor-help" @mouseenter="showTooltip = true"
@mouseleave="showTooltip = false" />
</template> </template>
<div class="p-2 text-sm" style="max-width: 200px;"> <div class="p-2 text-sm" style="max-width: 200px;">
待结账金额将在订单创建24小时后自动结账 待结账金额将在订单创建24小时后自动结账
@@ -105,17 +106,95 @@
</div> </div>
</div> </div>
<!-- 团队奖励明细与下级 --> <!-- 活跃下级奖励 -->
<div class="rounded-xl shadow-lg bg-gradient-to-r from-success-50/50 to-success-100/40 p-6"> <div class="rounded-xl shadow-lg bg-gradient-to-r from-success-50/50 to-success-100/40 p-6">
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2"> <div class="flex justify-between items-center mb-4">
<button type="button" @click="goToRewardsDetail" <div class="flex items-center">
class="w-full rounded-full border bg-white/90 py-3 px-4 shadow-sm flex items-center justify-center" <van-icon name="friends" class="text-xl mr-2" style="color: var(--color-success);" />
style="color: var(--van-text-color-2); border-color: var(--van-border-color);"> <span class="text-lg font-bold" style="color: var(--van-text-color);">活跃下级奖励</span>
<van-icon name="records" class="mr-1" /> </div>
团队奖励明细 <div class="text-right">
<div class="text-2xl font-bold" style="color: var(--color-success);">
¥
{{
(data?.active_reward?.total_reward || 0).toFixed(2)
}}
</div>
<!-- <div class="text-sm mt-1" style="color: var(--van-text-color-2);">活跃下级 0 </div> -->
</div>
</div>
<!-- 日期选择 -->
<div class="grid grid-cols-3 gap-2 mb-6">
<button v-for="item in activeDateOptions" :key="item.value" @click="selectedActiveDate = item.value"
class="rounded-full transition-all py-1 px-4 text-sm" :class="[
selectedActiveDate === item.value
? 'text-white shadow-md'
: 'bg-white/90 border',
]" :style="selectedActiveDate === item.value
? 'background-color: var(--color-success);'
: 'color: var(--van-text-color-2); border-color: var(--van-border-color);'">
{{ item.label }}
</button> </button>
<button type="button" @click="toSubordinateList" </div>
class="w-full rounded-full py-3 px-4 shadow-md flex items-center justify-center text-white"
<div class="grid grid-cols-2 gap-2 mb-6">
<div class="p-3 rounded-lg backdrop-blur-sm" style="background-color: rgba(16, 185, 129, 0.08);">
<div class="flex items-center text-sm" style="color: var(--van-text-color-2);">
<van-icon name="medal" class="mr-1" />{{ activeDateText }}奖励
</div>
<div class="text-xl font-bold mt-1" style="color: var(--color-success);">
¥
{{ (currentActiveData.active_reward || 0).toFixed(2) }}
</div>
</div>
<div class="p-3 rounded-lg backdrop-blur-sm" style="background-color: rgba(16, 185, 129, 0.08);">
<div class="flex items-center text-sm" style="color: var(--van-text-color-2);">
<van-icon name="discount" class="mr-1" />下级推广奖励
</div>
<div class="text-xl font-bold mt-1" style="color: var(--color-success);">
¥
{{
(currentActiveData.sub_promote_reward || 0).toFixed(
2
)
}}
</div>
</div>
<div class="p-3 rounded-lg backdrop-blur-sm" style="background-color: rgba(16, 185, 129, 0.08);">
<div class="flex items-center text-sm" style="color: var(--van-text-color-2);">
<van-icon name="fire" class="mr-1" />下级转化奖励
</div>
<div class="text-xl font-bold mt-1" style="color: var(--color-success);">
¥
{{
(
currentActiveData.sub_upgrade_reward || 0
).toFixed(2)
}}
</div>
</div>
<div class="p-3 rounded-lg backdrop-blur-sm" style="background-color: rgba(16, 185, 129, 0.08);">
<div class="flex items-center text-sm" style="color: var(--van-text-color-2);">
<van-icon name="cashier-o" class="mr-1" />下级提现奖励
</div>
<div class="text-xl font-bold mt-1" style="color: var(--color-success);">
¥
{{ (currentActiveData.sub_withdraw_reward || 0).toFixed(2) }}
</div>
</div>
</div>
<div class="flex items-center justify-between text-sm font-semibold cursor-pointer pt-4"
style="color: var(--color-success);" @click="goToActiveDetail">
<span>查看奖励明细</span>
<span class="text-lg"></span>
</div>
<!-- 添加查看下级按钮 -->
<div class="mt-4">
<button @click="toSubordinateList"
class="w-full text-white rounded-full py-2 px-4 shadow-md flex items-center justify-center bg-success"
style="background: linear-gradient(135deg, var(--color-success), var(--color-success-600));"> style="background: linear-gradient(135deg, var(--color-success), var(--color-success-600));">
<van-icon name="friends" class="mr-1" /> <van-icon name="friends" class="mr-1" />
查看我的下级 查看我的下级
@@ -150,12 +229,41 @@ const promoteDateOptions = [
]; ];
const selectedPromoteDate = ref("today"); const selectedPromoteDate = ref("today");
// 活跃下级数据
const activeDateOptions = [
{ label: "今日", value: "today" },
{ label: "近7天", value: "week" },
{ label: "近1月", value: "month" },
];
const selectedActiveDate = ref("today");
const dateTextMap = {
today: "今日",
week: "近7天",
month: "近1月",
};
// 计算当前直推数据 // 计算当前直推数据
const currentPromoteData = computed(() => { const currentPromoteData = computed(() => {
const range = dateRangeMap[selectedPromoteDate.value]; const range = dateRangeMap[selectedPromoteDate.value];
return data.value?.direct_push?.[range] || { commission: 0, report: 0 }; return data.value?.direct_push?.[range] || { commission: 0, report: 0 };
}); });
// 计算当前活跃数据
const currentActiveData = computed(() => {
const range = dateRangeMap[selectedActiveDate.value];
return (
data.value?.active_reward?.[range] || {
active_reward: 0,
sub_promote_reward: 0,
sub_upgrade_reward: 0,
sub_withdraw_reward: 0,
}
);
});
const activeDateText = computed(
() => dateTextMap[selectedActiveDate.value] || "今日"
);
const getData = async () => { const getData = async () => {
const { data: res, error } = await useApiFetch("/agent/revenue") const { data: res, error } = await useApiFetch("/agent/revenue")
.get() .get()
@@ -174,7 +282,7 @@ onMounted(() => {
// 路由跳转 // 路由跳转
const goToPromoteDetail = () => router.push({ name: "promoteDetails" }); const goToPromoteDetail = () => router.push({ name: "promoteDetails" });
const goToRewardsDetail = () => router.push({ name: "rewardsDetails" }); const goToActiveDetail = () => router.push({ name: "rewardsDetails" });
const toWithdraw = () => router.push({ name: "withdraw" }); const toWithdraw = () => router.push({ name: "withdraw" });

View File

@@ -101,7 +101,7 @@
} }
" class="custom-field" :class="{ 'van-field--error': rangeError }"> " class="custom-field" :class="{ 'van-field--error': rangeError }">
<template #label> <template #label>
<span class="text-gray-600 font-medium">💰 最低金额</span> <span class="text-gray-600 font-medium">💰 定价区间最低</span>
</template> </template>
<template #extra> <template #extra>
<span class="text-blue-500 font-medium ml-2"></span> <span class="text-blue-500 font-medium ml-2"></span>
@@ -123,7 +123,7 @@
} }
" class="custom-field" :class="{ 'van-field--error': rangeError }"> " class="custom-field" :class="{ 'van-field--error': rangeError }">
<template #label> <template #label>
<span class="text-gray-600 font-medium">💰 最高金额</span> <span class="text-gray-600 font-medium">💰 定价区间最高</span>
</template> </template>
<template #extra> <template #extra>
<span class="text-blue-500 font-medium ml-2"></span> <span class="text-blue-500 font-medium ml-2"></span>
@@ -490,7 +490,8 @@ const loadReportOptions = async () => {
const { data, error } = await useApiFetch("/agent/product_config").get().json(); const { data, error } = await useApiFetch("/agent/product_config").get().json();
if (error.value || data.value?.code !== 200) return; if (error.value || data.value?.code !== 200) return;
const list = data.value?.data?.agent_product_config || data.value?.data?.AgentProductConfig || []; const list = data.value?.data?.agent_product_config || data.value?.data?.AgentProductConfig || [];
reportOptions.value = list reportOptions.value = [...list]
.sort((a, b) => Number(a.product_id) - Number(b.product_id))
.map((p) => ({ .map((p) => ({
text: p.product_name || `报告${p.product_id}`, text: p.product_name || `报告${p.product_id}`,
value: p.product_id, value: p.product_id,

View File

@@ -100,7 +100,8 @@ const productConfig = ref(null);
const linkIdentifier = ref("") const linkIdentifier = ref("")
const reportTypes = computed(() => { const reportTypes = computed(() => {
if (!productConfig.value?.length) return [] if (!productConfig.value?.length) return []
return productConfig.value return [...productConfig.value]
.sort((a, b) => Number(a.product_id) - Number(b.product_id))
.map(item => ({ .map(item => ({
id: item.product_id, id: item.product_id,
text: item.product_name || `产品${item.product_id}`, text: item.product_name || `产品${item.product_id}`,