diff --git a/IosClientKit/Sources/CoreModel/Auth.swift b/IosClientKit/Sources/CoreModel/Auth.swift new file mode 100644 index 0000000..667f03e --- /dev/null +++ b/IosClientKit/Sources/CoreModel/Auth.swift @@ -0,0 +1,10 @@ +import Foundation + +/// 会话(极简,仅 token)。 +public struct Session: Hashable, Sendable { + public let token: String + + public init(token: String) { + self.token = token + } +} diff --git a/IosClientKit/Sources/CoreModel/Checkin.swift b/IosClientKit/Sources/CoreModel/Checkin.swift new file mode 100644 index 0000000..3996af7 --- /dev/null +++ b/IosClientKit/Sources/CoreModel/Checkin.swift @@ -0,0 +1,72 @@ +import Foundation + +/// 打卡状态(对应小程序 STATUSES / android CheckinStatus)。 +public enum CheckinStatus: String, CaseIterable, Hashable, Sendable { + case normal = "正常" + case late = "迟到" + case leave = "请假" + case absent = "不参加讨论" + case earlyLeave = "早退" +} + +/// 小组成员(打卡视角)。 +public struct GroupMember: Identifiable, Hashable, Sendable { + public let id: String + public let name: String + public let checkedIn: Bool + public let checkinTime: String? + public let status: CheckinStatus? + + public init(id: String, name: String, checkedIn: Bool, checkinTime: String?, status: CheckinStatus?) { + self.id = id + self.name = name + self.checkedIn = checkedIn + self.checkinTime = checkinTime + self.status = status + } +} + +/// 个人打卡历史条目。 +public struct PersonalCheckinRecord: Hashable, Sendable { + public let date: String + public let status: CheckinStatus + public let time: String + + public init(date: String, status: CheckinStatus, time: String) { + self.date = date + self.status = status + self.time = time + } +} + +/// 打卡页聚合数据。 +public struct CheckinRecord: Hashable, Sendable { + public let classDate: String + public let weekday: String + public let dayNum: Int + public let checked: Bool + public let status: CheckinStatus? + public let groupName: String + public let groupMembers: [GroupMember] + public let personalHistory: [PersonalCheckinRecord] + + public init( + classDate: String, + weekday: String, + dayNum: Int, + checked: Bool, + status: CheckinStatus?, + groupName: String, + groupMembers: [GroupMember], + personalHistory: [PersonalCheckinRecord] + ) { + self.classDate = classDate + self.weekday = weekday + self.dayNum = dayNum + self.checked = checked + self.status = status + self.groupName = groupName + self.groupMembers = groupMembers + self.personalHistory = personalHistory + } +} diff --git a/IosClientKit/Sources/CoreModel/Habit.swift b/IosClientKit/Sources/CoreModel/Habit.swift deleted file mode 100644 index a0dc84a..0000000 --- a/IosClientKit/Sources/CoreModel/Habit.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation - -/// 一个打卡习惯(对应 Android 端 Habit)。 -public struct Habit: Identifiable, Hashable, Sendable { - public let id: String - public let title: String - /// 备注 / 目标描述。 - public let detail: String - /// 今日是否已打卡。 - public let isCheckedInToday: Bool - /// 连续打卡天数。 - public let streakDays: Int - - public init( - id: String, - title: String, - detail: String, - isCheckedInToday: Bool, - streakDays: Int - ) { - self.id = id - self.title = title - self.detail = detail - self.isCheckedInToday = isCheckedInToday - self.streakDays = streakDays - } -} diff --git a/IosClientKit/Sources/CoreModel/HomeData.swift b/IosClientKit/Sources/CoreModel/HomeData.swift index a76e73f..95bc097 100644 --- a/IosClientKit/Sources/CoreModel/HomeData.swift +++ b/IosClientKit/Sources/CoreModel/HomeData.swift @@ -1,19 +1,65 @@ import Foundation -/// Home 页面的聚合数据(对应 Android 端 HomeData)。 -public struct HomeData: Identifiable, Hashable, Sendable { - public let id: String - /// 顶部问候语,例如「早上好,Andy」。 - public let greeting: String - /// 今日打卡摘要,例如「已完成 2 / 4」。 - public let summary: String - /// 今日待打卡的习惯列表。 - public let habits: [Habit] +/// 首页模块跳转目标。 +public enum ModuleDestination: Hashable, Sendable { + case checkin + case plan + case about +} - public init(id: String, greeting: String, summary: String, habits: [Habit]) { +/// 首页功能模块卡片(打卡介绍 / 计划介绍 / 关于我们)。 +public struct HomeModule: Identifiable, Hashable, Sendable { + public let id: String + public let emoji: String + public let title: String + public let description: String + public let destination: ModuleDestination + + public init( + id: String, + emoji: String, + title: String, + description: String, + destination: ModuleDestination + ) { self.id = id - self.greeting = greeting - self.summary = summary - self.habits = habits + self.emoji = emoji + self.title = title + self.description = description + self.destination = destination + } +} + +/// 产品介绍卡片。 +public struct IntroCard: Hashable, Sendable { + public let title: String + public let body: String + + public init(title: String, body: String) { + self.title = title + self.body = body + } +} + +/// 首页聚合数据(落地页)。 +public struct HomeData: Hashable, Sendable { + public let greeting: String + public let displayName: String + public let encouragement: String + public let modules: [HomeModule] + public let intros: [IntroCard] + + public init( + greeting: String, + displayName: String, + encouragement: String, + modules: [HomeModule], + intros: [IntroCard] + ) { + self.greeting = greeting + self.displayName = displayName + self.encouragement = encouragement + self.modules = modules + self.intros = intros } } diff --git a/IosClientKit/Sources/CoreModel/Plan.swift b/IosClientKit/Sources/CoreModel/Plan.swift new file mode 100644 index 0000000..4e24e9c --- /dev/null +++ b/IosClientKit/Sources/CoreModel/Plan.swift @@ -0,0 +1,119 @@ +import Foundation + +/// 计划类型(周/月/年)。 +public enum PlanType: String, CaseIterable, Hashable, Sendable { + case weekly + case monthly + case yearly + + public var label: String { + switch self { + case .weekly: return "周计划" + case .monthly: return "月计划" + case .yearly: return "年计划" + } + } +} + +/// 我提交的计划记录。 +public struct MyPlanRecord: Hashable, Sendable { + public let status: String + public let submittedTime: String + public let content: String + public let attachments: [String] + + public init(status: String, submittedTime: String, content: String, attachments: [String]) { + self.status = status + self.submittedTime = submittedTime + self.content = content + self.attachments = attachments + } +} + +/// 小组成员(计划视角)。 +public struct PlanMember: Identifiable, Hashable, Sendable { + public let id: String + public let name: String + public let filled: Bool + + public init(id: String, name: String, filled: Bool) { + self.id = id + self.name = name + self.filled = filled + } +} + +/// 小组计划统计(含成员)。 +public struct PlanGroup: Identifiable, Hashable, Sendable { + public let id: String + public let name: String + public let checkedCount: Int + public let memberCount: Int + public let members: [PlanMember] + + public init(id: String, name: String, checkedCount: Int, memberCount: Int, members: [PlanMember]) { + self.id = id + self.name = name + self.checkedCount = checkedCount + self.memberCount = memberCount + self.members = members + } +} + +/// 计划页聚合数据。 +public struct PlanRecord: Hashable, Sendable { + public let type: PlanType + public let periodKey: String + public let canSubmit: Bool + public let message: String? + public let myChecked: Bool + public let myRecord: MyPlanRecord? + public let groups: [PlanGroup] + public let unassignedCount: Int + + public init( + type: PlanType, + periodKey: String, + canSubmit: Bool, + message: String?, + myChecked: Bool, + myRecord: MyPlanRecord?, + groups: [PlanGroup], + unassignedCount: Int + ) { + self.type = type + self.periodKey = periodKey + self.canSubmit = canSubmit + self.message = message + self.myChecked = myChecked + self.myRecord = myRecord + self.groups = groups + self.unassignedCount = unassignedCount + } +} + +/// 提交计划页数据。 +public struct PlanSubmitData: Hashable, Sendable { + public let content: String + public let attachments: [String] + public let checked: Bool + public let canSubmit: Bool + public let message: String? + public let history: [MyPlanRecord] + + public init( + content: String, + attachments: [String], + checked: Bool, + canSubmit: Bool, + message: String?, + history: [MyPlanRecord] + ) { + self.content = content + self.attachments = attachments + self.checked = checked + self.canSubmit = canSubmit + self.message = message + self.history = history + } +} diff --git a/IosClientKit/Sources/CoreModel/Profile.swift b/IosClientKit/Sources/CoreModel/Profile.swift new file mode 100644 index 0000000..f5cccea --- /dev/null +++ b/IosClientKit/Sources/CoreModel/Profile.swift @@ -0,0 +1,53 @@ +import Foundation + +/// 用户所在的小组分组。 +public struct ClassGroup: Identifiable, Hashable, Sendable { + public let period: String + public let group: String + public let role: String + + public var id: String { period } + + public init(period: String, group: String, role: String) { + self.period = period + self.group = group + self.role = role + } +} + +/// 个人资料。 +public struct UserProfile: Identifiable, Hashable, Sendable { + public let displayName: String + public let name: String + public let studentId: String + public let phone: String? + public let role: String + public let group: String? + public let loginType: String + public let avatarUrl: String? + public let classGroups: [ClassGroup] + + public var id: String { studentId } + + public init( + displayName: String, + name: String, + studentId: String, + phone: String?, + role: String, + group: String?, + loginType: String, + avatarUrl: String?, + classGroups: [ClassGroup] + ) { + self.displayName = displayName + self.name = name + self.studentId = studentId + self.phone = phone + self.role = role + self.group = group + self.loginType = loginType + self.avatarUrl = avatarUrl + self.classGroups = classGroups + } +}