import Foundation import ComposableArchitecture @Reducer struct MeFeature { @Dependency(\.apiService) var apiService @ObservableState struct State: Equatable { var isFirstLoad: Bool = true var isUserInfoFirstLoad: Bool = true var userInfo: UserInfo? var isLoadingUserInfo: Bool = false var userInfoError: String? var moments: [MomentsInfo] = [] var isLoadingMoments: Bool = false var momentsError: String? var hasMore: Bool = true var isLoadingMore: Bool = false var isRefreshing: Bool = false var page: Int = 1 var pageSize: Int = 20 var uid: Int = 0 // 新增:显示指定用户ID,如果为nil则显示当前登录用户 var displayUID: Int? // 新增:DetailView相关状态 var showDetail: Bool = false var selectedMoment: MomentsInfo? // 新增:错误视图相关状态 var showErrorView: Bool = false var momentsFirstLoadFailed: Bool = false init(displayUID: Int? = nil) { self.displayUID = displayUID // 如果displayUID不为nil,说明要显示指定用户,将其设置为uid if let displayUID = displayUID { self.uid = displayUID } } // 获取实际要显示的用户ID var effectiveUID: Int { return displayUID ?? uid } // 判断是否显示其他用户 var isDisplayingOtherUser: Bool { return displayUID != nil && displayUID != uid } } enum Action: Equatable { case onAppear case refresh case loadMore case loadUserInfo case retryMoments case userInfoResponse(Result) case momentsResponse(Result) // 设置按钮点击 case settingButtonTapped // 新增:DetailView相关Action case showDetail(MomentsInfo) case detailDismissed } func reduce(into state: inout State, action: Action) -> Effect { switch action { case .onAppear: debugInfoSync("\n📱 MeFeature onAppear") debugInfoSync(" isFirstLoad: \(state.isFirstLoad)") debugInfoSync(" isUserInfoFirstLoad: \(state.isUserInfoFirstLoad)") debugInfoSync(" effectiveUID: \(state.effectiveUID)") // 每次显示都获取用户信息 let userInfoEffect = fetchUserInfo(uid: state.effectiveUID) // 只在首次进入时获取动态列表 if state.isFirstLoad { state.isFirstLoad = false return .merge( userInfoEffect, fetchMoments(uid: state.effectiveUID, page: 1, pageSize: state.pageSize) ) } else { return userInfoEffect } case .refresh: guard state.effectiveUID > 0 else { return .none } debugInfoSync("\n🔄 MeFeature refresh") debugInfoSync(" effectiveUID: \(state.effectiveUID)") state.isRefreshing = true state.page = 1 state.hasMore = true state.userInfoError = nil // 重置错误状态 state.momentsError = nil // 重置错误状态 state.showErrorView = false // 隐藏错误视图 return .merge( fetchUserInfo(uid: state.effectiveUID), fetchMoments(uid: state.effectiveUID, page: 1, pageSize: state.pageSize) ) case .loadUserInfo: guard state.effectiveUID > 0 else { return .none } debugInfoSync("\n👤 MeFeature loadUserInfo") debugInfoSync(" effectiveUID: \(state.effectiveUID)") return fetchUserInfo(uid: state.effectiveUID) case .retryMoments: guard state.effectiveUID > 0 else { return .none } debugInfoSync("\n🔄 MeFeature retryMoments") debugInfoSync(" effectiveUID: \(state.effectiveUID)") state.showErrorView = false // 隐藏错误视图 state.momentsFirstLoadFailed = false state.isLoadingMoments = true state.page = 1 state.hasMore = true state.momentsError = nil return fetchMoments(uid: state.effectiveUID, page: 1, pageSize: state.pageSize) case .loadMore: guard state.effectiveUID > 0, state.hasMore, !state.isLoadingMore else { return .none } state.isLoadingMore = true return fetchMoments(uid: state.effectiveUID, page: state.page + 1, pageSize: state.pageSize) case let .userInfoResponse(result): state.isLoadingUserInfo = false state.isRefreshing = false switch result { case let .success(userInfo): state.userInfo = userInfo state.userInfoError = nil case let .failure(error): state.userInfoError = error.localizedDescription } return .none case let .momentsResponse(result): state.isLoadingMoments = false state.isLoadingMore = false state.isRefreshing = false switch result { case let .success(resp): let myMoments = resp.data ?? [] // 将 MyMomentInfo 转换为 MomentsInfo,并填充用户信息 let newMoments = myMoments.map { myMoment in var momentsInfo = myMoment.toMomentsInfo() // 填充用户信息 if let userInfo = state.userInfo { // 使用默认的成员初始化器 momentsInfo = MomentsInfo( dynamicId: momentsInfo.dynamicId, uid: momentsInfo.uid, nick: userInfo.nick ?? userInfo.nickname ?? "未知用户", avatar: userInfo.avatar ?? "", type: momentsInfo.type, content: momentsInfo.content, likeCount: momentsInfo.likeCount, isLike: momentsInfo.isLike, commentCount: momentsInfo.commentCount, publishTime: momentsInfo.publishTime, worldId: momentsInfo.worldId, status: momentsInfo.status, playCount: momentsInfo.playCount, dynamicResList: momentsInfo.dynamicResList, gender: userInfo.gender, squareTop: momentsInfo.squareTop, topicTop: momentsInfo.topicTop, newUser: userInfo.newUser, defUser: userInfo.defUser, scene: momentsInfo.scene, userVipInfoVO: nil, // UserVipInfoVO 和 UserVipInfo 类型不匹配,暂时设为 nil headwearPic: userInfo.userHeadwear?.pic, headwearEffect: userInfo.userHeadwear?.effect, headwearType: userInfo.userHeadwear?.type, headwearName: userInfo.userHeadwear?.headwearName, headwearId: userInfo.userHeadwear?.headwearId, experLevelPic: userInfo.userLevelVo?.experUrl, charmLevelPic: userInfo.userLevelVo?.charmUrl, isCustomWord: momentsInfo.isCustomWord, labelList: momentsInfo.labelList ) } return momentsInfo } if state.page == 1 { state.moments = newMoments } else { state.moments += newMoments } state.hasMore = newMoments.count == state.pageSize if state.hasMore { state.page += 1 } state.momentsError = nil state.showErrorView = false // 隐藏错误视图 state.momentsFirstLoadFailed = false debugInfoSync("✅ 我的动态加载成功") debugInfoSync(" 加载数量: \(newMoments.count)") debugInfoSync(" 总数量: \(state.moments.count)") debugInfoSync(" 是否有更多: \(state.hasMore)") case let .failure(error): state.momentsError = error.localizedDescription // 如果是第一页加载失败,显示错误视图 if state.page == 1 { state.showErrorView = true state.momentsFirstLoadFailed = true } debugErrorSync("❌ 我的动态加载失败: \(error.localizedDescription)") } return .none case .settingButtonTapped: // 交由 MainFeature 处理 return .none case .showDetail(let moment): state.selectedMoment = moment state.showDetail = true return .none case .detailDismissed: state.showDetail = false state.selectedMoment = nil return .none } } private func fetchUserInfo(uid: Int) -> Effect { .run { send in debugInfoSync("👤 开始获取用户信息") debugInfoSync(" UID: \(uid)") if let userInfo = await UserInfoManager.fetchUserInfoFromServer(uid: String(uid), apiService: apiService) { debugInfoSync("✅ 用户信息获取成功") debugInfoSync(" 昵称: \(userInfo.nick ?? userInfo.nickname ?? "未知")") debugInfoSync(" 头像: \(userInfo.avatar ?? "无")") await send(.userInfoResponse(.success(userInfo))) } else { debugErrorSync("❌ 用户信息获取失败") await send(.userInfoResponse(.failure(.noData))) } } } private func fetchMoments(uid: Int, page: Int, pageSize: Int) -> Effect { .run { send in debugInfoSync("🔄 开始获取我的动态") debugInfoSync(" UID: \(uid)") debugInfoSync(" 页码: \(page)") debugInfoSync(" 页大小: \(pageSize)") do { let req = GetMyDynamicRequest(fromUid: uid, uid: uid, page: page, pageSize: pageSize) debugInfoSync("📡 发送请求: \(req.endpoint)") debugInfoSync(" 参数: fromUid=\(uid), uid=\(uid), page=\(page), pageSize=\(pageSize)") let resp = try await apiService.request(req) debugInfoSync("✅ API 请求成功") debugInfoSync(" 响应码: \(resp.code)") debugInfoSync(" 消息: \(resp.message)") debugInfoSync(" 数据数量: \(resp.data?.count ?? 0)") await send(.momentsResponse(.success(resp))) } catch { debugErrorSync("❌ API 请求失败: \(error.localizedDescription)") if let apiError = error as? APIError { debugErrorSync(" API错误类型: \(apiError)") } await send(.momentsResponse(.failure(error as? APIError ?? .unknown(error.localizedDescription)))) } } } }