// // OrderListCardView.swift // suixinkan // // Created by Codex on 2026/6/29. // import SwiftUI /// 主订单列表卡片,对齐 Android OrderView。 struct OrderListCardView: View { let item: OrderEntity let hideOrderWriteActions: Bool let showOrderSource: Bool let sourceSelection: OrderSourceSelection? let orderSourcePeople: [OrderSourcePerson] let leadsForPerson: (OrderSourcePerson) -> [OrderSourceLead] let leadsLoading: Bool let onRefund: () -> Void let onVerify: () -> Void let onUploadTask: () -> Void let onRefinedChange: (Int) -> Void let onSendGift: () -> Void let onCancelOrder: () -> Void let onHistoricalPhoto: () -> Void let onCallPhone: () -> Void let onOrderSourceSheetOpen: () -> Void let onOrderSourcePersonClick: (OrderSourcePerson) -> Void let onOrderSourceSelectionChange: (OrderSourceSelection) -> Void let callSourcePhone: (String) -> Void private var showRefundButton: Bool { !hideOrderWriteActions && (item.orderStatus == 18 || item.orderStatus == 30) && item.orderType != 19 } private var showVerifyButton: Bool { !hideOrderWriteActions && ( (item.photoTravel?.needCheckIn == true && item.orderStatus != 30) || item.orderType == 19 ) } var body: some View { VStack(alignment: .leading, spacing: 0) { HStack(alignment: .center) { Text("订单号:\(item.orderNumber)") .font(.system(size: 14)) .foregroundStyle(.black) .lineLimit(1) .minimumScaleFactor(0.72) Spacer() OrderStatusChip(text: item.orderStatusName, status: item.orderStatus) } Text(item.createdAt.isEmpty ? "--" : item.createdAt) .font(.system(size: 12)) .foregroundStyle(AppDesign.textSecondary) .padding(.top, 4) if !item.orderTypeLabel.isEmpty { Text(item.orderTypeLabel) .font(.system(size: 12)) .foregroundStyle(AppDesign.primary) .padding(.horizontal, 4) .padding(.vertical, 2) .background(AppDesign.primarySoft, in: RoundedRectangle(cornerRadius: 4)) .padding(.top, 4) } if showOrderSource { OrderSourcePicker( selection: sourceSelection, people: orderSourcePeople, leadsForPerson: leadsForPerson, leadsLoading: leadsLoading, onSheetOpen: onOrderSourceSheetOpen, onPersonClick: onOrderSourcePersonClick, onSelectionChange: onOrderSourceSelectionChange, callPhone: callSourcePhone ) .padding(.top, 10) } if showRefundButton || showVerifyButton { HStack(spacing: 12) { if showRefundButton { OrderActionButton( title: "退款", textColor: AppDesign.orderRefundText, backgroundColor: AppDesign.orderRefundBackground, maxWidth: showVerifyButton ? nil : .infinity, action: onRefund ) .frame(maxWidth: showVerifyButton ? .infinity : nil) } if showVerifyButton { OrderActionButton(title: "核销订单", action: onVerify) } } .padding(.top, 12) } if !hideOrderWriteActions && item.orderType == 19 { Button(action: onUploadTask) { Text("上传任务") .font(.system(size: 16)) .foregroundStyle(AppDesign.primary) .frame(maxWidth: .infinity) .frame(height: 48) .background(AppDesign.primarySoft, in: RoundedRectangle(cornerRadius: 12)) } .buttonStyle(.plain) .padding(.top, 12) } if item.orderStatus == 18 || item.orderStatus == 30 { OrderRefinedChoiceSection( currentSelection: item.isRefined, readOnly: hideOrderWriteActions, onSelectionChange: onRefinedChange ) .padding(.top, 12) } if item.orderStatus == 50, !item.actualRefundAmount.isEmpty, item.actualRefundAmount != "0" { OrderInfoRow(title: "退款金额", value: "¥\(item.actualRefundAmount)", valueColor: AppDesign.primary) .padding(.top, 8) } VStack(spacing: 8) { OrderInfoRow(title: "付款金额", value: "¥\(item.actualPayAmount)", valueColor: AppDesign.primary) OrderInfoRow( title: "付款时间", value: OrderListUI.displayPayTime(payTime: item.payTime, depositPayTime: item.depositPayTime) ) OrderInfoRow(title: "完成时间", value: item.completeTime.isEmpty ? "--" : item.completeTime) OrderInfoRow(title: "付款方式", value: item.payTypeName.isEmpty ? "--" : item.payTypeName) OrderInfoRow(title: "用户 UID", value: "\(item.userId)") OrderInfoRow(title: "手机号", value: OrderListUI.maskPhone(item.phone)) { HStack(spacing: 7) { Text(OrderListUI.maskPhone(item.phone)) .font(.system(size: 14, weight: .medium)) .foregroundStyle(.black) if !hideOrderWriteActions { OrderPhoneCallButton(action: onCallPhone) } } } OrderInfoRow(title: "关联项目", value: item.projectName.isEmpty ? "--" : item.projectName) if let photoTravel = item.photoTravel, !photoTravel.checkInTime.isEmpty { OrderInfoRow(title: "核销时间", value: photoTravel.checkInTime) } if let photoTravel = item.photoTravel, item.orderType != 19, item.orderType != 14 { OrderGiftStepperRow( title: "修图张数", valueText: "\(photoTravel.orderPhotoNum + photoTravel.retouchGiftPhotoNum) 张", editable: photoTravel.canGiftRetouch && !hideOrderWriteActions, onTap: onSendGift ) OrderGiftStepperRow( title: "视频剪辑", valueText: "\(photoTravel.orderVideoNum + photoTravel.retouchGiftVideoNum) 条", editable: photoTravel.canGiftRetouch && !hideOrderWriteActions, onTap: onSendGift ) } } .padding(.top, 13) if !item.remark.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { Divider().overlay(AppDesign.orderInputBackground).padding(.top, 14) Text("备注信息:") .font(.system(size: 14)) .foregroundStyle(AppDesign.orderLabelColor) .padding(.top, 10) Text(item.remark) .font(.system(size: 14)) .foregroundStyle(AppDesign.orderLabelColor) .padding(.top, 6) } if let materials = item.multiTravel?.materialList, !materials.isEmpty { Divider().overlay(AppDesign.orderInputBackground).padding(.top, 12) Text("历史拍摄信息:") .font(.system(size: 14)) .foregroundStyle(AppDesign.orderLabelColor) .padding(.top, 12) Button(action: onHistoricalPhoto) { HStack(spacing: 8) { ForEach(Array(materials.prefix(3).enumerated()), id: \.offset) { index, material in ZStack { RemoteImage( urlString: material.previewURLString, contentMode: .fill ) { Color(hex: 0xF4F4F4) } .aspectRatio(1.59, contentMode: .fill) .clipShape(RoundedRectangle(cornerRadius: 8)) if materials.count > 3 && index == 2 { RoundedRectangle(cornerRadius: 8) .fill(Color.black.opacity(0.5)) Text("查看更多") .font(.system(size: 14, weight: .medium)) .foregroundStyle(.white) } } .frame(maxWidth: .infinity) } } } .buttonStyle(.plain) .padding(.top, 8) } if item.photoTravel?.canCancelOrder == true && !hideOrderWriteActions { OrderActionButton(title: "取消订单", action: onCancelOrder) .padding(.top, 12) } } .padding(16) .frame(maxWidth: .infinity, alignment: .leading) .background(.white, in: RoundedRectangle(cornerRadius: 12)) .accessibilityIdentifier("orders.store.card.\(item.orderNumber)") } }