286 lines
9.7 KiB
Swift
286 lines
9.7 KiB
Swift
//
|
|
// ProjectViewControllers.swift
|
|
// suixinkan
|
|
//
|
|
// Created by Codex on 2026/6/26.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
/// 摄影师项目管理页。
|
|
final class ProjectManagementViewController: ModuleTableViewController {
|
|
private let viewModel = ProjectManagementViewModel()
|
|
|
|
override func viewDidLoad() {
|
|
title = "项目管理"
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
|
title: "新建",
|
|
style: .plain,
|
|
target: self,
|
|
action: #selector(createProject)
|
|
)
|
|
super.viewDidLoad()
|
|
wireViewModel(viewModel) { }
|
|
}
|
|
|
|
override func tableRowCount() -> Int { viewModel.items.count }
|
|
|
|
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
|
|
let item = viewModel.items[indexPath.row]
|
|
cell.configure(title: item.name, subtitle: item.statusName, detail: "¥\(item.price)")
|
|
}
|
|
|
|
override func didSelectTableRow(at indexPath: IndexPath) {
|
|
let item = viewModel.items[indexPath.row]
|
|
navigationController?.pushViewController(
|
|
ProjectDetailViewController(projectId: item.id, storeMode: false),
|
|
animated: true
|
|
)
|
|
}
|
|
|
|
override func reloadContent() async {
|
|
await viewModel.reload(api: services.projectAPI, scenicId: services.currentScenicId)
|
|
}
|
|
|
|
@objc private func createProject() {
|
|
navigationController?.pushViewController(
|
|
ProjectEditorViewController(projectId: nil),
|
|
animated: true
|
|
)
|
|
}
|
|
}
|
|
|
|
extension ProjectManagementViewModel: ViewModelBindable {}
|
|
|
|
/// 店铺项目管理页。
|
|
final class StoreProjectManagementViewController: ModuleTableViewController {
|
|
private let viewModel = StoreProjectManagementViewModel()
|
|
|
|
override func viewDidLoad() {
|
|
title = "店铺项目"
|
|
super.viewDidLoad()
|
|
wireViewModel(viewModel) { }
|
|
}
|
|
|
|
override func tableRowCount() -> Int { viewModel.filteredItems.count }
|
|
|
|
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
|
|
let item = viewModel.filteredItems[indexPath.row]
|
|
cell.configure(title: item.name, subtitle: item.typeName, detail: "¥\(item.price)")
|
|
}
|
|
|
|
override func didSelectTableRow(at indexPath: IndexPath) {
|
|
let item = viewModel.filteredItems[indexPath.row]
|
|
navigationController?.pushViewController(
|
|
ProjectDetailViewController(projectId: item.id, storeMode: true),
|
|
animated: true
|
|
)
|
|
}
|
|
|
|
override func reloadContent() async {
|
|
await viewModel.reload(api: services.projectAPI, userId: services.userId)
|
|
}
|
|
}
|
|
|
|
extension StoreProjectManagementViewModel: ViewModelBindable {}
|
|
|
|
/// 项目详情页。
|
|
final class ProjectDetailViewController: ModuleTableViewController {
|
|
private let projectId: Int
|
|
private let storeMode: Bool
|
|
private let photographerViewModel = ProjectManagementViewModel()
|
|
private let storeViewModel = StoreProjectManagementViewModel()
|
|
|
|
init(projectId: Int, storeMode: Bool) {
|
|
self.projectId = projectId
|
|
self.storeMode = storeMode
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
title = "项目详情"
|
|
super.viewDidLoad()
|
|
if storeMode {
|
|
storeViewModel.onChange = { [weak self] in self?.reloadTable() }
|
|
} else {
|
|
photographerViewModel.onChange = { [weak self] in self?.reloadTable() }
|
|
}
|
|
}
|
|
|
|
private var detail: PhotographerProjectDetailResponse? {
|
|
storeMode ? storeViewModel.selectedDetail : photographerViewModel.selectedDetail
|
|
}
|
|
|
|
override func tableRowCount() -> Int {
|
|
detail == nil ? 0 : 4
|
|
}
|
|
|
|
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
|
|
guard let detail else { return }
|
|
switch indexPath.row {
|
|
case 0: cell.configure(title: "项目名称", subtitle: detail.name)
|
|
case 1: cell.configure(title: "简介", subtitle: detail.description)
|
|
case 2: cell.configure(title: "价格", subtitle: detail.price)
|
|
default: cell.configure(title: "打卡点", subtitle: "\(detail.scenicList.count) 个")
|
|
}
|
|
}
|
|
|
|
override func reloadContent() async {
|
|
if storeMode {
|
|
await storeViewModel.loadDetail(id: projectId, api: services.projectAPI)
|
|
} else {
|
|
await photographerViewModel.loadDetail(id: projectId, api: services.projectAPI)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 摄影师项目编辑页。
|
|
final class ProjectEditorViewController: ModuleTableViewController {
|
|
private let viewModel = ProjectEditorViewModel(mode: .create)
|
|
private let nameField = UITextField()
|
|
private let descriptionField = UITextField()
|
|
private let priceField = UITextField()
|
|
private let projectId: Int?
|
|
|
|
init(projectId: Int?) {
|
|
self.projectId = projectId
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
title = projectId == nil ? "新建项目" : "编辑项目"
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
|
title: "保存",
|
|
style: .done,
|
|
target: self,
|
|
action: #selector(save)
|
|
)
|
|
super.viewDidLoad()
|
|
setupHeader()
|
|
wireViewModel(viewModel) { [weak self] in self?.fillFormIfNeeded() }
|
|
}
|
|
|
|
private func setupHeader() {
|
|
nameField.placeholder = "项目名称"
|
|
nameField.borderStyle = .roundedRect
|
|
descriptionField.placeholder = "项目简介"
|
|
descriptionField.borderStyle = .roundedRect
|
|
priceField.placeholder = "价格"
|
|
priceField.borderStyle = .roundedRect
|
|
priceField.keyboardType = .decimalPad
|
|
let stack = UIStackView(arrangedSubviews: [nameField, descriptionField, priceField])
|
|
stack.axis = .vertical
|
|
stack.spacing = 8
|
|
stack.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 132)
|
|
stack.layoutMargins = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
|
|
stack.isLayoutMarginsRelativeArrangement = true
|
|
tableView.tableHeaderView = stack
|
|
}
|
|
|
|
override func tableRowCount() -> Int { 0 }
|
|
|
|
override func reloadContent() async {
|
|
guard let projectId else { return }
|
|
if let detail = try? await services.projectAPI.projectDetail(id: projectId) {
|
|
viewModel.apply(detail)
|
|
fillFormIfNeeded()
|
|
}
|
|
}
|
|
|
|
private func fillFormIfNeeded() {
|
|
if nameField.text?.isEmpty != false { nameField.text = viewModel.name }
|
|
if descriptionField.text?.isEmpty != false { descriptionField.text = viewModel.descriptionText }
|
|
if priceField.text?.isEmpty != false { priceField.text = viewModel.price }
|
|
}
|
|
|
|
@objc private func save() {
|
|
viewModel.name = nameField.text ?? ""
|
|
viewModel.descriptionText = descriptionField.text ?? ""
|
|
viewModel.price = priceField.text ?? ""
|
|
Task {
|
|
let userId = Int(services.userId ?? "")
|
|
let success = await viewModel.submit(
|
|
scenicId: services.currentScenicId,
|
|
userId: userId,
|
|
api: services.projectAPI,
|
|
uploadService: services.ossUploadService
|
|
)
|
|
if success {
|
|
navigationController?.popViewController(animated: true)
|
|
} else if let message = viewModel.errorMessage {
|
|
services.toastCenter.show(message)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension ProjectEditorViewModel: ViewModelBindable {}
|
|
|
|
/// 店铺项目编辑页。
|
|
final class StoreProjectEditorViewController: ModuleTableViewController {
|
|
private let viewModel = StoreProjectEditorViewModel(mode: .create)
|
|
private let nameField = UITextField()
|
|
|
|
init(projectId: Int?) {
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
title = "店铺项目"
|
|
navigationItem.rightBarButtonItem = UIBarButtonItem(
|
|
title: "保存",
|
|
style: .done,
|
|
target: self,
|
|
action: #selector(save)
|
|
)
|
|
super.viewDidLoad()
|
|
nameField.placeholder = "项目名称"
|
|
nameField.borderStyle = .roundedRect
|
|
nameField.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: 52)
|
|
tableView.tableHeaderView = nameField
|
|
wireViewModel(viewModel) { }
|
|
}
|
|
|
|
override func tableRowCount() -> Int { viewModel.scenicList.count }
|
|
|
|
override func configureCell(_ cell: TitleSubtitleTableViewCell, at indexPath: IndexPath) {
|
|
let scenic = viewModel.scenicList[indexPath.row]
|
|
cell.configure(title: scenic.name, subtitle: viewModel.selectedScenicIds.contains(scenic.id) ? "已选择" : nil)
|
|
}
|
|
|
|
override func reloadContent() async {
|
|
guard let userId = Int(services.userId ?? "") else { return }
|
|
await viewModel.loadScenicList(api: services.projectAPI, userId: userId)
|
|
}
|
|
|
|
@objc private func save() {
|
|
viewModel.name = nameField.text ?? ""
|
|
Task {
|
|
guard let userId = Int(services.userId ?? "") else { return }
|
|
let success = await viewModel.submit(
|
|
userId: userId,
|
|
api: services.projectAPI,
|
|
uploadService: services.ossUploadService
|
|
)
|
|
if success { navigationController?.popViewController(animated: true) }
|
|
}
|
|
}
|
|
}
|
|
|
|
extension StoreProjectEditorViewModel: ViewModelBindable {}
|