2025-12-28 00:20:10 +08:00

294 lines
7.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="flex flex-col gap-5 overflow-y-auto px-60 py-6">
<div class="flex flex-col">
<div class="text-gray-500">欢迎回来</div>
<div>
<h1 class="text-3xl font-semibold">
{{ partnerDetails.data?.company_name }}
</h1>
</div>
</div>
<div class="rounded-lg text-base text-gray-900 shadow">
<div class="flex flex-col gap-2.5 p-4">
<div class="flex">
<div class="flex items-center gap-0.5">
<FeatherIcon name="award" class="h-5 text-gray-700" />
<h3 class="text-xl font-semibold">
{{ partnerDetails.data?.partner_type }} 等级
</h3>
</div>
</div>
<div class="pt-2">
<Progress
size="lg"
:value="tierProgressValue"
label="当前进度"
:hint="false"
>
<template #hint>
<span class="text-base font-medium text-gray-500">
{{ formatNumber(nextTierTarget) }} 以达到 {{ nextTier }}
</span>
</template>
</Progress>
</div>
<div class="my-1 h-px bg-gray-100" />
<div class="flex justify-between gap-4">
<div class="flex-1">
<div class="flex items-center justify-between">
<div class="text-sm text-gray-600">
本月贡献
</div>
<Button
label="详情"
@click="showPartnerContributionDialog = true"
/>
</div>
<div class="text-xl font-semibold py-2">
{{
formatCurrency(
partnerDetails.data
?.custom_ongoing_period_fc_invoice_contribution
) || '0.0'
}}
</div>
<div class="text-sm text-gray-600">
<span
>上月:
{{
formatCurrency(
partnerDetails.data?.custom_fc_invoice_contribution
) || '0.0'
}}</span
>
</div>
</div>
<div class="mx-1 w-px border-r" />
<div class="flex-1">
<div class="flex items-center justify-between">
<div class="text-sm text-gray-600">认证成员</div>
<Button label="查看" @click="showPartnerMembersDialog = true" />
</div>
<div class="flex items-center">
<div class="text-xl font-semibold py-2">
{{
partnerDetails.data?.custom_number_of_certified_members || 5
}}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="flex justify-between gap-4">
<div class="rounded-lg text-base flex-1 text-gray-900 p-4 shadow">
<div class="flex h-full flex-col justify-between gap-2">
<div class="flex">
<h3 class="font-semibold text-lg">合作伙伴推荐码</h3>
</div>
<ClickToCopyField :textContent="team.pg?.partner_referral_code" />
<span class="text-sm text-gray-600"
>与客户分享代码以链接到您的账户</span
>
</div>
</div>
<div class="rounded-lg text-base flex-1 text-gray-900 p-4 shadow">
<div class="flex h-full flex-col justify-between">
<div class="flex">
<h3 class="font-semibold text-lg">续订详情</h3>
</div>
<div class="flex items-center justify-between">
<div class="flex">
<span class="text-base font-medium text-gray-700">
{{ formatDate(partnerDetails.data?.end_date) }}
</span>
</div>
<div v-if="isRenewalPeriod()">
<Button
label="续订"
:disabled="false"
:variant="'solid'"
@click="showPartnerCreditsDialog = true"
/>
</div>
</div>
<span class="text-sm text-gray-600"
>{{ daysUntilRenewal }} 天后续订</span
>
</div>
</div>
</div>
<Dialog
:show="showPartnerContributionDialog"
v-model="showPartnerContributionDialog"
:options="{ size: '5xl', title: '本月贡献' }"
>
<template #body-content>
<PartnerContribution :partnerEmail="team.pg.partner_email" />
</template>
</Dialog>
<Dialog
:show="showPartnerCreditsDialog"
v-model="showPartnerCreditsDialog"
:options="{ title: '支付合作伙伴费用' }"
>
<template #body-content>
<PartnerCreditsForm
@success="
() => {
showPartnerCreditsDialog = false;
}
"
/>
</template>
</Dialog>
<Dialog
:show="showPartnerMembersDialog"
v-model="showPartnerMembersDialog"
:options="{ size: 'xl', title: '认证成员' }"
>
<template #body-content>
<PartnerMembers :partnerName="partnerDetails.data?.company_name" />
</template>
</Dialog>
</div>
</template>
<script setup>
import { computed, inject, ref, watch } from 'vue';
import dayjs from '../../utils/dayjs';
import { FeatherIcon, Button, createResource, Progress } from 'jingrow-ui';
import PartnerContribution from './PartnerContribution.vue';
import ClickToCopyField from '../ClickToCopyField.vue';
import PartnerCreditsForm from './PartnerCreditsForm.vue';
import PartnerMembers from './PartnerMembers.vue';
const team = inject('team');
const showPartnerContributionDialog = ref(false);
const showPartnerCreditsDialog = ref(false);
const showPartnerMembersDialog = ref(false);
const partnerDetails = createResource({
url: 'jcloud.api.partner.get_partner_details',
auto: true,
cache: 'partnerDetails',
params: {
partner_email: team.pg.partner_email
},
onSuccess() {
calculateNextTier(partnerDetails.data.partner_type);
}
});
const daysUntilRenewal = computed(() => {
const today = new Date();
const renewal = new Date(partnerDetails.data?.end_date);
return Math.ceil((renewal - today) / (1000 * 60 * 60 * 24));
});
function isRenewalPeriod() {
// 续费日期前15天
const renewal = dayjs(partnerDetails.data?.end_date);
const today = dayjs();
const daysDifference = renewal.diff(today, 'days');
return Boolean(daysDifference >= 0 && daysDifference <= 15);
}
const tierProgressValue = ref(0);
const nextTier = ref('');
const nextTierTarget = ref(0);
function calculateTierProgress(next_tier_value) {
console.log(
partnerDetails.data?.custom_ongoing_period_fc_invoice_contribution,
next_tier_value
);
return Math.ceil(
(partnerDetails.data?.custom_ongoing_period_fc_invoice_contribution /
next_tier_value) *
100
);
}
function calculateNextTier(tier) {
const target_cny = {
Gold: 500000,
Silver: 200000,
Bronze: 50000
};
const target_usd = {
Gold: 6000,
Silver: 2500,
Bronze: 600
};
const current_tier = partnerDetails.data?.partner_type;
let next_tier = '';
switch (current_tier) {
case 'Entry':
next_tier = 'Bronze';
nextTierTarget.value =
team.pg.currency === 'CNY' ? target_cny.Bronze : target_usd.Bronze;
break;
case 'Bronze':
next_tier = 'Silver';
nextTierTarget.value =
team.pg.currency === 'CNY' ? target_cny.Silver : target_usd.Silver;
break;
case 'Silver':
next_tier = 'Gold';
nextTierTarget.value =
team.pg.currency === 'CNY' ? target_cny.Gold : target_usd.Gold;
break;
default:
next_tier = 'Gold';
nextTierTarget.value =
team.pg.currency === 'CNY' ? target_cny.Gold : target_usd.Gold;
}
nextTier.value = next_tier;
tierProgressValue.value = calculateTierProgress(nextTierTarget.value);
nextTierTarget.value =
nextTierTarget.value -
partnerDetails.data?.custom_ongoing_period_fc_invoice_contribution;
}
watch(
() => partnerDetails.data,
(newData) => {
if (newData) {
calculateNextTier(newData.partner_type);
}
},
{ deep: true },
);
const formatDate = dateString => {
return new Date(dateString).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
};
const formatCurrency = amount => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: team.pg.currency,
maximumFractionDigits: 2
}).format(amount);
};
const formatNumber = value => {
return new Intl.NumberFormat('en-US', {
notation: 'compact',
compactDisplay: 'short'
}).format(value);
};
</script>