重构(会员契约): 会员结构体改用 ts-rs 生成类型

- shared-contracts 为 10 个会员结构体补 ts_rs::TS / ts(export),64 位整数字段补 ts(type = "number") 对齐前端 number
- 新增 10 个生成绑定;packages/shared 与 admin-web 改为 re-export 生成类型,仅 kind / status 等前端收窄联合用 Omit 组合保留
- 同步设计文档 §2.5 与决策日志
This commit is contained in:
2026-10-05 15:51:07 +08:00
parent 0930e402be
commit bc3e36ff33
15 changed files with 332 additions and 120 deletions
@@ -0,0 +1,20 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileMembershipModelAccessToken } from "./ProfileMembershipModelAccessToken";
import type { ProfileMembershipPlanToken } from "./ProfileMembershipPlanToken";
/**
* 后台按档位改会员价格与权益;`rank` 不在请求里,升级比较基准由代码内目录决定。
*/
export type AdminUpsertProfileMembershipPlanRequest = {
/**
* 档位 token,作为主键即档位身份。
*/
plan: ProfileMembershipPlanToken, title: string, monthPriceCents: number, yearPriceCents: number, periodPoints: number,
/**
* 模型权限 token:`basic` / `full`;本期只落字段、不做服务端拦截。
*/
modelAccess: ProfileMembershipModelAccessToken,
/**
* 并发上限;`128` 表示不设上限。
*/
concurrentJobLimit: number, enabled: boolean, };
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ProfileDailyFreePointsResponse = { dayKey: number, grantedPoints: number, remainingPoints: number, resetsAt: string, updatedAt: string, };
@@ -0,0 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileMembershipPlanResponse } from "./ProfileMembershipPlanResponse";
export type ProfileMembershipPlanAdminListResponse = { entries: Array<ProfileMembershipPlanResponse>,
/**
* 并发哨兵阈值:`concurrent_job_limit >= 该值` 即不设上限;由后端下发,前端不硬编码。
*/
unlimitedConcurrencyThreshold: number, };
@@ -0,0 +1,25 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileMembershipModelAccessToken } from "./ProfileMembershipModelAccessToken";
import type { ProfileMembershipPlanToken } from "./ProfileMembershipPlanToken";
export type ProfileMembershipPlanResponse = {
/**
* 档位 token:`normal` / `starter` / `plus` / `pro` / `max`;未知取值按 `max` 兜底。
*/
plan: ProfileMembershipPlanToken, title: string, rank: number, monthPriceCents: number, yearPriceCents: number, periodPoints: number,
/**
* 模型权限 token:`basic` / `full`;未知取值按 `full` 兜底。
*/
modelAccess: ProfileMembershipModelAccessToken,
/**
* 并发上限;`128` 表示不设上限。
*/
concurrentJobLimit: number,
/**
* 是否为运营推荐档位;由后端目录决定,前端不再硬编码档位 token。
*/
recommended: boolean,
/**
* 是否不设并发上限;由后端按哨兵值派生,前端不再硬编码 `128`。
*/
unlimitedConcurrency: boolean, enabled: boolean, };
@@ -0,0 +1,26 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileMembershipCycleKindToken } from "./ProfileMembershipCycleKindToken";
import type { ProfileMembershipPlanToken } from "./ProfileMembershipPlanToken";
import type { ProfileMembershipStatusToken } from "./ProfileMembershipStatusToken";
export type ProfileMembershipResponse = {
/**
* 会员状态 token:`normal` / `active`;未知取值按 `active` 兜底。
*/
status: ProfileMembershipStatusToken,
/**
* 当前档位 token;非会员与已到期都是 `normal`;未知取值按 `max` 兜底。
*/
plan: ProfileMembershipPlanToken, startedAt: string | null, expiresAt: string | null, updatedAt: string | null, cycleStartedAt: string | null, cycleResetsAt: string | null, cycleGrantedPoints: number, cycleRemainingPoints: number,
/**
* 当前期序号(1-based)。
*/
cycleIndex: number,
/**
* 本次购买总期数(月付 1 / 年付 12)。
*/
cycleCount: number,
/**
* 周期 token:`monthly` / `yearly`;未知取值按 `yearly` 兜底。
*/
cycleKind: ProfileMembershipCycleKindToken, };
@@ -0,0 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileMembershipPlanToken } from "./ProfileMembershipPlanToken";
export type ProfileMembershipUpgradeQuoteRequest = {
/**
* 目标档位 token:`starter` / `plus` / `pro` / `max`。
*/
targetPlan: ProfileMembershipPlanToken, };
@@ -0,0 +1,33 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileMembershipCycleKindToken } from "./ProfileMembershipCycleKindToken";
import type { ProfileMembershipPlanToken } from "./ProfileMembershipPlanToken";
/**
* 补差升级报价:付款前展示应付金额、补点与变更后的月度余额;下单时后端会用同一函数重算。
*/
export type ProfileMembershipUpgradeQuoteResponse = {
/**
* 当前档位 token;未知取值按 `max` 兜底。
*/
currentPlan: ProfileMembershipPlanToken,
/**
* 目标档位 token;未知取值按 `max` 兜底。
*/
targetPlan: ProfileMembershipPlanToken,
/**
* 周期 token:`monthly` / `yearly`;有效期内不支持月年互换,所以变更前后一致;
* 未知取值按 `yearly` 兜底。
*/
cycleKind: ProfileMembershipCycleKindToken, cycleIndex: number, cycleCount: number,
/**
* 应付金额(分);月付 = 月价差,年付 = 年价差 ÷ 12 × (后续完整月数 + 本期剩余比例),向上取整到分。
*/
amountCents: number,
/**
* 本期补点;年付按本期剩余比例向下取整。
*/
grantedPointsDelta: number,
/**
* 变更后月度余额 = 原剩余月度余额 + 补点(已用点不返还,永久泥点不动)。
*/
monthlyBalanceAfter: number, expiresAt: string | null, cycleResetsAt: string | null, remainingFullMonths: number, };
@@ -0,0 +1,13 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ProfileDailyFreePointsResponse } from "./ProfileDailyFreePointsResponse";
import type { ProfileMembershipPlanResponse } from "./ProfileMembershipPlanResponse";
import type { ProfileMembershipResponse } from "./ProfileMembershipResponse";
import type { ProfileMudPointBalanceResponse } from "./ProfileMudPointBalanceResponse";
import type { ProfileRechargeOrderResponse } from "./ProfileRechargeOrderResponse";
import type { ProfileRechargeProductResponse } from "./ProfileRechargeProductResponse";
export type ProfileRechargeCenterResponse = { mudPointBalance: ProfileMudPointBalanceResponse, membership: ProfileMembershipResponse, pointProducts: Array<ProfileRechargeProductResponse>,
/**
* 会员档位目录(后台可改价),会员购买 / 升级的价格与权益都以它为准。
*/
membershipPlans: Array<ProfileMembershipPlanResponse>, latestOrder: ProfileRechargeOrderResponse | null, hasPointsRecharged: boolean, dailyFreePoints: ProfileDailyFreePointsResponse, };
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ProfileRechargeOrderResponse = { orderId: string, productId: string, productTitle: string, kind: string, amountCents: number, status: string, paymentChannel: string, paidAt: string | null, providerTransactionId: string | null, createdAt: string, pointsDelta: number, membershipExpiresAt: string | null, expiredAt: string | null, expirationCheckedAt: string | null, expirationProviderState: string | null, expirationLastError: string | null, };
@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ProfileRechargeProductResponse = { productId: string, title: string, priceCents: number, kind: string, pointsAmount: number, bonusPoints: number, durationDays: number, badgeLabel: string, description: string, };
+39 -88
View File
@@ -1,18 +1,37 @@
import type { JsonObject } from './common';
import type { AdminUpsertProfileMembershipPlanRequest } from './generated/AdminUpsertProfileMembershipPlanRequest';
import type { ProfileDailyFreePointsResponse } from './generated/ProfileDailyFreePointsResponse';
import type { ProfileMembershipChangeKindToken } from './generated/ProfileMembershipChangeKindToken';
import type { ProfileMembershipCycleKindToken } from './generated/ProfileMembershipCycleKindToken';
import type { ProfileMembershipModelAccessToken } from './generated/ProfileMembershipModelAccessToken';
import type { ProfileMembershipPlanAdminListResponse } from './generated/ProfileMembershipPlanAdminListResponse';
import type { ProfileMembershipPlanResponse } from './generated/ProfileMembershipPlanResponse';
import type { ProfileMembershipPlanToken } from './generated/ProfileMembershipPlanToken';
import type { ProfileMembershipResponse } from './generated/ProfileMembershipResponse';
import type { ProfileMembershipStatusToken } from './generated/ProfileMembershipStatusToken';
import type { ProfileMembershipUpgradeQuoteRequest } from './generated/ProfileMembershipUpgradeQuoteRequest';
import type { ProfileMembershipUpgradeQuoteResponse } from './generated/ProfileMembershipUpgradeQuoteResponse';
import type { ProfileMudPointBalanceResponse as ProfileMudPointBalance } from './generated/ProfileMudPointBalanceResponse';
import type { ProfileRechargeCenterResponse as GeneratedProfileRechargeCenterResponse } from './generated/ProfileRechargeCenterResponse';
import type { ProfileRechargeOrderResponse } from './generated/ProfileRechargeOrderResponse';
import type { ProfileRechargeProductResponse } from './generated/ProfileRechargeProductResponse';
export type {
AdminUpsertProfileMembershipPlanRequest,
ProfileDailyFreePointsResponse,
ProfileMembershipChangeKindToken,
ProfileMembershipCycleKindToken,
ProfileMembershipModelAccessToken,
ProfileMembershipPlanAdminListResponse,
ProfileMembershipPlanResponse,
ProfileMembershipPlanToken,
ProfileMembershipResponse,
ProfileMembershipStatusToken,
ProfileMembershipUpgradeQuoteRequest,
ProfileMembershipUpgradeQuoteResponse,
ProfileMudPointBalance,
ProfileRechargeOrderResponse,
ProfileRechargeProductResponse,
};
export const SAVE_SNAPSHOT_VERSION = 2;
@@ -69,13 +88,7 @@ export type ProfileDashboardSummary = {
dailyFreePoints?: ProfileDailyFreePoints;
};
export type ProfileDailyFreePoints = {
dayKey: number;
grantedPoints: number;
remainingPoints: number;
resetsAt: string;
updatedAt: string;
};
export type ProfileDailyFreePoints = ProfileDailyFreePointsResponse;
export type ProfileWalletLedgerEntry = {
id: string;
@@ -148,101 +161,39 @@ export type ProfileRechargeOrderStatus =
| 'refunded'
| 'expired';
export type ProfileRechargeProduct = {
productId: string;
title: string;
priceCents: number;
/** 充点 / 会员商品;`kind` 是前端收窄的联合类型,其余字段以后端生成为准。 */
export type ProfileRechargeProduct = Omit<
ProfileRechargeProductResponse,
'kind'
> & {
kind: ProfileRechargeProductKind;
pointsAmount: number;
bonusPoints: number;
durationDays: number;
badgeLabel: string;
description: string;
};
/** 会员档位目录行;价格与权益的唯一真相源是后端 `profile_membership_plan` 表。 */
export type ProfileMembershipPlanRecord = {
plan: ProfileMembershipPlan;
title: string;
rank: number;
monthPriceCents: number;
yearPriceCents: number;
periodPoints: number;
modelAccess: ProfileMembershipModelAccess;
/** 并发上限;`128` 表示不设上限。 */
concurrentJobLimit: number;
/** 是否为运营推荐档位;由后端目录给出,前端不再硬编码档位 token。 */
recommended: boolean;
/** 是否不设并发上限;由后端按哨兵值派生,前端不再硬编码 `128`。 */
unlimitedConcurrency: boolean;
enabled: boolean;
};
export type ProfileMembershipPlanRecord = ProfileMembershipPlanResponse;
export type ProfileMembership = {
status: ProfileMembershipStatus;
/** 当前档位;非会员与已到期都是 `normal`。 */
plan: ProfileMembershipPlan;
startedAt: string | null;
expiresAt: string | null;
updatedAt: string | null;
cycleStartedAt: string | null;
cycleResetsAt: string | null;
cycleGrantedPoints: number;
cycleRemainingPoints: number;
/** 当前期序号(1-based)。 */
cycleIndex: number;
/** 本次购买总期数(月付 1 / 年付 12)。 */
cycleCount: number;
cycleKind: ProfileMembershipCycleKind;
};
export type ProfileMembership = ProfileMembershipResponse;
/** 补差升级报价;下单时后端会用同一套规则重算,前端展示的数字不是真相源。 */
export type ProfileMembershipUpgradeQuote = {
currentPlan: ProfileMembershipPlan;
targetPlan: ProfileMembershipPlan;
cycleKind: ProfileMembershipCycleKind;
cycleIndex: number;
cycleCount: number;
/** 应付金额(分)。 */
amountCents: number;
/** 本期补点。 */
grantedPointsDelta: number;
/** 变更后月度余额 = 原剩余月度余额 + 补点。 */
monthlyBalanceAfter: number;
expiresAt: string | null;
cycleResetsAt: string | null;
remainingFullMonths: number;
};
export type ProfileMembershipUpgradeQuote =
ProfileMembershipUpgradeQuoteResponse;
export type ProfileRechargeOrder = {
orderId: string;
productId: string;
productTitle: string;
/** 充值订单;`kind` / `status` 是前端收窄的联合类型,其余字段以后端生成为准。 */
export type ProfileRechargeOrder = Omit<
ProfileRechargeOrderResponse,
'kind' | 'status'
> & {
kind: ProfileRechargeProductKind;
amountCents: number;
status: ProfileRechargeOrderStatus;
paymentChannel: string;
paidAt: string | null;
providerTransactionId: string | null;
createdAt: string;
pointsDelta: number;
membershipExpiresAt: string | null;
expiredAt?: string | null;
expirationCheckedAt?: string | null;
expirationProviderState?: string | null;
expirationLastError?: string | null;
};
export type ProfileRechargeCenterResponse = {
// TODO mirror backend: should not nullable
mudPointBalance?: ProfileMudPointBalance;
membership: ProfileMembership;
/** 充值中心;结构以后端生成为准,仅把商品 / 订单收窄成带联合类型的本地别名。 */
export type ProfileRechargeCenterResponse = Omit<
GeneratedProfileRechargeCenterResponse,
'pointProducts' | 'latestOrder'
> & {
pointProducts: ProfileRechargeProduct[];
/** 会员档位目录(后台可改价);会员购买 / 升级的价格与权益以它为准。 */
membershipPlans: ProfileMembershipPlanRecord[];
latestOrder: ProfileRechargeOrder | null;
hasPointsRecharged: boolean;
dailyFreePoints?: ProfileDailyFreePoints;
};
export type WechatMiniProgramPayParams = {