实现数据 Tab 并修复汇总数据解析
This commit is contained in:
@ -6,23 +6,141 @@
|
||||
import SnapKit
|
||||
import UIKit
|
||||
|
||||
/// 数据 Tab 根页面。
|
||||
/// 数据 Tab 根页面,展示汇总指标与日明细列表。
|
||||
final class StatisticsViewController: BaseViewController {
|
||||
|
||||
private let titleLabel = UILabel()
|
||||
private let viewModel = StatisticsViewModel()
|
||||
private let statisticsAPI = NetworkServices.shared.statisticsAPI
|
||||
|
||||
private let summaryCardView = StatisticsSummaryCardView()
|
||||
private let dailyListView = StatisticsDailyListView()
|
||||
|
||||
private var hasInitialized = false
|
||||
private var isLoadingMore = false
|
||||
|
||||
override func setupNavigationBar() {
|
||||
title = "数据"
|
||||
}
|
||||
|
||||
override func setupUI() {
|
||||
title = "数据"
|
||||
titleLabel.text = "数据"
|
||||
titleLabel.font = .systemFont(ofSize: 24, weight: .medium)
|
||||
titleLabel.textAlignment = .center
|
||||
titleLabel.textColor = AppColor.text333
|
||||
view.addSubview(titleLabel)
|
||||
view.backgroundColor = UIColor(hex: 0xF7FAFF)
|
||||
|
||||
view.addSubview(summaryCardView)
|
||||
view.addSubview(dailyListView)
|
||||
}
|
||||
|
||||
override func setupConstraints() {
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
summaryCardView.snp.makeConstraints { make in
|
||||
make.top.equalTo(view.safeAreaLayoutGuide).offset(16)
|
||||
make.leading.trailing.equalToSuperview().inset(16)
|
||||
}
|
||||
dailyListView.snp.makeConstraints { make in
|
||||
make.top.equalTo(summaryCardView.snp.bottom).offset(16)
|
||||
make.leading.trailing.equalToSuperview().inset(16)
|
||||
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(16)
|
||||
}
|
||||
}
|
||||
|
||||
override func bindActions() {
|
||||
viewModel.onStateChange = { [weak self] in
|
||||
Task { @MainActor in self?.applyViewModel() }
|
||||
}
|
||||
viewModel.onShowMessage = { [weak self] message in
|
||||
Task { @MainActor in self?.showToast(message) }
|
||||
}
|
||||
|
||||
summaryCardView.onPeriodSelected = { [weak self] period in
|
||||
self?.selectPeriod(period)
|
||||
}
|
||||
dailyListView.onRangeTap = { [weak self] in
|
||||
self?.presentDateRangeSheet()
|
||||
}
|
||||
dailyListView.onRefresh = { [weak self] in
|
||||
self?.refreshList()
|
||||
}
|
||||
dailyListView.onLoadMore = { [weak self] in
|
||||
self?.loadMoreIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
guard !hasInitialized else { return }
|
||||
hasInitialized = true
|
||||
Task { await initializeStatistics() }
|
||||
}
|
||||
|
||||
private func applyViewModel() {
|
||||
summaryCardView.apply(
|
||||
selectedPeriod: viewModel.selectedPeriod,
|
||||
selectedPeriodTime: viewModel.selectedPeriodTime,
|
||||
summary: viewModel.statistics
|
||||
)
|
||||
dailyListView.apply(
|
||||
rangeText: viewModel.statisticsRangeText,
|
||||
items: viewModel.statisticsList,
|
||||
isRefreshing: viewModel.isRefreshing,
|
||||
canLoadMore: viewModel.canLoadMore
|
||||
)
|
||||
|
||||
if viewModel.isLoadingSummary {
|
||||
showLoading()
|
||||
} else {
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
private func initializeStatistics() async {
|
||||
showLoading()
|
||||
await viewModel.initStatistics(api: statisticsAPI)
|
||||
hideLoading()
|
||||
}
|
||||
|
||||
private func selectPeriod(_ period: String) {
|
||||
Task {
|
||||
showLoading()
|
||||
await viewModel.selectPeriod(period, api: statisticsAPI)
|
||||
hideLoading()
|
||||
}
|
||||
}
|
||||
|
||||
private func refreshList() {
|
||||
Task { await viewModel.refreshStatistics(api: statisticsAPI) }
|
||||
}
|
||||
|
||||
private func loadMoreIfNeeded() {
|
||||
guard viewModel.canLoadMore, !isLoadingMore else { return }
|
||||
isLoadingMore = true
|
||||
Task {
|
||||
await viewModel.loadMore(api: statisticsAPI)
|
||||
isLoadingMore = false
|
||||
}
|
||||
}
|
||||
|
||||
private func presentDateRangeSheet() {
|
||||
let controller = StatisticsDateRangeViewController(
|
||||
rangeStart: viewModel.rangeStartDate,
|
||||
rangeEnd: viewModel.rangeEndDate
|
||||
)
|
||||
controller.onShortcutSelected = { [weak self, weak controller] shortcut in
|
||||
guard let self else { return }
|
||||
Task {
|
||||
await self.viewModel.updateRangeByShortcut(shortcut, api: self.statisticsAPI)
|
||||
controller?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
controller.onRangeSelected = { [weak self, weak controller] start, end in
|
||||
guard let self else { return }
|
||||
Task {
|
||||
await self.viewModel.updateRangeByCalendar(start: start, end: end, api: self.statisticsAPI)
|
||||
controller?.dismiss(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
if let sheet = controller.sheetPresentationController {
|
||||
sheet.detents = [.medium(), .large()]
|
||||
sheet.prefersGrabberVisible = true
|
||||
}
|
||||
present(controller, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user