Add order tail flows and migrate queue, message, settlement, and audit modules.
Wire deposit orders, historical shooting, and multi-travel uploads into Orders, and replace home placeholders for queue management, message center, scenic settlement, and withdrawal audit. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -17,6 +17,8 @@ struct StoreOrderDetailView: View {
|
||||
|
||||
let item: OrderEntity
|
||||
@State private var viewModel: OrderDetailViewModel
|
||||
@State private var refundViewModel = OrderRefundViewModel()
|
||||
@State private var showRefundSheet = false
|
||||
|
||||
/// 使用列表订单初始化详情页,并创建详情 ViewModel。
|
||||
init(item: OrderEntity) {
|
||||
@ -96,10 +98,36 @@ struct StoreOrderDetailView: View {
|
||||
}
|
||||
|
||||
Section("后续功能") {
|
||||
placeholderButton("历史拍摄", title: "历史拍摄")
|
||||
placeholderButton("任务上传", title: "任务上传")
|
||||
placeholderButton("视频预告", title: "视频预告")
|
||||
placeholderButton("退款", title: "订单退款")
|
||||
Button {
|
||||
router.navigate(to: .orders(.historicalShooting(orderNumber: viewModel.display.orderNumber)))
|
||||
} label: {
|
||||
navigationRow("历史拍摄")
|
||||
}
|
||||
if item.orderType == 19 {
|
||||
Button {
|
||||
router.navigate(to: .orders(.multiTravelTaskUpload(orderNumber: viewModel.display.orderNumber)))
|
||||
} label: {
|
||||
navigationRow("任务上传")
|
||||
}
|
||||
}
|
||||
Button {
|
||||
router.navigate(to: .orders(.orderTrailer(orderNumber: viewModel.display.orderNumber, title: "视频预告")))
|
||||
} label: {
|
||||
navigationRow("视频预告")
|
||||
}
|
||||
Button {
|
||||
router.navigate(to: .orders(.orderTrailer(orderNumber: viewModel.display.orderNumber, title: "尾片上传")))
|
||||
} label: {
|
||||
navigationRow("尾片上传")
|
||||
}
|
||||
if refundViewModel.canRefund(item) {
|
||||
Button {
|
||||
refundViewModel.begin(item: item)
|
||||
showRefundSheet = true
|
||||
} label: {
|
||||
navigationRow("退款")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
@ -117,6 +145,17 @@ struct StoreOrderDetailView: View {
|
||||
} message: {
|
||||
Text(viewModel.errorMessage ?? "")
|
||||
}
|
||||
.sheet(isPresented: $showRefundSheet) {
|
||||
OrderRefundSheet(
|
||||
item: item,
|
||||
viewModel: refundViewModel,
|
||||
onCancel: { showRefundSheet = false },
|
||||
onSubmit: {
|
||||
Task { await submitRefund() }
|
||||
}
|
||||
)
|
||||
.presentationDetents([.medium, .large])
|
||||
}
|
||||
}
|
||||
|
||||
private var displayPayTime: String {
|
||||
@ -136,20 +175,24 @@ struct StoreOrderDetailView: View {
|
||||
)
|
||||
}
|
||||
|
||||
/// 构建尚未迁移业务入口的占位按钮。
|
||||
private func placeholderButton(_ label: String, title: String) -> some View {
|
||||
Button {
|
||||
router.navigate(to: .placeholder(title: title))
|
||||
} label: {
|
||||
HStack {
|
||||
Text(label)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
|
||||
.foregroundStyle(AppDesign.textSecondary)
|
||||
}
|
||||
/// 构建可跳转业务入口行。
|
||||
private func navigationRow(_ label: String) -> some View {
|
||||
HStack {
|
||||
Text(label)
|
||||
Spacer()
|
||||
Image(systemName: "chevron.right")
|
||||
.font(.system(size: AppMetrics.FontSize.caption, weight: .semibold))
|
||||
.foregroundStyle(AppDesign.textSecondary)
|
||||
}
|
||||
.foregroundStyle(AppDesign.textPrimary)
|
||||
}
|
||||
|
||||
/// 提交普通订单退款并刷新详情。
|
||||
private func submitRefund() async {
|
||||
let success = await refundViewModel.submit(api: ordersAPI, item: item)
|
||||
guard success else { return }
|
||||
showRefundSheet = false
|
||||
toastCenter.show("退款申请已提交")
|
||||
await viewModel.load(api: ordersAPI, fallbackStoreId: accountContext.currentStore?.id, forceReload: true)
|
||||
}
|
||||
|
||||
/// 将空金额转换为 0,避免详情页出现孤立货币符号。
|
||||
@ -158,6 +201,79 @@ struct StoreOrderDetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
/// 普通订单退款表单,负责收集退款模式、金额和原因。
|
||||
private struct OrderRefundSheet: View {
|
||||
let item: OrderEntity
|
||||
@Bindable var viewModel: OrderRefundViewModel
|
||||
let onCancel: () -> Void
|
||||
let onSubmit: () -> Void
|
||||
@FocusState private var focusedField: RefundInputField?
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section("订单") {
|
||||
OrderDetailRow(title: "订单号", value: item.orderNumber)
|
||||
OrderDetailRow(title: "可退金额", value: "¥\(viewModel.availableAmountText(for: item))")
|
||||
}
|
||||
|
||||
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)
|
||||
.focused($focusedField, equals: .amount)
|
||||
}
|
||||
}
|
||||
|
||||
Section("退款原因") {
|
||||
TextEditor(text: $viewModel.reason)
|
||||
.frame(minHeight: 96)
|
||||
.focused($focusedField, equals: .reason)
|
||||
}
|
||||
|
||||
if let errorMessage = viewModel.errorMessage {
|
||||
Section {
|
||||
Text(errorMessage)
|
||||
.font(.system(size: AppMetrics.FontSize.footnote))
|
||||
.foregroundStyle(Color(hex: 0xEF4444))
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle("订单退款")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("取消", action: onCancel)
|
||||
.disabled(viewModel.submitting)
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button(viewModel.submitting ? "提交中..." : "提交", action: onSubmit)
|
||||
.disabled(viewModel.submitting)
|
||||
}
|
||||
ToolbarItemGroup(placement: .keyboard) {
|
||||
Spacer()
|
||||
Button("完成") {
|
||||
focusedField = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 退款表单当前聚焦字段。
|
||||
private enum RefundInputField: Hashable {
|
||||
case amount
|
||||
case reason
|
||||
}
|
||||
|
||||
/// 核销订单详情页,展示核销列表项信息并支持再次发起核销。
|
||||
struct WriteOffOrderDetailView: View {
|
||||
@Environment(AccountContext.self) private var accountContext
|
||||
|
||||
Reference in New Issue
Block a user