Initial commit: OmniAI Web Frontend
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
import { CheckCircleOutlined, CloseOutlined, CrownOutlined, RocketOutlined } from "@ant-design/icons";
|
||||
import { useMemo, useState, type ReactNode } from "react";
|
||||
|
||||
type RechargeAudience = "personal" | "enterprise";
|
||||
|
||||
interface MembershipPlan {
|
||||
id: string;
|
||||
audience: RechargeAudience;
|
||||
name: string;
|
||||
subtitle: string;
|
||||
period: string;
|
||||
price: string;
|
||||
grant: string;
|
||||
comparisonLabel: string;
|
||||
badge?: string;
|
||||
icon: ReactNode;
|
||||
benefits: string[];
|
||||
}
|
||||
|
||||
const membershipPlans: MembershipPlan[] = [
|
||||
{
|
||||
id: "pro-month",
|
||||
audience: "personal",
|
||||
name: "专业版",
|
||||
subtitle: "Pro",
|
||||
period: "月付",
|
||||
price: "299 元 / 月",
|
||||
grant: "每月赠送 10000 积分,30 天有效",
|
||||
comparisonLabel: "专业版基础权益",
|
||||
icon: <CrownOutlined />,
|
||||
benefits: ["通用大模型全解锁", "积分与 API 消耗 9 折", "并发提升到 3 个", "去水印、插队加速、专属客服"],
|
||||
},
|
||||
{
|
||||
id: "pro-quarter",
|
||||
audience: "personal",
|
||||
name: "专业版",
|
||||
subtitle: "Pro",
|
||||
period: "季付",
|
||||
price: "897 元 / 季",
|
||||
grant: "连续 3 个月按月发放 Pro 积分",
|
||||
comparisonLabel: "相比月付新增",
|
||||
badge: "季度",
|
||||
icon: <CrownOutlined />,
|
||||
benefits: ["一次覆盖 3 个月使用周期", "每月延续 Pro 权益", "适合短期项目排期"],
|
||||
},
|
||||
{
|
||||
id: "pro-year",
|
||||
audience: "personal",
|
||||
name: "专业版",
|
||||
subtitle: "Pro",
|
||||
period: "年付",
|
||||
price: "1990 元 / 年",
|
||||
grant: "全年合计 140000 积分,默认按月分摊",
|
||||
comparisonLabel: "相比季付新增",
|
||||
badge: "年费优惠",
|
||||
icon: <CrownOutlined />,
|
||||
benefits: ["折合 10 个月费用", "前 100 名额外赠 20000 积分", "适合全年持续高频使用"],
|
||||
},
|
||||
{
|
||||
id: "enterprise-month",
|
||||
audience: "enterprise",
|
||||
name: "企业版",
|
||||
subtitle: "Enterprise",
|
||||
period: "月付",
|
||||
price: "499 元 / 月",
|
||||
grant: "每月赠送 2000 积分,30 天有效",
|
||||
comparisonLabel: "企业版基础权益",
|
||||
icon: <RocketOutlined />,
|
||||
benefits: ["企业私有模型与高性能模型", "默认 10 并发,可申请提升", "积分与 API 消耗 8 折", "用量报表与正式 API 权限"],
|
||||
},
|
||||
{
|
||||
id: "enterprise-quarter",
|
||||
audience: "enterprise",
|
||||
name: "企业版",
|
||||
subtitle: "Enterprise",
|
||||
period: "季付",
|
||||
price: "1497 元 / 季",
|
||||
grant: "连续 3 个月按月发放企业版积分",
|
||||
comparisonLabel: "相比月付新增",
|
||||
badge: "季度",
|
||||
icon: <RocketOutlined />,
|
||||
benefits: ["一次覆盖季度项目周期", "延续企业资源池与高并发", "适合阶段性团队投放"],
|
||||
},
|
||||
{
|
||||
id: "enterprise-year",
|
||||
audience: "enterprise",
|
||||
name: "企业版",
|
||||
subtitle: "Enterprise",
|
||||
period: "年付",
|
||||
price: "4990 元 / 年",
|
||||
grant: "全年合计 340000 积分,默认按月分摊",
|
||||
comparisonLabel: "相比季付新增",
|
||||
badge: "企业年费",
|
||||
icon: <RocketOutlined />,
|
||||
benefits: ["折合 10 个月费用", "前 100 名额外赠 100000 积分", "支持对公充值与子账户额度分配"],
|
||||
},
|
||||
];
|
||||
|
||||
const defaultSelectedPlanIds: Record<RechargeAudience, string> = {
|
||||
personal: "pro-month",
|
||||
enterprise: "enterprise-month",
|
||||
};
|
||||
|
||||
const rechargeRules = [
|
||||
"充值比例:固定 1 元 = 100 积分,平台可限时活动额外赠送积分",
|
||||
"有效期:充值积分到账起有效期 12 个月,系统按先进先出自动消耗",
|
||||
"退费规则:充值积分到账后不支持退换、折现,仅限平台内消费",
|
||||
];
|
||||
|
||||
interface RechargeModalProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
currentBalance?: number;
|
||||
}
|
||||
|
||||
export function RechargeModal({ open, onClose, currentBalance }: RechargeModalProps) {
|
||||
const [activeAudience, setActiveAudience] = useState<RechargeAudience>("personal");
|
||||
const [selectedPlanIds, setSelectedPlanIds] = useState<Record<RechargeAudience, string>>(defaultSelectedPlanIds);
|
||||
const visiblePlans = useMemo(() => membershipPlans.filter((plan) => plan.audience === activeAudience), [activeAudience]);
|
||||
const selectedPlanId = selectedPlanIds[activeAudience];
|
||||
|
||||
const handlePlanSelect = (plan: MembershipPlan) => {
|
||||
setSelectedPlanIds((current) => ({
|
||||
...current,
|
||||
[plan.audience]: plan.id,
|
||||
}));
|
||||
};
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
return (
|
||||
<div className="recharge-modal" role="dialog" aria-modal="true" aria-labelledby="recharge-modal-title">
|
||||
<button type="button" className="recharge-modal__backdrop" onClick={onClose} aria-label="关闭充值弹窗" />
|
||||
<section className="recharge-modal__panel" aria-describedby="recharge-modal-desc">
|
||||
<div className="recharge-modal__promo" role="note">
|
||||
<strong>限时活动</strong>
|
||||
<span>年付套餐前 100 名额外赠送积分,季度套餐适合短期项目集中投放,充值积分有效期 12 个月。</span>
|
||||
</div>
|
||||
|
||||
<header className="recharge-modal__header">
|
||||
<div>
|
||||
<span className="recharge-modal__eyebrow">会员与积分</span>
|
||||
<h2 id="recharge-modal-title">积分充值</h2>
|
||||
<p id="recharge-modal-desc">按个人或企业场景选择版本,重点展示相对左侧版本的新增权益。</p>
|
||||
</div>
|
||||
{currentBalance !== undefined ? (
|
||||
<span className="recharge-modal__balance">当前余额:{(currentBalance / 100).toFixed(2)} 积分</span>
|
||||
) : null}
|
||||
<button type="button" className="recharge-modal__close" onClick={onClose} aria-label="关闭">
|
||||
<CloseOutlined />
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div className="recharge-modal__audience-tabs" role="tablist" aria-label="充值对象">
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={activeAudience === "personal"}
|
||||
className={activeAudience === "personal" ? "is-active" : ""}
|
||||
onClick={() => setActiveAudience("personal")}
|
||||
>
|
||||
个人
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={activeAudience === "enterprise"}
|
||||
className={activeAudience === "enterprise" ? "is-active" : ""}
|
||||
onClick={() => setActiveAudience("enterprise")}
|
||||
>
|
||||
企业
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="recharge-modal__grid" data-audience={activeAudience}>
|
||||
{visiblePlans.map((plan) => {
|
||||
const isSelected = plan.id === selectedPlanId;
|
||||
|
||||
return (
|
||||
<article
|
||||
key={plan.id}
|
||||
className={`recharge-modal__card recharge-modal__card--${plan.id}${isSelected ? " is-selected" : ""}`}
|
||||
>
|
||||
{plan.badge ? <span className="recharge-modal__badge">{plan.badge}</span> : null}
|
||||
<div className="recharge-modal__card-head">
|
||||
<span className="recharge-modal__card-icon">{plan.icon}</span>
|
||||
<div>
|
||||
<h3>{plan.name}</h3>
|
||||
<span>{plan.subtitle}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span className="recharge-modal__period">{plan.period}</span>
|
||||
<div className="recharge-modal__price">
|
||||
<strong>{plan.price}</strong>
|
||||
</div>
|
||||
<p className="recharge-modal__grant">{plan.grant}</p>
|
||||
<span className="recharge-modal__diff-label">{plan.comparisonLabel}</span>
|
||||
<ul className="recharge-modal__features">
|
||||
{plan.benefits.map((benefit) => (
|
||||
<li key={benefit}>
|
||||
<CheckCircleOutlined />
|
||||
<span>{benefit}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button
|
||||
type="button"
|
||||
className={`recharge-modal__buy${isSelected ? " is-selected" : ""}`}
|
||||
aria-pressed={isSelected}
|
||||
onClick={() => handlePlanSelect(plan)}
|
||||
>
|
||||
{isSelected ? "当前方案" : "选择方案"}
|
||||
</button>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<footer className="recharge-modal__rules">
|
||||
<h3>积分充值规则</h3>
|
||||
<ol>
|
||||
{rechargeRules.map((rule) => (
|
||||
<li key={rule}>{rule}</li>
|
||||
))}
|
||||
</ol>
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user