Initial commit: suixinkan_ios UIKit rewrite project.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-26 14:33:31 +08:00
commit 9edf993432
297 changed files with 47151 additions and 0 deletions

View File

@ -0,0 +1,216 @@
//
// ScenicPermissionViewControllers.swift
// suixinkan
//
// Created by Codex on 2026/6/26.
//
import UIKit
///
final class ScenicSelectionViewController: ModuleTableViewController {
private let viewModel = ScenicSelectionViewModel()
private let searchBar = UISearchBar()
override func viewDidLoad() {
title = "选择景区"
super.viewDidLoad()
setupSearchBar()
wireViewModel(viewModel) { }
}
private func setupSearchBar() {
searchBar.placeholder = "搜索景区"
searchBar.delegate = self
searchBar.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 56)
tableView.tableHeaderView = searchBar
}
override func tableRowCount() -> Int {
viewModel.filteredItems.count
}
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)
}
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)
}
override func reloadContent() async {
viewModel.reload(from: services.accountContext)
}
}
extension ScenicSelectionViewModel: ViewModelBindable {}
extension ScenicSelectionViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
viewModel.searchQuery = searchText
}
}
///
final class PermissionApplyViewController: ModuleTableViewController {
private let viewModel = PermissionApplyViewModel()
override func viewDidLoad() {
title = "权限申请"
navigationItem.rightBarButtonItem = UIBarButtonItem(
title: "提交",
style: .done,
target: self,
action: #selector(submit)
)
super.viewDidLoad()
wireViewModel(viewModel) { }
}
override func numberOfSections(in tableView: UITableView) -> Int { 2 }
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
section == 0 ? viewModel.roleOptions.count : viewModel.scenicOptions.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
section == 0 ? "选择角色" : "选择景区"
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> 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 tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
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)
}
}
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()
override func viewDidLoad() {
title = "申请状态"
super.viewDidLoad()
viewModel.onChange = { [weak self] in self?.reloadTable() }
}
override func tableRowCount() -> Int {
viewModel.pending == nil ? 0 : 4
}
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)
}
}
override func reloadContent() async {
await viewModel.load(api: services.scenicPermissionAPI, applyCode: nil)
}
}
///
final class ScenicApplicationViewController: ModuleTableViewController {
private let viewModel = ScenicApplicationViewModel()
private let nameField = UITextField()
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
}
}
}
override func tableRowCount() -> Int { 3 }
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 ? "自营" : "合作")
}
}
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 {}