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,252 @@
//
// OrderDetailViewControllers.swift
// suixinkan
//
import SnapKit
import UIKit
///
final class StoreOrderDetailViewController: UIViewController {
private let item: OrderEntity
private let viewModel: OrderDetailViewModel
private let refundViewModel = OrderRefundViewModel()
private lazy var tableView: UITableView = {
let table = UITableView(frame: .zero, style: .insetGrouped)
table.dataSource = self
table.delegate = self
table.backgroundColor = AppDesignUIKit.pageBackground
return table
}()
init(item: OrderEntity) {
self.item = item
self.viewModel = OrderDetailViewModel(item: item)
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError() }
override func viewDidLoad() {
super.viewDidLoad()
title = "订单详情"
view.backgroundColor = AppDesignUIKit.pageBackground
view.addSubview(tableView)
tableView.snp.makeConstraints { make in make.edges.equalToSuperview() }
viewModel.onChange = { [weak self] in self?.tableView.reloadData() }
Task { await loadDetail() }
}
private func loadDetail() async {
await appServices.globalLoading.withLoading(message: "加载详情中...") {
await viewModel.load(api: appServices.ordersAPI, fallbackStoreId: appServices.accountContext.currentStore?.id)
}
if let error = viewModel.errorMessage {
showToast(error)
}
}
private func copyOrderNumber() {
UIPasteboard.general.string = viewModel.display.orderNumber
showToast("订单号已复制")
}
private func presentRefund() {
refundViewModel.begin(item: item)
let alert = UIAlertController(title: "订单退款", message: "可退 ¥\(refundViewModel.availableAmountText(for: item))", preferredStyle: .alert)
alert.addTextField { $0.placeholder = "退款原因" }
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
alert.addAction(UIAlertAction(title: "提交", style: .default) { [weak self] _ in
guard let self else { return }
self.refundViewModel.reason = alert.textFields?.first?.text ?? ""
Task {
let success = await self.refundViewModel.submit(api: self.appServices.ordersAPI, item: self.item)
if success {
self.showToast("退款申请已提交")
await self.viewModel.load(api: self.appServices.ordersAPI, fallbackStoreId: self.appServices.accountContext.currentStore?.id, forceReload: true)
} else if let message = self.refundViewModel.errorMessage {
self.showToast(message)
}
}
})
present(alert, animated: true)
}
}
extension StoreOrderDetailViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int { 6 }
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0: return viewModel.contextMessage == nil ? 0 : 1
case 1: return 7
case 2: return 4
case 3: return 4
case 4: return viewModel.shootingList.count
case 5: return 5
default: return 0
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
switch section {
case 1: "订单信息"
case 2: "支付信息"
case 3: "客户与项目"
case 4 where !viewModel.shootingList.isEmpty: "拍摄点"
case 5: "后续功能"
default: nil
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
cell.selectionStyle = .none
let display = viewModel.display
switch indexPath.section {
case 0:
cell.textLabel?.text = viewModel.contextMessage
cell.textLabel?.numberOfLines = 0
case 1:
let rows = ["订单号", "状态", "类型", "创建时间", "付款时间", "完成时间", "复制订单号"]
cell.textLabel?.text = rows[indexPath.row]
switch indexPath.row {
case 0: cell.detailTextLabel?.text = display.orderNumber
case 1: cell.detailTextLabel?.text = display.orderStatusName
case 2: cell.detailTextLabel?.text = display.orderTypeLabel
case 3: cell.detailTextLabel?.text = display.createdAt
case 4: cell.detailTextLabel?.text = displayPayTime
case 5: cell.detailTextLabel?.text = display.completeTime
default:
cell.textLabel?.textColor = AppDesignUIKit.primary
cell.selectionStyle = .default
}
case 2:
let rows = ["付款金额", "退款金额", "付款方式", "用户 UID"]
cell.textLabel?.text = rows[indexPath.row]
switch indexPath.row {
case 0: cell.detailTextLabel?.text = "¥\(emptyToZero(display.actualPayAmount))"
case 1: cell.detailTextLabel?.text = "¥\(emptyToZero(display.actualRefundAmount))"
case 2: cell.detailTextLabel?.text = display.payTypeName
default: cell.detailTextLabel?.text = "\(display.userId)"
}
case 3:
let rows = ["手机号", "关联项目", "项目 ID", "备注"]
cell.textLabel?.text = rows[indexPath.row]
switch indexPath.row {
case 0: cell.detailTextLabel?.text = display.phone
case 1: cell.detailTextLabel?.text = display.projectName
case 2: cell.detailTextLabel?.text = "\(display.projectId)"
default: cell.detailTextLabel?.text = display.remark
}
case 4:
let shooting = viewModel.shootingList[indexPath.row]
cell.textLabel?.text = shooting.scenicSpotName
cell.detailTextLabel?.text = shooting.staffName.isEmpty ? "状态 \(shooting.status)" : shooting.staffName
case 5:
let actions = ["历史拍摄", "任务上传", "视频预告", "尾片上传", "退款"]
cell.textLabel?.text = actions[indexPath.row]
cell.accessoryType = .disclosureIndicator
cell.selectionStyle = .default
if indexPath.row == 4, !refundViewModel.canRefund(item) {
cell.isUserInteractionEnabled = false
cell.textLabel?.textColor = AppDesignUIKit.textSecondary
}
default: break
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if indexPath.section == 1, indexPath.row == 6 { copyOrderNumber(); return }
guard indexPath.section == 5 else { return }
let orderNumber = viewModel.display.orderNumber
switch indexPath.row {
case 0:
HomeMenuRouting.pushOrders(.historicalShooting(orderNumber: orderNumber), from: self)
case 1 where item.orderType == 19:
HomeMenuRouting.pushOrders(.multiTravelTaskUpload(orderNumber: orderNumber), from: self)
case 2:
HomeMenuRouting.pushOrders(.orderTrailer(orderNumber: orderNumber, title: "视频预告"), from: self)
case 3:
HomeMenuRouting.pushOrders(.orderTrailer(orderNumber: orderNumber, title: "尾片上传"), from: self)
case 4:
presentRefund()
default: break
}
}
private var displayPayTime: String {
let payTime = viewModel.display.payTime
if payTime.isEmpty || payTime == "0" || payTime.hasPrefix("1970") { return item.depositPayTime }
return payTime
}
private func emptyToZero(_ value: String) -> String {
value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? "0" : value
}
}
///
final class WriteOffOrderDetailViewController: UIViewController {
private let item: WriteOffOrderItem
private lazy var tableView: UITableView = {
let table = UITableView(frame: .zero, style: .insetGrouped)
table.dataSource = self
table.backgroundColor = AppDesignUIKit.pageBackground
return table
}()
init(item: WriteOffOrderItem) {
self.item = item
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) { fatalError() }
override func viewDidLoad() {
super.viewDidLoad()
title = "核销详情"
view.addSubview(tableView)
tableView.snp.makeConstraints { make in make.edges.equalToSuperview() }
}
}
extension WriteOffOrderDetailViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 6 }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .value1, reuseIdentifier: nil)
cell.selectionStyle = .none
switch indexPath.row {
case 0:
cell.textLabel?.text = "订单号"
cell.detailTextLabel?.text = item.orderNumber
case 1:
cell.textLabel?.text = "项目"
cell.detailTextLabel?.text = item.projectName
case 2:
cell.textLabel?.text = "手机号"
cell.detailTextLabel?.text = item.userPhone
case 3:
cell.textLabel?.text = "金额"
cell.detailTextLabel?.text = "¥\(item.orderAmount)"
case 4:
cell.textLabel?.text = "状态"
cell.detailTextLabel?.text = item.orderStatusName
default:
cell.textLabel?.text = "核销时间"
cell.detailTextLabel?.text = item.orderVerificationTime
}
return cell
}
}