Files
suixinkan_ios_uikit/suixinkan_ios/Features/ScenicPermission/ViewControllers/ScenicPermissionViewControllers.swift
汉秋 d99a5b1bf8 Advance UIKit rewrite with AMap integration and core UI modules.
Integrate高德 SDK with simulator-safe build flags, add map views for operating area and punch points, refactor main tabs and key feature screens to UIKit with Diffable lists, and document Swift concurrency defaults in AGENTS.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 15:16:12 +08:00

262 lines
9.2 KiB
Swift

//
// ScenicPermissionViewControllers.swift
// suixinkan
//
// Created by Codex on 2026/6/26.
//
import CoreLocation
import UIKit
///
final class ScenicSelectionViewController: ModuleTableViewController {
private let viewModel = ScenicSelectionViewModel()
private let searchBar = UISearchBar()
private let locationProvider = ScenicSelectionLocationProvider()
/// UI
override func viewDidLoad() {
title = "选择景区"
navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "定位",
style: .plain,
target: self,
action: #selector(requestLocation)
)
super.viewDidLoad()
setupSearchBar()
wireViewModel(viewModel) { }
}
@objc private func requestLocation() {
viewModel.currentLocationText = "定位中..."
locationProvider.onLocation = { [weak self] location in
self?.viewModel.applyCurrentLocation(
latitude: location.coordinate.latitude,
longitude: location.coordinate.longitude
)
}
locationProvider.onFailure = { [weak self] message in
self?.services.toastCenter.show(message)
}
locationProvider.request()
}
/// SearchBar UI
private func setupSearchBar() {
searchBar.placeholder = "搜索景区"
searchBar.delegate = self
searchBar.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 56)
tableView.tableHeaderView = searchBar
}
/// tableCount
override func tableRowCount() -> Int {
viewModel.filteredItems.count
}
/// Cell
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
let item = viewModel.filteredItems[indexPath.row]
cell.configure(title: item.name, subtitle: item.address, detail: item.distanceText)
}
/// didSelectTableRow
override func didSelectTableRow(at indexPath: IndexPath) {
let item = viewModel.filteredItems[indexPath.row]
viewModel.select(
scenicId: item.id,
accountContext: services.accountContext,
permissionContext: services.permissionContext,
snapshotStore: AccountSnapshotStore()
)
navigationController?.popViewController(animated: true)
}
/// Content
override func reloadContent() async {
viewModel.reload(from: services.accountContext)
}
}
extension ScenicSelectionViewModel: ViewModelBindable {}
extension ScenicSelectionViewController: UISearchBarDelegate {
/// searchBar
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
viewModel.searchQuery = searchText
}
}
///
final class PermissionApplyViewController: ModuleTableViewController {
private let viewModel = PermissionApplyViewModel()
/// UI
override func viewDidLoad() {
title = "权限申请"
navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "提交",
style: .done,
target: self,
action: #selector(submit)
)
super.viewDidLoad()
wireViewModel(viewModel) { }
}
/// section
override func numberOfTableSections() -> Int { 2 }
/// section
override func tableRowCount(in section: Int) -> Int {
section == 0 ? viewModel.roleOptions.count : viewModel.scenicOptions.count
}
/// section
override func tableSectionTitle(for section: Int) -> String? {
section == 0 ? "选择角色" : "选择景区"
}
/// Cell
override func tableCell(for indexPath: IndexPath, row: ModuleTableRow, in tableView: UITableView) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: TitleSubtitleTableViewCell.reuseIdentifier,
for: indexPath
) as! TitleSubtitleTableViewCell
if indexPath.section == 0 {
let role = viewModel.roleOptions[indexPath.row]
cell.configure(title: role.name, subtitle: role.notes)
cell.accessoryType = viewModel.selectedRoleId == role.id ? .checkmark : .none
} else {
let scenic = viewModel.scenicOptions[indexPath.row]
cell.configure(title: scenic.name, subtitle: scenic.disabled ? "已有权限" : nil)
cell.accessoryType = scenic.selected ? .checkmark : .none
}
return cell
}
///
override func didSelectTableRow(at indexPath: IndexPath) {
if indexPath.section == 0 {
viewModel.selectRole(id: viewModel.roleOptions[indexPath.row].id)
Task { await viewModel.loadScenicListIfNeeded(api: services.scenicPermissionAPI, force: true) }
} else {
viewModel.toggleScenic(id: viewModel.scenicOptions[indexPath.row].id)
}
}
/// Content
override func reloadContent() async {
viewModel.bootstrap(rolePermissions: services.permissionContext.rolePermissions)
if viewModel.selectedRoleId != nil {
await viewModel.loadScenicListIfNeeded(api: services.scenicPermissionAPI, force: true)
}
}
///
@objc private func submit() {
Task {
await viewModel.submit(api: services.scenicPermissionAPI)
if viewModel.message == "提交成功,等待审核" {
services.toastCenter.show(viewModel.message ?? "提交成功")
navigationController?.popViewController(animated: true)
} else if let message = viewModel.message {
services.toastCenter.show(message)
}
}
}
}
extension PermissionApplyViewModel: ViewModelBindable {}
///
final class PermissionApplyStatusViewController: ModuleTableViewController {
private let viewModel = PermissionApplyStatusViewModel()
/// UI
override func viewDidLoad() {
title = "申请状态"
super.viewDidLoad()
viewModel.onChange = { [weak self] in self?.reloadTable() }
}
/// tableCount
override func tableRowCount() -> Int {
viewModel.pending == nil ? 0 : 4
}
/// Cell
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
guard let pending = viewModel.pending else { return }
switch indexPath.row {
case 0: cell.configure(title: "申请编号", subtitle: pending.code)
case 1: cell.configure(title: "角色", subtitle: pending.roleName)
case 2: cell.configure(title: "状态", subtitle: pending.statusLabel)
default: cell.configure(title: "申请时间", subtitle: pending.createdAt)
}
}
/// Content
override func reloadContent() async {
await viewModel.load(api: services.scenicPermissionAPI, applyCode: nil)
}
}
///
final class ScenicApplicationViewController: ModuleTableViewController {
private let viewModel = ScenicApplicationViewModel()
private let nameField = UITextField()
/// UI
override func viewDidLoad() {
title = "景区申请"
navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "提交",
style: .done,
target: self,
action: #selector(submit)
)
super.viewDidLoad()
nameField.placeholder = "景区名称"
nameField.borderStyle = .roundedRect
nameField.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 52)
tableView.tableHeaderView = nameField
wireViewModel(viewModel) { [weak self] in
if self?.nameField.text?.isEmpty != false {
self?.nameField.text = self?.viewModel.scenicName
}
}
}
/// tableCount
override func tableRowCount() -> Int { 3 }
/// Cell
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
switch indexPath.row {
case 0: cell.configure(title: "省份", subtitle: viewModel.selectedProvince)
case 1: cell.configure(title: "城市", subtitle: viewModel.selectedCity)
default: cell.configure(title: "合作类型", subtitle: viewModel.coopType == 1 ? "自营" : "合作")
}
}
/// Content
override func reloadContent() async {
await viewModel.loadInitial(api: services.scenicPermissionAPI)
}
///
@objc private func submit() {
viewModel.scenicName = nameField.text ?? ""
Task {
await viewModel.submit(api: services.scenicPermissionAPI, uploader: services.ossUploadService)
if let message = viewModel.message {
services.toastCenter.show(message)
}
}
}
}
extension ScenicApplicationViewModel: ViewModelBindable {}