鸿蒙掌上驾考宝典应用开发48:会员中心——应用内支付会员开通
# 第48篇会员中心——应用内支付会员开通## 一、引言会员功能是应用实现商业变现的重要方式。DriverLicenseExam 项目的 membership 组件实现了会员中心功能包括会员权益展示、开通会员、会员专属内容控制等。本文将深入解析会员功能的设计与实现。## 二、会员组件架构### 2.1 组件结构membership/├── src/main/ets/│ ├── components/ ← 会员 UI 组件│ ├── model/ ← 会员数据模型│ └── pages/ ← 会员页面├── Index.ets ← 模块导出└── oh-package.json5 ← 模块配置### 2.2 会员功能流程用户点击会员中心│├── 未登录 → 跳转到登录页面│└── 已登录 → 进入会员页面│├── 展示会员权益├── 展示会员价格└── 点击开通│├── 调用数字收银台支付│└── 支付成功 → 更新会员状态## 三、会员入口实现### 3.1 我的页面中的会员入口会员入口位于 MineView 的用户信息模块下方ets// MineView.ets - 会员中心入口Row() {Text(会员中心).width(72).height(28).fontSize(14).borderRadius(14).fontColor(#fff).backgroundColor(rgba(100, 187, 92, 1)).textAlign(TextAlign.Center).maxFontScale(1).onClick(() {if (AccountUtil.getAccountInfo().idToken ) {// 未登录 → 跳转登录页this.jumpLoginPage(a000******00);} else {// 已登录 → 进入会员中心this.vm.navStack.pushPathByName(membership, true);}});}.justifyContent(FlexAlign.End).width(100%);这个入口的设计体现了登录拦截逻辑- 未登录用户点击会员中心先跳转到登录页面- 已登录用户直接进入会员中心### 3.2 登录拦截etsprivate jumpLoginPage(quickLoginAnonymousPhone: string | undefined) {if (quickLoginAnonymousPhone) {const params: Recordstring, Object { anonymousPhone: quickLoginAnonymousPhone };this.vm.navStack.pushPathByName(QuickLoginPage, params, true);} else {const hint (this.getUIContext().getHostContext() as Context).resourceManager.getStringSync($r(app.string.get_mobile_number_error).id);showToast(hint, this.getUIContext());}}## 四、会员权益控制### 4.1 会员专属内容标识在数据模型中通过 needVip 字段标识会员专属内容ets// 视频数据模型中的会员标识export interface Video {poster: Resource;url: string;name: string;simpleDescription: string;description: string;copyrightNotice: string;time: string;needVip?: boolean; // true 会员专属false/undefined 公开}### 4.2 会员内容访问控制ets// 视频列表中的会员控制if (item.needVip !this.isLoggedIn) {showToast(开通会员后可观看, this.getUIContext());return;}// 或者跳转到会员页面if (item.needVip !this.isLoggedIn) {this.vm.navStack.pushPathByName(membership, true);return;}### 4.3 会员状态管理ets// 检查用户是否为会员get isLoggedIn(): boolean {return AccountUtil.getAccountInfo().idToken ! ;}// 会员状态可以通过服务端验证async checkMembershipStatus(): Promiseboolean {try {const response await https.getUserInfo();return response.data.isVIP;} catch (error) {return false;}}## 五、会员数据模型### 5.1 会员状态模型ets// 会员数据模型export interface MembershipInfo {isVIP: boolean; // 是否为会员expireDate: string; // 会员到期日期plan: string; // 当前套餐monthly/quarterly/yearlypurchaseDate: string; // 购买日期autoRenew: boolean; // 是否自动续费}// 会员状态管理export class MembershipManager {private static _instance: MembershipManager;Trace membershipInfo: MembershipInfo {isVIP: false,expireDate: ,plan: ,purchaseDate: ,autoRenew: false,};public static get instance(): MembershipManager {if (!MembershipManager._instance) {MembershipManager._instance new MembershipManager();}return MembershipManager._instance;}// 检查会员是否有效isMembershipValid(): boolean {if (!this.membershipInfo.isVIP) return false;if (!this.membershipInfo.expireDate) return false;const expire new Date(this.membershipInfo.expireDate);return expire new Date();}// 获取剩余天数getRemainingDays(): number {if (!this.isMembershipValid()) return 0;const expire new Date(this.membershipInfo.expireDate);const now new Date();return Math.ceil((expire.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));}}### 5.2 会员与本地存储会员状态需要持久化存储避免每次打开应用都重新查询ets// 保存会员信息到 PreferencessaveMembershipInfo(info: MembershipInfo) {const preferencesUtil PreferencesUtil.getInstance();const preference preferencesUtil.getPreferences(context);preferencesUtil.preferencesPut(preference, membershipInfo, JSON.stringify(info));}// 从 Preferences 读取会员信息loadMembershipInfo(): MembershipInfo | null {const preferencesUtil PreferencesUtil.getInstance();const preference preferencesUtil.getPreferences(context);const value preferencesUtil.getPreferencesValue(preference, membershipInfo);if (value) {return JSON.parse(value as string) as MembershipInfo;}return null;}## 六、会员页面设计### 5.1 会员权益展示ets// MemberShip.etsComponentV2export struct MemberShip {Local isVIP: boolean false;aboutToAppear() {this.checkVIPStatus();}build() {NavDestination() {Column() {// 会员标题Column() {Image($r(app.media.vip_icon)).width(80).height(80);Text(驾考会员).fontSize(24).fontWeight(FontWeight.Bold);Text(无限次模拟考试 全部视频课程).fontSize(14).fontColor(#666);}.padding({ top: 40, bottom: 24 });// 会员权益列表Column({ space: 12 }) {this.benefitItem(全部视频课程免费观看, $r(app.media.ic_video));this.benefitItem(无限次模拟考试, $r(app.media.ic_exam));this.benefitItem(错题本智能分析, $r(app.media.ic_analysis));this.benefitItem(去广告纯净体验, $r(app.media.ic_noad));}.padding(24);// 开通按钮Button(立即开通 ¥29.9/月).width(80%).height(48).backgroundColor(#64BB5C).borderRadius(24).fontColor(#fff).fontSize(16).margin({ top: 24 }).onClick(() {this.purchaseMembership();});}.width(100%).height(100%);}.title(会员中心);}BuilderbenefitItem(label: string, icon: Resource) {Row() {Image(icon).width(24).height(24);Text(label).fontSize(16).margin({ left: 12 });}.width(100%);}}### 5.2 支付流程ets// 开通会员 - 调用数字收银台purchaseMembership() {// 1. 创建支付订单// 2. 调用数字收银台支付// 3. 支付成功回调// 4. 更新会员状态showToast(开通成功欢迎成为会员, this.getUIContext());this.isVIP true;this.vm.navStack.pop();}## 六、会员功能的扩展性设计### 6.1 会员权益配置化会员权益可以通过配置方式管理便于后续调整ets// 会员权益配置const MEMBERSHIP_BENEFITS [{ label: 全部视频课程免费观看, icon: ic_video, needVIP: true },{ label: 无限次模拟考试, icon: ic_exam, needVIP: true },{ label: 错题本智能分析, icon: ic_analysis, needVIP: true },{ label: 去广告纯净体验, icon: ic_noad, needVIP: true },];// 判断用户是否有权限访问某个功能function hasAccess(benefit: string): boolean {const config MEMBERSHIP_BENEFITS.find(b b.label benefit);if (!config) return true;if (!config.needVIP) return true;return isVIP;}### 6.2 多套餐支持会员功能可以扩展为多套餐模式etsinterface MembershipPlan {name: string; // 套餐名称price: number; // 价格duration: number; // 有效期天benefits: string[]; // 权益列表}const PLANS: MembershipPlan[] [{ name: 月度会员, price: 29.9, duration: 30, benefits: [全部视频, 模拟考试, 去广告] },{ name: 季度会员, price: 69.9, duration: 90, benefits: [全部视频, 模拟考试, 去广告, 智能分析] },{ name: 年度会员, price: 199.9, duration: 365, benefits: [全部权益] },];## 七、总结会员中心组件实现了完整的会员功能闭环1. **入口控制**登录拦截确保只有登录用户可访问2. **权益展示**会员权益列表和价格展示3. **支付集成**调用数字收银台完成支付4. **内容控制**通过 needVip 字段控制会员专属内容5. **扩展性**支持多套餐、权益配置化---**关键源码文件**- components/membership/src/main/ets/ — 会员组件- products/entry/src/main/ets/pages/mine/MemberShip.ets — 会员页面- products/entry/src/main/ets/pages/mine/MineView.ets — 会员入口- commons/datasource/src/main/ets/Model.ets — Video 模型needVip 字段