feat: 更新素材管理和举报风险地图
This commit is contained in:
@ -9,11 +9,16 @@ import UIKit
|
||||
/// 举报摄影师首页,提供立即举报、我的举报、风险地图和规则入口。
|
||||
final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
private let viewModel: WildPhotographerReportHomeViewModel
|
||||
private let api: any WildPhotographerReportServing
|
||||
private let scrollView = UIScrollView()
|
||||
private let contentStack = UIStackView()
|
||||
|
||||
init(viewModel: WildPhotographerReportHomeViewModel = WildPhotographerReportHomeViewModel()) {
|
||||
init(
|
||||
viewModel: WildPhotographerReportHomeViewModel = WildPhotographerReportHomeViewModel(),
|
||||
api: any WildPhotographerReportServing = NetworkServices.shared.wildPhotographerReportAPI
|
||||
) {
|
||||
self.viewModel = viewModel
|
||||
self.api = api
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@ -25,20 +30,6 @@ final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
override func setupNavigationBar() {
|
||||
title = "举报摄影师"
|
||||
navigationItem.largeTitleDisplayMode = .never
|
||||
let backButton = UIButton(type: .system)
|
||||
backButton.backgroundColor = .white
|
||||
backButton.tintColor = AppColor.textPrimary
|
||||
backButton.setImage(UIImage(systemName: "chevron.left"), for: .normal)
|
||||
backButton.layer.cornerRadius = 25
|
||||
backButton.layer.shadowColor = UIColor.black.cgColor
|
||||
backButton.layer.shadowOpacity = 0.05
|
||||
backButton.layer.shadowOffset = CGSize(width: 0, height: 6)
|
||||
backButton.layer.shadowRadius = 16
|
||||
backButton.addTarget(self, action: #selector(backTapped), for: .touchUpInside)
|
||||
backButton.snp.makeConstraints { make in
|
||||
make.size.equalTo(50)
|
||||
}
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backButton)
|
||||
}
|
||||
|
||||
override func setupUI() {
|
||||
@ -68,6 +59,16 @@ final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
viewModel.onStateChange = { [weak self] in
|
||||
Task { @MainActor in self?.rebuildContent() }
|
||||
}
|
||||
viewModel.onShowMessage = { [weak self] message in
|
||||
Task { @MainActor in self?.showToast(message) }
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
Task {
|
||||
await viewModel.loadReportCopy(api: api)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@ -81,18 +82,16 @@ final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
case .normal:
|
||||
contentStack.addArrangedSubview(makeHeroCard())
|
||||
contentStack.addArrangedSubview(makeRiskMapEntry())
|
||||
contentStack.addArrangedSubview(makeNoticeCard())
|
||||
if viewModel.shouldShowNoticeModule {
|
||||
contentStack.addArrangedSubview(makeNoticeCard())
|
||||
}
|
||||
contentStack.addArrangedSubview(makeTrustCard())
|
||||
case .loading:
|
||||
contentStack.addArrangedSubview(makeStateCard(icon: "clock", title: "加载中", message: "正在加载举报服务"))
|
||||
case .empty:
|
||||
contentStack.addArrangedSubview(makeStateCard(icon: "exclamationmark.shield", title: viewModel.emptyTitle, message: viewModel.emptyMessage, buttonTitle: "恢复演示数据") { [weak self] in
|
||||
self?.viewModel.restoreDemoData()
|
||||
})
|
||||
contentStack.addArrangedSubview(makeStateCard(icon: "exclamationmark.shield", title: viewModel.emptyTitle, message: viewModel.emptyMessage))
|
||||
case .error:
|
||||
contentStack.addArrangedSubview(makeStateCard(icon: "wifi.exclamationmark", title: "加载失败", message: "举报服务暂时不可用,请稍后重试。", buttonTitle: "重新加载") { [weak self] in
|
||||
self?.viewModel.retryLoadAfterError()
|
||||
})
|
||||
contentStack.addArrangedSubview(makeStateCard(icon: "wifi.exclamationmark", title: "加载失败", message: "举报服务暂时不可用,请稍后重试。"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,31 +171,28 @@ final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
headerIcon.tintColor = AppColor.primary
|
||||
headerIcon.snp.makeConstraints { make in make.size.equalTo(24) }
|
||||
let title = WildReportUI.label("举报须知", font: .systemFont(ofSize: 18, weight: .bold), color: AppColor.textPrimary)
|
||||
let ruleButton = UIButton(type: .system)
|
||||
ruleButton.setTitle("举报规则", for: .normal)
|
||||
ruleButton.setImage(UIImage(systemName: "shield.lefthalf.filled"), for: .normal)
|
||||
ruleButton.titleLabel?.font = .systemFont(ofSize: 15, weight: .bold)
|
||||
ruleButton.tintColor = AppColor.primary
|
||||
ruleButton.setTitleColor(AppColor.primary, for: .normal)
|
||||
ruleButton.backgroundColor = AppColor.primaryLight
|
||||
ruleButton.layer.cornerRadius = 18
|
||||
ruleButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
|
||||
ruleButton.addTarget(self, action: #selector(ruleTapped), for: .touchUpInside)
|
||||
ruleButton.snp.makeConstraints { make in
|
||||
make.height.equalTo(36)
|
||||
}
|
||||
header.addArrangedSubview(headerIcon)
|
||||
header.addArrangedSubview(title)
|
||||
header.addArrangedSubview(UIView())
|
||||
header.addArrangedSubview(ruleButton)
|
||||
if viewModel.shouldShowRuleButton {
|
||||
let ruleButton = UIButton(type: .system)
|
||||
ruleButton.setTitle("举报规则", for: .normal)
|
||||
ruleButton.setImage(UIImage(systemName: "shield.lefthalf.filled"), for: .normal)
|
||||
ruleButton.titleLabel?.font = .systemFont(ofSize: 15, weight: .bold)
|
||||
ruleButton.tintColor = AppColor.primary
|
||||
ruleButton.setTitleColor(AppColor.primary, for: .normal)
|
||||
ruleButton.backgroundColor = AppColor.primaryLight
|
||||
ruleButton.layer.cornerRadius = 18
|
||||
ruleButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
|
||||
ruleButton.addTarget(self, action: #selector(ruleTapped), for: .touchUpInside)
|
||||
ruleButton.snp.makeConstraints { make in
|
||||
make.height.equalTo(36)
|
||||
}
|
||||
header.addArrangedSubview(ruleButton)
|
||||
}
|
||||
|
||||
let items = [
|
||||
"需实名登录",
|
||||
"请尽量上传清晰证据",
|
||||
"恶意举报将被追责"
|
||||
]
|
||||
card.stack.addArrangedSubview(header)
|
||||
items.forEach { item in
|
||||
viewModel.noticeItems.forEach { item in
|
||||
card.stack.addArrangedSubview(makeBullet(item))
|
||||
}
|
||||
return card
|
||||
@ -206,7 +202,7 @@ final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
let badges = UIStackView()
|
||||
badges.axis = .horizontal
|
||||
badges.distribution = .fillEqually
|
||||
badges.spacing = AppSpacing.sm
|
||||
badges.spacing = AppSpacing.xs
|
||||
[
|
||||
("实名", "身份核验 真实可靠", "person.crop.circle.badge.checkmark", AppColor.primary, AppColor.primaryLight),
|
||||
("安全", "数据加密 隐私保护", "checkmark.shield.fill", AppColor.success, AppColor.successBackground),
|
||||
@ -308,19 +304,14 @@ final class WildPhotographerReportHomeViewController: BaseViewController {
|
||||
}
|
||||
|
||||
@objc private func mapTapped() {
|
||||
let record = viewModel.reports.first ?? WildPhotographerReportMockStore.seedReports[0]
|
||||
navigationController?.pushViewController(
|
||||
WildReportRiskMapViewController(record: record, riskPoints: viewModel.riskPoints),
|
||||
WildReportRiskMapViewController(),
|
||||
animated: true
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func ruleTapped() {
|
||||
navigationController?.pushViewController(WildReportRuleViewController(), animated: true)
|
||||
}
|
||||
|
||||
@objc private func backTapped() {
|
||||
navigationController?.popViewController(animated: true)
|
||||
navigationController?.pushViewController(WildReportRuleViewController(ruleGroups: viewModel.ruleGroups), animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,7 +446,19 @@ private final class WildReportTrustItemView: UIView {
|
||||
|
||||
/// 举报规则页面。
|
||||
final class WildReportRuleViewController: BaseViewController {
|
||||
private let scrollView = UIScrollView()
|
||||
private let stack = UIStackView()
|
||||
private let ruleGroups: [WildReportRuleGroup]
|
||||
|
||||
init(ruleGroups: [WildReportRuleGroup]) {
|
||||
self.ruleGroups = ruleGroups
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func setupNavigationBar() {
|
||||
title = "举报规则"
|
||||
@ -463,24 +466,32 @@ final class WildReportRuleViewController: BaseViewController {
|
||||
|
||||
override func setupUI() {
|
||||
view.backgroundColor = AppColor.pageBackgroundSoft
|
||||
scrollView.alwaysBounceVertical = true
|
||||
scrollView.showsVerticalScrollIndicator = false
|
||||
stack.axis = .vertical
|
||||
stack.spacing = AppSpacing.sm
|
||||
view.addSubview(stack)
|
||||
addSection(title: "可举报行为", items: ["疑似打野摄影师主动揽客", "未佩戴工牌开展摄影服务", "引导游客线下付款或私下交易"])
|
||||
addSection(title: "材料要求", items: ["尽量提供现场图片、视频、位置和文字说明", "联系方式可选填,用于景区工作人员核实"])
|
||||
addSection(title: "处理说明", items: ["举报提交后景区公安会接收线索", "处理进度可在“我的举报”中查看", "请勿提交虚假或恶意举报"])
|
||||
view.addSubview(scrollView)
|
||||
scrollView.addSubview(stack)
|
||||
ruleGroups.forEach { group in
|
||||
addSection(title: group.title, items: group.items)
|
||||
}
|
||||
}
|
||||
|
||||
override func setupConstraints() {
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.edges.equalTo(view.safeAreaLayoutGuide)
|
||||
}
|
||||
stack.snp.makeConstraints { make in
|
||||
make.top.equalTo(view.safeAreaLayoutGuide).offset(AppSpacing.md)
|
||||
make.leading.trailing.equalToSuperview().inset(AppSpacing.md)
|
||||
make.edges.equalTo(scrollView.contentLayoutGuide).inset(AppSpacing.md)
|
||||
make.width.equalTo(scrollView.frameLayoutGuide).offset(-AppSpacing.md * 2)
|
||||
}
|
||||
}
|
||||
|
||||
private func addSection(title: String, items: [String]) {
|
||||
let card = WildReportCardView(spacing: AppSpacing.sm)
|
||||
card.stack.addArrangedSubview(WildReportUI.label(title, font: .app(.title), color: AppColor.textPrimary))
|
||||
if !title.isEmpty {
|
||||
card.stack.addArrangedSubview(WildReportUI.label(title, font: .app(.title), color: AppColor.textPrimary))
|
||||
}
|
||||
items.forEach { item in
|
||||
card.stack.addArrangedSubview(WildReportUI.label("· \(item)", font: .app(.body), color: AppColor.textSecondary, lines: 0))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user