Add role-based analyse APIs, summary/daily UI with date range sheet, and flexible parsing for string refund amounts from the backend. Co-authored-by: Cursor <cursoragent@cursor.com>
135 lines
3.9 KiB
Swift
135 lines
3.9 KiB
Swift
//
|
||
// StatisticsModels.swift
|
||
// suixinkan
|
||
//
|
||
|
||
import Foundation
|
||
|
||
/// 数据统计汇总响应,对齐 Android `StatisticsResponse`。
|
||
struct StatisticsSummaryResponse: Decodable, Equatable {
|
||
let orderAmountSum: String
|
||
let orderCount: Int
|
||
let orderPriceAvg: String
|
||
let receivedAmountSum: String
|
||
let refundAmountSum: String
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case orderAmountSum = "order_amount_sum"
|
||
case orderCount = "order_count"
|
||
case orderPriceAvg = "order_price_avg"
|
||
case receivedAmountSum = "received_amount_sum"
|
||
case refundAmountSum = "refund_amount_sum"
|
||
}
|
||
|
||
init(
|
||
orderAmountSum: String = "",
|
||
orderCount: Int = 0,
|
||
orderPriceAvg: String = "",
|
||
receivedAmountSum: String = "",
|
||
refundAmountSum: String = ""
|
||
) {
|
||
self.orderAmountSum = orderAmountSum
|
||
self.orderCount = orderCount
|
||
self.orderPriceAvg = orderPriceAvg
|
||
self.receivedAmountSum = receivedAmountSum
|
||
self.refundAmountSum = refundAmountSum
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||
orderAmountSum = try container.decodeIfPresent(String.self, forKey: .orderAmountSum) ?? ""
|
||
orderCount = try container.decodeIfPresent(Int.self, forKey: .orderCount) ?? 0
|
||
orderPriceAvg = try container.decodeIfPresent(String.self, forKey: .orderPriceAvg) ?? ""
|
||
receivedAmountSum = try container.decodeIfPresent(String.self, forKey: .receivedAmountSum) ?? ""
|
||
refundAmountSum = Self.decodeAmountString(from: container, forKey: .refundAmountSum)
|
||
}
|
||
|
||
private static func decodeAmountString(
|
||
from container: KeyedDecodingContainer<CodingKeys>,
|
||
forKey key: CodingKeys
|
||
) -> String {
|
||
if let value = try? container.decode(String.self, forKey: key) {
|
||
return value
|
||
}
|
||
if let value = try? container.decode(Double.self, forKey: key) {
|
||
return String(value)
|
||
}
|
||
if let value = try? container.decode(Int.self, forKey: key) {
|
||
return String(value)
|
||
}
|
||
return ""
|
||
}
|
||
}
|
||
|
||
/// 数据统计日明细行,对齐 Android `StatisticsPageEntity`。
|
||
struct StatisticsDailyItem: Decodable, Hashable {
|
||
let date: String
|
||
let orderCount: Int
|
||
let orderPrice: String
|
||
let refund: String
|
||
let received: String
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case date
|
||
case orderCount = "order_count"
|
||
case orderPrice = "order_price"
|
||
case refund
|
||
case received
|
||
}
|
||
|
||
init(
|
||
date: String = "",
|
||
orderCount: Int = 0,
|
||
orderPrice: String = "",
|
||
refund: String = "",
|
||
received: String = ""
|
||
) {
|
||
self.date = date
|
||
self.orderCount = orderCount
|
||
self.orderPrice = orderPrice
|
||
self.refund = refund
|
||
self.received = received
|
||
}
|
||
}
|
||
|
||
/// 分页列表响应,对齐 Android `ListDataResponse`。
|
||
struct ListDataResponse<T: Decodable>: Decodable {
|
||
let total: Int
|
||
let data: [T]
|
||
|
||
init(total: Int = 0, data: [T] = []) {
|
||
self.total = total
|
||
self.data = data
|
||
}
|
||
}
|
||
|
||
/// 汇总区周期选项,对齐 Android 顶部 chip。
|
||
enum StatisticsSummaryPeriod: String, CaseIterable {
|
||
case today = "今日"
|
||
case yesterday = "昨日"
|
||
case last7Days = "7日"
|
||
case thisMonth = "本月"
|
||
|
||
/// 汇总 API 的 `range` 参数值。
|
||
var rangeValue: String {
|
||
switch self {
|
||
case .today: "1"
|
||
case .yesterday: "2"
|
||
case .last7Days: "3"
|
||
case .thisMonth: "4"
|
||
}
|
||
}
|
||
|
||
static func fromDisplayName(_ name: String) -> StatisticsSummaryPeriod? {
|
||
StatisticsSummaryPeriod(rawValue: name)
|
||
}
|
||
}
|
||
|
||
/// 列表区日期快捷选项,对齐 Android `DateRangeBottomSheet` 快捷按钮。
|
||
enum StatisticsRangeShortcut: String, CaseIterable {
|
||
case today = "今日"
|
||
case yesterday = "昨日"
|
||
case last7Days = "7日"
|
||
case all = "全部"
|
||
}
|