From 21569b181f1545b3ffafffec81b156396940f793 Mon Sep 17 00:00:00 2001 From: leiyuee Date: Fri, 17 Jul 2026 16:33:51 +0800 Subject: [PATCH] no message --- src/api/api.ts | 2 - src/components/subscribe-plan-list/index.scss | 225 +++++++++--------- src/components/subscribe-plan-list/index.tsx | 95 +++++--- src/locales/en-US.json | 7 +- src/locales/zh-CN.json | 7 +- src/locales/zh-TW.json | 7 +- 6 files changed, 192 insertions(+), 151 deletions(-) diff --git a/src/api/api.ts b/src/api/api.ts index b3e9062..87f5839 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -25,7 +25,6 @@ type ListApiResponse = { data?: ListApiData; }; export type ProductPlanCustomInfo = { - rightTags?: string; discount_info?: string; point_amount?: string; illustrator?: string; @@ -40,7 +39,6 @@ export type ProductPlan = ApiParams & { price_amount?: number | string; original_price_amount?: number | string; level?: number | string; - recommended?: boolean; coins?: number | string; pointsGrantMode?: string; custom_info?: ProductPlanCustomInfo; diff --git a/src/components/subscribe-plan-list/index.scss b/src/components/subscribe-plan-list/index.scss index 113e13c..0dbfb67 100644 --- a/src/components/subscribe-plan-list/index.scss +++ b/src/components/subscribe-plan-list/index.scss @@ -114,15 +114,15 @@ .plan-grid { display: grid; - grid-template-columns: repeat(4, 357px); + grid-template-columns: repeat(4, 313px); align-items: start; justify-content: center; - gap: 10px; + gap: 12px; width: 100%; } .plan_grid_item { - width: 357px; + width: 313px; min-width: 0; } @@ -131,6 +131,7 @@ flex-direction: column; width: 100%; min-width: 0; + gap: 0; } .plan_item__header { @@ -138,9 +139,9 @@ z-index: 2; display: flex; flex-direction: column; - gap: 10px; - min-height: 287px; - padding: 24px 20px; + gap: 16px; + min-height: 266px; + padding: 20px; border-radius: 26px; box-sizing: border-box; background: #ffffff; @@ -149,10 +150,10 @@ .plan_item__title-row { display: flex; - align-items: flex-start; + align-items: center; justify-content: space-between; gap: 8px; - min-height: 28px; + min-height: 20px; } .plan_item__title { @@ -160,17 +161,9 @@ align-items: center; min-width: 0; color: #333333; - font-size: 20px; - font-weight: 500; - line-height: 28px; - } - - .plan_item__crown { - flex: 0 0 auto; - width: 24px; - height: 24px; - margin-right: 8px; - display: block; + font-size: 16px; + font-weight: 700; + line-height: 20px; } .plan_item__title span { @@ -180,39 +173,27 @@ white-space: nowrap; } - .plan_item__title-badges { - display: flex; - flex: 0 0 auto; - flex-wrap: wrap; - justify-content: flex-end; - gap: 6px; - max-width: 124px; - } - - .plan_item__title-badge { + .plan_item__discount-badge { display: inline-flex; + flex: 0 0 auto; align-items: center; justify-content: center; - height: 28px; - padding: 0 15px; - border-radius: 26px; + min-width: 66px; + max-width: 96px; + height: 20px; + padding: 0 10px; + overflow: hidden; + border-radius: 100px; box-sizing: border-box; + background: #f3efff; + color: #6f47f5; font-size: 12px; - font-weight: 500; - line-height: 26px; + font-weight: 400; + line-height: 20px; + text-overflow: ellipsis; white-space: nowrap; } - .plan_item__title-badge_recommended { - color: #e55936; - background: #ffe3c3; - } - - .plan_item__title-badge_top { - color: #6f47f5; - background: #ebe5ff; - } - .plan_item__price-block { display: flex; flex-direction: column; @@ -224,7 +205,6 @@ display: flex; align-items: flex-start; min-height: 44px; - padding-right: 72px; box-sizing: border-box; } @@ -240,7 +220,7 @@ margin-left: 2px; color: #333333; font-size: 36px; - font-weight: 500; + font-weight: 700; line-height: 44px; } @@ -252,7 +232,7 @@ margin-top: 18px; margin-left: 4px; color: #666666; - font-size: 16px; + font-size: 12px; font-weight: 400; line-height: 24px; white-space: nowrap; @@ -263,35 +243,16 @@ margin-top: 18px; margin-left: 4px; color: #999999; - font-size: 16px; - font-weight: 500; + font-size: 12px; + font-weight: 400; line-height: 24px; text-decoration: line-through; white-space: nowrap; } - .plan_item__price-discount { - position: absolute; - top: 20px; - right: 0; - display: inline-flex; - align-items: center; - justify-content: center; - height: 20px; - padding: 0 10px; - border-radius: 9px; - box-sizing: border-box; - background: #ebe5ff; - color: #333333; - font-size: 12px; - font-weight: 500; - line-height: 20px; - white-space: nowrap; - } - .plan_item__price-subtitle { margin: 0; - color: #666666; + color: #999999; font-size: 12px; font-weight: 400; line-height: 24px; @@ -301,7 +262,7 @@ position: relative; display: flex; align-items: center; - width: 314px; + width: 273px; max-width: 100%; height: 49px; padding: 0 12px; @@ -378,7 +339,7 @@ } .plan_item__cta.arco-btn:not(.arco-btn-disabled) { - background: linear-gradient(90deg, #333333 0%, #6f47f5 100%) !important; + background: #333333 !important; } .plan_item__cta.arco-btn-disabled, @@ -392,7 +353,7 @@ .plan_tier_selector { width: 100%; - max-width: 314px; + max-width: 273px; height: 44px; margin: 0 auto; box-sizing: border-box; @@ -489,7 +450,7 @@ .plan_commission { position: relative; - width: 314px; + width: 273px; max-width: 100%; height: 35px; padding: 0; @@ -548,16 +509,75 @@ .plan_item__features { position: relative; z-index: 1; - min-height: 510px; - margin-top: -10px; - padding: 46px 20px 24px; + min-height: 1028px; + margin-top: -58px; + padding: 70px 20px 20px; border-radius: 26px; box-sizing: border-box; - background: linear-gradient(0deg, #ffffff 70%, #f4f4f5 100%); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + background: #ffffff; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); } - .plan_item__feature-list { + .plan_goal { + display: flex; + flex-direction: column; + align-items: flex-start; + width: 100%; + min-height: 102px; + padding: 20px; + border-radius: 26px; + box-sizing: border-box; + background: #f9f6ff; + } + + .plan_goal__title { + display: flex; + align-items: center; + gap: 5px; + max-width: 100%; + color: #6f47f5; + font-size: 14px; + font-weight: 700; + line-height: 28px; + } + + .plan_goal__icon { + display: block; + flex: 0 0 auto; + width: 15px; + height: 15px; + object-fit: contain; + } + + .plan_goal__title span { + overflow: hidden; + min-width: 0; + text-overflow: ellipsis; + white-space: nowrap; + } + + .plan_goal__desc { + display: flex; + flex-direction: column; + margin: 6px 0 0; + color: #333333; + font-size: 12px; + font-weight: 400; + line-height: 18px; + } + + .plan_description { + width: 100%; + } + + .plan_description__divider { + width: 100%; + height: 1px; + margin: 20px 0; + background: #eeeeee; + } + + .plan_description__list { margin: 0; padding: 0; list-style: none; @@ -567,8 +587,8 @@ display: flex; align-items: flex-start; min-width: 0; - margin: 0 0 10px; - color: #666666; + margin: 0; + color: #333333; font-size: 12px; font-weight: 400; line-height: 24px; @@ -582,10 +602,10 @@ .plan_feature.plan_feature_title { display: block; margin: 0 0 10px; - color: #666666; - font-size: 12px; - font-weight: 500; - line-height: 24px; + color: #333333; + font-size: 14px; + font-weight: 700; + line-height: 28px; } .plan_feature__check { @@ -600,15 +620,15 @@ .plan_feature__text { flex: 1 1 auto; min-width: 0; - color: #666666; + color: #333333; font-size: 12px; - font-weight: 500; + font-weight: 400; line-height: 24px; } .desc_highlight { color: #6f47f5; - font-weight: 500; + font-weight: 700; } } @@ -629,36 +649,13 @@ } .plan-grid { - grid-template-columns: repeat(4, 320px); + grid-template-columns: repeat(4, 313px); width: max-content; justify-content: flex-start; } .plan_grid_item { - width: 320px; - } - - .plan_item__header { - min-height: 287px; - } - - .plan_item__title-row { - flex-direction: column; - } - - .plan_item__title-badges { - max-width: 100%; - justify-content: flex-start; - } - - .plan_item__price { - padding-right: 0; - } - - .plan_item__price-discount { - position: static; - margin-top: 20px; - margin-left: 8px; + width: 313px; } } } @@ -786,4 +783,4 @@ width: 14px; height: 14px; object-fit: cover; -} \ No newline at end of file +} diff --git a/src/components/subscribe-plan-list/index.tsx b/src/components/subscribe-plan-list/index.tsx index f1ce412..64a65bc 100644 --- a/src/components/subscribe-plan-list/index.tsx +++ b/src/components/subscribe-plan-list/index.tsx @@ -38,10 +38,13 @@ type PlanGroup = { const PLAN_INLINE_TAG_RE = /<\/?(?:mark|title|section)>/gi; const HIGHLIGHT_CLASS_NAME = "desc_highlight"; const SUBSCRIBE_PLAN_ASSETS = { - crown: new URL("@/assets/images/subscription/crown.png", import.meta.url).href, check: new URL("@/assets/images/home/feature-check-icon.png", import.meta.url).href, pointsIcon: new URL("@/assets/images/points/points-active.png", import.meta.url).href, }; +const FIGMA_TEMP_ASSETS = { + // Figma temporary asset. Replace with a local exported icon if the design asset is added to the repo. + goal: "https://www.figma.com/api/mcp/asset/b627a414-493d-430e-bbba-2d862a46e127", +}; function getPlanKey(plan: ProductPlan, index: number): string { if (plan.id != null && plan.id !== "") { @@ -65,6 +68,27 @@ function formatPlanTierLabel(plan: ProductPlan): string { return String(coins); } +function formatCurrencyAmount(value: number): string { + if (!Number.isFinite(value)) { + return "0"; + } + + if (Number.isInteger(value)) { + return String(value); + } + + return value.toFixed(2).replace(/\.?0+$/, ""); +} + +function formatPointPriceValue(plan: ProductPlan, price: number): string | null { + const coins = Number(plan.coins); + if (!Number.isFinite(price) || !Number.isFinite(coins) || price <= 0 || coins <= 0) { + return null; + } + + return formatCurrencyAmount((price / coins) * 100); +} + /** 去掉 mark/title/section 标签,保留纯文本 */ function stripPlanInlineTags(text: string): string { return text.replace(PLAN_INLINE_TAG_RE, "").trim(); @@ -282,9 +306,6 @@ export default function SubscribePlanList({ embedded = false, onBillingCycleChan const price = Number(plan.price ?? 0) / 100; // 价格单位为分,需要除以100转换为元 const original = Number(plan.original_price_amount) > 0 ? Number(plan.original_price_amount) : null; // 原价 const level = Number(plan.level ?? -1); // 会员等级 - const titleBadges: Array<{ type: string; text: string }> = []; // - if (plan.recommended) titleBadges.push({ type: "recommended", text: t("subscribe.recommended_plan") }); - if (plan.custom_info?.rightTags) titleBadges.push({ type: "top", text: plan.custom_info.rightTags }); const isLevel4Plan = level === 4; const isFreePlan = price <= 0; const isPurchasedLevel4Plan = isLevel4Plan && userMemberLevel === 4; // 已购买4级会员 Future Creator 课程 @@ -295,7 +316,7 @@ export default function SubscribePlanList({ embedded = false, onBillingCycleChan ? t("subscribe.current_plan") : userMemberLevel > level // 当前会员等级大于计划等级 ? t("subscribe.already_member_level", { level: t(memberLevelMap[userMemberLevel] ?? memberLevelMap[0]) }) - : t("subscribe.subscribe_now"); // 订阅按钮文本 + : t("subscribe.plan_cta_goal"); // 订阅按钮文本 // 点击CTA按钮 const handleCtaClick = () => { @@ -309,6 +330,10 @@ export default function SubscribePlanList({ embedded = false, onBillingCycleChan // 渲染描述段落 const priceUnit = isLevel4Plan ? t("subscribe.per_100_days") : plan.planCategory === "yearly" ? t("subscribe.per_year") : t("subscribe.per_month"); const pointsPeriod = isLevel4Plan ? t("subscribe.points_granted_once") : plan.planCategory === "yearly" ? (plan.pointsGrantMode === "monthly" ? t("subscribe.points_period_monthly") : t("subscribe.points_period_yearly")) : t("subscribe.points_period_monthly"); + const pointPriceValue = formatPointPriceValue(plan, price); + const pointPriceText = plan.custom_info?.point_amount ?? (pointPriceValue ? t("subscribe.plan_point_price", { value: pointPriceValue }) : ""); + const discountText = price > 0 ? (plan.custom_info?.discount_info ?? t("subscribe.plan_default_discount")) : ""; + const descriptionLines = splitPlanDescriptionLines(plan.description || ""); const renderDescSegments = (line: string) => getPlanDescriptionSegments(line).map((seg, segIdx) => ( @@ -322,29 +347,19 @@ export default function SubscribePlanList({ embedded = false, onBillingCycleChan
- {price > 0 ? : null} {plan.title}
- {titleBadges.length > 0 ? ( -
- {titleBadges.map((badge) => ( - - {badge.text} - - ))} -
- ) : null} + {discountText ? {discountText} : null}
- {price} + {formatCurrencyAmount(price)} {priceUnit} {original != null && original > price ? ¥{original} : null} - {plan.custom_info?.discount_info && price > 0 ? {plan.custom_info.discount_info} : null}
- {plan.custom_info?.point_amount ?

{plan.custom_info.point_amount}

: null} + {pointPriceText ?

{pointPriceText}

: null}
{price > 0 && plan.coins != null ? ( @@ -429,20 +444,36 @@ export default function SubscribePlanList({ embedded = false, onBillingCycleChan
-
    - {splitPlanDescriptionLines(plan.description || "").map((line, lineIdx) => - isSectionLine(line) ? ( -
  • - {renderDescSegments(line)} -
  • - ) : ( -
  • - - {renderDescSegments(line)} -
  • - ), - )} -
+
+
+ + {t("subscribe.plan_goal_title")} +
+

+ {t("subscribe.plan_goal_line1")} + {t("subscribe.plan_goal_line2")} +

+
+ + {descriptionLines.length > 0 ? ( +
+ + ) : null}
diff --git a/src/locales/en-US.json b/src/locales/en-US.json index eae957a..a0a1206 100644 --- a/src/locales/en-US.json +++ b/src/locales/en-US.json @@ -564,7 +564,6 @@ "subscribe.promo_carousel_label": "Membership benefit campaigns", "subscribe.billing_badge_hot": "HOT", "subscribe.billing_badge_value": "Best value", - "subscribe.recommended_plan": "Recommended", "subscribe.discount_off_8": "OFF 8%", "subscribe.discount_off_15": "OFF 15%", "subscribe.other_cycle_unavailable": "Other billing cycles are not available yet. Please choose single purchase", @@ -589,6 +588,12 @@ "subscribe.buy_now": "Buy now", "subscribe.points_package": "Points package", "subscribe.already_member_level": "You are already \"{{level}}\"", + "subscribe.plan_cta_goal": "Finish the first work", + "subscribe.plan_default_discount": "30% off limited offer", + "subscribe.plan_point_price": "100 points ≈ ¥{{value}}", + "subscribe.plan_goal_title": "More trials / steadier output", + "subscribe.plan_goal_line1": "Combine images, characters, videos,", + "subscribe.plan_goal_line2": "and shots into the first publishable work", "subscribe.qa_title": "FAQ", "subscribe.qa_subtitle": "Popi points and content rights", "subscribe.qa_footnote_line1": "Note: The rules above are for FAQ display on the official site. Actual terms follow", diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index 1d54ed3..40ca65b 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -564,7 +564,6 @@ "subscribe.promo_carousel_label": "会员权益活动", "subscribe.billing_badge_hot": "HOT", "subscribe.billing_badge_value": "性价比", - "subscribe.recommended_plan": "主推计划", "subscribe.discount_off_8": "OFF 8%", "subscribe.discount_off_15": "OFF 15%", "subscribe.other_cycle_unavailable": "其他周期暂未开放,请选择单次购买", @@ -589,6 +588,12 @@ "subscribe.buy_now": "立即购买", "subscribe.points_package": "积分包", "subscribe.already_member_level": "你已是{{level}}", + "subscribe.plan_cta_goal": "完成第一条作品", + "subscribe.plan_default_discount": "限时7折", + "subscribe.plan_point_price": "每100积分≈¥{{value}}元", + "subscribe.plan_goal_title": "多次试错 / 稳定出作品", + "subscribe.plan_goal_line1": "把图片、角色、视频和镜头", + "subscribe.plan_goal_line2": "组合成第一条可发布作品", "subscribe.qa_title": "常见问题", "subscribe.qa_subtitle": "Popi 积分与内容权益规则", "subscribe.qa_footnote_line1": "注:以上规则用于官网常见问题展示,具体执行以", diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index 49fe959..62ee338 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -565,7 +565,6 @@ "subscribe.promo_carousel_label": "會員權益活動", "subscribe.billing_badge_hot": "HOT", "subscribe.billing_badge_value": "性價比", - "subscribe.recommended_plan": "主推計劃", "subscribe.discount_off_8": "OFF 8%", "subscribe.discount_off_15": "OFF 15%", "subscribe.other_cycle_unavailable": "其他週期暫未開放,請選擇單次購買", @@ -590,6 +589,12 @@ "subscribe.buy_now": "立即購買", "subscribe.points_package": "積分包", "subscribe.already_member_level": "你已是{{level}}", + "subscribe.plan_cta_goal": "完成第一條作品", + "subscribe.plan_default_discount": "限時7折", + "subscribe.plan_point_price": "每100積分≈¥{{value}}元", + "subscribe.plan_goal_title": "多次試錯 / 穩定出作品", + "subscribe.plan_goal_line1": "把圖片、角色、影片和鏡頭", + "subscribe.plan_goal_line2": "組合成第一條可發布作品", "subscribe.qa_title": "常見問題", "subscribe.qa_subtitle": "Popi 積分與內容權益規則", "subscribe.qa_footnote_line1": "註:以上規則用於官網常見問題展示,具體執行以",