| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570 |
- //
- // LNOrderRecordCell.swift
- // Lanu
- //
- // Created by OneeChan on 2025/12/24.
- //
- import Foundation
- import UIKit
- import SnapKit
- class LNOrderRecordCell: UITableViewCell {
- private let dateLabel = UILabel()
- private let stateLabel = UILabel()
-
- private let gameIc = UIImageView()
- private let gameNameLabel = UILabel()
- private let orderIdLabel = UILabel()
-
- private let discountView = UIView()
- private let totalLabel = UILabel()
- private let countLabel = UILabel()
-
- private let avatar = UIImageView()
- private let nameLabel = UILabel()
- private let genderView = UIImageView()
-
- private let requestLine = UIView()
- private let requestView = UIView()
- private let requestLabel = UILabel()
-
- private let menuView = UIView()
- private let rejectButton = UIButton()
- private let acceptButton = UIButton()
- private let startButton = UIButton()
- private let completeButton = UIButton()
- private let commitButton = UIButton()
- private var curItem: LNOrderRecordItemVO?
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
-
- setupViews()
- }
-
- func update(_ item: LNOrderRecordItemVO) {
- gameIc.sd_setImage(with: URL(string: item.categoryIcon))
- dateLabel.text = TimeInterval(item.createTime / 1_000).formattedFullDateWithTime()
- gameNameLabel.text = item.bizCategoryName
- orderIdLabel.text = item.orderId
-
- discountView.isHidden = item.totalAmount >= item.price * Double(item.purchaseQty)
- totalLabel.text = item.totalAmount.toDisplay
- countLabel.text = "\(item.unit) x \(item.purchaseQty)"
-
- avatar.showAvatar(item.avatar)
- nameLabel.text = item.nickname
- genderView.image = switch item.gender {
- case .unknow: nil
- case .male: .icGenderMale
- case .female: .icGenderFemale
- }
- requestLabel.text = item.customerRemark
- requestLine.isHidden = item.customerRemark.isEmpty
- requestView.isHidden = item.customerRemark.isEmpty
-
- curItem = item
-
- updateByStateChanged()
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
- extension LNOrderRecordCell {
- private func updateByStateChanged() {
- guard let curItem else { return }
-
- menuView.isHidden = true
- rejectButton.isHidden = true
- acceptButton.isHidden = true
- startButton.isHidden = true
- completeButton.isHidden = true
- commitButton.isHidden = true
-
- if curItem.refundApply {
- stateLabel.text = .init(key: "A00052")
- stateLabel.textColor = .init(hex: "#F23051")
-
- menuView.isHidden = false
- commitButton.isHidden = false
- return
- }
-
- switch curItem.status {
- case .created, .waitingForAccept:
- stateLabel.text = .init(key: "A00055")
- stateLabel.textColor = .init(hex: "#FFB836")
-
- menuView.isHidden = false
- rejectButton.isHidden = false
- acceptButton.isHidden = false
- case .completed:
- stateLabel.text = .init(key: "A00137")
- stateLabel.textColor = .text_6
- case .refunded:
- stateLabel.text = .init(key: "A00138")
- stateLabel.textColor = .text_3
- case .accepted:
- stateLabel.text = .init(key: "A00165")
- stateLabel.textColor = .text_6
-
- menuView.isHidden = false
- startButton.isHidden = false
- case .rejected:
- stateLabel.text = .init(key: "A00140")
- stateLabel.textColor = .text_3
- case .servicing:
- stateLabel.text = .init(key: "A00080")
- stateLabel.textColor = .init(hex: "#FFB836")
-
- menuView.isHidden = false
- completeButton.isHidden = false
- case .serviceDone:
- stateLabel.text = .init(key: "A00137")
- stateLabel.textColor = .text_6
- case .cancelled:
- stateLabel.text = .init(key: "A00152")
- stateLabel.textColor = .text_3
- }
- }
-
- private func setupViews() {
- backgroundColor = .clear
-
- let container = UIView()
- container.backgroundColor = .fill
- container.layer.cornerRadius = 12
- contentView.addSubview(container)
- container.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(16)
- make.top.equalToSuperview().offset(10)
- make.bottom.equalToSuperview()
- }
-
- let stackView = UIStackView()
- stackView.axis = .vertical
- stackView.spacing = 0
- container.addSubview(stackView)
- stackView.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(12)
- make.top.equalToSuperview().offset(2)
- make.bottom.equalToSuperview().offset(-8).priority(.medium)
- }
-
- let top = buildTopView()
- stackView.addArrangedSubview(top)
-
- let line = UIView()
- line.backgroundColor = .fill_2
- line.snp.makeConstraints { make in
- make.height.equalTo(0.5).priority(.medium)
- }
- stackView.addArrangedSubview(line)
-
- let orderInfo = buildOrderInfo()
- stackView.addArrangedSubview(orderInfo)
-
- let userInfo = buildUserInfoView()
- stackView.addArrangedSubview(userInfo)
-
- let menu = buildBottomView()
- stackView.addArrangedSubview(menu)
- }
-
- private func buildTopView() -> UIView {
- let container = UIView()
- container.snp.makeConstraints { make in
- make.height.equalTo(30)
- }
-
- stateLabel.font = .heading_h5
- container.addSubview(stateLabel)
- stateLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.trailing.equalToSuperview()
- make.width.height.equalTo(0).priority(.low)
- }
-
- dateLabel.font = .body_xs
- dateLabel.textColor = .text_3
- container.addSubview(dateLabel)
- dateLabel.snp.makeConstraints { make in
- make.leading.equalToSuperview()
- make.centerY.equalToSuperview()
- make.trailing.lessThanOrEqualTo(stateLabel.snp.leading).offset(-5)
- }
-
- return container
- }
-
- private func buildOrderInfo() -> UIView {
- let container = UIView()
- container.snp.makeConstraints { make in
- make.height.equalTo(54)
- }
-
- let price = buildPriceView()
- container.addSubview(price)
- price.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.trailing.equalToSuperview()
- }
-
- let infoView = buildGameInfoView()
- container.addSubview(infoView)
- infoView.snp.makeConstraints { make in
- make.leading.equalToSuperview()
- make.centerY.equalToSuperview().inset(4)
- make.trailing.lessThanOrEqualTo(price.snp.leading).offset(-12)
- }
-
- return container
- }
-
- private func buildUserInfoView() -> UIView {
- let container = UIView()
- container.backgroundColor = .fill_1
- container.layer.cornerRadius = 12
-
- let stackView = UIStackView()
- stackView.axis = .vertical
- stackView.spacing = 4
- container.addSubview(stackView)
- stackView.snp.makeConstraints { make in
- make.edges.equalToSuperview().inset(8)
- }
-
- let userView = UIView()
- userView.onTap { [weak self] in
- guard let self else { return }
- guard let curItem else { return }
- pushToProfile(uid: curItem.buyerUserNo)
- }
- userView.snp.makeConstraints { make in
- make.height.equalTo(23).priority(.medium)
- }
- stackView.addArrangedSubview(userView)
-
- avatar.layer.cornerRadius = 11.5
- avatar.clipsToBounds = true
- userView.addSubview(avatar)
- avatar.snp.makeConstraints { make in
- make.leading.equalToSuperview()
- make.centerY.equalToSuperview()
- make.width.height.equalTo(23)
- }
-
- nameLabel.font = .body_s
- nameLabel.textColor = .text_5
- userView.addSubview(nameLabel)
- nameLabel.snp.makeConstraints { make in
- make.centerY.equalTo(avatar)
- make.leading.equalTo(avatar.snp.trailing).offset(8)
- }
-
- userView.addSubview(genderView)
- genderView.snp.makeConstraints { make in
- make.centerY.equalTo(avatar)
- make.leading.equalTo(nameLabel.snp.trailing).offset(3)
- make.width.height.equalTo(14)
- }
-
- requestLine.backgroundColor = .fill_3
- requestLine.snp.makeConstraints { make in
- make.height.equalTo(0.5)
- }
- stackView.addArrangedSubview(requestLine)
-
- stackView.addArrangedSubview(requestView)
-
- let titleLabel = UILabel()
- titleLabel.font = .heading_h5
- titleLabel.textColor = .text_4
- titleLabel.text = .init(key: "A00167")
- requestView.addSubview(titleLabel)
- titleLabel.snp.makeConstraints { make in
- make.leading.equalToSuperview()
- make.top.equalToSuperview()
- }
-
- requestLabel.font = .body_xs
- requestLabel.textColor = .text_4
- requestLabel.numberOfLines = 0
- requestLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
- requestLabel.setContentCompressionResistancePriority(.defaultHigh , for: .vertical)
- requestView.addSubview(requestLabel)
- requestLabel.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.top.equalTo(titleLabel.snp.bottom)
- make.bottom.equalToSuperview()
- }
-
- return container
- }
-
- private func buildBottomView() -> UIView {
- menuView.snp.makeConstraints { make in
- make.height.equalTo(38)
- }
-
- let stackView = UIStackView()
- stackView.axis = .horizontal
- stackView.spacing = 6
- menuView.addSubview(stackView)
- stackView.snp.makeConstraints { make in
- make.trailing.equalToSuperview()
- make.bottom.equalToSuperview()
- }
-
- rejectButton.setTitle(.init(key: "A00168"), for: .normal)
- rejectButton.setTitleColor(.text_3, for: .normal)
- rejectButton.titleLabel?.font = .heading_h5
- rejectButton.layer.cornerRadius = 15
- rejectButton.layer.borderWidth = 1
- rejectButton.layer.borderColor = UIColor.fill_3.cgColor
- rejectButton.contentEdgeInsets = .init(top: 8, left: 18, bottom: 8, right: 18)
- rejectButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- guard let curItem else { return }
- LNOrderManager.shared.rejectOrder(orderId: curItem.orderId) { [weak self] success in
- guard let self else { return }
- guard success else { return }
- curItem.status = .rejected
- updateByStateChanged()
- }
- }), for: .touchUpInside)
- rejectButton.snp.makeConstraints { make in
- make.height.equalTo(30)
- }
- stackView.addArrangedSubview(rejectButton)
-
- acceptButton.setTitle(.init(key: "A00169"), for: .normal)
- acceptButton.setTitleColor(.text_1, for: .normal)
- acceptButton.titleLabel?.font = .heading_h5
- acceptButton.layer.cornerRadius = 15
- acceptButton.setBackgroundImage(.primary_8, for: .normal)
- acceptButton.contentEdgeInsets = .init(top: 8, left: 10, bottom: 8, right: 10)
- acceptButton.clipsToBounds = true
- acceptButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- guard let curItem else { return }
- LNOrderManager.shared.acceptOrder(orderId: curItem.orderId) { [weak self] success in
- guard let self else { return }
- guard success else { return }
- curItem.status = .accepted
- updateByStateChanged()
- }
- }), for: .touchUpInside)
- acceptButton.snp.makeConstraints { make in
- make.height.equalTo(30)
- }
- stackView.addArrangedSubview(acceptButton)
-
- startButton.setTitle(.init(key: "A00064"), for: .normal)
- startButton.setTitleColor(.text_1, for: .normal)
- startButton.titleLabel?.font = .heading_h5
- startButton.layer.cornerRadius = 15
- startButton.setBackgroundImage(.primary_8, for: .normal)
- startButton.contentEdgeInsets = .init(top: 8, left: 10, bottom: 8, right: 10)
- startButton.clipsToBounds = true
- startButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- guard let curItem else { return }
- LNOrderManager.shared.startOrderService(orderId: curItem.orderId) { [weak self] success in
- guard let self else { return }
- guard success else { return }
- curItem.status = .servicing
- updateByStateChanged()
- }
- }), for: .touchUpInside)
- startButton.snp.makeConstraints { make in
- make.height.equalTo(30)
- }
- stackView.addArrangedSubview(startButton)
-
- completeButton.setTitle(.init(key: "A00151"), for: .normal)
- completeButton.setTitleColor(.text_1, for: .normal)
- completeButton.titleLabel?.font = .heading_h5
- completeButton.layer.cornerRadius = 15
- completeButton.setBackgroundImage(.primary_8, for: .normal)
- completeButton.contentEdgeInsets = .init(top: 8, left: 10, bottom: 8, right: 10)
- completeButton.clipsToBounds = true
- completeButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- guard let curItem else { return }
- LNOrderManager.shared.finishOrderService(orderId: curItem.orderId) { [weak self] success in
- guard let self else { return }
- guard success else { return }
- curItem.status = .serviceDone
- updateByStateChanged()
- }
- }), for: .touchUpInside)
- completeButton.snp.makeConstraints { make in
- make.height.equalTo(30)
- }
- stackView.addArrangedSubview(completeButton)
-
- commitButton.setTitle(.init(key: "A00170"), for: .normal)
- commitButton.setTitleColor(.text_6, for: .normal)
- commitButton.titleLabel?.font = .heading_h5
- commitButton.layer.cornerRadius = 15
- commitButton.setBackgroundImage(.primary_7, for: .normal)
- commitButton.contentEdgeInsets = .init(top: 8, left: 10, bottom: 8, right: 10)
- commitButton.clipsToBounds = true
- commitButton.addAction(UIAction(handler: { [weak self] _ in
- guard let self else { return }
- guard let curItem else { return }
- pushToProtest(curItem.orderId) { [weak self] in
- guard let self else { return }
- curItem.status = .serviceDone
- updateByStateChanged()
- }
- }), for: .touchUpInside)
- commitButton.snp.makeConstraints { make in
- make.height.equalTo(30)
- }
- stackView.addArrangedSubview(commitButton)
-
- let cover = UIView()
- cover.backgroundColor = .fill
- cover.layer.cornerRadius = 14
- cover.isUserInteractionEnabled = false
- commitButton.insertSubview(cover, at: 0)
- cover.snp.makeConstraints { make in
- make.edges.equalToSuperview().inset(1)
- }
-
- return menuView
- }
-
- private func buildGameInfoView() -> UIView {
- let container = UIView()
-
- gameIc.layer.cornerRadius = 20
- gameIc.clipsToBounds = true
- container.addSubview(gameIc)
- gameIc.snp.makeConstraints { make in
- make.leading.equalToSuperview()
- make.verticalEdges.equalToSuperview()
- make.width.height.equalTo(50)
- }
-
- let textInfo = UIView()
- container.addSubview(textInfo)
- textInfo.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.leading.equalTo(gameIc.snp.trailing).offset(8)
- make.trailing.equalToSuperview()
- }
-
- gameNameLabel.textColor = .text_5
- gameNameLabel.font = .heading_h4
- textInfo.addSubview(gameNameLabel)
- gameNameLabel.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.top.equalToSuperview()
- }
-
- orderIdLabel.font = .body_xs
- orderIdLabel.textColor = .text_5
- textInfo.addSubview(orderIdLabel)
- orderIdLabel.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.bottom.equalToSuperview()
- make.top.equalTo(gameNameLabel.snp.bottom).offset(2)
- }
-
- return container
- }
-
- private func buildPriceView() -> UIView {
- let container = UIView()
-
- totalLabel.font = .heading_h3
- totalLabel.textColor = .text_5
- container.addSubview(totalLabel)
- totalLabel.snp.makeConstraints { make in
- make.top.trailing.equalToSuperview()
- }
-
- let coin = UIImageView.coinImageView()
- container.addSubview(coin)
- coin.snp.makeConstraints { make in
- make.centerY.equalTo(totalLabel)
- make.trailing.equalTo(totalLabel.snp.leading)
- make.width.height.equalTo(16)
- }
-
- let discount = buildDiscount()
- container.addSubview(discount)
- discount.snp.makeConstraints { make in
- make.centerY.equalTo(coin)
- make.leading.equalToSuperview()
- make.trailing.equalTo(coin.snp.leading).offset(-4)
- }
-
- countLabel.font = .body_m
- countLabel.textColor = .text_5
- countLabel.textAlignment = .right
- countLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
- countLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
- container.addSubview(countLabel)
- countLabel.snp.makeConstraints { make in
- make.trailing.bottom.equalToSuperview()
- make.top.equalTo(totalLabel.snp.bottom)
- }
-
- return container
- }
-
- private func buildDiscount() -> UIView {
- discountView.layer.cornerRadius = 4
- discountView.backgroundColor = .init(hex: "#FF6F32")
-
- let titleLabel = UILabel()
- titleLabel.text = .init(key: "A00129")
- titleLabel.font = .body_xs
- titleLabel.textColor = .text_1
- discountView.addSubview(titleLabel)
- titleLabel.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview().inset(5)
- make.verticalEdges.equalToSuperview().inset(2)
- }
-
- return discountView
- }
- }
- #if DEBUG
- import SwiftUI
- struct LNOrderRecordCellPreview: UIViewRepresentable {
- func makeUIView(context: Context) -> some UIView {
- let container = UIView()
- container.backgroundColor = .lightGray
-
- let view = LNOrderRecordCell()
- container.addSubview(view)
- view.snp.makeConstraints { make in
- make.horizontalEdges.equalToSuperview()
- make.centerY.equalToSuperview()
- make.height.equalTo(133)
- }
-
- return container
- }
-
- func updateUIView(_ uiView: UIViewType, context: Context) { }
- }
- #Preview(body: {
- LNOrderRecordCellPreview()
- })
- #endif // DEBUG
|