添加提交任务流程并抽取资料编辑页

This commit is contained in:
2026-07-07 10:12:20 +08:00
parent af450fb4cc
commit ef1d3b4af5
23 changed files with 3186 additions and 170 deletions

View File

@ -0,0 +1,225 @@
//
// 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
}
}