Implement statistics tab aligned with Android and fix summary decode.
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>
This commit is contained in:
134
suixinkan/Features/Statistics/Models/StatisticsModels.swift
Normal file
134
suixinkan/Features/Statistics/Models/StatisticsModels.swift
Normal file
@ -0,0 +1,134 @@
|
||||
//
|
||||
// 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 = "全部"
|
||||
}
|
||||
Reference in New Issue
Block a user