// // LNOrderListItemCell.swift // Lanu // // Created by OneeChan on 2025/11/18. // import Foundation import UIKit import SnapKit class LNOrderListItemCell: UITableViewCell { private let dateLabel = UILabel() private let stateLabel = UILabel() private let avatar = UIImageView() private let userNameLabel = UILabel() private let gameLabel = UILabel() private let priceLabel = UILabel() private let countLabel = UILabel() private let operationButton = UIButton() private let descLabel = UILabel() private let discountView = UIView() private let totalLabel = UILabel() private var curItem: LNOrderListItemVO? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupViews() } func update(_ item: LNOrderListItemVO) { avatar.showAvatar(item.avatar) dateLabel.text = TimeInterval(item.createTime / 1_000).formattedFullDate() userNameLabel.text = item.nickname gameLabel.text = item.bizCategoryName priceLabel.text = "\(item.price.toDisplay)" countLabel.text = "\(item.unit) x \(item.purchaseQty)" totalLabel.text = item.totalAmount.toDisplay discountView.isHidden = item.totalAmount >= item.price * Double(item.purchaseQty) curItem = item updateByStateChanged() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } extension LNOrderListItemCell { @objc private func handleOperationButtonClick() { guard let orderItem = curItem else { return } switch orderItem.status { case .created, .waitingForAccept: // 可以取消 LNCommonAlertView.showCancelOrderAlert(orderId: orderItem.orderId) { success in guard success else { return } orderItem.status = .cancelled } break case .completed: // 可以评价 let panel = LNOrderCommentPanel() panel.update(orderItem.avatar, orderId: orderItem.orderId) panel.handler = { star, comment in orderItem.star = star } panel.popup() break case .serviceDone: // 可以点击完成 LNCommonAlertView.showFinishOrderAlert(orderId: orderItem.orderId) { success in guard success else { return } orderItem.status = .completed } break case .refunded, .accepted, .rejected, .cancelled, .servicing: // 无操作选项 break } } } extension LNOrderListItemCell { private func updateByStateChanged() { guard let curItem else { return } if curItem.refundApply { stateLabel.text = .init(key: "A00049") stateLabel.textColor = .init(hex: "#FFB836") operationButton.isHidden = true descLabel.isHidden = false descLabel.text = .init(key: "A00148") return } operationButton.isHidden = true operationButton.setBackgroundImage(nil, for: .normal) descLabel.isHidden = true switch curItem.status { case .created, .waitingForAccept: stateLabel.text = .init(key: "A00055") stateLabel.textColor = .init(hex: "#FFB836") operationButton.isHidden = false operationButton.layer.borderColor = UIColor.fill_3.cgColor operationButton.setTitleColor(.text_3, for: .normal) operationButton.setTitle(.init(key: "A00003"), for: .normal) case .completed: stateLabel.text = .init(key: "A00137") stateLabel.textColor = .text_6 if curItem.star == 0 { operationButton.isHidden = false operationButton.layer.borderColor = UIColor.text_6.cgColor operationButton.setTitleColor(.text_6, for: .normal) operationButton.setTitle(.init(key: "A00149"), for: .normal) } case .refunded: stateLabel.text = .init(key: "A00138") stateLabel.textColor = .text_3 operationButton.isHidden = true descLabel.isHidden = false descLabel.text = .init(key: "A00150") case .accepted: stateLabel.text = .init(key: "A00139") stateLabel.textColor = .text_6 case .rejected: stateLabel.text = .init(key: "A00140") stateLabel.textColor = .text_6 case .servicing: stateLabel.text = .init(key: "A00141") stateLabel.textColor = .init(hex: "#FFB836") case .serviceDone: stateLabel.text = .init(key: "A00141") stateLabel.textColor = .init(hex: "#FFB836") operationButton.isHidden = false operationButton.layer.borderColor = UIColor.clear.cgColor operationButton.setTitleColor(.text_1, for: .normal) operationButton.setTitle(.init(key: "A00151"), for: .normal) operationButton.setBackgroundImage(.primary_8, for: .normal) case .cancelled: stateLabel.text = .init(key: "A00152") stateLabel.textColor = .text_3 } } private func setupViews() { backgroundColor = .clear onTap { [weak self] in guard let self else { return } guard let curItem else { return } pushToOrderDetail(orderId: curItem.orderId) } 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(6) make.bottom.equalToSuperview().offset(-6) } let top = buildTopView() container.addSubview(top) top.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview().offset(5) } let line = UIView() line.backgroundColor = .fill_2 container.addSubview(line) line.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview().inset(11) make.top.equalTo(top.snp.bottom) make.height.equalTo(0.5) } let mid = buildMidView() container.addSubview(mid) mid.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalTo(top.snp.bottom).offset(3) } let bottom = buildBottomView() container.addSubview(bottom) bottom.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalTo(mid.snp.bottom).offset(3) make.bottom.equalToSuperview().offset(-5) } } 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().offset(-12) 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().offset(12) make.centerY.equalToSuperview() make.trailing.lessThanOrEqualTo(stateLabel.snp.leading).offset(-5) } return container } private func buildMidView() -> UIView { let container = UIView() let price = buildPriceView() container.addSubview(price) price.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-12) } let infoView = buildUserInfoView() container.addSubview(infoView) infoView.snp.makeConstraints { make in make.leading.equalToSuperview().offset(12) make.verticalEdges.equalToSuperview().inset(4) make.trailing.lessThanOrEqualTo(price.snp.leading).offset(-12) } return container } private func buildBottomView() -> UIView { let container = UIView() container.snp.makeConstraints { make in make.height.equalTo(38) } totalLabel.font = .heading_h3 totalLabel.textColor = .text_5 container.addSubview(totalLabel) totalLabel.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalToSuperview().offset(-12) } let coin = UIImageView.coinImageView() container.addSubview(coin) coin.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalTo(totalLabel.snp.leading).offset(-2) make.width.height.equalTo(20) } let text = UILabel() text.font = .body_s text.textColor = .text_5 text.text = .init(key: "A00124") container.addSubview(text) text.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalTo(coin.snp.leading) } let discount = buildDiscount() container.addSubview(discount) discount.snp.makeConstraints { make in make.centerY.equalToSuperview() make.trailing.equalTo(text.snp.leading).offset(-5) } operationButton.layer.cornerRadius = 15 operationButton.layer.borderWidth = 1 operationButton.clipsToBounds = true operationButton.titleLabel?.font = .heading_h5 operationButton.addTarget(self, action: #selector(handleOperationButtonClick), for: .touchUpInside) container.addSubview(operationButton) operationButton.snp.makeConstraints { make in make.height.equalTo(30) make.centerY.equalToSuperview() make.leading.equalToSuperview().offset(12) make.width.equalTo(77) } descLabel.font = .body_xs descLabel.textColor = .text_3 descLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) descLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) container.addSubview(descLabel) descLabel.snp.makeConstraints { make in make.leading.equalToSuperview().offset(12) make.centerY.equalToSuperview() make.trailing.lessThanOrEqualTo(discount.snp.leading).offset(-16) } return container } private func buildUserInfoView() -> UIView { let container = UIView() container.onTap { [weak self] in guard let self else { return } guard let curItem else { return } pushToProfile(uid: curItem.sellerUserNo) } avatar.layer.cornerRadius = 20 avatar.clipsToBounds = true container.addSubview(avatar) avatar.snp.makeConstraints { make in make.leading.verticalEdges.equalToSuperview() make.width.height.equalTo(40) } let textInfo = UIView() container.addSubview(textInfo) textInfo.snp.makeConstraints { make in make.centerY.equalToSuperview() make.leading.equalTo(avatar.snp.trailing).offset(8) make.trailing.equalToSuperview() } userNameLabel.textColor = .text_5 userNameLabel.font = .heading_h4 textInfo.addSubview(userNameLabel) userNameLabel.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.top.equalToSuperview() } gameLabel.font = .body_m gameLabel.textColor = .text_5 textInfo.addSubview(gameLabel) gameLabel.snp.makeConstraints { make in make.horizontalEdges.equalToSuperview() make.bottom.equalToSuperview() make.top.equalTo(userNameLabel.snp.bottom).offset(2) } return container } private func buildPriceView() -> UIView { let container = UIView() let coin = UIImageView.coinImageView() container.addSubview(coin) coin.snp.makeConstraints { make in make.top.equalToSuperview() make.leading.equalToSuperview() make.width.height.equalTo(16) } priceLabel.font = .body_s priceLabel.textColor = .text_5 container.addSubview(priceLabel) priceLabel.snp.makeConstraints { make in make.trailing.equalToSuperview() make.leading.equalTo(coin.snp.trailing) make.centerY.equalTo(coin) } countLabel.font = .body_xs countLabel.textColor = .text_4 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(coin.snp.bottom).offset(2) } 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(6) make.verticalEdges.equalToSuperview().inset(3) } return discountView } } #if DEBUG import SwiftUI struct LNOrderListItemCellPreview: UIViewRepresentable { func makeUIView(context: Context) -> some UIView { let container = UIView() container.backgroundColor = .lightGray let view = LNOrderListItemCell() 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: { LNOrderListItemCellPreview() }) #endif // DEBUG