新增线下收款记录和 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
@@ -22,8 +22,14 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
private let freeCountField = UITextField()
private let singlePriceField = UITextField()
private let packagePriceField = UITextField()
private let autoRetouchSectionView = UIView()
private let autoRetouchTitleLabel = UILabel()
private let autoRetouchDetailLabel = UILabel()
private let noRetouchOption = TravelAlbumModeOptionView()
private let aiRetouchOption = TravelAlbumModeOptionView()
private let cancelButton = UIButton(type: .system)
private let confirmButton = UIButton(type: .system)
private var autoRetouchConfiguration: TravelAlbumAutoRetouchConfiguration = .disabled
init(viewModel: TravelAlbumEntryViewModel, api: any TravelAlbumServing) {
self.viewModel = viewModel
@@ -31,8 +37,16 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
super.init(nibName: nil, bundle: nil)
modalPresentationStyle = .pageSheet
if let sheetPresentationController {
sheetPresentationController.detents = [.medium(), .large()]
let formDetent = UISheetPresentationController.Detent.Identifier("createTravelAlbumForm")
sheetPresentationController.detents = [
.custom(identifier: formDetent) { context in
min(590, context.maximumDetentValue)
},
.large(),
]
sheetPresentationController.selectedDetentIdentifier = formDetent
sheetPresentationController.prefersGrabberVisible = false
sheetPresentationController.preferredCornerRadius = AppRadius.xl
}
}
@@ -62,6 +76,7 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
configureTextField(freeCountField, placeholder: "请输入免费张数", keyboardType: .numberPad)
configureTextField(singlePriceField, placeholder: "请输入单张照片价格", keyboardType: .decimalPad)
configureTextField(packagePriceField, placeholder: "请输入打包价格", keyboardType: .decimalPad)
configureAutoRetouchSection()
configureActionButton(cancelButton, title: "取消", backgroundColor: UIColor(hex: 0xF4F4F4), titleColor: AppColor.textSecondary)
configureActionButton(confirmButton, title: "确定", backgroundColor: AppColor.primary, titleColor: .white)
@@ -112,6 +127,8 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
[freeCountField, singlePriceField, packagePriceField].forEach {
$0.addTarget(self, action: #selector(textFieldEditingChanged(_:)), for: .editingChanged)
}
noRetouchOption.addTarget(self, action: #selector(noRetouchTapped), for: .touchUpInside)
aiRetouchOption.addTarget(self, action: #selector(aiRetouchTapped), for: .touchUpInside)
}
override func viewDidDisappear(_ animated: Bool) {
@@ -148,6 +165,45 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
fieldsStack.addArrangedSubview(makeFieldGroup(title: "免费张数", required: false, field: freeCountField))
fieldsStack.addArrangedSubview(makeFieldGroup(title: "单张照片价格(元)", required: true, field: singlePriceField))
fieldsStack.addArrangedSubview(makeFieldGroup(title: "打包价格(元)", required: false, field: packagePriceField))
fieldsStack.addArrangedSubview(autoRetouchSectionView)
}
private func configureAutoRetouchSection() {
autoRetouchSectionView.backgroundColor = .white
autoRetouchSectionView.layer.cornerRadius = AppRadius.sm
autoRetouchSectionView.layer.borderWidth = 1
autoRetouchSectionView.layer.borderColor = AppColor.border.cgColor
autoRetouchSectionView.clipsToBounds = true
autoRetouchTitleLabel.text = "修图方式"
autoRetouchTitleLabel.font = .app(.bodyMedium)
autoRetouchTitleLabel.textColor = AppColor.textPrimary
autoRetouchDetailLabel.text = "选择 AI 修图后,需要再选一个效果模板"
autoRetouchDetailLabel.font = .app(.caption)
autoRetouchDetailLabel.textColor = AppColor.textSecondary
let optionsStack = UIStackView(arrangedSubviews: [noRetouchOption, aiRetouchOption])
optionsStack.axis = .horizontal
optionsStack.spacing = AppSpacing.xs
optionsStack.distribution = .fillEqually
autoRetouchSectionView.addSubview(autoRetouchTitleLabel)
autoRetouchSectionView.addSubview(autoRetouchDetailLabel)
autoRetouchSectionView.addSubview(optionsStack)
autoRetouchTitleLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(AppSpacing.sm)
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
autoRetouchDetailLabel.snp.makeConstraints { make in
make.top.equalTo(autoRetouchTitleLabel.snp.bottom).offset(AppSpacing.xxs)
make.leading.trailing.equalTo(autoRetouchTitleLabel)
}
optionsStack.snp.makeConstraints { make in
make.top.equalTo(autoRetouchDetailLabel.snp.bottom).offset(AppSpacing.sm)
make.leading.trailing.bottom.equalToSuperview().inset(AppSpacing.sm)
make.height.equalTo(72)
}
updateAutoRetouchSection()
}
private func makeFieldGroup(title: String, required: Bool, field: UITextField) -> UIView {
@@ -188,6 +244,7 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
freeCount: freeCountField.text ?? "",
singlePrice: singlePriceField.text ?? "",
packagePrice: packagePriceField.text ?? "",
autoRetouchConfiguration: autoRetouchConfiguration,
order: nil,
api: api
)
@@ -208,6 +265,43 @@ final class CreateTravelAlbumSheetViewController: BaseViewController {
}
}
@objc private func noRetouchTapped() {
autoRetouchConfiguration = .disabled
updateAutoRetouchSection()
}
@objc private func aiRetouchTapped() {
presentTemplatePicker()
}
private func presentTemplatePicker() {
guard presentedViewController == nil else { return }
let controller = TravelAlbumAutoRetouchSettingSheetViewController(
configuration: autoRetouchConfiguration,
startsWithModeSelection: false
)
controller.onConfirm = { [weak self] configuration in
guard let self else { return }
self.autoRetouchConfiguration = configuration
self.updateAutoRetouchSection()
}
present(controller, animated: true)
}
private func updateAutoRetouchSection() {
let isEnabled = autoRetouchConfiguration.isEnabled
noRetouchOption.apply(
title: TravelAlbumRetouchMode.disabled.title,
desc: "保留原图",
selected: !isEnabled
)
aiRetouchOption.apply(
title: TravelAlbumRetouchMode.aiRetouch.title,
desc: autoRetouchConfiguration.template?.title ?? "点击选模板",
selected: isEnabled
)
}
private func sanitizeMoneyInput(_ value: String) -> String {
var result = ""
var hasDot = false