Files

179 lines
5.8 KiB
Plaintext

<template>
<view class="plan-cards">
<view class="section-title-container">
<view class="section-title-bar"></view>
<text class="section-title">{{
t("Mobile.MySubscriptions.planGrid")
}}</text>
</view>
<view class="cards-list">
<view
v-for="plan in plans"
:key="plan.id"
class="plan-card"
:class="{ 'plan-current': plan.id === currentPlanId }"
>
<!-- 标签 -->
<view class="plan-badges">
<view v-if="plan.id === currentPlanId" class="badge badge-active">
<text class="badge-text">{{
t("Mobile.MySubscriptions.currentPlan")
}}</text>
</view>
<view v-else-if="plan.isHot" class="badge badge-hot">
<text class="badge-text">{{
t("Mobile.MySubscriptions.statusHot")
}}</text>
</view>
</view>
<!-- 主体内容 -->
<view class="plan-card-body">
<!-- 套餐信息 -->
<text class="plan-name">{{ plan.name }}</text>
<text v-if="plan.description" class="plan-desc">{{
plan.description
}}</text>
<view class="plan-price-row">
<text class="plan-price-symbol">¥</text>
<text class="plan-price-value">{{
formatNumber(plan.price, 2)
}}</text>
<text class="plan-period">{{ getPeriodUnit(plan.period) }}</text>
</view>
<view class="plan-credits-tag">
<text class="plan-credits-text">
{{
`${formatNumber(plan.creditAmount, 0)} ${t("Mobile.MySubscriptions.creditUnit")}${t("Mobile.MySubscriptions.perMonth")}`
}}
</text>
</view>
<!-- 按钮(移入副标题及价格信息下方,与 PC 端保持一致) -->
<view class="plan-action-area">
<view
class="plan-btn"
:class="{
'plan-btn-processing': processingId === plan.id,
'plan-btn-current': plan.id === currentPlanId,
'plan-btn-disabled':
plan.price <= 0 && plan.id !== currentPlanId,
}"
@tap="handleAction(plan)"
>
<text class="plan-btn-text">{{ getButtonText(plan) }}</text>
</view>
</view>
<!-- 分割线(与 PC 端保持一致) -->
<view class="plan-divider"></view>
<!-- 权益列表 -->
<view class="benefits" v-if="getBaseBenefits(plan).length > 0">
<view class="benefit-group">
<view
v-for="(item, index) in getBaseBenefits(plan)"
:key="index"
class="benefit-item"
>
<view
class="benefit-icon-container"
:class="item.selected ? 'icon-check' : 'icon-cross'"
>
<text class="benefit-icon-text">{{
item.selected ? "✓" : "✗"
}}</text>
</view>
<text class="benefit-text">{{ item.description }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import type {
SystemSubscriptionPlan,
SystemSubscriptionPlanGroup,
SystemSubscriptionPlanItem,
} from "@/subpackages/types/interfaces/subscription";
import { useI18n } from "@/utils/i18n";
import { getPeriodUnit } from "../../utils.uts";
import { formatDate, formatNumber } from "@/utils/system";
import { useSubscriptionPurchase } from "../../hooks/useSubscriptionPurchase";
const { t } = useI18n();
const { processingId, handlePaySubscription } = useSubscriptionPurchase();
interface Props {
plans: SystemSubscriptionPlan[];
currentPlanId: number | null;
currentEndTime: string | null;
currentPlanPrice?: number | null;
}
const props = withDefaults(defineProps<Props>(), {
currentPlanPrice: null,
});
const getActionVerb = (planPrice: number): string => {
if (props.currentPlanId == null) {
return t("Mobile.MySubscriptions.subscribeNow");
}
const currentPrice = props.currentPlanPrice ?? 0;
if (planPrice <= currentPrice) {
return t("Mobile.MySubscriptions.subscribeNow");
}
return t("Mobile.MySubscriptions.upgradeNow");
};
const getButtonText = (plan: SystemSubscriptionPlan): string => {
if (plan.id === props.currentPlanId) {
const currentPlanBtnText = t("Mobile.MySubscriptions.currentPlanButton");
const renewNowText = t("Mobile.MySubscriptions.renewNow");
return `${currentPlanBtnText}(${renewNowText})`;
}
const verbText = getActionVerb(plan.price);
let periodText = t("Mobile.MySubscriptions.continuousMonthly");
if (plan.period === 3) {
periodText = t("Mobile.MySubscriptions.continuousQuarterly");
} else if (plan.period === 12) {
periodText = t("Mobile.MySubscriptions.continuousYearly");
}
return `${verbText}${plan.name}${periodText}`;
};
const handleAction = async (plan: SystemSubscriptionPlan) => {
if (plan.price <= 0 && plan.id !== props.currentPlanId) return;
await handlePaySubscription(plan.id);
};
const getBaseBenefits = (
plan: SystemSubscriptionPlan,
): SystemSubscriptionPlanItem[] => {
const list = [] as SystemSubscriptionPlanItem[];
const groups = plan.itemGroups;
if (groups != null) {
for (let i = 0; i < groups.length; i++) {
const g = groups[i];
if (g.groupType === "BASE" && g.items != null) {
for (let j = 0; j < g.items.length; j++) {
list.push(g.items[j]);
}
}
}
}
return list;
};
</script>
<style lang="scss" scoped>
@import "./plan-cards.scss";
</style>