接入举报摄影师正式接口

This commit is contained in:
2026-07-08 16:38:15 +08:00
parent 4a78a0c21a
commit 290a01e699
12 changed files with 2586 additions and 218 deletions

View File

@ -9,12 +9,17 @@ import UIKit
///
final class WildPhotographerReportListViewController: BaseViewController {
private let viewModel: WildPhotographerReportListViewModel
private let api: any WildPhotographerReportServing
private let scrollView = UIScrollView()
private let stack = UIStackView()
private let filterTabBar = WildReportFilterTabBarView()
init(homeViewModel: WildPhotographerReportHomeViewModel) {
init(
homeViewModel: WildPhotographerReportHomeViewModel,
api: any WildPhotographerReportServing = NetworkServices.shared.wildPhotographerReportAPI
) {
self.viewModel = WildPhotographerReportListViewModel(homeViewModel: homeViewModel)
self.api = api
super.init(nibName: nil, bundle: nil)
}
@ -31,11 +36,19 @@ final class WildPhotographerReportListViewController: BaseViewController {
view.backgroundColor = AppColor.pageBackgroundSoft
scrollView.showsVerticalScrollIndicator = false
scrollView.alwaysBounceVertical = true
scrollView.delegate = self
stack.axis = .vertical
stack.spacing = 14
filterTabBar.onSelect = { [weak self] filter in
self?.viewModel.selectFilter(filter)
guard let self else { return }
Task {
await self.viewModel.selectFilter(
filter,
api: self.api,
scenicId: self.currentScenicId
)
}
}
view.addSubview(scrollView)
@ -56,6 +69,13 @@ final class WildPhotographerReportListViewController: BaseViewController {
}
}
override func viewDidLoad() {
super.viewDidLoad()
Task {
await viewModel.loadInitial(api: api, scenicId: currentScenicId)
}
}
override func bindActions() {
viewModel.onStateChange = { [weak self] in
Task { @MainActor in self?.reloadContent(animated: true) }
@ -93,7 +113,7 @@ final class WildPhotographerReportListViewController: BaseViewController {
let reports = viewModel.filteredReports
if reports.isEmpty {
stack.addArrangedSubview(WildReportListEmptyView())
stack.addArrangedSubview(viewModel.isLoading ? WildReportListLoadingView(text: "正在加载举报记录...") : WildReportListEmptyView())
} else {
reports.forEach { record in
let card = WildReportListCardView(record: record)
@ -103,7 +123,7 @@ final class WildPhotographerReportListViewController: BaseViewController {
}
}
let footer = WildReportUI.label(viewModel.footerTip, font: .app(.caption), color: UIColor(hex: 0x9CA3AF), lines: 0)
let footer = WildReportUI.label(viewModel.footerDisplayText, font: .app(.caption), color: UIColor(hex: 0x9CA3AF), lines: 0)
footer.textAlignment = .center
let footerWrap = UIView()
footerWrap.addSubview(footer)
@ -120,6 +140,23 @@ final class WildPhotographerReportListViewController: BaseViewController {
animated: true
)
}
private var currentScenicId: Int? {
let scenicId = AppStore.shared.currentScenicId
return scenicId > 0 ? scenicId : nil
}
}
extension WildPhotographerReportListViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let threshold: CGFloat = 80
let visibleBottom = scrollView.contentOffset.y + scrollView.bounds.height
let triggerY = scrollView.contentSize.height - threshold
guard visibleBottom >= triggerY, scrollView.contentSize.height > scrollView.bounds.height else { return }
Task {
await viewModel.loadMoreIfNeeded(api: api, scenicId: currentScenicId)
}
}
}
/// 使
@ -180,7 +217,7 @@ private final class WildReportFilterTabBarView: UIView {
}
///
private final class WildReportListCardView: UIControl {
private final class WildReportListCardView: UIControl, UIGestureRecognizerDelegate {
var onOpen: (() -> Void)?
var onShare: (() -> Void)?
@ -215,7 +252,11 @@ private final class WildReportListCardView: UIControl {
layer.cornerRadius = 16
layer.borderWidth = 1
layer.borderColor = AppColor.cardOutline.cgColor
addTarget(self, action: #selector(openTapped), for: .touchUpInside)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(openTapped))
tapRecognizer.delegate = self
tapRecognizer.cancelsTouchesInView = false
addGestureRecognizer(tapRecognizer)
let contentStack = UIStackView()
contentStack.axis = .vertical
@ -365,6 +406,17 @@ private final class WildReportListCardView: UIControl {
@objc private func shareTapped() {
onShare?()
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
var currentView: UIView? = touch.view
while let view = currentView {
if view is UIButton {
return false
}
currentView = view.superview
}
return true
}
}
///
@ -429,6 +481,35 @@ private final class WildReportListEmptyView: UIView {
}
}
///
private final class WildReportListLoadingView: UIView {
init(text: String) {
super.init(frame: .zero)
backgroundColor = .white
layer.cornerRadius = 16
let indicator = UIActivityIndicatorView(style: .medium)
indicator.color = AppColor.primary
indicator.startAnimating()
let label = WildReportUI.label(text, font: .systemFont(ofSize: 15, weight: .semibold), color: AppColor.textSecondary)
let stack = UIStackView(arrangedSubviews: [indicator, label])
stack.axis = .vertical
stack.alignment = .center
stack.spacing = 12
addSubview(stack)
stack.snp.makeConstraints { make in
make.top.bottom.equalToSuperview().inset(48)
make.leading.trailing.equalToSuperview().inset(16)
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
///
final class WildPhotographerReportDetailViewController: BaseViewController {
private let viewModel: WildPhotographerReportDetailViewModel
@ -619,7 +700,7 @@ final class WildPhotographerReportDetailViewController: BaseViewController {
private func makeReportInfoCard() -> UIView {
let card = WildReportCardView(spacing: 0, inset: 0)
card.layer.cornerRadius = 18
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "举报类型", value: viewModel.record.reportType.rawValue))
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "举报类型", value: viewModel.record.reportType.label))
card.stack.addArrangedSubview(makeInsetDivider())
card.stack.addArrangedSubview(WildReportDetailInfoRowView(title: "举报说明", value: viewModel.descriptionText, multiline: true))
card.stack.addArrangedSubview(makeInsetDivider())