Commit a0eb657f by suolong

表演的列表数据api

parent 350e7cac
Showing with 606 additions and 96 deletions
......@@ -3,6 +3,7 @@
NS_ASSUME_NONNULL_BEGIN
@class FUSOnlineUserModel;
@class FUSShowRoomUserContributeModel;
@interface FUSTicketShowCollectTicketStageDataModel : FUSBaseModel
......@@ -42,31 +43,32 @@ NS_ASSUME_NONNULL_BEGIN
/// Ticket Show - 主播端 - 主播切换限时表演的集票(collectTicket/toggle)
@interface FUSTicketShowCollectTicketToggleResultModel : FUSBaseModel
#pragma mark - 公共返回字段
/// 响应码(接口返回)
@property (nonatomic, assign) NSInteger code;
/// 响应描述
@property (nonatomic, copy) NSString *msg;
/// socket:数据类型(观众端=1,主播端=4)
@property (nonatomic, assign) NSInteger dataType;
#pragma mark - /ticketshow/collectTicket/toggle & /ticketshow/progress/getinfo(共享字段)
/// socket:房间ID(部分推送平铺字段)
/// 房间ID(接口返回平铺字段;Socket 推送也可能带同名字段)
@property (nonatomic, copy) NSString *roomId;
/// socket:频道ID(部分推送平铺字段)
/// 频道ID(接口返回平铺字段;Socket 推送也可能带同名字段)
@property (nonatomic, copy) NSString *channelId;
/// socket:回合ID(部分推送平铺字段)
/// 回合ID(接口返回平铺字段;Socket 推送也可能带同名字段)
@property (nonatomic, copy) NSString *roundId;
/// socket:当前阶段状态(0:集票中 1:待表演 2:表演中 9999:已结束)
/// 当前阶段状态(0:集票中 1:待表演 2:表演中 9999:已结束)
@property (nonatomic, assign) NSInteger showStatus;
/// socket:阶段时长(毫秒)
/// 阶段时长(毫秒)
@property (nonatomic, assign) NSInteger showStatusTime;
/// socket:剩余时间(毫秒)
/// 剩余时间(毫秒)
@property (nonatomic, assign) NSInteger remaintime;
/// 集票目标总数
......@@ -78,17 +80,58 @@ NS_ASSUME_NONNULL_BEGIN
/// 集票表演主题标题
@property (nonatomic, copy) NSString *showTheme;
/// socket:购买用户信息(赠票/购票的用户)
/// 阶段信息(部分接口会下发在该字段内;若为空则使用平铺字段)
@property (nonatomic, strong, nullable) FUSTicketShowCollectTicketStageDataModel *stageData;
/// MVP信息(为空对象表示无MVP)
@property (nonatomic, strong, nullable) FUSTicketShowCollectTicketMVPInfoModel *mvpInfo;
#pragma mark - /ticketshow/buy/getdata(购票弹窗数据)
/// 集票中:推荐“一键直购开始表演”的购买数量
@property (nonatomic, assign) NSInteger directBuyNum;
/// 表演中:推荐“票票力支持”的购买数量
@property (nonatomic, assign) NSInteger showStrengthNum;
/// 抢当 MVP:推荐购买数量(用于达到/超过当前 MVP)
@property (nonatomic, assign) NSInteger mvpBuyNum;
/// 当前用户已持有票数
@property (nonatomic, assign) NSInteger userBuyNum;
/// 单张票价格(单位以服务端为准)
@property (nonatomic, assign) NSInteger buyPrice;
#pragma mark - Socket 推送扩展字段(ROOM_CID_TICKET_SHOW_REALTIME_DATA)
/// Socket:数据类型(观众端=1,主播端=4;用于区分推送来源)
@property (nonatomic, assign) NSInteger dataType;
/// Socket:购买用户信息(赠票/购票的用户)
@property (nonatomic, strong, nullable) FUSOnlineUserModel *buyUser;
/// socket:buyUser 的购买数量
/// Socket:buyUser 的购买数量
@property (nonatomic, assign) NSInteger buyNum;
/// 阶段信息
@property (nonatomic, strong, nullable) FUSTicketShowCollectTicketStageDataModel *stageData;
@end
/// MVP信息(为空对象表示无MVP)
@property (nonatomic, strong, nullable) FUSTicketShowCollectTicketMVPInfoModel *mvpInfo;
#pragma mark - /ticketshow/rank/list(票的贡献榜)
/// Ticket Show - 视图 - 票的贡献榜列表返回
@interface FUSTicketShowRankListResultModel : FUSBaseModel
/// 当前页
@property (nonatomic, assign) NSInteger page;
/// 每页数量
@property (nonatomic, assign) NSInteger pageSize;
/// 总数量
@property (nonatomic, assign) NSInteger allTotal;
/// 列表数据
@property (nonatomic, copy) NSArray<FUSShowRoomUserContributeModel *> *dataList;
@end
......
#import "FUSTicketShowCollectTicketToggleResultModel.h"
#import "FUSOnlineUserModel.h"
#import "FUSShowRoomUserContributeModel.h"
@implementation FUSTicketShowCollectTicketStageDataModel
@end
......@@ -21,3 +22,13 @@
}
@end
@implementation FUSTicketShowRankListResultModel
+ (NSDictionary<NSString *,id> *)modelContainerPropertyGenericClass {
return @{
@"dataList": FUSShowRoomUserContributeModel.class
};
}
@end
......@@ -30,6 +30,7 @@
NS_ASSUME_NONNULL_BEGIN
@class FUSTicketShowCollectTicketToggleResultModel;
@class FUSTicketShowRankListResultModel;
@class FUSBarrageCardModel;
......@@ -956,6 +957,34 @@ NS_ASSUME_NONNULL_BEGIN
succeed:(void (^)(FUSTicketShowCollectTicketToggleResultModel *model))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure;
/// Ticket Show - 视图 - 获取购票弹窗所需数据(观众端)
/// 接口:POST /ticketshow/buy/getdata
/// 说明:用于观众端进入“限时表演购票”弹窗时刷新当前阶段/剩余时间/票价/推荐购票数量/持有票数等信息
/// @param roomId 房间ID
/// @param channelId 频道ID
/// @param roundId 回合ID
/// @param succeed 成功回调
/// @param failure 失败回调(参数错误 code=-3)
+ (void)fus_ticketShowBuyGetDataWithRoomId:(NSString *)roomId
channelId:(NSString *)channelId
roundId:(NSString *)roundId
succeed:(void (^)(FUSTicketShowCollectTicketToggleResultModel *model))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure;
/// Ticket Show - 视图 - 获取票的贡献列表(观众端)
/// 接口:POST /ticketshow/rank/list
/// 说明:用于展示“票的贡献”列表(弹窗内贡献 Tab)
/// @param roomId 房间ID
/// @param channelId 频道ID
/// @param roundId 回合ID
/// @param succeed 成功回调
/// @param failure 失败回调(参数错误 code=-3)
+ (void)fus_ticketShowRankListWithRoomId:(NSString *)roomId
channelId:(NSString *)channelId
roundId:(NSString *)roundId
succeed:(void (^)(FUSTicketShowRankListResultModel *model))succeed
failure:(void (^)(NSString *msg, NSInteger code))failure;
/// 开始直播前准备
/// @param succeed 成功回调
......
......@@ -9,6 +9,7 @@
#import "FUSLiveHttpHelper.h"
#import "FUSTicketShowCollectTicketToggleResultModel.h"
#import "FUSLiveHelper.h"
#import "FUSShowRoomUserContributeModel.h"
#import "FUSSocketMessageHelper.h"
#import "FUSGiftDataCenter.h"
......@@ -3119,6 +3120,68 @@
if (failure) failure(dataDict[@"msg"], code);
}];
}
+ (void)fus_ticketShowBuyGetDataWithRoomId:(NSString *)roomId
channelId:(NSString *)channelId
roundId:(NSString *)roundId
succeed:(void (^)(FUSTicketShowCollectTicketToggleResultModel * _Nonnull))succeed
failure:(void (^)(NSString * _Nonnull, NSInteger))failure {
NSString *uid = FUSCacheDataShare.shareStore.userDetailInfo.uid;
if ([NSString isNull:uid]
|| [NSString isNull:roomId]
|| [NSString isNull:channelId]
|| [NSString isNull:roundId]) {
/// 与同模块其他接口保持一致:参数不完整直接失败返回,避免无意义请求与服务端兜底不一致
if (failure) failure([NSString fus_localString:@"参数错误"], -3);
return;
}
NSDictionary *params = @{
/// 服务端字段约定:uid/roomId/channelId/roundId 均为必传
@"uid": uid,
@"roomId": roomId,
@"channelId": channelId,
@"roundId": roundId
};
[FUSHttpHelper postRequestBinaryWithUrl:FUSShowRoomURLs.fus_URL_TicketShow_Buy_GetData params:params success:^(NSDictionary * _Nullable dataDict, int code) {
FUSTicketShowCollectTicketToggleResultModel *model = [FUSTicketShowCollectTicketToggleResultModel fus_modelWithDict:dataDict];
if (succeed) succeed(model);
} failure:^(NSDictionary * _Nullable dataDict, int code) {
if (failure) failure(dataDict[@"msg"], code);
}];
}
+ (void)fus_ticketShowRankListWithRoomId:(NSString *)roomId
channelId:(NSString *)channelId
roundId:(NSString *)roundId
succeed:(void (^)(FUSTicketShowRankListResultModel * _Nonnull))succeed
failure:(void (^)(NSString *, NSInteger))failure {
NSString *uid = FUSCacheDataShare.shareStore.userDetailInfo.uid;
if ([NSString isNull:uid]
|| [NSString isNull:roomId]
|| [NSString isNull:channelId]
|| [NSString isNull:roundId]) {
/// 与同模块其他接口保持一致:参数不完整直接失败返回,避免无意义请求与服务端兜底不一致
if (failure) failure([NSString fus_localString:@"参数错误"], -3);
return;
}
NSDictionary *params = @{
/// 服务端字段约定:uid/roomId/channelId/roundId 均为必传
@"uid": uid,
@"roomId": roomId,
@"channelId": channelId,
@"roundId": roundId
};
[FUSHttpHelper postRequestBinaryWithUrl:FUSShowRoomURLs.fus_URL_TicketShow_Rank_List params:params success:^(NSDictionary * _Nullable dataDict, int code) {
FUSTicketShowRankListResultModel *model = [FUSTicketShowRankListResultModel fus_modelWithDict:dataDict];
if (succeed) succeed(model);
} failure:^(NSDictionary * _Nullable dataDict, int code) {
if (failure) failure(dataDict[@"msg"], code);
}];
}
/// 获取用户直播评分历史列表
+ (void)fus_requestUserliveAssessHistoryGetListWithDateStr:(NSString *)dateStr succeed:(void (^)(FUSUserLiveAssessHistoryModel * _Nonnull))succeed failure:(void (^)(NSString * _Nonnull, NSInteger))failure{
NSDictionary *parm = @{@"dateStr": dateStr};
......
......@@ -119,11 +119,53 @@
if (self.showTimeTargetTicketNum > 0 && self.showTimeLastFinalTicketNum >= 0) {
remaining = MAX(0, self.showTimeTargetTicketNum - self.showTimeLastFinalTicketNum);
}
[popView fus_updateRemainingTicketCount:remaining mvpNeedTicketCount:self.showTimeMvpNeedTicketCount];
/// 先用本地缓存数据做首屏展示,避免弹窗出现短暂空白;网络返回后再刷新为最新值
[popView fus_updateRemainingTicketCount:remaining mvpNeedTicketCount:self.showTimeMvpNeedTicketCount buyPrice:-1];
popView.confirmHandler = ^(FUSLiveShowTimeTicketPurchaseOption option) {
[FUSDialogView fus_showDialog:[NSString fus_localString:@"购票接口未接入"]];
};
FUSRoomInfoModel *roomInfoModel = FUSLiveHelper.shareInstance.roomInfoModel;
NSString *roomId = roomInfoModel.roomId;
NSString *channelId = roomInfoModel.channelId;
NSString *roundId = self.showTimeRoundId;
if ([NSString isNull:roomId] || [NSString isNull:channelId] || [NSString isNull:roundId]) {
/// 弹窗展示依赖当前回合信息,缺少关键标识直接返回,避免无效请求
return;
}
__weak typeof(self) weakSelf = self;
[FUSLiveHttpHelper fus_ticketShowBuyGetDataWithRoomId:roomId channelId:channelId roundId:roundId succeed:^(FUSTicketShowCollectTicketToggleResultModel * _Nonnull model) {
/// UI 更新必须回主线程;同时兼容弹窗可能已被用户关闭的场景
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
if (!popView.superview) {
return;
}
FUSLiveShowTimeTicketBuyGetDataViewState *viewState = [popView fus_updateWithBuyGetDataModel:model];
strongSelf.showTimeTargetTicketNum = viewState.targetTicketNum;
strongSelf.showTimeLastFinalTicketNum = viewState.finalTicketNum;
strongSelf.showTimeStageStatus = viewState.stageStatus;
strongSelf.showTimeCountdownRemainSeconds = viewState.countdownRemainingSeconds;
strongSelf.showTimeMvpNeedTicketCount = viewState.mvpNeedTicketCount;
});
} failure:^(NSString * _Nonnull msg, NSInteger code) {
}];
[FUSLiveHttpHelper fus_ticketShowRankListWithRoomId:roomId channelId:channelId roundId:roundId succeed:^(FUSTicketShowRankListResultModel * _Nonnull model) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!popView.superview) {
return;
}
[popView fus_updateContributionList:(model.dataList ?: @[])];
});
} failure:^(NSString * _Nonnull msg, NSInteger code) {
}];
}
#pragma mark - Getter
......
......@@ -2,6 +2,29 @@
NS_ASSUME_NONNULL_BEGIN
@class FUSShowRoomUserContributeModel;
@class FUSTicketShowCollectTicketToggleResultModel;
/// 购票弹窗的“视图侧状态”快照
/// 说明:由 View 根据接口 Model 做兜底/换算后生成,便于外部缓存下一次首屏展示
@interface FUSLiveShowTimeTicketBuyGetDataViewState : NSObject
/// 当前阶段状态(0:集票中 1:待表演 2:表演中 9999:已结束)
@property (nonatomic, assign) NSInteger stageStatus;
/// 倒计时剩余秒数(<0 表示不展示倒计时)
@property (nonatomic, assign) NSInteger countdownRemainingSeconds;
/// 本轮目标票数(<=0 表示未知)
@property (nonatomic, assign) NSInteger targetTicketNum;
/// 当前已集票数(<0 表示未知)
@property (nonatomic, assign) NSInteger finalTicketNum;
/// 抢当 MVP 所需票数(<0 表示未知/不展示)
@property (nonatomic, assign) NSInteger mvpNeedTicketCount;
@end
/// “限时表演”观众端:购票入口弹窗(从底部上滑展示)
@interface FUSLiveShowTimeTicketActionPopView : UIView
......@@ -44,12 +67,20 @@ typedef NS_ENUM(NSInteger, FUSLiveShowTimeTicketPurchaseOption) {
/// 更新“补全所有票/抢当MVP所需”的票数显示
/// @param remainingTicketCount 还差多少张票(<0 表示未知,不展示)
/// @param mvpNeedTicketCount 抢当MVP需要多少张票(<0 表示未知,不展示)
/// @param buyPrice 单张票价格(<=0 表示未知,价格展示为 --)
- (void)fus_updateRemainingTicketCount:(NSInteger)remainingTicketCount
mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount;
mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount
buyPrice:(NSInteger)buyPrice;
/// 更新底部“你持有张数 / MVP持有张数”
/// @param ownedTicketCount 当前用户持有票数(<0 表示未知)
/// @param mvpOwnedTicketCount 当前 MVP 用户持有票数(<0 表示未知;无 MVP 时建议传 -1)
- (void)fus_updateOwnedTicketCount:(NSInteger)ownedTicketCount
mvpOwnedTicketCount:(NSInteger)mvpOwnedTicketCount;
/// 更新“票的贡献”列表数据
/// @param contributionList 元素建议包含:nickname/face/ticketCount(字段缺失会兜底空展示)
- (void)fus_updateContributionList:(NSArray<NSDictionary *> *)contributionList;
/// @param contributionList 列表模型(字段缺失会兜底空展示)
- (void)fus_updateContributionList:(NSArray<FUSShowRoomUserContributeModel *> *)contributionList;
/// 更新顶部“已集票数”显示
/// @param currentTicketCount 已集票数(<0 表示未知)
......@@ -65,6 +96,8 @@ typedef NS_ENUM(NSInteger, FUSLiveShowTimeTicketPurchaseOption) {
/// @param remainingSeconds 剩余秒数;<0 表示不展示倒计时
- (void)fus_updateCountdownRemainingSeconds:(NSInteger)remainingSeconds;
- (FUSLiveShowTimeTicketBuyGetDataViewState *)fus_updateWithBuyGetDataModel:(FUSTicketShowCollectTicketToggleResultModel *)model;
/// 主动关闭弹窗(会带动画并移除)
- (void)fus_dismiss;
......
......@@ -7,6 +7,10 @@
#import "FUSShowRoomCenterBunble.h"
#import "FUSLiveShowTimeTicketContributionListView.h"
#import "FUSLiveShowTimeTicketNoticeView.h"
#import "FUSTicketShowCollectTicketToggleResultModel.h"
@implementation FUSLiveShowTimeTicketBuyGetDataViewState
@end
@interface FUSLiveShowTimeTicketOptionCardView : UIControl
......@@ -161,7 +165,10 @@
@property (nonatomic, copy) void (^selectHandler)(FUSLiveShowTimeTicketPurchaseOption option);
- (void)fus_setSelectedOption:(FUSLiveShowTimeTicketPurchaseOption)option;
- (void)fus_updateRemainingTicketCount:(NSInteger)remainingTicketCount mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount stageStatus:(NSInteger)stageStatus;
- (void)fus_updateRemainingTicketCount:(NSInteger)remainingTicketCount
mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount
buyPrice:(NSInteger)buyPrice
stageStatus:(NSInteger)stageStatus;
@end
......@@ -224,15 +231,35 @@
self.mvpNeedOptionView.selected = (option == FUSLiveShowTimeTicketPurchaseOptionMVPRequiredTickets);
}
- (void)fus_updateRemainingTicketCount:(NSInteger)remainingTicketCount mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount stageStatus:(NSInteger)stageStatus {
[self.oneTicketOptionView fus_setupCountText:@"x1" priceText:@"100" tagText:nil];
- (void)fus_updateRemainingTicketCount:(NSInteger)remainingTicketCount
mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount
buyPrice:(NSInteger)buyPrice
stageStatus:(NSInteger)stageStatus {
NSString *(^priceTextForCount)(NSInteger) = ^NSString *(NSInteger count) {
/// 价格/数量不可用时统一展示占位,避免出现 “0” 误导为免费
if (buyPrice <= 0 || count <= 0) {
return @"--";
}
/// 这里用 long long 做乘法,避免 NSInteger 在 32 位环境下溢出导致展示异常
long long total = (long long)buyPrice * (long long)count;
if (total < 0) {
return @"--";
}
return [NSString stringWithFormat:@"%lld", total];
};
NSString *fillCountText = (remainingTicketCount >= 0 ? [NSString stringWithFormat:@"x%zd", (NSInteger)MAX(0, remainingTicketCount)] : @"x--");
[self.oneTicketOptionView fus_setupCountText:@"x1" priceText:priceTextForCount(1) tagText:nil];
NSInteger fillCount = (remainingTicketCount >= 0 ? (NSInteger)MAX(0, remainingTicketCount) : -1);
NSString *fillCountText = (fillCount >= 0 ? [NSString stringWithFormat:@"x%zd", fillCount] : @"x--");
NSString *fillPriceText = (fillCount >= 0 ? priceTextForCount(fillCount) : @"--");
NSString *fillTag = (stageStatus == 2 ? @"黑票票力" : [NSString fus_localString:@"直接开始"]);
[self.fillAllOptionView fus_setupCountText:fillCountText priceText:@"100" tagText:fillTag];
[self.fillAllOptionView fus_setupCountText:fillCountText priceText:fillPriceText tagText:fillTag];
NSString *mvpCountText = (mvpNeedTicketCount >= 0 ? [NSString stringWithFormat:@"x%zd", (NSInteger)MAX(0, mvpNeedTicketCount)] : @"x--");
[self.mvpNeedOptionView fus_setupCountText:mvpCountText priceText:@"100" tagText:[NSString fus_localString:@"抢当MVP"]];
NSInteger mvpCount = (mvpNeedTicketCount >= 0 ? (NSInteger)MAX(0, mvpNeedTicketCount) : -1);
NSString *mvpCountText = (mvpCount >= 0 ? [NSString stringWithFormat:@"x%zd", mvpCount] : @"x--");
NSString *mvpPriceText = (mvpCount >= 0 ? priceTextForCount(mvpCount) : @"--");
[self.mvpNeedOptionView fus_setupCountText:mvpCountText priceText:mvpPriceText tagText:[NSString fus_localString:@"抢当MVP"]];
}
@end
......@@ -292,6 +319,7 @@
@property (nonatomic, assign) NSInteger stageStatus;
@property (nonatomic, assign) NSInteger ownedTicketCount;
@property (nonatomic, assign) NSInteger mvpOwnedTicketCount;
@property (nonatomic, assign) NSInteger buyPrice;
@property (nonatomic, strong) MASConstraint *headerLabelHeightConstraint;
......@@ -327,6 +355,7 @@
self.stageStatus = -1;
self.ownedTicketCount = -1;
self.mvpOwnedTicketCount = -1;
self.buyPrice = -1;
self.currentTabIndex = 0;
self.bgBtn = [UIButton buttonWithType:UIButtonTypeCustom];
......@@ -720,9 +749,11 @@
}
- (void)fus_updateRemainingTicketCount:(NSInteger)remainingTicketCount
mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount {
mvpNeedTicketCount:(NSInteger)mvpNeedTicketCount
buyPrice:(NSInteger)buyPrice {
self.remainingTicketCount = remainingTicketCount;
self.mvpNeedTicketCount = mvpNeedTicketCount;
self.buyPrice = buyPrice;
[self fus_applyCountsToOptionViews];
}
......@@ -733,7 +764,7 @@
[self fus_applyBottomCountsUI];
}
- (void)fus_updateContributionList:(NSArray<NSDictionary *> *)contributionList {
- (void)fus_updateContributionList:(NSArray<FUSShowRoomUserContributeModel *> *)contributionList {
self.contributionListView.contributionList = (contributionList ?: @[]);
}
......@@ -768,6 +799,70 @@
[self fus_refreshCountdownText];
}
- (FUSLiveShowTimeTicketBuyGetDataViewState *)fus_updateWithBuyGetDataModel:(FUSTicketShowCollectTicketToggleResultModel *)model {
NSInteger stageStatus = 0;
NSInteger target = 0;
NSInteger finalNum = 0;
NSInteger remainSeconds = -1;
NSInteger mvpNeedCount = -1;
if (model) {
stageStatus = (model.stageData ? model.stageData.showStatus : model.showStatus);
NSInteger durationMs = (model.stageData ? model.stageData.showStatusTime : model.showStatusTime);
NSInteger remainMs = (model.stageData ? model.stageData.remaintime : model.remaintime);
if (durationMs > 0 && remainMs >= 0 && remainMs <= durationMs) {
remainSeconds = (NSInteger)llround(((NSTimeInterval)remainMs) / 1000.0);
}
target = MAX(0, model.targetTicketNum);
finalNum = MAX(0, model.finalTicketNum);
NSInteger fillCount = (stageStatus == 2 ? model.showStrengthNum : model.directBuyNum);
NSInteger expectedRemaining = (target > 0 ? MAX(0, target - finalNum) : -1);
if (fillCount <= 0 && expectedRemaining > 0 && stageStatus != 2) {
fillCount = expectedRemaining;
}
mvpNeedCount = model.mvpBuyNum;
if (mvpNeedCount <= 0) {
if (model.mvpInfo && [NSString stringWithObject:model.mvpInfo.mvpUserId].length > 0) {
mvpNeedCount = MAX(0, (NSInteger)model.mvpInfo.mvpUserNum + 1);
} else {
mvpNeedCount = -1;
}
}
NSInteger ownedTicketCount = model.userBuyNum;
NSInteger mvpOwnedTicketCount = -1;
if (model.mvpInfo && [NSString stringWithObject:model.mvpInfo.mvpUserId].length > 0) {
mvpOwnedTicketCount = MAX(0, model.mvpInfo.mvpUserNum);
}
[self fus_updateStageStatus:stageStatus];
self.mainActionTitle = (stageStatus == 2 ? [NSString fus_localString:@"支持主播"] : [NSString fus_localString:@"进入限时表演"]);
[self fus_updateCountdownRemainingSeconds:remainSeconds];
[self fus_updateCollectedTicketCount:finalNum targetTicketCount:target];
[self fus_updateRemainingTicketCount:fillCount mvpNeedTicketCount:mvpNeedCount buyPrice:model.buyPrice];
[self fus_updateOwnedTicketCount:ownedTicketCount mvpOwnedTicketCount:mvpOwnedTicketCount];
} else {
[self fus_updateStageStatus:0];
self.mainActionTitle = [NSString fus_localString:@"进入限时表演"];
[self fus_updateCountdownRemainingSeconds:-1];
[self fus_updateCollectedTicketCount:0 targetTicketCount:0];
[self fus_updateRemainingTicketCount:-1 mvpNeedTicketCount:-1 buyPrice:-1];
[self fus_updateOwnedTicketCount:-1 mvpOwnedTicketCount:-1];
}
FUSLiveShowTimeTicketBuyGetDataViewState *state = [[FUSLiveShowTimeTicketBuyGetDataViewState alloc] init];
state.stageStatus = stageStatus;
state.countdownRemainingSeconds = remainSeconds;
state.targetTicketNum = target;
state.finalTicketNum = finalNum;
state.mvpNeedTicketCount = mvpNeedCount;
return state;
}
- (void)fus_applyHeaderUI {
if (self.stageStatus == 2) {
self.collectedLabel.attributedText = nil;
......@@ -815,7 +910,7 @@
}
- (void)fus_applyCountsToOptionViews {
[self.optionGroupView fus_updateRemainingTicketCount:self.remainingTicketCount mvpNeedTicketCount:self.mvpNeedTicketCount stageStatus:self.stageStatus];
[self.optionGroupView fus_updateRemainingTicketCount:self.remainingTicketCount mvpNeedTicketCount:self.mvpNeedTicketCount buyPrice:self.buyPrice stageStatus:self.stageStatus];
}
- (void)fus_onSelectOption:(UIControl *)sender {
......
......@@ -2,20 +2,14 @@
NS_ASSUME_NONNULL_BEGIN
@class FUSShowRoomUserContributeModel;
/// “限时表演-票的贡献”列表 cell
@interface FUSLiveShowTimeTicketContributionCell : UITableViewCell
/// 刷新贡献数据
/// @param face 头像 URL(可为空)
/// @param nickname 昵称(可为空)
/// @param ticketCount 票数
/// @param isMVP 是否为 MVP(控制左侧 MVP 标签展示)
- (void)fus_setupWithFace:(NSString *)face
nickname:(NSString *)nickname
ticketCount:(NSInteger)ticketCount
isMVP:(BOOL)isMVP;
/// 刷新贡献数据(Model)
- (void)fus_setupWithContributeModel:(nullable FUSShowRoomUserContributeModel *)model;
@end
NS_ASSUME_NONNULL_END
......@@ -5,6 +5,11 @@
#import <Masonry/Masonry.h>
#import "FUSShowRoomCenterBunble.h"
#import "FUSShowRoomUserContributeModel.h"
@interface FUSLiveShowTimeTicketContributionCell ()
- (void)fus_setupWithFace:(NSString *)face nickname:(NSString *)nickname ticketCount:(NSInteger)ticketCount isMVP:(BOOL)isMVP;
@end
@implementation FUSLiveShowTimeTicketContributionCell {
/// 头像(圆形裁切)
......@@ -13,15 +18,22 @@
UILabel *_nicknameLabel;
/// MVP 标签(仅 MVP 用户展示)
UILabel *_mvpTagLabel;
/// 在线等级
UILabel *_onlineLabel;
/// 性别和年龄按钮
UIButton *_genderAndAgeBtn;
/// VIP 标签
UIImageView *_vipImageView;
/// 新用户标签
UIImageView *_newImageView;
/// 首充标签
UIImageView *_firstLoveImageView;
/// 票券图标
UIImageView *_ticketIconView;
/// 票数
UILabel *_countLabel;
/// 底部分割线
UIView *_dividerView;
/// MVP 标签宽度约束(用于 show/hide 时收缩宽度)
MASConstraint *_mvpWidthConstraint;
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
......@@ -36,7 +48,7 @@
_faceImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_faceImageView.contentMode = UIViewContentModeScaleAspectFill;
_faceImageView.layer.cornerRadius = 16;
_faceImageView.layer.cornerRadius = 20;
_faceImageView.layer.masksToBounds = YES;
[self.contentView addSubview:_faceImageView];
......@@ -56,6 +68,40 @@
_mvpTagLabel.layer.masksToBounds = YES;
[self.contentView addSubview:_mvpTagLabel];
_onlineLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_onlineLabel.font = [UIFont fus_themeFont:12];
_onlineLabel.textColor = UIColor.whiteColor;
_onlineLabel.backgroundColor = [UIColor colorWithHex:@"#87878A" alpha:0.32];
_onlineLabel.layer.cornerRadius = 7;
_onlineLabel.layer.masksToBounds = YES;
_onlineLabel.textAlignment = NSTextAlignmentCenter;
[self.contentView addSubview:_onlineLabel];
_vipImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_vipImageView.contentMode = UIViewContentModeScaleAspectFit;
_vipImageView.hidden = YES;
[self.contentView addSubview:_vipImageView];
_newImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_newImageView.contentMode = UIViewContentModeScaleAspectFit;
_newImageView.hidden = YES;
[self.contentView addSubview:_newImageView];
_firstLoveImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
_firstLoveImageView.contentMode = UIViewContentModeScaleToFill;
_firstLoveImageView.image = [FUSShowRoomCenterBunble imageNamed:@"live_first_love_img"];
_firstLoveImageView.hidden = YES;
[self.contentView addSubview:_firstLoveImageView];
_genderAndAgeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_genderAndAgeBtn.titleLabel.font = [UIFont fus_themeFont:9];
_genderAndAgeBtn.layer.borderColor = [UIColor colorWithHex:@"#D6D6D7"].CGColor;
_genderAndAgeBtn.layer.borderWidth = 0.5;
_genderAndAgeBtn.layer.cornerRadius = 7;
_genderAndAgeBtn.layer.masksToBounds = YES;
_genderAndAgeBtn.userInteractionEnabled = NO;
[self.contentView addSubview:_genderAndAgeBtn];
_countLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_countLabel.font = [UIFont fus_themeBoldFont:14];
_countLabel.textColor = [UIColor colorWithHex:@"#1F1F1F"];
......@@ -74,32 +120,72 @@
[_faceImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(16);
make.centerY.equalTo(self.contentView);
make.width.height.mas_equalTo(32);
make.width.height.mas_equalTo(40);
}];
[_ticketIconView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.contentView).offset(-16);
make.centerY.equalTo(self.contentView);
make.width.height.mas_equalTo(14);
make.width.mas_equalTo(30);
make.height.mas_equalTo(16);
}];
[_countLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(_ticketIconView.mas_left).offset(-6);
make.top.bottom.equalTo(self.contentView);
make.width.mas_equalTo(70);
make.centerY.equalTo(self.contentView);
make.width.mas_greaterThanOrEqualTo(40);
}];
[_mvpTagLabel mas_makeConstraints:^(MASConstraintMaker *make) {
[_nicknameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_faceImageView.mas_right).offset(10);
make.centerY.equalTo(self.contentView);
make.top.equalTo(self.contentView).offset(12);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_onlineLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_nicknameLabel.mas_right).offset(6);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.height.mas_equalTo(14);
_mvpWidthConstraint = make.width.mas_equalTo(0);
make.width.mas_greaterThanOrEqualTo(20);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_nicknameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_faceImageView.mas_right).offset(10);
make.right.equalTo(_countLabel.mas_left).offset(-10);
make.top.bottom.equalTo(self.contentView);
[_vipImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_onlineLabel.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.width.height.mas_equalTo(14);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_newImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_vipImageView.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.width.height.mas_equalTo(0);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_firstLoveImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_newImageView.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.width.mas_equalTo(32);
make.height.mas_equalTo(11);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_mvpTagLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_firstLoveImageView.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.height.mas_equalTo(14);
make.width.mas_equalTo(34);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_genderAndAgeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_nicknameLabel);
make.top.equalTo(_nicknameLabel.mas_bottom).offset(2);
make.height.mas_equalTo(14);
make.width.mas_equalTo(30);
make.bottom.lessThanOrEqualTo(self.contentView).offset(-12);
}];
[_dividerView mas_makeConstraints:^(MASConstraintMaker *make) {
......@@ -119,6 +205,132 @@
_nicknameLabel.text = @"";
_countLabel.text = @"";
_mvpTagLabel.hidden = YES;
_vipImageView.hidden = YES;
_newImageView.hidden = YES;
_firstLoveImageView.hidden = YES;
_onlineLabel.text = @"";
_genderAndAgeBtn.hidden = YES;
}
- (void)fus_setupWithContributeModel:(FUSShowRoomUserContributeModel *)model {
[self fus_setupWithFace:(model.face ?: @"")
nickname:(model.nickname ?: @"")
ticketCount:MAX(0, model.total)
isMVP:(model.mvp == 1)];
_onlineLabel.text = [NSString stringWithFormat:@"%ld", (long)MAX(0, model.lev)];
NSInteger levelValue = (NSInteger)model.level;
if (levelValue <= 0 && model.inPay) {
levelValue = 1;
}
UIImage *vipImage = (levelValue > 0 ? [UIImage fus_imageWithLevel:levelValue] : nil);
BOOL showVip = (vipImage != nil);
_vipImageView.image = vipImage;
_vipImageView.hidden = !showVip;
BOOL showNew = (model.isnew == 1 || model.inNew == 1);
_newImageView.image = (showNew ? [FUSShowRoomCenterBunble imageNamed:@"live_chat_new_user_icon"] : nil);
_newImageView.hidden = !showNew;
BOOL isFirstCharge = ([model.privilege[@"firstChargePower"] integerValue] == 1);
_firstLoveImageView.hidden = !isFirstCharge;
_genderAndAgeBtn.hidden = NO;
if (model.sex == 0) {
[_genderAndAgeBtn setImage:[UIImage fus_girlIcon] forState:UIControlStateNormal];
[_genderAndAgeBtn setTitleColor:[UIColor colorWithHex:@"#FE96B0"] forState:UIControlStateNormal];
} else if (model.sex == 1) {
[_genderAndAgeBtn setImage:[UIImage fus_boyIcon] forState:UIControlStateNormal];
[_genderAndAgeBtn setTitleColor:[UIColor colorWithHex:@"#76C4FF"] forState:UIControlStateNormal];
} else {
[_genderAndAgeBtn setImage:[UIImage fus_secretIcon] forState:UIControlStateNormal];
[_genderAndAgeBtn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
}
if (model.age > 0) {
_genderAndAgeBtn.contentEdgeInsets = UIEdgeInsetsMake(0, 4, 0, 4);
_genderAndAgeBtn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 2);
_genderAndAgeBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 2, 0, 0);
[_genderAndAgeBtn setTitle:[NSString stringWithFormat:@"%ld", (long)model.age] forState:UIControlStateNormal];
[_genderAndAgeBtn mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(30);
}];
} else {
_genderAndAgeBtn.contentEdgeInsets = UIEdgeInsetsZero;
_genderAndAgeBtn.imageEdgeInsets = UIEdgeInsetsZero;
_genderAndAgeBtn.titleEdgeInsets = UIEdgeInsetsZero;
[_genderAndAgeBtn setTitle:@"" forState:UIControlStateNormal];
[_genderAndAgeBtn mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(14);
}];
}
_onlineLabel.hidden = NO;
_mvpTagLabel.hidden = !(model.mvp == 1);
[_onlineLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_nicknameLabel.mas_right).offset(6);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.height.mas_equalTo(14);
make.width.mas_greaterThanOrEqualTo(20);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_vipImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_onlineLabel.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
if (!showVip) {
make.width.height.mas_equalTo(0);
return;
}
make.height.mas_equalTo(14);
make.width.mas_equalTo(levelValue <= 30 ? 14 : 28);
}];
[_newImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
UIView *leftView = (showVip ? _vipImageView : _onlineLabel);
make.left.equalTo(leftView.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
if (showNew) {
make.width.height.mas_equalTo(20);
} else {
make.width.height.mas_equalTo(0);
}
}];
[_firstLoveImageView mas_remakeConstraints:^(MASConstraintMaker *make) {
UIView *leftView = (showNew ? _newImageView : (showVip ? _vipImageView : _onlineLabel));
make.left.equalTo(leftView.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.width.mas_equalTo(isFirstCharge ? 32 : 0);
make.height.mas_equalTo(isFirstCharge ? 11 : 0);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[_mvpTagLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
UIView *leftView = nil;
if (!_firstLoveImageView.hidden) {
leftView = _firstLoveImageView;
} else if (showNew) {
leftView = _newImageView;
} else if (showVip) {
leftView = _vipImageView;
} else {
leftView = _onlineLabel;
}
make.left.equalTo(leftView.mas_right).offset(4);
make.centerY.equalTo(_nicknameLabel.mas_centerY);
make.height.mas_equalTo(14);
make.width.mas_equalTo((model.mvp == 1) ? 34 : 0);
make.right.lessThanOrEqualTo(_countLabel.mas_left).offset(-10);
}];
[self.contentView layoutIfNeeded];
}
- (void)fus_setupWithFace:(NSString *)face nickname:(NSString *)nickname ticketCount:(NSInteger)ticketCount isMVP:(BOOL)isMVP {
......@@ -133,17 +345,6 @@
_nicknameLabel.text = (nickname.length > 0 ? nickname : @"");
_countLabel.text = [NSString stringWithFormat:@"%zd", (NSInteger)MAX(0, ticketCount)];
_mvpTagLabel.hidden = !isMVP;
[_mvpWidthConstraint uninstall];
[_mvpTagLabel mas_updateConstraints:^(MASConstraintMaker *make) {
_mvpWidthConstraint = make.width.mas_equalTo(isMVP ? 34 : 0);
}];
[_nicknameLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(isMVP ? _mvpTagLabel.mas_right : _faceImageView.mas_right).offset(isMVP ? 6 : 10);
make.right.equalTo(_countLabel.mas_left).offset(-10);
make.top.bottom.equalTo(self.contentView);
}];
}
@end
......@@ -2,13 +2,14 @@
NS_ASSUME_NONNULL_BEGIN
@class FUSShowRoomUserContributeModel;
/// “限时表演-票的贡献”列表 View(内部为 UITableView,支持滚动)
@interface FUSLiveShowTimeTicketContributionListView : UIView
/// 票的贡献列表数据源(元素建议包含:nickname/face/ticketCount/isMVP)
@property (nonatomic, copy) NSArray<NSDictionary *> *contributionList;
/// 票的贡献列表数据源
@property (nonatomic, copy) NSArray<FUSShowRoomUserContributeModel *> *contributionList;
@end
NS_ASSUME_NONNULL_END
......@@ -5,6 +5,7 @@
#import <Masonry/Masonry.h>
#import "FUSLiveShowTimeTicketContributionCell.h"
#import "FUSShowRoomUserContributeModel.h"
@interface FUSLiveShowTimeTicketContributionListView () <UITableViewDelegate, UITableViewDataSource>
......@@ -31,7 +32,7 @@
self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.backgroundColor = UIColor.whiteColor;
self.tableView.rowHeight = 52;
self.tableView.rowHeight = 64;
[self.tableView registerClass:FUSLiveShowTimeTicketContributionCell.class forCellReuseIdentifier:NSStringFromClass(FUSLiveShowTimeTicketContributionCell.class)];
[self addSubview:self.tableView];
......@@ -42,7 +43,7 @@
return self;
}
- (void)setContributionList:(NSArray<NSDictionary *> *)contributionList {
- (void)setContributionList:(NSArray<FUSShowRoomUserContributeModel *> *)contributionList {
/// copy 保证外部可变数组传入时不会被后续修改影响 UI 展示
_contributionList = [contributionList copy] ?: @[];
[self.tableView reloadData];
......@@ -54,36 +55,12 @@
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FUSLiveShowTimeTicketContributionCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(FUSLiveShowTimeTicketContributionCell.class) forIndexPath:indexPath];
NSDictionary *item = nil;
FUSShowRoomUserContributeModel *model = nil;
if (indexPath.row < self.contributionList.count) {
item = self.contributionList[indexPath.row];
model = self.contributionList[indexPath.row];
}
id nicknameValue = item[@"nickname"];
NSString *nickname = ([nicknameValue isKindOfClass:NSString.class] ? (NSString *)nicknameValue : @"");
id faceValue = item[@"face"];
NSString *face = ([faceValue isKindOfClass:NSString.class] ? (NSString *)faceValue : @"");
NSInteger ticketCount = 0;
id countValue = item[@"ticketCount"];
if ([countValue isKindOfClass:NSNumber.class]) {
ticketCount = [(NSNumber *)countValue integerValue];
} else if ([countValue isKindOfClass:NSString.class]) {
ticketCount = [(NSString *)countValue integerValue];
}
BOOL isMVP = NO;
id isMVPValue = item[@"isMVP"];
if ([isMVPValue isKindOfClass:NSNumber.class]) {
isMVP = ([(NSNumber *)isMVPValue integerValue] == 1);
} else if ([isMVPValue isKindOfClass:NSString.class]) {
isMVP = ([(NSString *)isMVPValue integerValue] == 1);
}
[cell fus_setupWithFace:face nickname:nickname ticketCount:ticketCount isMVP:isMVP];
[cell fus_setupWithContributeModel:model];
return cell;
}
@end
......@@ -67,6 +67,9 @@ NS_ASSUME_NONNULL_BEGIN
/// 贡献值
@property (nonatomic, assign) NSInteger total;
/// 是否为 MVP(Ticket Show 贡献榜字段:mvp,0 否 1 是)
@property (nonatomic, assign) NSInteger mvp;
@end
NS_ASSUME_NONNULL_END
......@@ -592,6 +592,12 @@ NS_ASSUME_NONNULL_BEGIN
/// Ticket Show - 视图 - 获取表演票的集票信息(观众端进房刷新)
+ (NSString *)fus_URL_TicketShow_Progress_GetInfo;
/// Ticket Show - 视图 - 购票弹窗数据(观众端:购票入口弹窗展示前拉取)
+ (NSString *)fus_URL_TicketShow_Buy_GetData;
/// Ticket Show - 视图 - 获取票的贡献列表(观众端:购票弹窗/贡献页展示)
+ (NSString *)fus_URL_TicketShow_Rank_List;
@end
......
......@@ -976,6 +976,18 @@
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/ticketshow/progress/getinfo"];
}
/// Ticket Show - 视图 - 购票弹窗数据(观众端:购票入口弹窗展示前拉取)
+ (NSString *)fus_URL_TicketShow_Buy_GetData
{
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/ticketshow/buy/getdata"];
}
/// Ticket Show - 视图 - 获取票的贡献列表(观众端:购票弹窗/贡献页展示)
+ (NSString *)fus_URL_TicketShow_Rank_List
{
return [FUSConfig.sharedInstanced.pathConfigs apiUrl:@"/ticketshow/rank/list"];
}
@end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment