import Foundation // MARK: - 响应数据模型 /// 最新动态响应结构 struct MomentsLatestResponse: Codable, Equatable, Sendable { let code: Int let message: String let data: MomentsListData? let timestamp: Int? } /// 动态列表数据 struct MomentsListData: Codable, Equatable, Sendable { let dynamicList: [MomentsInfo] let nextDynamicId: Int } /// 动态信息结构 public struct MomentsInfo: Codable, Equatable, Sendable, Identifiable { let dynamicId: Int let uid: Int let nick: String let avatar: String let type: Int let content: String let likeCount: Int let isLike: Bool let commentCount: Int let publishTime: Int let worldId: Int let status: Int // data.md 里部分字段可选 let playCount: Int? let dynamicResList: [MomentsPicture]? // 以下字段后端未返回,全部可选 let gender: Int? let squareTop: Int? let topicTop: Int? let newUser: Bool? let defUser: Int? let scene: String? let userVipInfoVO: UserVipInfo? let headwearPic: String? let headwearEffect: String? let headwearType: Int? let headwearName: String? let headwearId: Int? let experLevelPic: String? let charmLevelPic: String? let isCustomWord: Bool? let labelList: [String]? // 计算属性 public var id: Int { dynamicId } // Identifiable 协议要求 var isSquareTop: Bool { (squareTop ?? 0) != 0 } var isTopicTop: Bool { (topicTop ?? 0) != 0 } var formattedPublishTime: Date { Date(timeIntervalSince1970: TimeInterval(publishTime) / 1000.0) } } /// 动态图片信息 struct MomentsPicture: Codable, Equatable, Sendable { let id: Int? let resUrl: String? let format: String? let width: Int? let height: Int? let resDuration: Int? // 可选字段,因为有些图片没有这个字段 } /// 用户VIP信息 - 完整版本,所有字段都是可选的 struct UserVipInfo: Codable, Equatable, Sendable { let vipLevel: Int? let vipName: String? let vipIcon: String? let vipLogo: String? let nameplateId: Int? let nameplateUrl: String? let userCardBG: String? let expireTime: Int? let preventKick: Bool? let preventTrace: Bool? let preventFollow: Bool? let micNickColour: String? let micCircle: String? let enterRoomEffects: String? let medalSeat: Int? let friendNickColour: String? let visitHide: Bool? let visitListView: Bool? let privateChatLimit: Bool? let roomPicScreen: Bool? let uploadGifAvatar: Bool? let enterHide: Bool? } // MARK: - 内容类型枚举 /// 动态内容类型 enum MomentsContentType: Int, CaseIterable { case text = 0 // 纯文字 case picture = 2 // 图片 /// 转换为API参数字符串 static func toAPIParameter(_ types: [MomentsContentType]) -> String { return types.map { String($0.rawValue) }.joined(separator: ",") } } // MARK: - 最新动态 API 请求 /// 获取最新动态列表的API请求 struct LatestDynamicsRequest: APIRequestProtocol { typealias Response = MomentsLatestResponse let endpoint: String = APIEndpoint.latestDynamics.path let method: HTTPMethod = .GET let dynamicId: String let pageSize: Int let types: [MomentsContentType] /// 初始化请求 /// - Parameters: /// - dynamicId: 最新动态的ID,用于分页加载。首次请求传空字符串 /// - pageSize: 每页返回的数据数量,默认20 /// - types: 动态内容类型数组,默认包含文字和图片 init( dynamicId: String = "", pageSize: Int = 20, types: [MomentsContentType] = [.text, .picture] ) { self.dynamicId = dynamicId self.pageSize = pageSize self.types = types } var queryParameters: [String: String]? { return [ "dynamicId": dynamicId, "pageSize": String(pageSize), "types": MomentsContentType.toAPIParameter(types) ] } var bodyParameters: [String: Any]? { nil } var includeBaseParameters: Bool { true } // Loading 配置 var shouldShowLoading: Bool { true } var shouldShowError: Bool { true } } // MARK: - 发布动态 API 请求与响应 /// 动态图片资源信息 struct ResListItem: Codable, Equatable { let resUrl: String let width: Int let height: Int let format: String } /// 发布动态请求 struct PublishFeedRequest: APIRequestProtocol { typealias Response = PublishFeedResponse let endpoint: String = APIEndpoint.publishFeed.path let method: HTTPMethod = .POST let content: String let uid: String let type: String var pub_sign: String let resList: [ResListItem]? var queryParameters: [String: String]? { nil } var bodyParameters: [String: Any]? { var params: [String: Any] = [ "content": content, "uid": uid, "type": type, "pub_sign": pub_sign ] if let resList = resList, !resList.isEmpty { params["resList"] = resList.map { [ "resUrl": $0.resUrl, "width": $0.width, "height": $0.height, "format": $0.format ] } } return params } var includeBaseParameters: Bool { true } var shouldShowLoading: Bool { true } var shouldShowError: Bool { true } /// async 工厂方法,主线程生成 pub_sign static func make(content: String, uid: String, type: String = "0", resList: [ResListItem]? = nil) async -> PublishFeedRequest { let base = await MainActor.run { BaseRequest() } var mutableBase = base mutableBase.generateSignature(with: [ "content": content, "uid": uid, "type": type ]) return PublishFeedRequest( content: content, uid: uid, type: type, pub_sign: mutableBase.pubSign, resList: resList ) } /// 禁止外部直接调用 private init(content: String, uid: String, type: String, pub_sign: String, resList: [ResListItem]?) { self.content = content self.uid = uid self.type = type self.pub_sign = pub_sign self.resList = resList } } /// 发布动态响应 struct PublishFeedResponse: Codable, Equatable { let code: Int let message: String let data: PublishFeedData? let timestamp: Int? } /// 发布动态返回数据 struct PublishFeedData: Codable, Equatable { let dynamicId: Int? } // MARK: - 我的动态 API 请求 /// 我的动态信息结构 - 专门用于 /dynamic/getMyDynamic 接口 struct MyMomentInfo: Codable, Equatable, Sendable { // 服务器可能返回的完整字段(均用可选兼容不同版本) let dynamicId: Int? let uid: Int let nick: String? let avatar: String? let type: Int let content: String let likeCount: Int? let isLike: Bool? let commentCount: Int? let publishTime: Int64 let worldId: Int? let status: Int? let playCount: Int? let dynamicResList: [MomentsPicture]? // 资源列表(图片/视频) // 转换为 MomentsInfo 的辅助方法 func toMomentsInfo() -> MomentsInfo { return MomentsInfo( dynamicId: dynamicId ?? 0, uid: uid, nick: nick ?? "", avatar: avatar ?? "", type: type, content: content, likeCount: likeCount ?? 0, isLike: isLike ?? false, commentCount: commentCount ?? 0, // 注意:UI 的 formatDisplayTime 期望毫秒,这里不做 /1000 转换 publishTime: Int(publishTime), worldId: worldId ?? 0, status: status ?? 1, playCount: playCount, dynamicResList: dynamicResList, gender: nil, squareTop: nil, topicTop: nil, newUser: nil, defUser: nil, scene: nil, userVipInfoVO: nil, headwearPic: nil, headwearEffect: nil, headwearType: nil, headwearName: nil, headwearId: nil, experLevelPic: nil, charmLevelPic: nil, isCustomWord: nil, labelList: nil ) } } /// 我的动态响应结构 struct MyMomentsResponse: Codable, Equatable, Sendable { let code: Int let message: String let data: [MyMomentInfo]? let timestamp: Int64? } struct GetMyDynamicRequest: APIRequestProtocol { typealias Response = MyMomentsResponse let endpoint: String = APIEndpoint.getMyDynamic.path let method: HTTPMethod = .POST let fromUid: Int let uid: Int let page: Int let pageSize: Int init(fromUid: Int, uid: Int, page: Int = 1, pageSize: Int = 20) { self.fromUid = fromUid self.uid = uid self.page = page self.pageSize = pageSize } var queryParameters: [String: String]? { [ "fromUid": String(fromUid), "uid": String(uid), "page": String(page), "pageSize": String(pageSize) ] } var bodyParameters: [String: Any]? { nil } var includeBaseParameters: Bool { true } var shouldShowLoading: Bool { true } var shouldShowError: Bool { true } } // MARK: - 动态点赞 API 请求与响应 /// 动态点赞响应结构 struct LikeDynamicResponse: Codable, Equatable, Sendable { let code: Int let message: String let data: LikeDynamicData? let timestamp: Int? } /// 动态点赞返回数据 struct LikeDynamicData: Codable, Equatable, Sendable { let success: Bool? let likeCount: Int? } /// 动态点赞请求 struct LikeDynamicRequest: APIRequestProtocol { typealias Response = LikeDynamicResponse let endpoint: String = APIEndpoint.dynamicLike.path let method: HTTPMethod = .POST let dynamicId: Int let uid: Int let status: Int // 0: 取消点赞, 1: 点赞 let likedUid: Int let worldId: Int init(dynamicId: Int, uid: Int, status: Int, likedUid: Int, worldId: Int) { self.dynamicId = dynamicId self.uid = uid self.status = status self.likedUid = likedUid self.worldId = worldId } var bodyParameters: [String: Any]? { nil } var queryParameters: [String: String]? { return [ "dynamicId": String(dynamicId), "uid": String(uid), "status": String(status), "likedUid": String(likedUid), "worldId": String(worldId) ] } var includeBaseParameters: Bool { true } var shouldShowLoading: Bool { true } var shouldShowError: Bool { true } } // MARK: - 删除动态 API 请求与响应 /// 删除动态响应结构 struct DeleteDynamicResponse: Codable, Equatable, Sendable { let code: Int let message: String let data: DeleteDynamicData? let timestamp: Int? } /// 删除动态返回数据 struct DeleteDynamicData: Codable, Equatable, Sendable { let success: Bool? } /// 删除动态请求 struct DeleteDynamicRequest: APIRequestProtocol { typealias Response = DeleteDynamicResponse let endpoint: String = APIEndpoint.deleteDynamic.path let method: HTTPMethod = .POST let dynamicId: Int let uid: Int init(dynamicId: Int, uid: Int) { self.dynamicId = dynamicId self.uid = uid } var queryParameters: [String: String]? { nil } var bodyParameters: [String: Any]? { return [ "dynamicId": dynamicId, "uid": uid ] } var includeBaseParameters: Bool { true } var shouldShowLoading: Bool { true } var shouldShowError: Bool { true } }