// // GroupMemberListVC.swift // QuickLocation // // Created by 八条 on 2026/6/29. // import UIKit import RxSwift import RxCocoa import RxDataSources import ObjectMapper class GroupMemberListVC: BaseViewController { fileprivate var rootView: GroupMemberListView! override func loadView() { rootView = GroupMemberListView(frame: UIScreen.main.bounds) view = rootView } private var viewModel: GroupMemberListVM override func viewDidLoad() { super.viewDidLoad() bindViewModel() reactiveAction() requestGroupInfo() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) rootView.unlockVipMaskView.isHidden = AppContextManager.shared.vip > 1 } private func reactiveAction() { } private func bindViewModel() { viewModel.output.sectionedItems .bind(to: rootView.collectionView.rx.items(dataSource: memberDataSource)) .disposed(by: disposeBag) viewModel.output.drivingSectionedItems .bind(to: rootView.drivingEventCV.rx.items(dataSource: drivingDataSource)) .disposed(by: disposeBag) viewModel.output.scheduleSectionedItems .bind(to: rootView.tableView.rx.items(dataSource: scheduleDataSource)) .disposed(by: disposeBag) viewModel.output.scheduleSectionedItems .subscribe(onNext: { [weak self] items in self?.rootView.updateTableViewHeight(count: items.first?.items.count ?? 0) }).disposed(by: disposeBag) // 日期选择 → 滚动报告到顶部 + 请求驾驶数据 rootView.selectedDate .skip(1) .subscribe(onNext: { [weak self] date in self?.rootView.scrollReportToTop() self?.requestDrivingEvents(for: date) }).disposed(by: disposeBag) // 成员点击 → 重置日期到当天(selectedDate 发射 → 自动触发 API 请求) rootView.collectionView.rx.modelSelected(GroupMemberModel.self) .subscribe(onNext: { [weak self] model in guard let self = self else { return } self.viewModel.memberId = model.user_id self.rootView.selectedMemberIsSelf = self.viewModel.isCurrentUser(id: model.user_id) self.rootView.selectedDate.accept(Date()) self.rootView.scrollToToday() self.rootView.scrollReportToTop() self.rootView.collectionView.reloadData() }).disposed(by: disposeBag) } /// 根据日期生成起止时间戳并请求驾驶数据 private func requestDrivingEvents(for date: Date) { guard !viewModel.memberId.isEmpty else { return } let calendar = Calendar.current let start = calendar.startOfDay(for: date) let end: Date if calendar.isDateInToday(date) { end = Date() // 当天以当前时间为结束 } else { end = calendar.date(bySettingHour: 23, minute: 59, second: 59, of: date) ?? date } requestDrivingEvents(start_time: "\(Int64(start.timeIntervalSince1970 * 1000))", end_time: "\(Int64(end.timeIntervalSince1970 * 1000))") requestPlayback(date: "\(Int64(start.timeIntervalSince1970 * 1000))") } // MARK: - dataSource private lazy var scheduleDataSource: RxTableViewSectionedReloadDataSource = { RxTableViewSectionedReloadDataSource { _, tableView, indexPath, model in let cell: ScheduleRecordCell = tableView.dequeueReusableCell(for: indexPath) cell.configure(model) return cell } }() private lazy var memberDataSource: RxCollectionViewSectionedReloadDataSource = { RxCollectionViewSectionedReloadDataSource { [weak self] datasource, collectionView, indexPath, model in let cell: GroupMemberListCell = collectionView.dequeueReusableCell(for: indexPath) cell.configure(model: model, isCurrentUser: self?.viewModel.isCurrentUser(id: model.user_id) ?? false, isSelected: model.user_id == self?.viewModel.memberId) return cell } }() private lazy var drivingDataSource: RxCollectionViewSectionedReloadDataSource = { RxCollectionViewSectionedReloadDataSource { _, collectionView, indexPath, item in let cell: DrivingEventCell = collectionView.dequeueReusableCell(for: indexPath) cell.configure(item) return cell } }() // MARK: - API private func requestGroupInfo() { DLToast.showLoading() GroupService.groupInfoByKey(viewModel.groupKey).subscribe { response in DLToast.dismiss() guard let model = response.model else { return } self.viewModel.groupModel = model self.viewModel.loadData(response.list) self.rootView.selectedMemberIsSelf = self.viewModel.isCurrentUser(id: self.viewModel.memberId) // 首次加载后请求今日驾驶数据 if !self.viewModel.memberId.isEmpty { self.requestDrivingEvents(for: Date()) } }.disposed(by: disposeBag) } // 驾驶事件 private func requestDrivingEvents(start_time: String, end_time: String) { DrivingService.drivingEvents(user_id: viewModel.memberId, start_time: start_time, end_time: end_time).subscribe { response in guard let model = response.model else { return } self.rootView.mileageLab.text = String(format: "%.1fkm", model.distance_km) self.rootView.speedLab.text = String(format: "%.0fkm/h", model.max_speed) self.viewModel.updateDrivingStats(model) }.disposed(by: disposeBag) } // 行程记录 private func requestPlayback(date: String) { let start = CFAbsoluteTimeGetCurrent() dl.showLoading(text: "行程记录获取中...") DrivingService.playback(user_id: viewModel.memberId, date: date).subscribe(onNext: { [weak self] response in let elapsed = CFAbsoluteTimeGetCurrent() - start print("[playback] total: \(String(format: "%.1f", elapsed))s, items: \(response.list.count)") self?.dl.dismiss() self?.viewModel.loadScheduleRecords(response.list) }, onError: { _ in self.dl.dismiss() }).disposed(by: disposeBag) } // MARK: - Init init(groupKey: String) { viewModel = GroupMemberListVM(groupKey: groupKey) super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }