Files

246 lines
10 KiB
Swift

//
// OfflineCollectionHomeView.swift
// suixinkan
//
import SnapKit
import UIKit
/// 收款首页中的线下收款入口、今日汇总和历史逾期提醒区域。
final class OfflineCollectionHomeView: UIView {
var onRegister: (() -> Void)?
var onOpenToday: (() -> Void)?
var onOpenOverdue: (() -> Void)?
private let contentStack = UIStackView()
private let sectionTitleLabel = UILabel()
private let overdueControl = UIControl()
private let overdueTitleLabel = UILabel()
private let overdueDetailLabel = UILabel()
private let overdueActionLabel = UILabel()
private let registerControl = UIControl()
private let registerIconView = UIImageView()
private let registerTitleLabel = UILabel()
private let registerSubtitleLabel = UILabel()
private let registerActionLabel = UILabel()
private let summaryControl = UIControl()
private let summaryTitleLabel = UILabel()
private let summaryAmountLabel = UILabel()
private let summaryCountLabel = UILabel()
private let summaryRegisteredLabel = UILabel()
private let summaryStatusLabel = UILabel()
private let summaryActionLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
setupConstraints()
bindActions()
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
/// 根据今日与历史逾期汇总刷新页面内容。
func apply(
today: OfflineDailySummary,
overdueDayCount: Int,
overdueRecordCount: Int,
overdueAmountFen: Int
) {
let hasOverdue = overdueDayCount > 0 && overdueAmountFen > 0
overdueControl.isHidden = !hasOverdue
overdueDetailLabel.text = "\(overdueDayCount) 个营业日,共 \(overdueRecordCount) 笔,待补缴 \(OfflineCollectionMoney.display(overdueAmountFen))"
summaryAmountLabel.text = OfflineCollectionMoney.display(today.pendingAmountFen)
summaryCountLabel.text = "\(today.pendingCount) 笔线下收款"
summaryRegisteredLabel.text = "今日已登记 \(OfflineCollectionMoney.display(today.totalAmountFen))"
let isSettled = today.totalCount > 0 && today.pendingAmountFen == 0
summaryStatusLabel.text = isSettled ? "今日已结清" : ""
summaryStatusLabel.isHidden = !isSettled
summaryActionLabel.text = today.pendingAmountFen > 0 ? "去补缴" : "查看明细"
summaryActionLabel.backgroundColor = today.pendingAmountFen > 0
? AppColor.primary
: UIColor(hex: 0xEEF2F7)
summaryActionLabel.textColor = today.pendingAmountFen > 0
? .white
: AppColor.textSecondary
}
private func setupUI() {
backgroundColor = .clear
contentStack.axis = .vertical
contentStack.spacing = AppSpacing.md
sectionTitleLabel.text = "线下收款"
sectionTitleLabel.font = .systemFont(ofSize: 16, weight: .semibold)
sectionTitleLabel.textColor = AppColor.textPrimary
configureCard(overdueControl, backgroundColor: UIColor(hex: 0xFFF1F0))
overdueControl.layer.borderColor = UIColor(hex: 0xFFCCC7).cgColor
overdueControl.layer.borderWidth = 1
overdueTitleLabel.text = "存在逾期未补缴"
overdueTitleLabel.font = .systemFont(ofSize: 15, weight: .semibold)
overdueTitleLabel.textColor = AppColor.danger
overdueDetailLabel.font = .systemFont(ofSize: 13)
overdueDetailLabel.textColor = UIColor(hex: 0x8C2F27)
overdueDetailLabel.numberOfLines = 0
configureActionLabel(overdueActionLabel, title: "立即处理", background: AppColor.danger, foreground: .white)
configureCard(registerControl, backgroundColor: .white)
registerIconView.image = UIImage(systemName: "plus.circle.fill")
registerIconView.tintColor = AppColor.primary
registerIconView.contentMode = .scaleAspectFit
registerTitleLabel.text = "线下收款登记"
registerTitleLabel.font = .systemFont(ofSize: 16, weight: .semibold)
registerTitleLabel.textColor = AppColor.textPrimary
registerSubtitleLabel.text = "线下收款后,请及时登记并在当日完成补缴"
registerSubtitleLabel.font = .systemFont(ofSize: 13)
registerSubtitleLabel.textColor = AppColor.textSecondary
registerSubtitleLabel.numberOfLines = 0
configureActionLabel(registerActionLabel, title: "去登记", background: UIColor(hex: 0xEEF5FF), foreground: AppColor.primary)
configureCard(summaryControl, backgroundColor: .white)
summaryTitleLabel.text = "今日待补缴"
summaryTitleLabel.font = .systemFont(ofSize: 15, weight: .semibold)
summaryTitleLabel.textColor = AppColor.textPrimary
summaryAmountLabel.font = .systemFont(ofSize: 30, weight: .bold)
summaryAmountLabel.textColor = AppColor.textPrimary
summaryCountLabel.font = .systemFont(ofSize: 13)
summaryCountLabel.textColor = UIColor(hex: 0xD97706)
summaryRegisteredLabel.font = .systemFont(ofSize: 13)
summaryRegisteredLabel.textColor = AppColor.textSecondary
summaryStatusLabel.font = .systemFont(ofSize: 13, weight: .semibold)
summaryStatusLabel.textColor = AppColor.success
configureActionLabel(summaryActionLabel, title: "查看明细", background: UIColor(hex: 0xEEF2F7), foreground: AppColor.textSecondary)
addSubview(contentStack)
[sectionTitleLabel, overdueControl, registerControl, summaryControl].forEach(contentStack.addArrangedSubview)
let overdueTextStack = UIStackView(arrangedSubviews: [overdueTitleLabel, overdueDetailLabel])
overdueTextStack.axis = .vertical
overdueTextStack.spacing = 5
overdueControl.addSubview(overdueTextStack)
overdueControl.addSubview(overdueActionLabel)
let registerTextStack = UIStackView(arrangedSubviews: [registerTitleLabel, registerSubtitleLabel])
registerTextStack.axis = .vertical
registerTextStack.spacing = 5
registerControl.addSubview(registerIconView)
registerControl.addSubview(registerTextStack)
registerControl.addSubview(registerActionLabel)
let summaryTextStack = UIStackView(arrangedSubviews: [
summaryTitleLabel,
summaryAmountLabel,
summaryCountLabel,
summaryRegisteredLabel,
summaryStatusLabel,
])
summaryTextStack.axis = .vertical
summaryTextStack.spacing = 6
summaryControl.addSubview(summaryTextStack)
summaryControl.addSubview(summaryActionLabel)
}
private func setupConstraints() {
contentStack.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
sectionTitleLabel.snp.makeConstraints { make in
make.height.equalTo(24)
}
overdueControl.snp.makeConstraints { make in
make.height.greaterThanOrEqualTo(84)
}
overdueControl.subviews.first?.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview().inset(AppSpacing.md)
make.trailing.lessThanOrEqualTo(overdueActionLabel.snp.leading).offset(-AppSpacing.sm)
}
overdueActionLabel.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(AppSpacing.md)
make.centerY.equalToSuperview()
make.height.equalTo(32)
}
registerControl.snp.makeConstraints { make in
make.height.greaterThanOrEqualTo(96)
}
registerIconView.snp.makeConstraints { make in
make.leading.equalToSuperview().inset(AppSpacing.md)
make.centerY.equalToSuperview()
make.width.height.equalTo(34)
}
registerTitleLabel.superview?.snp.makeConstraints { make in
make.leading.equalTo(registerIconView.snp.trailing).offset(AppSpacing.sm)
make.centerY.equalToSuperview()
make.trailing.lessThanOrEqualTo(registerActionLabel.snp.leading).offset(-AppSpacing.sm)
}
registerActionLabel.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(AppSpacing.md)
make.centerY.equalToSuperview()
make.height.equalTo(32)
}
summaryControl.snp.makeConstraints { make in
make.height.greaterThanOrEqualTo(180)
}
summaryTitleLabel.superview?.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview().inset(AppSpacing.md)
make.trailing.lessThanOrEqualTo(summaryActionLabel.snp.leading).offset(-AppSpacing.sm)
}
summaryActionLabel.snp.makeConstraints { make in
make.trailing.equalToSuperview().inset(AppSpacing.md)
make.bottom.equalToSuperview().inset(AppSpacing.md)
make.height.equalTo(34)
}
}
private func bindActions() {
overdueControl.addTarget(self, action: #selector(overdueTapped), for: .touchUpInside)
registerControl.addTarget(self, action: #selector(registerTapped), for: .touchUpInside)
summaryControl.addTarget(self, action: #selector(summaryTapped), for: .touchUpInside)
}
private func configureCard(_ control: UIControl, backgroundColor: UIColor) {
control.backgroundColor = backgroundColor
control.layer.cornerRadius = AppRadius.lg
control.clipsToBounds = true
}
private func configureActionLabel(
_ label: UILabel,
title: String,
background: UIColor,
foreground: UIColor
) {
label.text = " \(title) "
label.font = .systemFont(ofSize: 13, weight: .semibold)
label.textAlignment = .center
label.textColor = foreground
label.backgroundColor = background
label.layer.cornerRadius = 16
label.clipsToBounds = true
label.setContentCompressionResistancePriority(.required, for: .horizontal)
}
@objc private func overdueTapped() {
onOpenOverdue?()
}
@objc private func registerTapped() {
onRegister?()
}
@objc private func summaryTapped() {
onOpenToday?()
}
}