完善景区排队设置页与全局按钮配置迁移。

重构排队设置与变更日志交互,补充 Overlay 与资源,并将多页面主操作按钮统一到 UIButton Configuration,同步更新相关单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-14 16:21:53 +08:00
parent efb3925257
commit 6336feff27
49 changed files with 1996 additions and 590 deletions

View File

@ -16,6 +16,8 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
private let scrollView = UIScrollView()
private let contentStack = UIStackView()
private let descriptionView = UITextView()
private let descriptionPlaceholderLabel = UILabel()
private let descriptionCountLabel = UILabel()
private let contactField = UITextField()
private let submitButton = UIButton(type: .system)
private var pickerTarget: WildReportPickerTarget = .image
@ -25,12 +27,12 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
init(
homeViewModel: WildPhotographerReportHomeViewModel,
locationProvider: any LocationProviding = LocationProvider.shared,
api: any WildPhotographerReportServing = NetworkServices.shared.wildPhotographerReportAPI,
uploader: any WildReportAttachmentUploading = NetworkServices.shared.ossUploadService
api: (any WildPhotographerReportServing)? = nil,
uploader: (any WildReportAttachmentUploading)? = nil
) {
self.homeViewModel = homeViewModel
self.api = api
self.uploader = uploader
self.api = api ?? NetworkServices.shared.wildPhotographerReportAPI
self.uploader = uploader ?? NetworkServices.shared.ossUploadService
self.viewModel = WildPhotographerReportSubmitViewModel(
homeViewModel: homeViewModel,
locationProvider: locationProvider
@ -64,6 +66,14 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
descriptionView.textContainerInset = UIEdgeInsets(top: 10, left: 8, bottom: 34, right: 8)
descriptionView.delegate = self
descriptionPlaceholderLabel.text = "请描述摄影师的位置、特征、行为..."
descriptionPlaceholderLabel.font = .systemFont(ofSize: 15)
descriptionPlaceholderLabel.textColor = UIColor(hex: 0x9CA3AF)
descriptionCountLabel.font = .systemFont(ofSize: 14)
descriptionCountLabel.textColor = UIColor(hex: 0x6B7280)
descriptionCountLabel.textAlignment = .right
contactField.placeholder = "请输入摄影师微信号或手机号(选填)"
contactField.font = .app(.body)
contactField.textColor = AppColor.textPrimary
@ -271,34 +281,28 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
private func makeDescriptionCard() -> UIView {
let card = sectionCard(index: 3, title: "举报说明")
descriptionView.text = viewModel.description
updateDescriptionInputState()
let inputContainer = UIView()
inputContainer.backgroundColor = UIColor(hex: 0xFBFCFE)
inputContainer.layer.cornerRadius = 12
inputContainer.layer.borderWidth = 1
inputContainer.layer.borderColor = UIColor(hex: 0xCDD5E1).cgColor
let placeholder = UILabel()
placeholder.text = "请描述摄影师的位置、特征、行为..."
placeholder.font = .systemFont(ofSize: 15)
placeholder.textColor = UIColor(hex: 0x9CA3AF)
placeholder.isHidden = !viewModel.description.isEmpty
let count = WildReportUI.label("\(viewModel.description.count)/500", font: .systemFont(ofSize: 14), color: UIColor(hex: 0x6B7280))
count.textAlignment = .right
inputContainer.addSubview(descriptionView)
inputContainer.addSubview(placeholder)
inputContainer.addSubview(count)
inputContainer.addSubview(descriptionPlaceholderLabel)
inputContainer.addSubview(descriptionCountLabel)
descriptionView.snp.makeConstraints { make in
make.edges.equalToSuperview()
make.height.equalTo(132)
}
placeholder.snp.makeConstraints { make in
make.top.equalToSuperview().offset(18)
make.leading.equalToSuperview().offset(14)
let textOriginX = descriptionView.textContainerInset.left
+ descriptionView.textContainer.lineFragmentPadding
descriptionPlaceholderLabel.snp.makeConstraints { make in
make.top.equalToSuperview().offset(descriptionView.textContainerInset.top)
make.leading.equalToSuperview().offset(textOriginX)
make.trailing.lessThanOrEqualToSuperview().inset(14)
}
count.snp.makeConstraints { make in
descriptionCountLabel.snp.makeConstraints { make in
make.trailing.bottom.equalToSuperview().inset(12)
}
card.stack.addArrangedSubview(inputContainer)
@ -376,6 +380,11 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
return card
}
private func updateDescriptionInputState() {
descriptionPlaceholderLabel.isHidden = !viewModel.description.isEmpty
descriptionCountLabel.text = "\(viewModel.description.count)/500"
}
private func makePaymentCard() -> UIView {
let card = sectionCard(index: 6, title: "线下微信、支付宝截图", optional: true)
card.stack.addArrangedSubview(makeEvidenceUploadBlock(
@ -561,7 +570,12 @@ final class WildPhotographerReportSubmitViewController: BaseViewController {
)
}
}
@objc private func contactChanged() { viewModel.updateContact(contactField.text ?? "") }
@objc private func contactChanged() {
viewModel.updateContact(contactField.text ?? "")
guard contactField.markedTextRange == nil,
contactField.text != viewModel.contact else { return }
contactField.text = viewModel.contact
}
@objc private func dismissKeyboard() { view.endEditing(true) }
@MainActor
@ -654,6 +668,10 @@ extension WildPhotographerReportSubmitViewController: UITextViewDelegate {
func textViewDidChange(_ textView: UITextView) {
viewModel.updateDescription(textView.text)
if textView.markedTextRange == nil, textView.text != viewModel.description {
textView.text = viewModel.description
}
updateDescriptionInputState()
}
func textViewDidEndEditing(_ textView: UITextView) {