新增线下收款记录和 ai 修图优化

This commit is contained in:
han xin
2026-08-21 15:51:52 +08:00
parent 6fe9928b49
commit 5cf4409bad
40 changed files with 5482 additions and 56 deletions
@@ -12,6 +12,7 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
private let viewModel = PaymentCollectionDetailsViewModel()
private let paymentAPI = NetworkServices.shared.paymentAPI
private let offlineCollectionViewModel = OfflineCollectionHomeViewModel()
private let scrollView = UIScrollView()
private let contentContainerView = UIView()
@@ -48,6 +49,7 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
private let voiceCardView = UIView()
private let voiceTitleLabel = UILabel()
private let voiceSwitch = UISwitch()
private let offlineCollectionView = OfflineCollectionHomeView()
private var amountDialog: PaymentSetAmountDialogView?
private var appliedBrandConfig: PayPageConfig?
@@ -100,9 +102,9 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
override func setupUI() {
let usesBranding = viewModel.usesNalatiBranding
view.backgroundColor = usesBranding ? .clear : AppColor.pageBackground
scrollView.showsVerticalScrollIndicator = !usesBranding
scrollView.isScrollEnabled = !usesBranding
scrollView.alwaysBounceVertical = false
scrollView.showsVerticalScrollIndicator = true
scrollView.isScrollEnabled = true
scrollView.alwaysBounceVertical = true
contentStack.axis = .vertical
contentStack.spacing = usesBranding ? brandSectionSpacing : AppSpacing.md
@@ -201,6 +203,8 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
contentStack.addArrangedSubview(recordRow)
contentStack.addArrangedSubview(voiceCardView)
}
// 线下收款与原有真实收款功能并列,不替换二维码或收款记录入口。
contentStack.addArrangedSubview(offlineCollectionView)
let qrDisplayView = usesBranding ? qrContainerView : qrImageView
let qrContentStack = UIStackView(arrangedSubviews: [
@@ -330,15 +334,14 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
make.edges.equalToSuperview()
make.width.equalTo(scrollView.snp.width)
if viewModel.usesNalatiBranding {
make.height.equalTo(scrollView.snp.height)
make.height.greaterThanOrEqualTo(scrollView.snp.height)
}
}
contentStack.snp.makeConstraints { make in
make.width.equalTo(scrollView.snp.width).offset(-AppSpacing.screenHorizontalInset * 2)
if viewModel.usesNalatiBranding {
make.centerX.centerY.equalToSuperview()
make.top.greaterThanOrEqualToSuperview()
make.bottom.lessThanOrEqualToSuperview()
make.centerX.equalToSuperview()
make.top.bottom.equalToSuperview().inset(AppSpacing.screenHorizontalInset)
} else {
make.edges.equalToSuperview().inset(AppSpacing.screenHorizontalInset)
}
@@ -352,6 +355,18 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
viewModel.onShowMessage = { [weak self] message in
Task { @MainActor in self?.showToast(message) }
}
offlineCollectionViewModel.onStateChange = { [weak self] in
Task { @MainActor in self?.applyOfflineCollection() }
}
offlineCollectionView.onRegister = { [weak self] in
self?.openOfflineCollectionRegistration()
}
offlineCollectionView.onOpenToday = { [weak self] in
self?.openOfflineCollectionDaily(date: self?.offlineCollectionViewModel.todayBusinessDate)
}
offlineCollectionView.onOpenOverdue = { [weak self] in
self?.openOfflineCollectionDaily(date: self?.offlineCollectionViewModel.earliestOverdueBusinessDate)
}
setAmountButton.addTarget(self, action: #selector(setAmountTapped), for: .touchUpInside)
saveQRButton.addTarget(self, action: #selector(saveQRTapped), for: .touchUpInside)
@@ -369,6 +384,7 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
applyBrandNavigationAppearanceIfNeeded()
offlineCollectionViewModel.load()
}
override func viewWillDisappear(_ animated: Bool) {
@@ -432,6 +448,17 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
amountDialog?.dismiss()
amountDialog = nil
}
applyOfflineCollection()
}
@MainActor
private func applyOfflineCollection() {
offlineCollectionView.apply(
today: offlineCollectionViewModel.todaySummary,
overdueDayCount: offlineCollectionViewModel.overdueSummaries.count,
overdueRecordCount: offlineCollectionViewModel.overdueRecordCount,
overdueAmountFen: offlineCollectionViewModel.overdueAmountFen
)
}
private func setActionRowAvailable(_ isAvailable: Bool) {
@@ -668,6 +695,24 @@ final class PaymentCollectionDetailsViewController: BaseViewController {
@objc private func voiceSwitchChanged() {
viewModel.toggleReceiveVoice()
}
private func openOfflineCollectionRegistration() {
let controller = OfflineCollectionRegistrationViewController(
context: offlineCollectionViewModel.context,
service: offlineCollectionViewModel.service
)
navigationController?.pushViewController(controller, animated: true)
}
private func openOfflineCollectionDaily(date: String?) {
guard let date else { return }
let controller = OfflineCollectionDailyViewController(
businessDate: date,
context: offlineCollectionViewModel.context,
service: offlineCollectionViewModel.service
)
navigationController?.pushViewController(controller, animated: true)
}
}
/// 收款详情信息行。