@@ -35,6 +35,12 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
3535 var publicKey : String = " " // publicKey(reality): reality
3636 var shortId : String = " " // shortId(reality): reality
3737 var spiderX : String = " " // spiderX(reality): reality
38+ // 统计
39+ var totalUp : Int64 = 0 // 总上传
40+ var totalDown : Int64 = 0 // 总下载
41+ var todayUp : Int64 = 0 // 今日上传
42+ var todayDown : Int64 = 0 // 今日下载
43+ var lastUpdate : Date = Date ( ) // 最后更新时间
3844
3945 // Identifiable 协议的要求
4046 var id : String {
@@ -49,7 +55,7 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
4955
5056 // 对应编码的 `CodingKeys` 枚举
5157 enum CodingKeys : String , CodingKey {
52- case uuid, remark, speed, sort, `protocol`, subid, address, port, password, alterId, encryption, network, headerType, host, path, security, allowInsecure, flow, sni, alpn, fingerprint, publicKey, shortId, spiderX
58+ case uuid, remark, speed, sort, `protocol`, subid, address, port, password, alterId, encryption, network, headerType, host, path, security, allowInsecure, flow, sni, alpn, fingerprint, publicKey, shortId, spiderX, totalUp , totalDown , todayUp , todayDown , lastUpdate
5359 }
5460
5561 // 提供默认值的初始化器
@@ -103,6 +109,10 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
103109 self . publicKey = publicKey
104110 self . shortId = shortId
105111 self . spiderX = spiderX
112+ self . totalUp = 0
113+ self . totalDown = 0
114+ self . todayUp = 0
115+ self . todayDown = 0
106116 }
107117
108118 // 自定义表名
@@ -136,6 +146,12 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
136146 static let publicKey = Column ( CodingKeys . publicKey)
137147 static let shortId = Column ( CodingKeys . shortId)
138148 static let spiderX = Column ( CodingKeys . spiderX)
149+ // 统计
150+ static let totalUp = Column ( CodingKeys . totalUp)
151+ static let totalDown = Column ( CodingKeys . totalDown)
152+ static let todayUp = Column ( CodingKeys . todayUp)
153+ static let todayDown = Column ( CodingKeys . todayDown)
154+ static let lastUpdate = Column ( CodingKeys . lastUpdate)
139155 }
140156
141157 // 定义迁移
@@ -144,7 +160,7 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
144160 migrator. registerMigration ( " createProfileTable " ) { db in
145161 try db. create ( table: databaseTableName) { t in
146162 t. column ( Columns . uuid. name, . text) . notNull ( ) . primaryKey ( )
147- t. column ( Columns . remark. name, . text) . notNull ( )
163+ t. column ( Columns . remark. name, . text) . notNull ( ) . defaults ( to : " " )
148164 t. column ( Columns . speed. name, . integer) . notNull ( )
149165 t. column ( Columns . sort. name, . integer) . notNull ( )
150166 t. column ( Columns . protocol. name, . text) . notNull ( )
@@ -167,6 +183,12 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
167183 t. column ( Columns . publicKey. name, . text)
168184 t. column ( Columns . shortId. name, . text)
169185 t. column ( Columns . spiderX. name, . text)
186+ // 统计
187+ t. column ( Columns . totalUp. name, . integer) . notNull ( ) . defaults ( to: 0 )
188+ t. column ( Columns . totalDown. name, . integer) . notNull ( ) . defaults ( to: 0 )
189+ t. column ( Columns . todayUp. name, . integer) . notNull ( ) . defaults ( to: 0 )
190+ t. column ( Columns . todayDown. name, . integer) . notNull ( ) . defaults ( to: 0 )
191+ t. column ( Columns . lastUpdate. name, . datetime) . defaults ( to: " CURRENT_DATETIME " )
170192 }
171193 }
172194 }
@@ -181,6 +203,73 @@ struct ProfileDTO: Codable, Identifiable, Equatable, Hashable, Transferable, Tab
181203 logger. info ( " save error: \( error) " )
182204 }
183205 }
206+
207+ /// 更新 `profile_stat` 表中指定 `uuid` 的统计数据
208+ static func update_stat( uuid: String , up: Int , down: Int , lastUpdate: Date ) throws {
209+ let sql = """
210+ UPDATE profile
211+ SET
212+ todayUp = todayUp + ?,
213+ todayDown = todayDown + ?,
214+ totalUp = totalUp + ?,
215+ totalDown = totalDown + ?,
216+ lastUpdate = ?
217+ WHERE uuid = ?
218+ """
219+ do {
220+ let dbWriter = AppDatabase . shared. dbWriter
221+ try dbWriter. write { db in
222+ try db. execute (
223+ sql: sql,
224+ arguments: [ up, down, up, down, lastUpdate, uuid]
225+ )
226+ }
227+ } catch {
228+ logger. info ( " update_stat error: \( error) " )
229+ }
230+ }
231+
232+ /// 清空 `profile_stat` 表中指定 `uuid` 的今日数据
233+ /// 如果 `lastUpdate` 日期非今天,则将 `todayUp` 和 `todayDown` 清零,并更新 `lastUpdate` 为当前时间
234+ /// - Parameters:
235+ /// - uuid: 唯一标识符
236+ static func clearTodayData( uuid: String ) throws {
237+ // 获取当前日期的开始时间(00:00:00)
238+ let calendar = Calendar . current
239+ let todayStart = calendar. startOfDay ( for: Date ( ) )
240+ do {
241+ let dbReader = AppDatabase . shared. reader
242+ return try dbReader. read { db in
243+ let sql = " SELECT lastUpdate FROM profile WHERE uuid = ? "
244+ // 查询指定 `uuid` 的 `lastUpdate`
245+ guard let lastUpdate: Date = try Date . fetchOne ( db, sql: sql, arguments: [ uuid] ) else {
246+ // 如果未查询到记录,直接返回
247+ return
248+ }
249+ // 如果 `lastUpdate` 小于今日开始时间,表示非今天,需要清空今日数据
250+ if lastUpdate < todayStart {
251+ do {
252+ let dbWriter = AppDatabase . shared. dbWriter
253+ return try dbWriter. write { db in
254+ try db. execute (
255+ sql: """
256+ UPDATE profile
257+ SET todayUp = 0, todayDown = 0, lastUpdate = ?
258+ WHERE uuid = ?
259+ """ ,
260+ arguments: [ Date ( ) , uuid]
261+ )
262+ }
263+ } catch {
264+ logger. info ( " getFastOne error: \( error) " )
265+ }
266+ }
267+ }
268+ } catch {
269+ logger. info ( " clearTodayData error: \( error) " )
270+ return
271+ }
272+ }
184273}
185274
186275// MARK: - UI Model (SwiftUI 绑定)
0 commit comments