294 lines
7.9 KiB
Vue
294 lines
7.9 KiB
Vue
<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> |