From 28fc0a1026a45c386bf58899a068fef49a965184 Mon Sep 17 00:00:00 2001 From: AndyChen1024 Date: Fri, 11 Sep 2026 20:47:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(entry):=20=E6=96=B0=E5=A2=9E=E6=9C=AC?= =?UTF-8?q?=E5=9C=B0=20mock=20=E6=95=B0=E6=8D=AE=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ets/data/repository/CheckinRepository.ets | 78 ++++++++++++++++ .../ets/data/repository/HomeRepository.ets | 93 +++++++++++++++++++ .../src/main/ets/data/repository/MockUtil.ets | 8 ++ .../ets/data/repository/PlanRepository.ets | 56 +++++++++++ .../ets/data/repository/ProfileRepository.ets | 43 +++++++++ .../ets/data/repository/SessionRepository.ets | 30 ++++++ 6 files changed, 308 insertions(+) create mode 100644 entry/src/main/ets/data/repository/CheckinRepository.ets create mode 100644 entry/src/main/ets/data/repository/HomeRepository.ets create mode 100644 entry/src/main/ets/data/repository/MockUtil.ets create mode 100644 entry/src/main/ets/data/repository/PlanRepository.ets create mode 100644 entry/src/main/ets/data/repository/ProfileRepository.ets create mode 100644 entry/src/main/ets/data/repository/SessionRepository.ets diff --git a/entry/src/main/ets/data/repository/CheckinRepository.ets b/entry/src/main/ets/data/repository/CheckinRepository.ets new file mode 100644 index 0000000..2cd6e0c --- /dev/null +++ b/entry/src/main/ets/data/repository/CheckinRepository.ets @@ -0,0 +1,78 @@ +import { CheckinRecord, CheckinStatus, GroupMember, PersonalCheckinRecord } from '../../model/CheckinModels'; +import { mockDelay } from './MockUtil'; + +/** + * 打卡数据仓库契约。 + */ +export abstract class CheckinRepository { + abstract observeCheckin(): Promise; + abstract submitCheckin(status: string): Promise; +} + +/** + * 本地 mock 实现:内存 seed,提交更新自身状态。 + */ +export class FakeCheckinRepository extends CheckinRepository { + private record: CheckinRecord = FakeCheckinRepository.seed(); + + async observeCheckin(): Promise { + await mockDelay(250); + return this.record; + } + + async submitCheckin(status: string): Promise { + await mockDelay(300); + this.record.checked = true; + this.record.status = status; + // 更新"我"(第一个成员)在小组成员列表里的状态 + if (this.record.groupMembers.length > 0) { + const me = this.record.groupMembers[0]; + me.checkedIn = true; + me.status = status; + me.checkinTime = '今天 09:12'; + } + return this.record; + } + + private static seed(): CheckinRecord { + const r = new CheckinRecord(); + r.classDate = '2026-09-06'; + r.weekday = '周日'; + r.dayNum = '06'; + r.checked = false; + r.status = ''; + r.groupName = '进阶一组'; + r.groupMembers = [ + FakeCheckinRepository.member('u-1001', '张三', false, '', ''), + FakeCheckinRepository.member('u-1002', '李四', true, CheckinStatus.NORMAL, '今天 09:05'), + FakeCheckinRepository.member('u-1003', '王五', true, CheckinStatus.LATE, '今天 09:18'), + FakeCheckinRepository.member('u-1004', '赵六', false, '', ''), + FakeCheckinRepository.member('u-1005', '孙七', true, CheckinStatus.LEAVE, '今天 08:40') + ]; + r.personalHistory = [ + FakeCheckinRepository.history('h-1', '2026-08-30', CheckinStatus.NORMAL, '08:52'), + FakeCheckinRepository.history('h-2', '2026-08-23', CheckinStatus.LATE, '09:21'), + FakeCheckinRepository.history('h-3', '2026-08-16', CheckinStatus.ABSENT, '--') + ]; + return r; + } + + private static member(id: string, name: string, checkedIn: boolean, status: string, checkinTime: string): GroupMember { + const m = new GroupMember(); + m.id = id; + m.name = name; + m.checkedIn = checkedIn; + m.status = status; + m.checkinTime = checkinTime; + return m; + } + + private static history(id: string, date: string, status: string, time: string): PersonalCheckinRecord { + const h = new PersonalCheckinRecord(); + h.id = id; + h.date = date; + h.status = status; + h.time = time; + return h; + } +} diff --git a/entry/src/main/ets/data/repository/HomeRepository.ets b/entry/src/main/ets/data/repository/HomeRepository.ets new file mode 100644 index 0000000..1aa6ea4 --- /dev/null +++ b/entry/src/main/ets/data/repository/HomeRepository.ets @@ -0,0 +1,93 @@ +import { HomeData, HomeModule, IntroCard } from '../../model/HomeModels'; +import { mockDelay } from './MockUtil'; + +/** + * 首页数据仓库契约。 + */ +export abstract class HomeRepository { + abstract observeHome(): Promise; + abstract observeGuestHome(): Promise; +} + +/** + * 本地 mock 实现:登录态与游客态两套 seed。 + */ +export class FakeHomeRepository extends HomeRepository { + async observeHome(): Promise { + await mockDelay(250); + return FakeHomeRepository.seed(true); + } + + async observeGuestHome(): Promise { + await mockDelay(250); + return FakeHomeRepository.seed(false); + } + + private static seed(loggedIn: boolean): HomeData { + const data = new HomeData(); + if (loggedIn) { + data.greeting = '晚上好'; + data.displayName = '张三'; + data.encouragement = '每日精进,持续成长'; + } else { + data.greeting = '欢迎来到明缘云道场'; + data.displayName = '游客'; + data.encouragement = '登录后即可打卡、提交计划'; + } + data.modules = FakeHomeRepository.buildModules(); + data.intros = FakeHomeRepository.buildIntros(); + return data; + } + + private static buildModules(): HomeModule[] { + const checkin = new HomeModule(); + checkin.id = 'checkin'; + checkin.emoji = '📋'; + checkin.title = '打卡介绍'; + checkin.description = '每日打卡记录'; + + const plan = new HomeModule(); + plan.id = 'plan'; + plan.emoji = '📝'; + plan.title = '计划介绍'; + plan.description = '周/月/年计划'; + + const about = new HomeModule(); + about.id = 'about'; + about.emoji = 'ℹ️'; + about.title = '关于我们'; + about.description = '了解明缘云道场'; + + return [checkin, plan, about]; + } + + private static buildIntros(): IntroCard[] { + const list: IntroCard[] = []; + + const learn = new IntroCard(); + learn.emoji = '📚'; + learn.heading = '学习成长工具'; + learn.body = '明缘云道场是一款专注于个人成长的效率工具,通过每周打卡与计划管理,帮助你养成良好的学习习惯。'; + list.push(learn); + + const checkin = new IntroCard(); + checkin.emoji = '✅'; + checkin.heading = '周打卡'; + checkin.body = '每周打卡,支持多种状态记录。查看小组打卡情况,与同学们互相监督、共同进步。'; + list.push(checkin); + + const plan = new IntroCard(); + plan.emoji = '📝'; + plan.heading = '计划管理'; + plan.body = '提供周计划、月计划、年计划三级管理,支持文字与图片上传,让成长有迹可循。'; + list.push(plan); + + const group = new IntroCard(); + group.emoji = '👥'; + group.heading = '小组共学'; + group.body = '加入学习小组,查看组员的打卡与计划完成情况,与志同道合的伙伴一起成长。'; + list.push(group); + + return list; + } +} diff --git a/entry/src/main/ets/data/repository/MockUtil.ets b/entry/src/main/ets/data/repository/MockUtil.ets new file mode 100644 index 0000000..56793f2 --- /dev/null +++ b/entry/src/main/ets/data/repository/MockUtil.ets @@ -0,0 +1,8 @@ +/** + * mock 延迟工具:模拟网络往返,让加载态可见。 + */ +export function mockDelay(ms: number): Promise { + return new Promise((resolve: () => void) => { + setTimeout(resolve, ms); + }); +} diff --git a/entry/src/main/ets/data/repository/PlanRepository.ets b/entry/src/main/ets/data/repository/PlanRepository.ets new file mode 100644 index 0000000..791f136 --- /dev/null +++ b/entry/src/main/ets/data/repository/PlanRepository.ets @@ -0,0 +1,56 @@ +import { PlanGroup, PlanRecord, PlanType } from '../../model/PlanModels'; +import { mockDelay } from './MockUtil'; + +/** + * 计划数据仓库契约。 + */ +export abstract class PlanRepository { + abstract observePlan(type: string): Promise; +} + +/** + * 本地 mock 实现:按类型(周/月/年)缓存 seed。 + */ +export class FakePlanRepository extends PlanRepository { + private cache: Map = new Map(); + + constructor() { + super(); + this.cache.set(PlanType.WEEKLY, FakePlanRepository.seed(PlanType.WEEKLY, '2026-W37', '周四截止,请及时提交')); + this.cache.set(PlanType.MONTHLY, FakePlanRepository.seed(PlanType.MONTHLY, '2026-09', '')); + this.cache.set(PlanType.YEARLY, FakePlanRepository.seed(PlanType.YEARLY, '2026', '')); + } + + async observePlan(type: string): Promise { + await mockDelay(250); + const rec = this.cache.get(type); + return rec ? rec : FakePlanRepository.seed(type, '', ''); + } + + private static seed(type: string, periodKey: string, message: string): PlanRecord { + const r = new PlanRecord(); + r.type = type; + r.periodKey = periodKey; + r.canSubmit = true; + r.message = message; + r.myChecked = false; + r.myContent = ''; + r.mySubmittedTime = ''; + r.unassignedCount = 1; + r.groups = [ + FakePlanRepository.group('g-1', '进阶一组', 3, 5), + FakePlanRepository.group('g-2', '进阶二组', 4, 5), + FakePlanRepository.group('g-3', '进阶三组', 2, 4) + ]; + return r; + } + + private static group(id: string, name: string, checkedCount: number, memberCount: number): PlanGroup { + const g = new PlanGroup(); + g.id = id; + g.name = name; + g.checkedCount = checkedCount; + g.memberCount = memberCount; + return g; + } +} diff --git a/entry/src/main/ets/data/repository/ProfileRepository.ets b/entry/src/main/ets/data/repository/ProfileRepository.ets new file mode 100644 index 0000000..cba5b7c --- /dev/null +++ b/entry/src/main/ets/data/repository/ProfileRepository.ets @@ -0,0 +1,43 @@ +import { ClassGroup, UserProfile } from '../../model/ProfileModels'; +import { mockDelay } from './MockUtil'; + +/** + * 我的资料数据仓库契约。 + */ +export abstract class ProfileRepository { + abstract observeProfile(): Promise; +} + +/** + * 本地 mock 实现。 + */ +export class FakeProfileRepository extends ProfileRepository { + async observeProfile(): Promise { + await mockDelay(250); + return FakeProfileRepository.seed(); + } + + private static seed(): UserProfile { + const p = new UserProfile(); + p.displayName = '张三'; + p.name = '张三'; + p.studentId = '20260001'; + p.phone = '138****1234'; + p.role = '成员'; + p.group = '进阶一组'; + p.loginType = '微信授权'; + p.avatarUrl = ''; + p.classGroups = [ + FakeProfileRepository.classGroup('2026-W37', '进阶一组', '成员') + ]; + return p; + } + + private static classGroup(period: string, group: string, role: string): ClassGroup { + const c = new ClassGroup(); + c.period = period; + c.group = group; + c.role = role; + return c; + } +} diff --git a/entry/src/main/ets/data/repository/SessionRepository.ets b/entry/src/main/ets/data/repository/SessionRepository.ets new file mode 100644 index 0000000..89322ff --- /dev/null +++ b/entry/src/main/ets/data/repository/SessionRepository.ets @@ -0,0 +1,30 @@ +import { SessionManager } from 'common'; +import { mockDelay } from './MockUtil'; + +/** + * 会话数据仓库契约:ViewModel 只依赖此契约。 + */ +export abstract class SessionRepository { + abstract isLoggedIn(): boolean; + abstract login(): Promise; + abstract logout(): void; +} + +/** + * 实现:封装 common 的 SessionManager(持久化 SessionStore)。 + * M1 为模拟登录(写死 token);M2 起接真实微信/手机号登录。 + */ +export class SessionRepositoryImpl extends SessionRepository { + isLoggedIn(): boolean { + return SessionManager.get().isLoggedIn; + } + + async login(): Promise { + await mockDelay(300); + SessionManager.get().setSession('mock-token-0001', '', 'u-1001', '张三'); + } + + logout(): void { + SessionManager.get().clear(); + } +}