feat: 重造领域模型并对齐 android(home/checkin/plan/profile/session)
This commit is contained in:
10
IosClientKit/Sources/CoreModel/Auth.swift
Normal file
10
IosClientKit/Sources/CoreModel/Auth.swift
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// 会话(极简,仅 token)。
|
||||||
|
public struct Session: Hashable, Sendable {
|
||||||
|
public let token: String
|
||||||
|
|
||||||
|
public init(token: String) {
|
||||||
|
self.token = token
|
||||||
|
}
|
||||||
|
}
|
||||||
72
IosClientKit/Sources/CoreModel/Checkin.swift
Normal file
72
IosClientKit/Sources/CoreModel/Checkin.swift
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,65 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Home 页面的聚合数据(对应 Android 端 HomeData)。
|
/// 首页模块跳转目标。
|
||||||
public struct HomeData: Identifiable, Hashable, Sendable {
|
public enum ModuleDestination: Hashable, Sendable {
|
||||||
public let id: String
|
case checkin
|
||||||
/// 顶部问候语,例如「早上好,Andy」。
|
case plan
|
||||||
public let greeting: String
|
case about
|
||||||
/// 今日打卡摘要,例如「已完成 2 / 4」。
|
}
|
||||||
public let summary: String
|
|
||||||
/// 今日待打卡的习惯列表。
|
|
||||||
public let habits: [Habit]
|
|
||||||
|
|
||||||
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.id = id
|
||||||
|
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.greeting = greeting
|
||||||
self.summary = summary
|
self.displayName = displayName
|
||||||
self.habits = habits
|
self.encouragement = encouragement
|
||||||
|
self.modules = modules
|
||||||
|
self.intros = intros
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
119
IosClientKit/Sources/CoreModel/Plan.swift
Normal file
119
IosClientKit/Sources/CoreModel/Plan.swift
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
53
IosClientKit/Sources/CoreModel/Profile.swift
Normal file
53
IosClientKit/Sources/CoreModel/Profile.swift
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user