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>
This commit is contained in:
2026-06-26 15:16:12 +08:00
parent 9edf993432
commit d99a5b1bf8
124 changed files with 5195 additions and 1536 deletions

View File

@ -5,20 +5,44 @@
// 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
@ -26,15 +50,18 @@ final class ScenicSelectionViewController: ModuleTableViewController {
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(
@ -46,6 +73,7 @@ final class ScenicSelectionViewController: ModuleTableViewController {
navigationController?.popViewController(animated: true)
}
/// Content
override func reloadContent() async {
viewModel.reload(from: services.accountContext)
}
@ -54,6 +82,7 @@ final class ScenicSelectionViewController: ModuleTableViewController {
extension ScenicSelectionViewModel: ViewModelBindable {}
extension ScenicSelectionViewController: UISearchBarDelegate {
/// searchBar
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
viewModel.searchQuery = searchText
}
@ -63,6 +92,7 @@ extension ScenicSelectionViewController: UISearchBarDelegate {
final class PermissionApplyViewController: ModuleTableViewController {
private let viewModel = PermissionApplyViewModel()
/// UI
override func viewDidLoad() {
title = "权限申请"
navigationItem.rightBarButtonItem = UIBarButtonItem(
@ -75,17 +105,21 @@ final class PermissionApplyViewController: ModuleTableViewController {
wireViewModel(viewModel) { }
}
override func numberOfSections(in tableView: UITableView) -> Int { 2 }
/// section
override func numberOfTableSections() -> Int { 2 }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
/// section
override func tableRowCount(in section: Int) -> Int {
section == 0 ? viewModel.roleOptions.count : viewModel.scenicOptions.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
/// section
override func tableSectionTitle(for section: Int) -> String? {
section == 0 ? "选择角色" : "选择景区"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
/// Cell
override func tableCell(for indexPath: IndexPath, row: ModuleTableRow, in tableView: UITableView) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: TitleSubtitleTableViewCell.reuseIdentifier,
for: indexPath
@ -102,8 +136,8 @@ final class PermissionApplyViewController: ModuleTableViewController {
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
///
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) }
@ -112,6 +146,7 @@ final class PermissionApplyViewController: ModuleTableViewController {
}
}
/// Content
override func reloadContent() async {
viewModel.bootstrap(rolePermissions: services.permissionContext.rolePermissions)
if viewModel.selectedRoleId != nil {
@ -119,6 +154,7 @@ final class PermissionApplyViewController: ModuleTableViewController {
}
}
///
@objc private func submit() {
Task {
await viewModel.submit(api: services.scenicPermissionAPI)
@ -138,16 +174,19 @@ 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 {
@ -158,6 +197,7 @@ final class PermissionApplyStatusViewController: ModuleTableViewController {
}
}
/// Content
override func reloadContent() async {
await viewModel.load(api: services.scenicPermissionAPI, applyCode: nil)
}
@ -168,6 +208,7 @@ final class ScenicApplicationViewController: ModuleTableViewController {
private let viewModel = ScenicApplicationViewModel()
private let nameField = UITextField()
/// UI
override func viewDidLoad() {
title = "景区申请"
navigationItem.rightBarButtonItem = UIBarButtonItem(
@ -188,8 +229,10 @@ final class ScenicApplicationViewController: ModuleTableViewController {
}
}
/// 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)
@ -198,10 +241,12 @@ final class ScenicApplicationViewController: ModuleTableViewController {
}
}
/// Content
override func reloadContent() async {
await viewModel.loadInitial(api: services.scenicPermissionAPI)
}
///
@objc private func submit() {
viewModel.scenicName = nameField.text ?? ""
Task {