实现数据 Tab 并修复汇总数据解析

This commit is contained in:
2026-07-06 16:32:14 +08:00
parent be18ecd841
commit 9464e32a0a
32 changed files with 1769 additions and 10 deletions

View File

@ -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)
}
}