From 6f02bc7cf5d696c22f2c086570643d6045d857b1 Mon Sep 17 00:00:00 2001 From: CodeST <694468528@qq.com> Date: Wed, 3 Dec 2025 18:19:51 +0800 Subject: [PATCH] 2 --- Shared/KBAPI.h | 2 +- keyBoard.xcodeproj/project.pbxproj | 20 +++++++++ keyBoard/Class/Home/M/KBCharacter.h | 50 +++++++++++++++++++++ keyBoard/Class/Home/M/KBCharacter.m | 18 ++++++++ keyBoard/Class/Home/VM/KBHomeVM.h | 34 +++++++++++++++ keyBoard/Class/Home/VM/KBHomeVM.m | 68 +++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 keyBoard/Class/Home/M/KBCharacter.h create mode 100644 keyBoard/Class/Home/M/KBCharacter.m create mode 100644 keyBoard/Class/Home/VM/KBHomeVM.h create mode 100644 keyBoard/Class/Home/VM/KBHomeVM.m diff --git a/Shared/KBAPI.h b/Shared/KBAPI.h index ccf91e7..da520d6 100644 --- a/Shared/KBAPI.h +++ b/Shared/KBAPI.h @@ -19,7 +19,7 @@ // 兼容旧命名(如有使用 API_APPLE_LOGIN 的位置,映射到统一命名) #define API_APPLE_LOGIN @"/user/appleLogin" // Apple 登录 #define API_LOGOUT @"/user/logout" // 退出登录 - +#define KB_API_CHARACTER_LIST @"/character/list" // 排行榜角色列表 // 应用配置 #ifndef KB_API_APP_CONFIG diff --git a/keyBoard.xcodeproj/project.pbxproj b/keyBoard.xcodeproj/project.pbxproj index d94d4a9..1dd486e 100644 --- a/keyBoard.xcodeproj/project.pbxproj +++ b/keyBoard.xcodeproj/project.pbxproj @@ -105,6 +105,8 @@ 0498BD6E2EE0285D006CC1D5 /* KBForgetVerPwdVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD6D2EE0285D006CC1D5 /* KBForgetVerPwdVC.m */; }; 0498BD712EE02A41006CC1D5 /* KBForgetPwdNewPwdVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD702EE02A41006CC1D5 /* KBForgetPwdNewPwdVC.m */; }; 0498BD742EE02E3D006CC1D5 /* KBRegistVerEmailVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD732EE02E3D006CC1D5 /* KBRegistVerEmailVC.m */; }; + 0498BD782EE04286006CC1D5 /* KBHomeVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD772EE04286006CC1D5 /* KBHomeVM.m */; }; + 0498BD7B2EE04518006CC1D5 /* KBCharacter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */; }; 049FB20B2EC1C13800FAB05D /* KBSkinBottomActionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */; }; 049FB20E2EC1CD2800FAB05D /* KBAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB20D2EC1CD2800FAB05D /* KBAlert.m */; }; 049FB2112EC1F72F00FAB05D /* KBMyListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 049FB2102EC1F72F00FAB05D /* KBMyListCell.m */; }; @@ -385,6 +387,10 @@ 0498BD702EE02A41006CC1D5 /* KBForgetPwdNewPwdVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBForgetPwdNewPwdVC.m; sourceTree = ""; }; 0498BD722EE02E3D006CC1D5 /* KBRegistVerEmailVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBRegistVerEmailVC.h; sourceTree = ""; }; 0498BD732EE02E3D006CC1D5 /* KBRegistVerEmailVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBRegistVerEmailVC.m; sourceTree = ""; }; + 0498BD762EE04286006CC1D5 /* KBHomeVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBHomeVM.h; sourceTree = ""; }; + 0498BD772EE04286006CC1D5 /* KBHomeVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBHomeVM.m; sourceTree = ""; }; + 0498BD792EE04518006CC1D5 /* KBCharacter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBCharacter.h; sourceTree = ""; }; + 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBCharacter.m; sourceTree = ""; }; 049FB2092EC1C13800FAB05D /* KBSkinBottomActionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBSkinBottomActionView.h; sourceTree = ""; }; 049FB20A2EC1C13800FAB05D /* KBSkinBottomActionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBSkinBottomActionView.m; sourceTree = ""; }; 049FB20C2EC1CD2800FAB05D /* KBAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAlert.h; sourceTree = ""; }; @@ -884,6 +890,15 @@ path = VM; sourceTree = ""; }; + 0498BD752EE04271006CC1D5 /* VM */ = { + isa = PBXGroup; + children = ( + 0498BD762EE04286006CC1D5 /* KBHomeVM.h */, + 0498BD772EE04286006CC1D5 /* KBHomeVM.m */, + ); + path = VM; + sourceTree = ""; + }; 049FB2162EC20A6600FAB05D /* BMLongPressDragCellCollectionView */ = { isa = PBXGroup; children = ( @@ -1015,6 +1030,8 @@ 04FC95B32EB1E3B1007BD342 /* M */ = { isa = PBXGroup; children = ( + 0498BD792EE04518006CC1D5 /* KBCharacter.h */, + 0498BD7A2EE04518006CC1D5 /* KBCharacter.m */, ); path = M; sourceTree = ""; @@ -1065,6 +1082,7 @@ 04FC95B62EB1E3B1007BD342 /* Home */ = { isa = PBXGroup; children = ( + 0498BD752EE04271006CC1D5 /* VM */, 04FC95B32EB1E3B1007BD342 /* M */, 04FC95B42EB1E3B1007BD342 /* V */, 04FC95B52EB1E3B1007BD342 /* VC */, @@ -1691,6 +1709,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0498BD782EE04286006CC1D5 /* KBHomeVM.m in Sources */, 04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */, 04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */, 04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */, @@ -1774,6 +1793,7 @@ 04122F6E2EC5F40800EF7AB3 /* FGIAPProductsFilter.m in Sources */, 04122F6F2EC5F40800EF7AB3 /* FGIAPManager.m in Sources */, 04122F702EC5F40800EF7AB3 /* FGIAPService.m in Sources */, + 0498BD7B2EE04518006CC1D5 /* KBCharacter.m in Sources */, 04122FB32EC73C0100EF7AB3 /* KBVipReviewListCell.m in Sources */, 048908DA2EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout.m in Sources */, 04C6EABF2EAF86530089C901 /* main.m in Sources */, diff --git a/keyBoard/Class/Home/M/KBCharacter.h b/keyBoard/Class/Home/M/KBCharacter.h new file mode 100644 index 0000000..1685275 --- /dev/null +++ b/keyBoard/Class/Home/M/KBCharacter.h @@ -0,0 +1,50 @@ +// +// KBCharacter.h +// 首页 - 排行榜角色模型(MJExtension 解析) +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// 排行榜角色/角色卡片模型 +/// 对应后端返回字段: +/// { +/// "id": 0, +/// "title": "", +/// "characterBackground": "", +/// "avatarUrl": "", +/// "download": "", +/// "tag": 0, +/// "rank": 0 +/// } +@interface KBCharacter : NSObject + +/// 唯一标识,对应后端的 id +@property (nonatomic, copy, nullable) NSString *characterId; + +/// 标题/名称 +@property (nonatomic, copy, nullable) NSString *title; + +/// 角色背景(颜色值、图片地址或后端定义的 key) +@property (nonatomic, copy, nullable) NSString *characterBackground; + +/// 头像地址 +@property (nonatomic, copy, nullable) NSString *avatarUrl; + +/// 下载量文案或数值(后端返回字符串) +@property (nonatomic, copy, nullable) NSString *download; + +/// 标签(例如分类、类型)原样保存 +@property (nonatomic, assign) NSInteger tag; + +/// 排名序号(1、2、3...) +@property (nonatomic, assign) NSInteger rank; + +/// 本地字段:是否已添加到键盘(仅客户端使用) +@property (nonatomic, assign) BOOL added; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/keyBoard/Class/Home/M/KBCharacter.m b/keyBoard/Class/Home/M/KBCharacter.m new file mode 100644 index 0000000..7d4eb54 --- /dev/null +++ b/keyBoard/Class/Home/M/KBCharacter.m @@ -0,0 +1,18 @@ +// +// KBCharacter.m +// + +#import "KBCharacter.h" +#import + +@implementation KBCharacter + ++ (NSDictionary *)mj_replacedKeyFromPropertyName { + // 后端字段 id -> characterId + return @{ + @"characterId": @"id" + }; +} + +@end + diff --git a/keyBoard/Class/Home/VM/KBHomeVM.h b/keyBoard/Class/Home/VM/KBHomeVM.h new file mode 100644 index 0000000..b33a09a --- /dev/null +++ b/keyBoard/Class/Home/VM/KBHomeVM.h @@ -0,0 +1,34 @@ +// +// KBHomeVM.h +// keyBoard +// +// Created by Mac on 2025/12/3. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class KBCharacter; + +/// 首页排行榜回调 +typedef void(^KBHomeRankCompletion)(NSArray * _Nullable list, + NSError * _Nullable error); + +@interface KBHomeVM : NSObject + +/// 最近一次成功请求到的排行榜数据 +@property (nonatomic, copy, readonly, nullable) NSArray *rankList; + +/// 请求排行榜列表(GET /character/list) +/// - Parameters: +/// - params: 额外查询参数(可为空),例如分页、筛选 tag 等; +/// - needShow: 是否在请求期间显示加载 HUD; +/// - completion: 回调,list 为解析后的模型数组,error 非空表示失败。 +- (void)fetchRankListWithParams:(nullable NSDictionary *)params + needShow:(BOOL)needShow + completion:(KBHomeRankCompletion)completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/keyBoard/Class/Home/VM/KBHomeVM.m b/keyBoard/Class/Home/VM/KBHomeVM.m new file mode 100644 index 0000000..e13a7fa --- /dev/null +++ b/keyBoard/Class/Home/VM/KBHomeVM.m @@ -0,0 +1,68 @@ +// +// KBHomeVM.m +// keyBoard +// +// Created by Mac on 2025/12/3. +// + +#import "KBHomeVM.h" +#import "KBCharacter.h" +#import "KBNetworkManager.h" +#import "KBHUD.h" +#import "KBBizCode.h" + +@interface KBHomeVM () +@property (nonatomic, copy, readwrite, nullable) NSArray *rankList; +@end + +@implementation KBHomeVM + +- (void)fetchRankListWithParams:(nullable NSDictionary *)params + needShow:(BOOL)needShow + completion:(KBHomeRankCompletion)completion { + if (needShow) { + [KBHUD show]; + } + + [[KBNetworkManager shared] GET:KB_API_CHARACTER_LIST + parameters:params + headers:nil + autoShowBusinessError:NO + completion:^(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error) { + if (needShow) { + [KBHUD dismiss]; + } + + if (error) { + // 若是业务错误,优先展示服务端 message + 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; + } + + // 使用 MJExtension 将数组字典解析为模型数组 + NSArray *list = [KBCharacter mj_objectArrayWithKeyValuesArray:(NSArray *)dataObj]; + self.rankList = list; + + if (completion) { + completion(list, nil); + } + }]; +} + +@end