// // 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 } }