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:
108
suixinkan/UI/Statistics/StatisticsDailyCell.swift
Normal file
108
suixinkan/UI/Statistics/StatisticsDailyCell.swift
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user