176 lines
6.8 KiB
Swift
176 lines
6.8 KiB
Swift
//
|
||
// 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<ScheduleRecordSection> = {
|
||
RxTableViewSectionedReloadDataSource<ScheduleRecordSection> { _, tableView, indexPath, model in
|
||
let cell: ScheduleRecordCell = tableView.dequeueReusableCell(for: indexPath)
|
||
cell.configure(model)
|
||
return cell
|
||
}
|
||
}()
|
||
|
||
private lazy var memberDataSource: RxCollectionViewSectionedReloadDataSource<GroupMemberListSectionModel> = {
|
||
RxCollectionViewSectionedReloadDataSource<GroupMemberListSectionModel> { [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<DrivingEventSection> = {
|
||
RxCollectionViewSectionedReloadDataSource<DrivingEventSection> { _, 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")
|
||
}
|
||
}
|