f
This commit is contained in:
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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" });
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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}`,
|
||||||
|
|||||||
Reference in New Issue
Block a user