first commit
This commit is contained in:
779
membership/README.md
Normal file
779
membership/README.md
Normal file
@@ -0,0 +1,779 @@
|
||||
# OneApp Membership - 会员系统模块文档
|
||||
|
||||
## 模块概述
|
||||
|
||||
`oneapp_membership` 是 OneApp 的会员系统核心模块,专注于积分系统和签到功能。该模块提供用户积分管理、签到中心、积分任务等功能,与社区、账户等模块深度集成。
|
||||
|
||||
### 基本信息
|
||||
- **模块名称**: oneapp_membership
|
||||
- **版本**: 0.0.1
|
||||
- **类型**: Flutter Package
|
||||
- **主要功能**: 积分系统、签到功能、积分任务管理
|
||||
|
||||
### 核心导出组件
|
||||
|
||||
```dart
|
||||
library oneapp_membership;
|
||||
|
||||
// 积分页面
|
||||
export 'src/app_modules/app_points/pages/user_points_page.dart';
|
||||
// 签到中心页面
|
||||
export 'src/app_modules/app_signin/pages/signIn_center_page.dart';
|
||||
// 会员事件
|
||||
export 'src/app_event/membership_event.dart';
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
oneapp_membership/
|
||||
├── lib/
|
||||
│ ├── oneapp_membership.dart # 主导出文件
|
||||
│ ├── generated/ # 生成的国际化文件
|
||||
│ ├── l10n/ # 国际化资源文件
|
||||
│ └── src/ # 源代码目录
|
||||
│ ├── app_modules/ # 应用模块
|
||||
│ │ ├── app_points/ # 积分模块
|
||||
│ │ │ ├── pages/ # 积分页面
|
||||
│ │ │ ├── blocs/ # 积分状态管理
|
||||
│ │ │ ├── widges/ # 积分组件
|
||||
│ │ │ ├── scene/ # 积分场景
|
||||
│ │ │ └── beans/ # 积分数据模型
|
||||
│ │ └── app_signin/ # 签到模块
|
||||
│ │ └── pages/ # 签到页面
|
||||
│ ├── app_net_service/ # 网络服务
|
||||
│ └── app_event/ # 应用事件
|
||||
├── assets/ # 静态资源
|
||||
├── test/ # 测试文件
|
||||
└── pubspec.yaml # 依赖配置
|
||||
```
|
||||
|
||||
## 核心功能模块
|
||||
|
||||
### 1. 用户积分页面 (UserPointsPage)
|
||||
|
||||
基于真实项目代码的用户积分管理页面:
|
||||
|
||||
```dart
|
||||
/// 用户积分页面
|
||||
class UserPointsPage extends BaseStatefulWidget with RouteObjProvider {
|
||||
UserPointsPage({Key? key, required this.userId});
|
||||
|
||||
final String userId;
|
||||
|
||||
@override
|
||||
BaseStatefulWidgetState<UserPointsPage> getState() => _UserPointsPageState();
|
||||
}
|
||||
|
||||
class _UserPointsPageState extends BaseStatefulWidgetState<UserPointsPage>
|
||||
with WidgetsBindingObserver {
|
||||
|
||||
/// 是否需要添加推送积分
|
||||
bool needAddPushPoints = false;
|
||||
|
||||
/// 是否使用通用导航栏
|
||||
bool useCommonNavigation = false;
|
||||
|
||||
@override
|
||||
List<Widget> get rightActions => [
|
||||
PointsRuleWidge(
|
||||
lable: MemberShipIntlDelegate.current.pointsRule,
|
||||
onTap: () async {
|
||||
// 获取积分规则
|
||||
final rsp3 = await UserPointsTask.getRule(ruleKey: "integrationRule");
|
||||
if ((rsp3.data ?? '').isNotEmpty) {
|
||||
String jumpUrl = 'oneapp://component?routeKey=Key_Community_Postdetail&postId=${rsp3.data}&userName=';
|
||||
|
||||
try {
|
||||
Uri uri = Uri.tryParse(jumpUrl)!;
|
||||
final routeKey = uri.queryParameters['routeKey'];
|
||||
final meta = RouteCenterAPI.routeMetaBy(routeKey!);
|
||||
NavigatorProxy().launchMeta(
|
||||
meta,
|
||||
meta.routePath,
|
||||
arguments: uri.queryParameters,
|
||||
);
|
||||
} catch (e) {
|
||||
// 处理跳转异常
|
||||
}
|
||||
} else {
|
||||
ToastHelper.showToast(msg: '获取文章失败');
|
||||
}
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
@override
|
||||
String get titleText => MemberShipIntlDelegate.current.myPoints;
|
||||
|
||||
@override
|
||||
double get elevation => 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
addNotifyPoints();
|
||||
}
|
||||
|
||||
/// 添加通知积分
|
||||
Future<void> addNotifyPoints() async {
|
||||
bool haveNotifyPermission = await Permission.notification.isGranted;
|
||||
if (haveNotifyPermission) {
|
||||
PointsAddCenter().addPoints(PointsOpenPush());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 积分组件架构
|
||||
|
||||
实际项目包含的积分相关组件:
|
||||
|
||||
- **point_score_head_section.dart**: 积分头部区域组件
|
||||
- **points_rule_widget.dart**: 积分规则组件
|
||||
- **points_task_cell.dart**: 积分任务单元格组件
|
||||
- **PointsAddCenter**: 积分添加中心
|
||||
- **points_open_push.dart**: 积分推送开启
|
||||
|
||||
### 3. 会员权益管理
|
||||
|
||||
#### 权益服务系统
|
||||
```dart
|
||||
// 会员权益服务
|
||||
class MemberBenefitsService {
|
||||
final BenefitsRepository _repository;
|
||||
final MembershipService _membershipService;
|
||||
|
||||
MemberBenefitsService(this._repository, this._membershipService);
|
||||
|
||||
// 获取用户可用权益
|
||||
Future<Result<List<MemberBenefit>>> getUserBenefits(String userId) async {
|
||||
try {
|
||||
final membership = await _membershipService.getUserMembership(userId);
|
||||
return membership.fold(
|
||||
(failure) => Left(BenefitsFailure.membershipNotFound()),
|
||||
(membershipInfo) async {
|
||||
final benefits = await _repository.getBenefitsForTier(
|
||||
membershipInfo.tier,
|
||||
);
|
||||
return Right(benefits);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
return Left(BenefitsFailure.loadFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// 使用权益
|
||||
Future<Result<BenefitUsage>> useBenefit({
|
||||
required String userId,
|
||||
required String benefitId,
|
||||
Map<String, dynamic>? context,
|
||||
}) async {
|
||||
try {
|
||||
// 检查权益可用性
|
||||
final benefit = await _repository.getBenefitById(benefitId);
|
||||
if (benefit == null) {
|
||||
return Left(BenefitsFailure.benefitNotFound());
|
||||
}
|
||||
|
||||
// 检查使用条件
|
||||
final canUseResult = await _canUseBenefit(userId, benefit);
|
||||
if (canUseResult.isLeft()) {
|
||||
return Left(canUseResult.fold((l) => l, (r) => throw Exception()));
|
||||
}
|
||||
|
||||
// 记录使用
|
||||
final usage = BenefitUsage(
|
||||
id: generateId(),
|
||||
userId: userId,
|
||||
benefitId: benefitId,
|
||||
usedAt: DateTime.now(),
|
||||
context: context,
|
||||
);
|
||||
|
||||
await _repository.recordBenefitUsage(usage);
|
||||
|
||||
// 执行权益逻辑
|
||||
await _executeBenefitLogic(benefit, usage);
|
||||
|
||||
return Right(usage);
|
||||
} catch (e) {
|
||||
return Left(BenefitsFailure.usageFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// 获取权益使用历史
|
||||
Future<Result<List<BenefitUsage>>> getBenefitUsageHistory({
|
||||
required String userId,
|
||||
String? benefitId,
|
||||
DateRange? dateRange,
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
try {
|
||||
final usageHistory = await _repository.getBenefitUsageHistory(
|
||||
userId: userId,
|
||||
benefitId: benefitId,
|
||||
dateRange: dateRange,
|
||||
page: page,
|
||||
pageSize: pageSize,
|
||||
);
|
||||
return Right(usageHistory);
|
||||
} catch (e) {
|
||||
return Left(BenefitsFailure.historyLoadFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 会员权益模型
|
||||
class MemberBenefit {
|
||||
final String id;
|
||||
final String name;
|
||||
final String description;
|
||||
final BenefitType type;
|
||||
final BenefitCategory category;
|
||||
final Map<String, dynamic> configuration;
|
||||
final UsageLimit usageLimit;
|
||||
final List<MembershipTier> eligibleTiers;
|
||||
final DateTime? validFrom;
|
||||
final DateTime? validUntil;
|
||||
final bool isActive;
|
||||
|
||||
const MemberBenefit({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.type,
|
||||
required this.category,
|
||||
required this.configuration,
|
||||
required this.usageLimit,
|
||||
required this.eligibleTiers,
|
||||
this.validFrom,
|
||||
this.validUntil,
|
||||
this.isActive = true,
|
||||
});
|
||||
|
||||
// 免费充电权益
|
||||
factory MemberBenefit.freeCharging({int times = 1}) {
|
||||
return MemberBenefit(
|
||||
id: 'free_charging',
|
||||
name: '免费充电',
|
||||
description: '每月享受 $times 次免费充电服务',
|
||||
type: BenefitType.service,
|
||||
category: BenefitCategory.charging,
|
||||
configuration: {'free_times': times},
|
||||
usageLimit: UsageLimit.monthly(times),
|
||||
eligibleTiers: [
|
||||
MembershipTier.gold,
|
||||
MembershipTier.platinum,
|
||||
MembershipTier.diamond,
|
||||
MembershipTier.vip,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// 优先客服权益
|
||||
factory MemberBenefit.prioritySupport() {
|
||||
return MemberBenefit(
|
||||
id: 'priority_support',
|
||||
name: '优先客服',
|
||||
description: '享受7x24小时优先客服支持',
|
||||
type: BenefitType.service,
|
||||
category: BenefitCategory.support,
|
||||
configuration: {'priority_level': 'high'},
|
||||
usageLimit: UsageLimit.unlimited(),
|
||||
eligibleTiers: [
|
||||
MembershipTier.gold,
|
||||
MembershipTier.platinum,
|
||||
MembershipTier.diamond,
|
||||
MembershipTier.vip,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 会员商城
|
||||
|
||||
#### 积分商城服务
|
||||
```dart
|
||||
// 积分商城服务
|
||||
class MembershipStoreService {
|
||||
final StoreRepository _repository;
|
||||
final PointsService _pointsService;
|
||||
final OrderService _orderService;
|
||||
|
||||
MembershipStoreService(
|
||||
this._repository,
|
||||
this._pointsService,
|
||||
this._orderService,
|
||||
);
|
||||
|
||||
// 获取商品列表
|
||||
Future<Result<List<StoreItem>>> getStoreItems({
|
||||
StoreCategory? category,
|
||||
MembershipTier? minTier,
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
try {
|
||||
final items = await _repository.getStoreItems(
|
||||
category: category,
|
||||
minTier: minTier,
|
||||
page: page,
|
||||
pageSize: pageSize,
|
||||
);
|
||||
return Right(items);
|
||||
} catch (e) {
|
||||
return Left(StoreFailure.loadFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// 兑换商品
|
||||
Future<Result<StoreOrder>> redeemItem({
|
||||
required String userId,
|
||||
required String itemId,
|
||||
int quantity = 1,
|
||||
String? deliveryAddress,
|
||||
}) async {
|
||||
try {
|
||||
// 获取商品信息
|
||||
final item = await _repository.getStoreItemById(itemId);
|
||||
if (item == null) {
|
||||
return Left(StoreFailure.itemNotFound());
|
||||
}
|
||||
|
||||
// 检查积分余额
|
||||
final totalCost = item.pointsPrice * quantity;
|
||||
final pointsResult = await _pointsService.getUserPoints(userId);
|
||||
|
||||
return pointsResult.fold(
|
||||
(failure) => Left(StoreFailure.pointsCheckFailed()),
|
||||
(balance) async {
|
||||
if (balance.availablePoints < totalCost) {
|
||||
return Left(StoreFailure.insufficientPoints());
|
||||
}
|
||||
|
||||
// 检查库存
|
||||
if (item.stock != null && item.stock! < quantity) {
|
||||
return Left(StoreFailure.insufficientStock());
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
final order = StoreOrder(
|
||||
id: generateId(),
|
||||
userId: userId,
|
||||
itemId: itemId,
|
||||
itemName: item.name,
|
||||
quantity: quantity,
|
||||
pointsPrice: item.pointsPrice,
|
||||
totalPoints: totalCost,
|
||||
deliveryAddress: deliveryAddress,
|
||||
status: StoreOrderStatus.pending,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
// 扣除积分
|
||||
await _pointsService.spendPoints(
|
||||
userId: userId,
|
||||
points: totalCost,
|
||||
reason: PointsSpendReason.storeRedemption,
|
||||
metadata: {'order_id': order.id, 'item_id': itemId},
|
||||
);
|
||||
|
||||
// 保存订单
|
||||
await _repository.createStoreOrder(order);
|
||||
|
||||
// 更新库存
|
||||
if (item.stock != null) {
|
||||
await _repository.updateItemStock(itemId, -quantity);
|
||||
}
|
||||
|
||||
return Right(order);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
return Left(StoreFailure.redeemFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
// 获取兑换记录
|
||||
Future<Result<List<StoreOrder>>> getRedemptionHistory({
|
||||
required String userId,
|
||||
StoreOrderStatus? status,
|
||||
int page = 1,
|
||||
int pageSize = 20,
|
||||
}) async {
|
||||
try {
|
||||
final orders = await _repository.getStoreOrders(
|
||||
userId: userId,
|
||||
status: status,
|
||||
page: page,
|
||||
pageSize: pageSize,
|
||||
);
|
||||
return Right(orders);
|
||||
} catch (e) {
|
||||
return Left(StoreFailure.historyLoadFailed(e.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 商城商品模型
|
||||
class StoreItem {
|
||||
final String id;
|
||||
final String name;
|
||||
final String description;
|
||||
final String imageUrl;
|
||||
final int pointsPrice;
|
||||
final StoreCategory category;
|
||||
final MembershipTier? requiredTier;
|
||||
final int? stock;
|
||||
final bool isVirtual;
|
||||
final Map<String, dynamic>? metadata;
|
||||
final DateTime? validUntil;
|
||||
final bool isActive;
|
||||
|
||||
const StoreItem({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.imageUrl,
|
||||
required this.pointsPrice,
|
||||
required this.category,
|
||||
this.requiredTier,
|
||||
this.stock,
|
||||
this.isVirtual = false,
|
||||
this.metadata,
|
||||
this.validUntil,
|
||||
this.isActive = true,
|
||||
});
|
||||
|
||||
bool get isInStock => stock == null || stock! > 0;
|
||||
bool get isExpired => validUntil != null && validUntil!.isBefore(DateTime.now());
|
||||
bool get isAvailable => isActive && isInStock && !isExpired;
|
||||
}
|
||||
```
|
||||
|
||||
## 页面组件设计
|
||||
|
||||
### 会员主页
|
||||
```dart
|
||||
// 会员主页
|
||||
class MembershipHomePage extends StatefulWidget {
|
||||
@override
|
||||
_MembershipHomePageState createState() => _MembershipHomePageState();
|
||||
}
|
||||
|
||||
class _MembershipHomePageState extends State<MembershipHomePage> {
|
||||
late MembershipBloc _membershipBloc;
|
||||
late PointsBloc _pointsBloc;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_membershipBloc = context.read<MembershipBloc>();
|
||||
_pointsBloc = context.read<PointsBloc>();
|
||||
|
||||
_membershipBloc.add(LoadMembershipInfo());
|
||||
_pointsBloc.add(LoadPointsBalance());
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
_buildAppBar(),
|
||||
SliverToBoxAdapter(child: _buildMembershipCard()),
|
||||
SliverToBoxAdapter(child: _buildPointsSection()),
|
||||
SliverToBoxAdapter(child: _buildBenefitsSection()),
|
||||
SliverToBoxAdapter(child: _buildQuickActions()),
|
||||
SliverToBoxAdapter(child: _buildPromotions()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMembershipCard() {
|
||||
return BlocBuilder<MembershipBloc, MembershipState>(
|
||||
builder: (context, state) {
|
||||
if (state is MembershipLoaded) {
|
||||
return MembershipCard(
|
||||
membershipInfo: state.membershipInfo,
|
||||
onUpgrade: () => _navigateToUpgrade(),
|
||||
);
|
||||
}
|
||||
return MembershipCardSkeleton();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPointsSection() {
|
||||
return BlocBuilder<PointsBloc, PointsState>(
|
||||
builder: (context, state) {
|
||||
if (state is PointsLoaded) {
|
||||
return PointsOverviewCard(
|
||||
balance: state.balance,
|
||||
onViewHistory: () => _navigateToPointsHistory(),
|
||||
onEarnMore: () => _navigateToEarnPoints(),
|
||||
);
|
||||
}
|
||||
return PointsCardSkeleton();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 会员卡片组件
|
||||
```dart
|
||||
// 会员卡片组件
|
||||
class MembershipCard extends StatelessWidget {
|
||||
final MembershipInfo membershipInfo;
|
||||
final VoidCallback? onUpgrade;
|
||||
|
||||
const MembershipCard({
|
||||
Key? key,
|
||||
required this.membershipInfo,
|
||||
this.onUpgrade,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: EdgeInsets.all(16),
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: _getGradientForTier(membershipInfo.tier),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_buildHeader(),
|
||||
SizedBox(height: 16),
|
||||
_buildProgress(),
|
||||
SizedBox(height: 16),
|
||||
_buildActions(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader() {
|
||||
return Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundColor: Colors.white.withOpacity(0.2),
|
||||
child: Icon(
|
||||
_getIconForTier(membershipInfo.tier),
|
||||
color: Colors.white,
|
||||
size: 28,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
membershipInfo.tierName,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'会员编号: ${membershipInfo.memberNumber}',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white.withOpacity(0.8),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (membershipInfo.tier != MembershipTier.vip)
|
||||
TextButton(
|
||||
onPressed: onUpgrade,
|
||||
child: Text(
|
||||
'升级',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.white.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProgress() {
|
||||
if (membershipInfo.tier == MembershipTier.vip) {
|
||||
return Container(); // VIP 不显示进度
|
||||
}
|
||||
|
||||
final nextTier = _getNextTier(membershipInfo.tier);
|
||||
final currentPoints = membershipInfo.totalPoints;
|
||||
final requiredPoints = _getRequiredPointsForTier(nextTier);
|
||||
final progress = currentPoints / requiredPoints;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'距离${_getTierName(nextTier)}还需 ${requiredPoints - currentPoints} 积分',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.9),
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
LinearProgressIndicator(
|
||||
value: progress.clamp(0.0, 1.0),
|
||||
backgroundColor: Colors.white.withOpacity(0.3),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 状态管理
|
||||
|
||||
### 会员状态管理
|
||||
```dart
|
||||
// 会员状态 BLoC
|
||||
class MembershipBloc extends Bloc<MembershipEvent, MembershipState> {
|
||||
final MembershipService _membershipService;
|
||||
final PointsService _pointsService;
|
||||
|
||||
MembershipBloc(this._membershipService, this._pointsService)
|
||||
: super(MembershipInitial()) {
|
||||
on<LoadMembershipInfo>(_onLoadMembershipInfo);
|
||||
on<UpgradeMembership>(_onUpgradeMembership);
|
||||
on<RefreshMembershipInfo>(_onRefreshMembershipInfo);
|
||||
}
|
||||
|
||||
Future<void> _onLoadMembershipInfo(
|
||||
LoadMembershipInfo event,
|
||||
Emitter<MembershipState> emit,
|
||||
) async {
|
||||
emit(MembershipLoading());
|
||||
|
||||
final result = await _membershipService.getUserMembership(event.userId);
|
||||
result.fold(
|
||||
(failure) => emit(MembershipError(failure.message)),
|
||||
(membershipInfo) => emit(MembershipLoaded(membershipInfo)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onUpgradeMembership(
|
||||
UpgradeMembership event,
|
||||
Emitter<MembershipState> emit,
|
||||
) async {
|
||||
emit(MembershipUpgrading());
|
||||
|
||||
final result = await _membershipService.upgradeMembership(
|
||||
userId: event.userId,
|
||||
targetTier: event.targetTier,
|
||||
paymentMethod: event.paymentMethod,
|
||||
);
|
||||
|
||||
result.fold(
|
||||
(failure) => emit(MembershipError(failure.message)),
|
||||
(_) {
|
||||
add(LoadMembershipInfo(event.userId));
|
||||
emit(MembershipUpgradeSuccess());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 与其他模块集成
|
||||
|
||||
### 社区集成
|
||||
```dart
|
||||
// 会员社区权益服务
|
||||
class MembershipCommunityIntegration {
|
||||
final MembershipService _membershipService;
|
||||
final CommunityService _communityService;
|
||||
|
||||
MembershipCommunityIntegration(
|
||||
this._membershipService,
|
||||
this._communityService,
|
||||
);
|
||||
|
||||
// 检查发布权限
|
||||
Future<bool> canPublishPremiumContent(String userId) async {
|
||||
final membership = await _membershipService.getUserMembership(userId);
|
||||
return membership.fold(
|
||||
(_) => false,
|
||||
(info) => info.tier.index >= MembershipTier.gold.index,
|
||||
);
|
||||
}
|
||||
|
||||
// 获取会员专属话题
|
||||
Future<List<Topic>> getMemberExclusiveTopics(String userId) async {
|
||||
final membership = await _membershipService.getUserMembership(userId);
|
||||
return membership.fold(
|
||||
(_) => [],
|
||||
(info) => _communityService.getTopicsForMemberTier(info.tier),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 依赖管理
|
||||
|
||||
### 集成模块依赖
|
||||
- **basic_utils**: 基础工具类
|
||||
- **basic_uis**: 基础 UI 组件
|
||||
- **oneapp_community**: 社区功能集成
|
||||
- **oneapp_after_sales**: 售后服务集成
|
||||
- **app_account**: 账户系统集成
|
||||
|
||||
### 第三方依赖
|
||||
- **fluwx**: 微信支付集成(会员升级付费)
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 会员系统异常
|
||||
```dart
|
||||
// 会员系统异常
|
||||
abstract class MembershipFailure {
|
||||
const MembershipFailure();
|
||||
|
||||
factory MembershipFailure.loadFailed(String message) = LoadFailure;
|
||||
factory MembershipFailure.upgradeFailed(String message) = UpgradeFailure;
|
||||
factory MembershipFailure.paymentFailed() = PaymentFailure;
|
||||
factory MembershipFailure.upgradeNotAllowed() = UpgradeNotAllowedFailure;
|
||||
factory MembershipFailure.insufficientPoints() = InsufficientPointsFailure;
|
||||
}
|
||||
|
||||
// 积分系统异常
|
||||
abstract class PointsFailure {
|
||||
const PointsFailure();
|
||||
|
||||
factory PointsFailure.insufficientPoints() = InsufficientPointsFailure;
|
||||
factory PointsFailure.earnFailed(String message) = EarnFailure;
|
||||
factory PointsFailure.spendFailed(String message) = SpendFailure;
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
`oneapp_membership` 模块为 OneApp 构建了完整的会员生态体系,通过等级管理、积分系统、权益服务和商城功能,提升了用户粘性和付费转化。模块与社区、账户、售后服务等模块深度集成,为用户提供了全方位的会员体验和价值认知。
|
||||
Reference in New Issue
Block a user