feat(entry): 新增本地 mock 数据层
This commit is contained in:
78
entry/src/main/ets/data/repository/CheckinRepository.ets
Normal file
78
entry/src/main/ets/data/repository/CheckinRepository.ets
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { CheckinRecord, CheckinStatus, GroupMember, PersonalCheckinRecord } from '../../model/CheckinModels';
|
||||||
|
import { mockDelay } from './MockUtil';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打卡数据仓库契约。
|
||||||
|
*/
|
||||||
|
export abstract class CheckinRepository {
|
||||||
|
abstract observeCheckin(): Promise<CheckinRecord>;
|
||||||
|
abstract submitCheckin(status: string): Promise<CheckinRecord>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地 mock 实现:内存 seed,提交更新自身状态。
|
||||||
|
*/
|
||||||
|
export class FakeCheckinRepository extends CheckinRepository {
|
||||||
|
private record: CheckinRecord = FakeCheckinRepository.seed();
|
||||||
|
|
||||||
|
async observeCheckin(): Promise<CheckinRecord> {
|
||||||
|
await mockDelay(250);
|
||||||
|
return this.record;
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitCheckin(status: string): Promise<CheckinRecord> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
entry/src/main/ets/data/repository/HomeRepository.ets
Normal file
93
entry/src/main/ets/data/repository/HomeRepository.ets
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import { HomeData, HomeModule, IntroCard } from '../../model/HomeModels';
|
||||||
|
import { mockDelay } from './MockUtil';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首页数据仓库契约。
|
||||||
|
*/
|
||||||
|
export abstract class HomeRepository {
|
||||||
|
abstract observeHome(): Promise<HomeData>;
|
||||||
|
abstract observeGuestHome(): Promise<HomeData>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地 mock 实现:登录态与游客态两套 seed。
|
||||||
|
*/
|
||||||
|
export class FakeHomeRepository extends HomeRepository {
|
||||||
|
async observeHome(): Promise<HomeData> {
|
||||||
|
await mockDelay(250);
|
||||||
|
return FakeHomeRepository.seed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async observeGuestHome(): Promise<HomeData> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
entry/src/main/ets/data/repository/MockUtil.ets
Normal file
8
entry/src/main/ets/data/repository/MockUtil.ets
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* mock 延迟工具:模拟网络往返,让加载态可见。
|
||||||
|
*/
|
||||||
|
export function mockDelay(ms: number): Promise<void> {
|
||||||
|
return new Promise<void>((resolve: () => void) => {
|
||||||
|
setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
56
entry/src/main/ets/data/repository/PlanRepository.ets
Normal file
56
entry/src/main/ets/data/repository/PlanRepository.ets
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { PlanGroup, PlanRecord, PlanType } from '../../model/PlanModels';
|
||||||
|
import { mockDelay } from './MockUtil';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划数据仓库契约。
|
||||||
|
*/
|
||||||
|
export abstract class PlanRepository {
|
||||||
|
abstract observePlan(type: string): Promise<PlanRecord>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地 mock 实现:按类型(周/月/年)缓存 seed。
|
||||||
|
*/
|
||||||
|
export class FakePlanRepository extends PlanRepository {
|
||||||
|
private cache: Map<string, PlanRecord> = new Map<string, PlanRecord>();
|
||||||
|
|
||||||
|
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<PlanRecord> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
entry/src/main/ets/data/repository/ProfileRepository.ets
Normal file
43
entry/src/main/ets/data/repository/ProfileRepository.ets
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { ClassGroup, UserProfile } from '../../model/ProfileModels';
|
||||||
|
import { mockDelay } from './MockUtil';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 我的资料数据仓库契约。
|
||||||
|
*/
|
||||||
|
export abstract class ProfileRepository {
|
||||||
|
abstract observeProfile(): Promise<UserProfile>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地 mock 实现。
|
||||||
|
*/
|
||||||
|
export class FakeProfileRepository extends ProfileRepository {
|
||||||
|
async observeProfile(): Promise<UserProfile> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
entry/src/main/ets/data/repository/SessionRepository.ets
Normal file
30
entry/src/main/ets/data/repository/SessionRepository.ets
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { SessionManager } from 'common';
|
||||||
|
import { mockDelay } from './MockUtil';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 会话数据仓库契约:ViewModel 只依赖此契约。
|
||||||
|
*/
|
||||||
|
export abstract class SessionRepository {
|
||||||
|
abstract isLoggedIn(): boolean;
|
||||||
|
abstract login(): Promise<void>;
|
||||||
|
abstract logout(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实现:封装 common 的 SessionManager(持久化 SessionStore)。
|
||||||
|
* M1 为模拟登录(写死 token);M2 起接真实微信/手机号登录。
|
||||||
|
*/
|
||||||
|
export class SessionRepositoryImpl extends SessionRepository {
|
||||||
|
isLoggedIn(): boolean {
|
||||||
|
return SessionManager.get().isLoggedIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(): Promise<void> {
|
||||||
|
await mockDelay(300);
|
||||||
|
SessionManager.get().setSession('mock-token-0001', '', 'u-1001', '张三');
|
||||||
|
}
|
||||||
|
|
||||||
|
logout(): void {
|
||||||
|
SessionManager.get().clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user