Implement orders tab aligned with Android, including scan verify flows.

Add role-based order/deposit lists, AVFoundation QR scanning, verify dialogs, and ViewModel tests so photographers, scenic admins, and store admins match Android behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 16:59:53 +08:00
parent 6492f80ef0
commit 31d2b6094b
27 changed files with 4226 additions and 17 deletions

View File

@ -0,0 +1,91 @@
//
// MultiVerifyScenicSpotViewController.swift
// suixinkan
//
import SnapKit
import UIKit
/// Sheet
final class MultiVerifyScenicSpotViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var onConfirm: ((MultiTravelScenicSpotEntity) -> Void)?
var onCancel: (() -> Void)?
private var spots: [MultiTravelScenicSpotEntity]
private var selectedSpot: MultiTravelScenicSpotEntity?
private let tableView = UITableView(frame: .zero, style: .plain)
private let confirmButton = UIButton(type: .system)
init(spots: [MultiTravelScenicSpotEntity], selected: MultiTravelScenicSpotEntity?) {
self.spots = spots
self.selectedSpot = selected ?? spots.first
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "选择打卡点"
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "取消", style: .plain, target: self, action: #selector(cancelTapped))
tableView.dataSource = self
tableView.delegate = self
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "spot")
confirmButton.setTitle("确认核销", for: .normal)
confirmButton.backgroundColor = AppColor.primary
confirmButton.setTitleColor(.white, for: .normal)
confirmButton.layer.cornerRadius = 8
confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
view.addSubview(tableView)
view.addSubview(confirmButton)
tableView.snp.makeConstraints { make in
make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
make.bottom.equalTo(confirmButton.snp.top).offset(-12)
}
confirmButton.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview().inset(16)
make.bottom.equalTo(view.safeAreaLayoutGuide).inset(16)
make.height.equalTo(48)
}
}
@objc private func cancelTapped() {
onCancel?()
dismiss(animated: true)
}
@objc private func confirmTapped() {
guard let selectedSpot else { return }
onConfirm?(selectedSpot)
dismiss(animated: true)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
spots.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "spot", for: indexPath)
let spot = spots[indexPath.row]
var config = cell.defaultContentConfiguration()
config.text = spot.name
config.secondaryText = "\(spot.scenicName) · \(spot.distanceText)"
cell.contentConfiguration = config
cell.accessoryType = spot.scenicSpotId == selectedSpot?.scenicSpotId ? .checkmark : .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedSpot = spots[indexPath.row]
tableView.reloadData()
}
}