Implement statistics tab aligned with Android and fix summary decode.

Add role-based analyse APIs, summary/daily UI with date range sheet, and flexible parsing for string refund amounts from the backend.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 16:32:14 +08:00
parent 39a9038a3b
commit 6492f80ef0
32 changed files with 1769 additions and 10 deletions

View File

@ -0,0 +1,108 @@
//
// StatisticsDailyCell.swift
// suixinkan
//
import SnapKit
import UIKit
/// Android `DailyDataBox`
final class StatisticsDailyCell: UITableViewCell {
static let reuseIdentifier = "StatisticsDailyCell"
private let dateLabel = UILabel()
private let orderCountTitle = UILabel()
private let orderCountValue = UILabel()
private let averageTitle = UILabel()
private let averageValue = UILabel()
private let refundTitle = UILabel()
private let refundValue = UILabel()
private let receivedTitle = UILabel()
private let receivedValue = UILabel()
private let divider = UIView()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(with item: StatisticsDailyItem, showsDivider: Bool) {
dateLabel.text = item.date
orderCountValue.text = "\(item.orderCount)"
averageValue.text = "\(item.orderPrice)"
refundValue.text = "\(item.refund)"
receivedValue.text = "\(item.received)"
divider.isHidden = !showsDivider
}
private func setupUI() {
selectionStyle = .none
backgroundColor = .clear
dateLabel.font = .systemFont(ofSize: 14)
dateLabel.textColor = .black
let metricColor = UIColor(hex: 0x4B5563)
[orderCountTitle, averageTitle, refundTitle, receivedTitle].forEach {
$0.font = .systemFont(ofSize: 14)
$0.textColor = metricColor
}
orderCountTitle.text = "订单数"
averageTitle.text = "客单价"
refundTitle.text = "退款"
receivedTitle.text = "实收"
[orderCountValue, averageValue].forEach {
$0.font = .systemFont(ofSize: 14, weight: .semibold)
$0.textColor = .black
}
refundValue.font = .systemFont(ofSize: 14, weight: .semibold)
refundValue.textColor = UIColor(hex: 0xEF4444)
receivedValue.font = .systemFont(ofSize: 14, weight: .semibold)
receivedValue.textColor = UIColor(hex: 0x22C55E)
divider.backgroundColor = UIColor(hex: 0xF4F4F4)
let metricsRow = UIStackView()
metricsRow.axis = .horizontal
metricsRow.distribution = .fillEqually
metricsRow.alignment = .fill
metricsRow.spacing = 8
metricsRow.addArrangedSubview(metricColumn(title: orderCountTitle, value: orderCountValue))
metricsRow.addArrangedSubview(metricColumn(title: averageTitle, value: averageValue))
metricsRow.addArrangedSubview(metricColumn(title: refundTitle, value: refundValue))
metricsRow.addArrangedSubview(metricColumn(title: receivedTitle, value: receivedValue))
contentView.addSubview(dateLabel)
contentView.addSubview(metricsRow)
contentView.addSubview(divider)
dateLabel.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(UIEdgeInsets(top: 12, left: 0, bottom: 0, right: 0))
}
metricsRow.snp.makeConstraints { make in
make.top.equalTo(dateLabel.snp.bottom).offset(12)
make.leading.trailing.equalToSuperview()
make.bottom.equalToSuperview().inset(12)
}
divider.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
make.height.equalTo(1)
}
}
private func metricColumn(title: UILabel, value: UILabel) -> UIStackView {
let stack = UIStackView(arrangedSubviews: [title, value])
stack.axis = .vertical
stack.spacing = 4
stack.alignment = .leading
return stack
}
}