This commit is contained in:
2025-12-03 19:19:20 +08:00
parent b00283cd96
commit 716f91bdd0
8 changed files with 147 additions and 47 deletions

View File

@@ -19,7 +19,8 @@
// 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名) // 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名)
#define API_APPLE_LOGIN @"/user/appleLogin" // Apple 登录 #define API_APPLE_LOGIN @"/user/appleLogin" // Apple 登录
#define API_LOGOUT @"/user/logout" // 退出登录 #define API_LOGOUT @"/user/logout" // 退出登录
#define KB_API_CHARACTER_LIST @"/character/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" // 排行榜标签列表 #define KB_API_TAG_LIST @"/tag/list" // 排行榜标签列表
// 应用配置 // 应用配置

View File

@@ -6,16 +6,20 @@
// //
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "KBCharacter.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
/// 首页排行榜卡片 Cell两列 /// 首页排行榜卡片 Cell两列
@interface HomeRankCardCell : UICollectionViewCell @interface HomeRankCardCell : UICollectionViewCell
/// 当前展示的角色模型
@property (nonatomic, strong, nullable) KBCharacter *character;
/// 点击加号/勾选按钮回调 /// 点击加号/勾选按钮回调
@property (nonatomic, copy, nullable) void (^onTapAction)(void); @property (nonatomic, copy, nullable) void (^onTapAction)(void);
/// 统一配置数据 /// 旧的配置方法(兼容用,不推荐继续使用)
- (void)configureWithTitle:(NSString *)title - (void)configureWithTitle:(NSString *)title
desc:(NSString *)desc desc:(NSString *)desc
people:(NSString *)people people:(NSString *)people
@@ -24,4 +28,3 @@ NS_ASSUME_NONNULL_BEGIN
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -11,7 +11,7 @@
@interface HomeRankCardCell () @interface HomeRankCardCell ()
@property (nonatomic, strong) UIView *shadowView; // @property (nonatomic, strong) UIView *shadowView; //
@property (nonatomic, strong) UIView *cardView; // @property (nonatomic, strong) UIImageView *cardView; //
@property (nonatomic, strong) UIView *badgeCircle; // @property (nonatomic, strong) UIView *badgeCircle; //
@property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *descLabel; @property (nonatomic, strong) UILabel *descLabel;
@@ -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 #pragma mark - Lazy UI
- (UIView *)shadowView { - (UIView *)shadowView {
@@ -135,12 +146,15 @@
return _shadowView; return _shadowView;
} }
- (UIView *)cardView { - (UIImageView *)cardView {
if (!_cardView) { if (!_cardView) {
_cardView = [UIView new]; _cardView = [[UIImageView alloc] init];
_cardView.backgroundColor = UIColor.whiteColor; _cardView.backgroundColor = UIColor.whiteColor;
_cardView.layer.cornerRadius = 18.0; _cardView.layer.cornerRadius = 18.0;
_cardView.layer.masksToBounds = YES; _cardView.layer.masksToBounds = YES;
_cardView.contentMode = UIViewContentModeScaleAspectFill;
//
_cardView.image = [UIImage imageNamed:@"home_rank_card_bg"];
} }
return _cardView; return _cardView;
} }

View File

@@ -7,12 +7,15 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import "JXCategoryListContainerView.h" #import "JXCategoryListContainerView.h"
#import "KBTag.h"
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface HomeRankContentVC : UIViewController<JXCategoryListContentViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout> @interface HomeRankContentVC : UIViewController<JXCategoryListContentViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
@property (nonatomic, strong) UICollectionView *collectionView; @property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) KBTag *tagModel;
/// 指定标签 id 的构造方法index 对应的 tagId 由 HomeRankVC 传入
- (instancetype)initWithTagId:(nullable NSString *)tagId;
@end @end

View File

@@ -12,35 +12,55 @@
// Cell // Cell
#import "HomeRankCardCell.h" #import "HomeRankCardCell.h"
#import "KBHomeVM.h"
#import "KBCharacter.h"
@interface HomeRankContentVC () @interface HomeRankContentVC ()
@property (nonatomic, strong) NSArray<NSDictionary *> *dataSource; // @property (nonatomic, copy, nullable) NSString *tagId; // id
@property (nonatomic, strong) KBHomeVM *homeVM;
@property (nonatomic, strong) NSArray<KBCharacter *> *characters; //
@end @end
@implementation HomeRankContentVC @implementation HomeRankContentVC
- (instancetype)initWithTagId:(NSString *)tagId {
if (self = [super init]) {
_tagId = [tagId copy];
}
return self;
}
- (instancetype)init {
return [self initWithTagId:nil];
}
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = COLOR_WITH_RGB(246/255.0, 253/255.0, 249/255.0, 1.0); // 绿 self.view.backgroundColor = COLOR_WITH_RGB(246/255.0, 253/255.0, 249/255.0, 1.0); // 绿
self.characters = @[];
// self.homeVM = [KBHomeVM new];
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.view addSubview:self.collectionView]; [self.view addSubview:self.collectionView];
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) { [self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view); make.edges.equalTo(self.view);
}]; }];
// tag
[self loadCharactersForCurrentTag];
}
- (void)loadCharactersForCurrentTag {
KBWeakSelf
[self.homeVM fetchRankListByTagId:self.tagId
needShow:YES
completion:^(NSArray<KBCharacter *> * _Nullable list, NSError * _Nullable error) {
if (error) {
return;
}
weakSelf.characters = list ?: @[];
[weakSelf.collectionView reloadData];
}];
} }
- (UICollectionView *)collectionView{ - (UICollectionView *)collectionView{
@@ -66,26 +86,21 @@
#pragma mark - UICollectionViewDataSource #pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.dataSource.count; return self.characters.count;
} }
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { - (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
HomeRankCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HomeRankCardCell" forIndexPath:indexPath]; HomeRankCardCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HomeRankCardCell" forIndexPath:indexPath];
NSDictionary *d = self.dataSource[indexPath.item]; KBCharacter *c = self.characters[indexPath.item];
BOOL added = [d[@"added"] boolValue]; // cell cell
[cell configureWithTitle:d[@"title"] cell.character = c;
desc:d[@"desc"]
people:d[@"people"]
added:added];
KBWeakSelf KBWeakSelf
cell.onTapAction = ^{ cell.onTapAction = ^{
// / // / UI
NSMutableArray *m = [weakSelf.dataSource mutableCopy]; NSMutableArray *m = [weakSelf.characters mutableCopy];
NSMutableDictionary *md = [m[indexPath.item] mutableCopy]; KBCharacter *mc = m[indexPath.item];
BOOL cur = [md[@"added"] boolValue]; mc.added = !mc.added;
md[@"added"] = @(!cur); weakSelf.characters = [m copy];
m[indexPath.item] = md;
weakSelf.dataSource = [m copy];
[weakSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]]; [weakSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]];
}; };
return cell; return cell;
@@ -105,13 +120,13 @@
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ - (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); CGFloat width = MIN(KB_SCREEN_WIDTH - 76, 420);
HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)]; HomeRankDetailPopView *content = [[HomeRankDetailPopView alloc] initWithFrame:CGRectMake(0, 0, width, 460)];
NSString *title = d[@"title"] ?: @"High EQ"; NSString *title = c.characterName ?: @"High EQ";
NSString *people = d[@"people"] ?: @"Download: 1 Million"; NSString *people = c.download ?: @"Download: 1 Million";
NSString *desc = @"Be Neither Too Close\nNor Too Distant"; // NSString *desc = @"Be Neither Too Close\nNor Too Distant"; //
[content configWithAvatar:nil title:title download:people desc:desc]; [content configWithAvatar:nil title:title download:people desc:desc];

View File

@@ -179,11 +179,13 @@
// <JXCategoryListContentViewDelegate> // <JXCategoryListContentViewDelegate>
- (id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index { - (id<JXCategoryListContentViewDelegate>)listContainerView:(JXCategoryListContainerView *)listContainerView initListForIndex:(NSInteger)index {
KBTag *tagModel = self.tags[index]; NSString *tagId = nil;
HomeRankContentVC *list = [[HomeRankContentVC alloc] init]; if (index >= 0 && index < self.tags.count) {
list.tagModel = tagModel; KBTag *tag = self.tags[index];
tagId = tag.tagId;
}
HomeRankContentVC *list = [[HomeRankContentVC alloc] initWithTagId:tagId];
self.collectionView = list.collectionView; self.collectionView = list.collectionView;
return list; return list;
} }

View File

@@ -37,6 +37,11 @@ typedef void(^KBHomeTagCompletion)(NSArray<KBTag *> * _Nullable list,
needShow:(BOOL)needShow needShow:(BOOL)needShow
completion:(KBHomeRankCompletion)completion; completion:(KBHomeRankCompletion)completion;
/// 根据 tagId 获取角色列表GET /character/listByTag
- (void)fetchRankListByTagId:(nullable NSString *)tagId
needShow:(BOOL)needShow
completion:(KBHomeRankCompletion)completion;
/// 请求排行榜标签列表GET /tag/list /// 请求排行榜标签列表GET /tag/list
/// - Parameters: /// - Parameters:
/// - params: 额外查询参数(可为空); /// - params: 额外查询参数(可为空);

View File

@@ -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<KBCharacter *> *list = [KBCharacter mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj];
if (completion) {
completion(list, nil);
}
}];
}
- (void)fetchTagListWithParams:(nullable NSDictionary *)params - (void)fetchTagListWithParams:(nullable NSDictionary *)params
needShow:(BOOL)needShow needShow:(BOOL)needShow
completion:(KBHomeTagCompletion)completion { completion:(KBHomeTagCompletion)completion {