208 lines
7.2 KiB
Swift
208 lines
7.2 KiB
Swift
//
|
||
// OrderDialogViews.swift
|
||
// suixinkan
|
||
//
|
||
// Created by Codex on 2026/6/29.
|
||
//
|
||
|
||
import SwiftUI
|
||
|
||
/// 普通订单退款弹窗,对齐 Android OrderRefundDialog。
|
||
struct OrderRefundDialogView: View {
|
||
@ObservedObject var viewModel: OrderRefundViewModel
|
||
let order: OrderEntity
|
||
let onDismiss: () -> Void
|
||
let onSuccess: () -> Void
|
||
|
||
@Environment(\.ordersAPI) private var ordersAPI
|
||
|
||
var body: some View {
|
||
NavigationStack {
|
||
Form {
|
||
Section("订单号") {
|
||
Text(order.orderNumber)
|
||
}
|
||
|
||
Section("退款方式") {
|
||
Picker("退款方式", selection: $viewModel.mode) {
|
||
ForEach(OrderRefundMode.allCases) { mode in
|
||
Text(mode.title).tag(mode)
|
||
}
|
||
}
|
||
.pickerStyle(.segmented)
|
||
|
||
if viewModel.mode == .partial {
|
||
TextField("退款金额", text: $viewModel.amount)
|
||
.keyboardType(.decimalPad)
|
||
} else {
|
||
Text("可退金额:¥\(viewModel.availableAmountText(for: order))")
|
||
.foregroundStyle(AppDesign.textSecondary)
|
||
}
|
||
}
|
||
|
||
Section("退款原因") {
|
||
TextField("请输入退款原因", text: $viewModel.reason, axis: .vertical)
|
||
.lineLimit(3...6)
|
||
}
|
||
|
||
if let errorMessage = viewModel.errorMessage {
|
||
Section {
|
||
Text(errorMessage)
|
||
.foregroundStyle(.red)
|
||
}
|
||
}
|
||
}
|
||
.navigationTitle("订单退款")
|
||
.navigationBarTitleDisplayMode(.inline)
|
||
.toolbar {
|
||
ToolbarItem(placement: .cancellationAction) {
|
||
Button("取消", action: onDismiss)
|
||
}
|
||
ToolbarItem(placement: .confirmationAction) {
|
||
Button(viewModel.submitting ? "提交中" : "确认") {
|
||
Task {
|
||
let success = await viewModel.submit(api: ordersAPI, item: order)
|
||
if success {
|
||
onSuccess()
|
||
}
|
||
}
|
||
}
|
||
.disabled(viewModel.submitting)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 赠送修图/视频弹窗,对齐 Android SendGiftDialog。
|
||
struct SendGiftDialogView: View {
|
||
@State private var photoNum: Int
|
||
@State private var videoNum: Int
|
||
let context: OrdersViewModel.SendGiftContext
|
||
let onDismiss: () -> Void
|
||
let onConfirm: (Int, Int) -> Void
|
||
|
||
init(context: OrdersViewModel.SendGiftContext, onDismiss: @escaping () -> Void, onConfirm: @escaping (Int, Int) -> Void) {
|
||
self.context = context
|
||
self.onDismiss = onDismiss
|
||
self.onConfirm = onConfirm
|
||
_photoNum = State(initialValue: context.sendPhotoNum)
|
||
_videoNum = State(initialValue: context.sendVideoNum)
|
||
}
|
||
|
||
var body: some View {
|
||
NavigationStack {
|
||
Form {
|
||
Section {
|
||
stepperRow(
|
||
title: "修图张数(已有\(context.nowPhotoNum)张,最多赠20张)",
|
||
value: $photoNum,
|
||
range: 0...20
|
||
)
|
||
stepperRow(
|
||
title: "视频剪辑(已有\(context.nowVideoNum)条,最多赠5条)",
|
||
value: $videoNum,
|
||
range: 0...5
|
||
)
|
||
}
|
||
}
|
||
.navigationTitle("赠送修图/视频")
|
||
.navigationBarTitleDisplayMode(.inline)
|
||
.toolbar {
|
||
ToolbarItem(placement: .cancellationAction) {
|
||
Button("取消", action: onDismiss)
|
||
}
|
||
ToolbarItem(placement: .confirmationAction) {
|
||
Button("确认") {
|
||
onConfirm(photoNum, videoNum)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private func stepperRow(title: String, value: Binding<Int>, range: ClosedRange<Int>) -> some View {
|
||
HStack {
|
||
Text(title)
|
||
.font(.system(size: 13))
|
||
.foregroundStyle(AppDesign.orderLabelColor)
|
||
Spacer()
|
||
Button("-") { value.wrappedValue = max(range.lowerBound, value.wrappedValue - 1) }
|
||
.buttonStyle(.plain)
|
||
Text("\(value.wrappedValue)")
|
||
.frame(minWidth: 30)
|
||
Button("+") { value.wrappedValue = min(range.upperBound, value.wrappedValue + 1) }
|
||
.buttonStyle(.plain)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 店长订单退款弹窗,支持全额/部分退款。
|
||
struct StoreOrderRefundDialogView: View {
|
||
let orderNumber: String
|
||
let actualPayAmount: String
|
||
let initialMode: OrderRefundMode
|
||
let onDismiss: () -> Void
|
||
let onConfirm: (OrderRefundMode, String, String) -> Void
|
||
|
||
@State private var mode: OrderRefundMode
|
||
@State private var amount = ""
|
||
@State private var reason = ""
|
||
|
||
init(
|
||
orderNumber: String,
|
||
actualPayAmount: String,
|
||
initialMode: OrderRefundMode,
|
||
onDismiss: @escaping () -> Void,
|
||
onConfirm: @escaping (OrderRefundMode, String, String) -> Void
|
||
) {
|
||
self.orderNumber = orderNumber
|
||
self.actualPayAmount = actualPayAmount
|
||
self.initialMode = initialMode
|
||
self.onDismiss = onDismiss
|
||
self.onConfirm = onConfirm
|
||
_mode = State(initialValue: initialMode)
|
||
_amount = State(initialValue: actualPayAmount)
|
||
}
|
||
|
||
var body: some View {
|
||
NavigationStack {
|
||
Form {
|
||
Section("订单号") {
|
||
Text(orderNumber)
|
||
}
|
||
Section("退款方式") {
|
||
Picker("退款方式", selection: $mode) {
|
||
ForEach(OrderRefundMode.allCases) { item in
|
||
Text(item.title).tag(item)
|
||
}
|
||
}
|
||
.pickerStyle(.segmented)
|
||
if mode == .partial {
|
||
TextField("退款金额", text: $amount)
|
||
.keyboardType(.decimalPad)
|
||
}
|
||
}
|
||
Section("退款原因") {
|
||
TextField("请输入退款原因", text: $reason, axis: .vertical)
|
||
.lineLimit(3...6)
|
||
}
|
||
}
|
||
.navigationTitle("申请退款")
|
||
.navigationBarTitleDisplayMode(.inline)
|
||
.toolbar {
|
||
ToolbarItem(placement: .cancellationAction) {
|
||
Button("取消", action: onDismiss)
|
||
}
|
||
ToolbarItem(placement: .confirmationAction) {
|
||
Button("提交") {
|
||
let refundAmount = mode == .full ? actualPayAmount : amount
|
||
onConfirm(mode, refundAmount, reason)
|
||
}
|
||
.disabled(reason.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|