新增门店订单与核销管理列表,对齐 Android 订单能力并完善账号级缓存。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-29 14:46:10 +08:00
parent c4de3d17d0
commit 08492df6ce
51 changed files with 3668 additions and 102 deletions

View File

@ -0,0 +1,101 @@
//
// DateRangePickerSheet.swift
// suixinkan
//
// Created by Codex on 2026/6/29.
//
import SwiftUI
/// Sheet Android DateRangePickerDialog
struct DateRangePickerSheet: View {
@Environment(\.dismiss) private var dismiss
let initialStartDate: Date?
let initialEndDate: Date?
let onConfirm: (Date?, Date?) -> Void
@State private var draftStartDate = Date()
@State private var draftEndDate = Date()
@State private var hasStartDate = false
@State private var hasEndDate = false
var body: some View {
NavigationStack {
Form {
Toggle("设置开始日期", isOn: $hasStartDate)
if hasStartDate {
DatePicker("开始日期", selection: $draftStartDate, displayedComponents: .date)
}
Toggle("设置结束日期", isOn: $hasEndDate)
if hasEndDate {
DatePicker("结束日期", selection: $draftEndDate, displayedComponents: .date)
}
}
.navigationTitle("时间筛选")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("清空") {
onConfirm(nil, nil)
dismiss()
}
}
ToolbarItem(placement: .confirmationAction) {
Button("确定") {
let start = hasStartDate ? draftStartDate : nil
let end = hasEndDate ? draftEndDate : nil
if let start, let end {
onConfirm(min(start, end), max(start, end))
} else {
onConfirm(start, end)
}
dismiss()
}
}
}
.onAppear {
if let initialStartDate {
draftStartDate = initialStartDate
hasStartDate = true
}
if let initialEndDate {
draftEndDate = initialEndDate
hasEndDate = true
}
}
}
}
}
///
enum OrderDateRangeFormatter {
private static let formatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
///
static func displayText(start: Date?, end: Date?, placeholder: String = "时间筛选") -> String {
let startText = start.map { formatter.string(from: $0) } ?? ""
let endText = end.map { formatter.string(from: $0) } ?? ""
switch (startText.isEmpty, endText.isEmpty) {
case (true, true):
return placeholder
case (false, false):
return "\(startText) - \(endText)"
case (false, true):
return "\(startText) - "
case (true, false):
return " - \(endText)"
}
}
/// API
static func queryValue(from date: Date?) -> String? {
guard let date else { return nil }
return formatter.string(from: date)
}
}