feat: 优化线下收款展示细节

This commit is contained in:
2026-08-26 10:47:43 +08:00
parent 825a0448cc
commit 4351c26e74
10 changed files with 55 additions and 59 deletions
@@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "payment_method_alipay_generated.png", "filename" : "payment_method_alipay_official.png",
"idiom" : "universal" "idiom" : "universal"
} }
], ],
Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "payment_method_wechat_generated.png", "filename" : "payment_method_wechat_official.png",
"idiom" : "universal" "idiom" : "universal"
} }
], ],
Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

@@ -332,7 +332,14 @@ enum OfflineCollectionMoney {
static func responseFen(_ value: String) -> Int? { parseFen(value) } static func responseFen(_ value: String) -> Int? { parseFen(value) }
static func apiAmount(_ fen: Int) -> String { "\(fen / 100).\(String(format: "%02d", fen % 100))" } static func apiAmount(_ fen: Int) -> String { "\(fen / 100).\(String(format: "%02d", fen % 100))" }
static func display(_ fen: Int) -> String { "¥\(apiAmount(fen))" } static func displayAmount(_ fen: Int) -> String {
let whole = fen / 100
let cents = fen % 100
if cents == 0 { return "\(whole)" }
if cents.isMultiple(of: 10) { return "\(whole).\(cents / 10)" }
return "\(whole).\(String(format: "%02d", cents))"
}
static func display(_ fen: Int) -> String { "¥\(displayAmount(fen))" }
} }
/// 线下收款统一使用的营业日工具。 /// 线下收款统一使用的营业日工具。
@@ -30,7 +30,6 @@ final class OfflineCollectionDailyViewController: BaseViewController {
private let countValue = UILabel() private let countValue = UILabel()
private let settledValue = UILabel() private let settledValue = UILabel()
private let pendingValue = UILabel() private let pendingValue = UILabel()
private let pendingStatusLabel = UILabel()
private let statusButton = UIButton(type: .system) private let statusButton = UIButton(type: .system)
private let bottomContainer = UIView() private let bottomContainer = UIView()
private let settlementButton = OfflineCollectionGradientButton( private let settlementButton = OfflineCollectionGradientButton(
@@ -99,7 +98,7 @@ final class OfflineCollectionDailyViewController: BaseViewController {
tableView.backgroundColor = .clear tableView.backgroundColor = .clear
tableView.separatorStyle = .none tableView.separatorStyle = .none
tableView.rowHeight = UITableView.automaticDimension tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 82 tableView.estimatedRowHeight = 96
tableView.showsVerticalScrollIndicator = false tableView.showsVerticalScrollIndicator = false
tableView.contentInset.bottom = 12 tableView.contentInset.bottom = 12
tableView.register(OfflineCollectionRecordCell.self, forCellReuseIdentifier: OfflineCollectionRecordCell.reuseIdentifier) tableView.register(OfflineCollectionRecordCell.self, forCellReuseIdentifier: OfflineCollectionRecordCell.reuseIdentifier)
@@ -151,13 +150,13 @@ final class OfflineCollectionDailyViewController: BaseViewController {
summaryCard.layer.shadowRadius = 10 summaryCard.layer.shadowRadius = 10
summaryCard.layer.shadowOffset = CGSize(width: 0, height: 4) summaryCard.layer.shadowOffset = CGSize(width: 0, height: 4)
summaryDateLabel.font = .systemFont(ofSize: 18, weight: .bold) summaryDateLabel.font = .systemFont(ofSize: 17, weight: .bold)
summaryDateLabel.textColor = UIColor(hex: 0x081739) summaryDateLabel.textColor = UIColor(hex: 0x081739)
let topLeft = metric(title: "线下收款总额", value: totalValue) let topLeft = metric(title: "线下收款总额", value: totalValue)
let topRight = metric(title: "登记笔数", value: countValue) let topRight = metric(title: "登记笔数", value: countValue)
let bottomLeft = metric(title: "已补缴", value: settledValue) let bottomLeft = metric(title: "已补缴", value: settledValue)
let bottomRight = metric(title: "待补缴", value: pendingValue, badge: pendingStatusLabel) let bottomRight = metric(title: "待补缴", value: pendingValue)
let grid = UIView() let grid = UIView()
[topLeft, topRight, bottomLeft, bottomRight].forEach(grid.addSubview) [topLeft, topRight, bottomLeft, bottomRight].forEach(grid.addSubview)
topLeft.snp.makeConstraints { make in topLeft.snp.makeConstraints { make in
@@ -196,25 +195,26 @@ final class OfflineCollectionDailyViewController: BaseViewController {
summaryCard.addSubview(summaryDateLabel) summaryCard.addSubview(summaryDateLabel)
summaryCard.addSubview(grid) summaryCard.addSubview(grid)
summaryDateLabel.snp.makeConstraints { make in summaryDateLabel.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(16) make.top.equalToSuperview().offset(14)
make.height.equalTo(24) make.leading.trailing.equalToSuperview().inset(16)
make.height.equalTo(22)
} }
grid.snp.makeConstraints { make in grid.snp.makeConstraints { make in
make.top.equalTo(summaryDateLabel.snp.bottom).offset(8) make.top.equalTo(summaryDateLabel.snp.bottom).offset(6)
make.leading.trailing.equalToSuperview().inset(10) make.leading.trailing.equalToSuperview().inset(10)
make.bottom.equalToSuperview().inset(10) make.bottom.equalToSuperview().inset(8)
} }
summaryCard.snp.makeConstraints { make in make.height.equalTo(238) } summaryCard.snp.makeConstraints { make in make.height.equalTo(196) }
} }
private func metric(title: String, value: UILabel, badge: UILabel? = nil) -> UIView { private func metric(title: String, value: UILabel) -> UIView {
let titleLabel = UILabel() let titleLabel = UILabel()
titleLabel.text = title titleLabel.text = title
titleLabel.font = .systemFont(ofSize: 13) titleLabel.font = .systemFont(ofSize: 12)
titleLabel.textColor = UIColor(hex: 0x7B8494) titleLabel.textColor = UIColor(hex: 0x7B8494)
titleLabel.textAlignment = .center titleLabel.textAlignment = .center
value.font = .systemFont(ofSize: 22, weight: .bold) value.font = .systemFont(ofSize: 20, weight: .bold)
value.textColor = UIColor(hex: 0x081739) value.textColor = UIColor(hex: 0x081739)
value.textAlignment = .center value.textAlignment = .center
value.adjustsFontSizeToFitWidth = true value.adjustsFontSizeToFitWidth = true
@@ -223,23 +223,7 @@ final class OfflineCollectionDailyViewController: BaseViewController {
let stack = UIStackView(arrangedSubviews: [titleLabel, value]) let stack = UIStackView(arrangedSubviews: [titleLabel, value])
stack.axis = .vertical stack.axis = .vertical
stack.alignment = .fill stack.alignment = .fill
stack.spacing = 8 stack.spacing = 6
if let badge {
badge.text = "未结清"
badge.font = .systemFont(ofSize: 12, weight: .medium)
badge.textColor = UIColor(hex: 0xFF7600)
badge.textAlignment = .center
badge.backgroundColor = UIColor(hex: 0xFFF0E2)
badge.layer.cornerRadius = 7
badge.clipsToBounds = true
badge.snp.makeConstraints { make in make.width.equalTo(72); make.height.equalTo(26) }
let badgeContainer = UIView()
badgeContainer.addSubview(badge)
badge.snp.makeConstraints { make in make.center.equalToSuperview() }
stack.addArrangedSubview(badgeContainer)
badgeContainer.snp.makeConstraints { make in make.height.equalTo(26) }
stack.spacing = 5
}
let container = UIView() let container = UIView()
container.addSubview(stack) container.addSubview(stack)
@@ -286,7 +270,6 @@ final class OfflineCollectionDailyViewController: BaseViewController {
settledValue.text = OfflineCollectionMoney.display(viewModel.summary.settledAmountFen) settledValue.text = OfflineCollectionMoney.display(viewModel.summary.settledAmountFen)
pendingValue.text = OfflineCollectionMoney.display(viewModel.summary.pendingAmountFen) pendingValue.text = OfflineCollectionMoney.display(viewModel.summary.pendingAmountFen)
pendingValue.textColor = viewModel.summary.pendingCount > 0 ? UIColor(hex: 0xFF7600) : UIColor(hex: 0x081739) pendingValue.textColor = viewModel.summary.pendingCount > 0 ? UIColor(hex: 0xFF7600) : UIColor(hex: 0x081739)
pendingStatusLabel.isHidden = viewModel.summary.pendingCount == 0
if let error = viewModel.errorMessage, !viewModel.isLoading { if let error = viewModel.errorMessage, !viewModel.isLoading {
statusButton.isHidden = false statusButton.isHidden = false
@@ -469,12 +452,11 @@ private final class OfflineCollectionRecordCell: UITableViewCell {
idLabel.font = .systemFont(ofSize: 9.5, weight: .medium) idLabel.font = .systemFont(ofSize: 9.5, weight: .medium)
idLabel.textColor = UIColor(hex: 0x6F7B8F) idLabel.textColor = UIColor(hex: 0x6F7B8F)
idLabel.backgroundColor = UIColor(hex: 0xF0F2F6) idLabel.textAlignment = .left
idLabel.layer.cornerRadius = 5 idLabel.numberOfLines = 0
idLabel.clipsToBounds = true idLabel.lineBreakMode = .byCharWrapping
idLabel.textAlignment = .center idLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
idLabel.adjustsFontSizeToFitWidth = true idLabel.setContentCompressionResistancePriority(.required, for: .vertical)
idLabel.minimumScaleFactor = 0.7
amountLabel.font = .systemFont(ofSize: 16, weight: .bold) amountLabel.font = .systemFont(ofSize: 16, weight: .bold)
amountLabel.textColor = UIColor(hex: 0x081739) amountLabel.textColor = UIColor(hex: 0x081739)
@@ -493,18 +475,17 @@ private final class OfflineCollectionRecordCell: UITableViewCell {
separator.backgroundColor = UIColor(hex: 0xE7EBF1) separator.backgroundColor = UIColor(hex: 0xE7EBF1)
let idContainer = UIView() let idContainer = UIView()
idContainer.backgroundColor = UIColor(hex: 0xF0F2F6)
idContainer.layer.cornerRadius = 5
idContainer.clipsToBounds = true
idContainer.addSubview(idLabel) idContainer.addSubview(idLabel)
idLabel.snp.makeConstraints { make in idLabel.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview() make.edges.equalToSuperview().inset(UIEdgeInsets(top: 3, left: 6, bottom: 3, right: 6))
make.trailing.lessThanOrEqualToSuperview()
} }
idContainer.snp.makeConstraints { make in make.height.equalTo(20) }
let leftStack = UIStackView(arrangedSubviews: [titleLabel, idContainer])
leftStack.axis = .vertical
leftStack.spacing = 4
card.addSubview(iconView) card.addSubview(iconView)
card.addSubview(leftStack) card.addSubview(titleLabel)
card.addSubview(idContainer)
card.addSubview(amountLabel) card.addSubview(amountLabel)
card.addSubview(statusLabel) card.addSubview(statusLabel)
card.addSubview(timeLabel) card.addSubview(timeLabel)
@@ -514,34 +495,39 @@ private final class OfflineCollectionRecordCell: UITableViewCell {
card.snp.makeConstraints { make in card.snp.makeConstraints { make in
make.top.bottom.equalToSuperview() make.top.bottom.equalToSuperview()
make.leading.trailing.equalToSuperview().inset(16) make.leading.trailing.equalToSuperview().inset(16)
make.height.greaterThanOrEqualTo(78) make.height.greaterThanOrEqualTo(90)
} }
iconView.snp.makeConstraints { make in iconView.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(12) make.leading.equalToSuperview().offset(12)
make.centerY.equalToSuperview() make.top.equalToSuperview().offset(10)
make.width.height.equalTo(38) make.width.height.equalTo(38)
} }
leftStack.snp.makeConstraints { make in titleLabel.snp.makeConstraints { make in
make.leading.equalTo(iconView.snp.trailing).offset(10) make.leading.equalTo(iconView.snp.trailing).offset(10)
make.centerY.equalToSuperview() make.centerY.equalTo(iconView)
make.width.equalTo(106)
} }
amountLabel.snp.makeConstraints { make in amountLabel.snp.makeConstraints { make in
make.leading.greaterThanOrEqualTo(leftStack.snp.trailing).offset(4) make.leading.greaterThanOrEqualTo(titleLabel.snp.trailing).offset(4)
make.centerY.equalToSuperview() make.centerY.equalTo(iconView)
make.width.equalTo(68) make.width.equalTo(68)
} }
statusLabel.snp.makeConstraints { make in statusLabel.snp.makeConstraints { make in
make.leading.equalTo(amountLabel.snp.trailing).offset(4) make.leading.equalTo(amountLabel.snp.trailing).offset(4)
make.centerY.equalToSuperview() make.trailing.equalToSuperview().inset(12)
make.centerY.equalTo(iconView)
make.width.equalTo(50) make.width.equalTo(50)
make.height.equalTo(27) make.height.equalTo(27)
} }
timeLabel.snp.makeConstraints { make in timeLabel.snp.makeConstraints { make in
make.leading.equalTo(statusLabel.snp.trailing).offset(2) make.trailing.equalToSuperview().inset(12)
make.trailing.equalToSuperview().inset(10) make.centerY.equalTo(idContainer)
make.centerY.equalToSuperview() make.width.equalTo(40)
make.width.greaterThanOrEqualTo(34) }
idContainer.snp.makeConstraints { make in
make.leading.equalTo(iconView)
make.top.equalTo(iconView.snp.bottom).offset(6)
make.trailing.lessThanOrEqualTo(timeLabel.snp.leading).offset(-8)
make.bottom.equalToSuperview().inset(10)
} }
separator.snp.makeConstraints { make in separator.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(12) make.leading.equalToSuperview().offset(12)
@@ -363,7 +363,7 @@ extension OfflineCollectionRegistrationViewController: UITextFieldDelegate {
} }
} }
/// 登记页的收款方式单选卡,展示生成的品牌图标和右上角选中标记。 /// 登记页的收款方式单选卡,展示官方品牌图标和右上角选中标记。
@MainActor @MainActor
final class OfflinePaymentMethodButton: UIControl { final class OfflinePaymentMethodButton: UIControl {
let method: OfflineCollectionPaymentMethod let method: OfflineCollectionPaymentMethod
@@ -51,6 +51,9 @@ final class OfflineCollectionAPITests: XCTestCase {
XCTAssertEqual(OfflineCollectionMoney.parseFen("0.01"), 1) XCTAssertEqual(OfflineCollectionMoney.parseFen("0.01"), 1)
XCTAssertEqual(OfflineCollectionMoney.parseFen("12.3"), 1_230) XCTAssertEqual(OfflineCollectionMoney.parseFen("12.3"), 1_230)
XCTAssertEqual(OfflineCollectionMoney.apiAmount(9_999_999), "99999.99") XCTAssertEqual(OfflineCollectionMoney.apiAmount(9_999_999), "99999.99")
XCTAssertEqual(OfflineCollectionMoney.displayAmount(200), "2")
XCTAssertEqual(OfflineCollectionMoney.displayAmount(210), "2.1")
XCTAssertEqual(OfflineCollectionMoney.displayAmount(222), "2.22")
XCTAssertNil(OfflineCollectionMoney.parseFen("0")) XCTAssertNil(OfflineCollectionMoney.parseFen("0"))
XCTAssertNil(OfflineCollectionMoney.parseFen("100000.00")) XCTAssertNil(OfflineCollectionMoney.parseFen("100000.00"))
XCTAssertNil(OfflineCollectionMoney.parseFen("1.001")) XCTAssertNil(OfflineCollectionMoney.parseFen("1.001"))