diff --git a/Shared/KBAPI.h b/Shared/KBAPI.h index b0c4fc3..604141a 100644 --- a/Shared/KBAPI.h +++ b/Shared/KBAPI.h @@ -19,8 +19,9 @@ // 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名) #define API_APPLE_LOGIN @"/user/appleLogin" // Apple 登录 #define API_LOGOUT @"/user/logout" // 退出登录 -#define KB_API_CHARACTER_LIST @"/character/list" // 排行榜角色列表 -#define KB_API_TAG_LIST @"/tag/list" // 排行榜标签列表 +#define KB_API_CHARACTER_LIST @"/character/list" // 排行榜角色列表(综合) +#define KB_API_CHARACTER_LIST_BY_TAG @"/character/listByTag" // 根据 tagId 获取角色列表 +#define KB_API_TAG_LIST @"/tag/list" // 排行榜标签列表 // 应用配置 #ifndef KB_API_APP_CONFIG diff --git a/keyBoard/Class/Home/V/HomeRankCardCell.h b/keyBoard/Class/Home/V/HomeRankCardCell.h index 547f084..bf523e3 100644 --- a/keyBoard/Class/Home/V/HomeRankCardCell.h +++ b/keyBoard/Class/Home/V/HomeRankCardCell.h @@ -6,16 +6,20 @@ // #import +#import "KBCharacter.h" NS_ASSUME_NONNULL_BEGIN /// 首页排行榜卡片 Cell(两列) @interface HomeRankCardCell : UICollectionViewCell +/// 当前展示的角色模型 +@property (nonatomic, strong, nullable) KBCharacter *character; + /// 点击加号/勾选按钮回调 @property (nonatomic, copy, nullable) void (^onTapAction)(void); -/// 统一配置数据 +/// 旧的配置方法(兼容用,不推荐继续使用) - (void)configureWithTitle:(NSString *)title desc:(NSString *)desc people:(NSString *)people @@ -24,4 +28,3 @@ NS_ASSUME_NONNULL_BEGIN @end NS_ASSUME_NONNULL_END - diff --git a/keyBoard/Class/Home/V/HomeRankCardCell.m b/keyBoard/Class/Home/V/HomeRankCardCell.m index aebe906..08b14b8 100644 --- a/keyBoard/Class/Home/V/HomeRankCardCell.m +++ b/keyBoard/Class/Home/V/HomeRankCardCell.m @@ -10,13 +10,13 @@ #import "UIView+KBShadow.h" @interface HomeRankCardCell () -@property (nonatomic, strong) UIView *shadowView; // 阴影容器(不裁剪) -@property (nonatomic, strong) UIView *cardView; // 白色圆角卡片 -@property (nonatomic, strong) UIView *badgeCircle; // 顶部圆形描边 +@property (nonatomic, strong) UIView *shadowView; // 阴影容器(不裁剪) +@property (nonatomic, strong) UIImageView *cardView; // 卡片背景图片 +@property (nonatomic, strong) UIView *badgeCircle; // 顶部圆形描边 @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *descLabel; @property (nonatomic, strong) UILabel *peopleLabel; -@property (nonatomic, strong) UIButton *actionBtn; // 加号/勾选按钮 +@property (nonatomic, strong) UIButton *actionBtn; // 加号/勾选按钮 @property (nonatomic, assign) BOOL added; @end @@ -125,6 +125,17 @@ } } +- (void)setCharacter:(KBCharacter *)character { + _character = character; + + NSString *title = character.characterName ?: @""; + NSString *people = character.download ?: @""; + NSString *desc = @"Be Neither Too Close\nNor Too Distant..."; // 目前暂无描述字段,先用示例文案 + BOOL added = character.added; + + [self configureWithTitle:title desc:desc people:people added:added]; +} + #pragma mark - Lazy UI - (UIView *)shadowView { @@ -135,12 +146,15 @@ return _shadowView; } -- (UIView *)cardView { +- (UIImageView *)cardView { if (!_cardView) { - _cardView = [UIView new]; + _cardView = [[UIImageView alloc] init]; _cardView.backgroundColor = UIColor.whiteColor; _cardView.layer.cornerRadius = 18.0; _cardView.layer.masksToBounds = YES; + _cardView.contentMode = UIViewContentModeScaleAspectFill; + // 默认卡片背景图(可按需要替换) + _cardView.image = [UIImage imageNamed:@"home_rank_card_bg"]; } return _cardView; } diff --git a/keyBoard/Class/Home/VC/HomeRankContentVC.h b/keyBoard/Class/Home/VC/HomeRankContentVC.h index 6dd8c2e..a4b01c9 100644 --- a/keyBoard/Class/Home/VC/HomeRankContentVC.h +++ b/keyBoard/Class/Home/VC/HomeRankContentVC.h @@ -7,12 +7,15 @@ #import #import "JXCategoryListContainerView.h" -#import "KBTag.h" + NS_ASSUME_NONNULL_BEGIN @interface HomeRankContentVC : UIViewController + @property (nonatomic, strong) UICollectionView *collectionView; -@property (nonatomic, strong) KBTag *tagModel; + +/// 指定标签 id 的构造方法;index 对应的 tagId 由 HomeRankVC 传入 +- (instancetype)initWithTagId:(nullable NSString *)tagId; @end diff --git a/keyBoard/Class/Home/VC/HomeRankContentVC.m b/keyBoard/Class/Home/VC/HomeRankContentVC.m index 6ae6924..e7d0ec9 100644 --- a/keyBoard/Class/Home/VC/HomeRankContentVC.m +++ b/keyBoard/Class/Home/VC/HomeRankContentVC.m @@ -12,35 +12,55 @@ // 自定义卡片 Cell #import "HomeRankCardCell.h" +#import "KBHomeVM.h" +#import "KBCharacter.h" @interface HomeRankContentVC () -@property (nonatomic, strong) NSArray *dataSource; // 简单模拟数据 +@property (nonatomic, copy, nullable) NSString *tagId; // 当前标签 id +@property (nonatomic, strong) KBHomeVM *homeVM; +@property (nonatomic, strong) NSArray *characters; // 当前标签下的角色列表 @end @implementation HomeRankContentVC +- (instancetype)initWithTagId:(NSString *)tagId { + if (self = [super init]) { + _tagId = [tagId copy]; + } + return self; +} + +- (instancetype)init { + return [self initWithTagId:nil]; +} + - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = COLOR_WITH_RGB(246/255.0, 253/255.0, 249/255.0, 1.0); // 淡绿色背景 - - // 数据 - self.dataSource = @[ - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(NO)}, - @{@"title":@"High EQ", @"desc":@"Be Neither Too Close\nNor Too Distant...", @"people":@"Two Million People\nHave Used It", @"added":@(YES)} - ]; - + self.characters = @[]; + self.homeVM = [KBHomeVM new]; [self.view addSubview:self.collectionView]; [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view); }]; + + // 加载当前 tag 下的角色列表 + [self loadCharactersForCurrentTag]; +} + +- (void)loadCharactersForCurrentTag { + KBWeakSelf + [self.homeVM fetchRankListByTagId:self.tagId + needShow:YES + completion:^(NSArray * _Nullable list, NSError * _Nullable error) { + if (error) { + return; + } + weakSelf.characters = list ?: @[]; + [weakSelf.collectionView reloadData]; + }]; } - (UICollectionView *)collectionView{ @@ -66,26 +86,21 @@ #pragma mark - UICollectionViewDataSource - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - return self.dataSource.count; + return self.characters.count; } - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { HomeRankCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HomeRankCardCell" forIndexPath:indexPath]; - NSDictionary *d = self.dataSource[indexPath.item]; - BOOL added = [d[@"added"] boolValue]; - [cell configureWithTitle:d[@"title"] - desc:d[@"desc"] - people:d[@"people"] - added:added]; + KBCharacter *c = self.characters[indexPath.item]; + // 直接把模型交给 cell,由 cell 自己负责展示 + cell.character = c; KBWeakSelf cell.onTapAction = ^{ - // 切换添加/已添加状态并刷新该项 - NSMutableArray *m = [weakSelf.dataSource mutableCopy]; - NSMutableDictionary *md = [m[indexPath.item] mutableCopy]; - BOOL cur = [md[@"added"] boolValue]; - md[@"added"] = @(!cur); - m[indexPath.item] = md; - weakSelf.dataSource = [m copy]; + // 切换添加/已添加状态并刷新该项(只是本地 UI 状态) + NSMutableArray *m = [weakSelf.characters mutableCopy]; + KBCharacter *mc = m[indexPath.item]; + mc.added = !mc.added; + weakSelf.characters = [m copy]; [weakSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]]; }; return cell; @@ -105,13 +120,13 @@ - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ // 点击卡片 -> 展示弹窗 - NSDictionary *d = self.dataSource[indexPath.item]; + KBCharacter *c = self.characters[indexPath.item]; // 自定义内容视图(尺寸可按需调节) CGFloat width = MIN(KB_SCREEN_WIDTH - 76, 420); HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)]; - NSString *title = d[@"title"] ?: @"High EQ"; - NSString *people = d[@"people"] ?: @"Download: 1 Million"; + NSString *title = c.characterName ?: @"High EQ"; + NSString *people = c.download ?: @"Download: 1 Million"; NSString *desc = @"Be Neither Too Close\nNor Too Distant"; // 示例文案 [content configWithAvatar:nil title:title download:people desc:desc]; diff --git a/keyBoard/Class/Home/VC/HomeRankVC.m b/keyBoard/Class/Home/VC/HomeRankVC.m index f764764..c4bb586 100644 --- a/keyBoard/Class/Home/VC/HomeRankVC.m +++ b/keyBoard/Class/Home/VC/HomeRankVC.m @@ -179,11 +179,13 @@ // 返回各个列表菜单下的实例,该实例需要遵守并实现 协议 - (id)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index { - KBTag *tagModel = self.tags[index]; - HomeRankContentVC *list = [[HomeRankContentVC alloc] init]; - list.tagModel = tagModel; + NSString *tagId = nil; + if (index >= 0 && index < self.tags.count) { + KBTag *tag = self.tags[index]; + tagId = tag.tagId; + } + HomeRankContentVC *list = [[HomeRankContentVC alloc] initWithTagId:tagId]; self.collectionView = list.collectionView; - return list; } diff --git a/keyBoard/Class/Home/VM/KBHomeVM.h b/keyBoard/Class/Home/VM/KBHomeVM.h index cd8d7e7..7f4f3c9 100644 --- a/keyBoard/Class/Home/VM/KBHomeVM.h +++ b/keyBoard/Class/Home/VM/KBHomeVM.h @@ -37,6 +37,11 @@ typedef void(^KBHomeTagCompletion)(NSArray * _Nullable list, needShow:(BOOL)needShow completion:(KBHomeRankCompletion)completion; +/// 根据 tagId 获取角色列表(GET /character/listByTag) +- (void)fetchRankListByTagId:(nullable NSString *)tagId + needShow:(BOOL)needShow + completion:(KBHomeRankCompletion)completion; + /// 请求排行榜标签列表(GET /tag/list) /// - Parameters: /// - params: 额外查询参数(可为空); diff --git a/keyBoard/Class/Home/VM/KBHomeVM.m b/keyBoard/Class/Home/VM/KBHomeVM.m index b681078..058e233 100644 --- a/keyBoard/Class/Home/VM/KBHomeVM.m +++ b/keyBoard/Class/Home/VM/KBHomeVM.m @@ -67,6 +67,63 @@ }]; } +- (void)fetchRankListByTagId:(nullable NSString *)tagId + needShow:(BOOL)needShow + completion:(KBHomeRankCompletion)completion { + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + if (tagId.length) { + params[@"tagId"] = tagId; + } + [self fetchRankListByTagParams:params + needShow:needShow + completion:completion]; +} + +// 内部辅助方法:调用 /character/listByTag +- (void)fetchRankListByTagParams:(NSDictionary *)params + needShow:(BOOL)needShow + completion:(KBHomeRankCompletion)completion { + if (needShow) { + [KBHUD show]; + } + + [[KBNetworkManager shared] GET:KB_API_CHARACTER_LIST_BY_TAG + parameters:params + headers:nil + autoShowBusinessError:NO + completion:^(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (needShow) { + [KBHUD dismiss]; + } + + if (error) { + NSString *msg = KBBizMessageFromJSONObject(json) ?: error.localizedDescription ?: KBLocalized(@"Network error"); + [KBHUD showInfo:msg]; + if (completion) { + completion(nil, error); + } + return; + } + + id dataObj = json[KBData] ?: json[@"data"]; + if (![dataObj isKindOfClass:[NSArray class]]) { + NSError *e = [NSError errorWithDomain:KBNetworkErrorDomain + code:KBNetworkErrorInvalidResponse + userInfo:@{NSLocalizedDescriptionKey: KBLocalized(@"Invalid response")}]; + [KBHUD showInfo:e.localizedDescription]; + if (completion) { + completion(nil, e); + } + return; + } + + NSArray *list = [KBCharacter mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj]; + if (completion) { + completion(list, nil); + } + }]; +} + - (void)fetchTagListWithParams:(nullable NSDictionary *)params needShow:(BOOL)needShow completion:(KBHomeTagCompletion)completion {