Files
suixinkan_uikit/suixinkan/UI/Task/TaskOrderSelectViewController.swift
汉秋 3c4ca7eefb Add submit-task flow aligned with Android and extract profile edit page.
Implement task creation with cloud/local media, order linking, and OSS upload; wire home entry and move profile nickname/avatar editing to ProfileEditViewController.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 10:12:20 +08:00

226 lines
7.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// TaskOrderSelectViewController.swift
// suixinkan
//
import SnapKit
import UIKit
/// Android `OrderSelectScreen`
final class TaskOrderSelectViewController: BaseViewController {
var onConfirmed: ((String?) -> Void)?
private let viewModel: TaskOrderSelectViewModel
private let taskAPI = NetworkServices.shared.taskAPI
private let tableView = UITableView(frame: .zero, style: .plain)
private let confirmButton = AppButton(title: "确定")
private let emptyLabel = UILabel()
private let bottomBar = UIView()
init(initialOrderNumber: String? = nil) {
viewModel = TaskOrderSelectViewModel(initialOrderNumber: initialOrderNumber)
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setupNavigationBar() {
title = "订单列表"
}
override func setupUI() {
tableView.backgroundColor = AppColor.pageBackground
tableView.separatorStyle = .none
tableView.register(TaskOrderCell.self, forCellReuseIdentifier: TaskOrderCell.reuseIdentifier)
tableView.dataSource = self
tableView.delegate = self
emptyLabel.text = "无有效订单"
emptyLabel.font = .app(.body)
emptyLabel.textColor = AppColor.textPrimary
emptyLabel.textAlignment = .center
emptyLabel.isHidden = true
bottomBar.backgroundColor = .white
view.addSubview(tableView)
view.addSubview(emptyLabel)
view.addSubview(bottomBar)
bottomBar.addSubview(confirmButton)
}
override func setupConstraints() {
bottomBar.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview()
}
confirmButton.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(AppSpacing.md)
}
tableView.snp.makeConstraints { make in
make.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
make.bottom.equalTo(bottomBar.snp.top)
}
emptyLabel.snp.makeConstraints { make in
make.center.equalTo(tableView)
}
}
override func bindActions() {
viewModel.onStateChange = { [weak self] in
Task { @MainActor in self?.applyViewModel() }
}
viewModel.onShowMessage = { [weak self] message in
Task { @MainActor in self?.showToast(message) }
}
confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
}
override func viewDidLoad() {
super.viewDidLoad()
Task { await viewModel.loadOrders(api: taskAPI) }
}
@MainActor
private func applyViewModel() {
emptyLabel.isHidden = viewModel.isLoading || !viewModel.orders.isEmpty
tableView.reloadData()
if viewModel.isLoading {
showLoading()
} else {
hideLoading()
}
}
@objc private func confirmTapped() {
onConfirmed?(viewModel.confirmedOrderNumber())
navigationController?.popViewController(animated: true)
}
}
extension TaskOrderSelectViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
viewModel.orders.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: TaskOrderCell.reuseIdentifier,
for: indexPath
) as! TaskOrderCell
let order = viewModel.orders[indexPath.row]
cell.apply(
order: order,
isSelected: viewModel.selectedOrderNumber == order.orderNumber
)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
viewModel.toggleSelection(orderNumber: viewModel.orders[indexPath.row].orderNumber)
}
}
/// cell
private final class TaskOrderCell: UITableViewCell {
static let reuseIdentifier = "TaskOrderCell"
private let cardView = UIView()
private let projectRow = TaskInfoRowView(label: "项目名称:")
private let statusRow = TaskInfoRowView(label: "订单状态:")
private let numberRow = TaskInfoRowView(label: "订单编号:")
private let payTimeRow = TaskInfoRowView(label: "付款时间:")
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
selectionStyle = .none
backgroundColor = .clear
contentView.backgroundColor = .clear
cardView.backgroundColor = .white
cardView.layer.cornerRadius = AppRadius.sm
cardView.layer.borderWidth = 1
cardView.layer.borderColor = AppColor.border.cgColor
contentView.addSubview(cardView)
cardView.addSubview(projectRow)
cardView.addSubview(statusRow)
cardView.addSubview(numberRow)
cardView.addSubview(payTimeRow)
cardView.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 0, left: AppSpacing.md, bottom: AppSpacing.sm, right: AppSpacing.md))
}
projectRow.snp.makeConstraints { make in
make.top.leading.trailing.equalToSuperview().inset(AppSpacing.md)
}
statusRow.snp.makeConstraints { make in
make.top.equalTo(projectRow.snp.bottom).offset(AppSpacing.xs)
make.leading.trailing.equalTo(projectRow)
}
numberRow.snp.makeConstraints { make in
make.top.equalTo(statusRow.snp.bottom).offset(AppSpacing.xs)
make.leading.trailing.equalTo(projectRow)
}
payTimeRow.snp.makeConstraints { make in
make.top.equalTo(numberRow.snp.bottom).offset(AppSpacing.xs)
make.leading.trailing.bottom.equalToSuperview().inset(AppSpacing.md)
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func apply(order: AvailableOrder, isSelected: Bool) {
projectRow.apply(value: order.projectName.isEmpty ? "--" : order.projectName)
statusRow.apply(value: order.orderStatusLabel.isEmpty ? "--" : order.orderStatusLabel)
numberRow.apply(value: order.orderNumber)
payTimeRow.apply(value: order.payTime.isEmpty ? "--" : order.payTime)
cardView.layer.borderColor = isSelected ? AppColor.danger.cgColor : AppColor.border.cgColor
cardView.layer.borderWidth = isSelected ? 2 : 1
}
}
///
private final class TaskInfoRowView: UIView {
private let labelView = UILabel()
private let valueView = UILabel()
init(label: String) {
super.init(frame: .zero)
labelView.text = label
labelView.font = .app(.body)
labelView.textColor = AppColor.textSecondary
valueView.font = .app(.body)
valueView.textColor = AppColor.textPrimary
valueView.numberOfLines = 0
addSubview(labelView)
addSubview(valueView)
labelView.snp.makeConstraints { make in
make.leading.top.bottom.equalToSuperview()
make.width.equalTo(80)
}
valueView.snp.makeConstraints { make in
make.leading.equalTo(labelView.snp.trailing).offset(AppSpacing.xs)
make.trailing.top.bottom.equalToSuperview()
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func apply(value: String) {
valueView.text = value
}
}