diff --git a/entry/src/main/ets/viewmodel/CheckinViewModel.ets b/entry/src/main/ets/viewmodel/CheckinViewModel.ets new file mode 100644 index 0000000..b712ba7 --- /dev/null +++ b/entry/src/main/ets/viewmodel/CheckinViewModel.ets @@ -0,0 +1,62 @@ +import { CheckinRecord } from '../model/CheckinModels'; +import { CheckinRepository } from '../data/repository/CheckinRepository'; +import { SessionRepository } from '../data/repository/SessionRepository'; +import { ServiceLocator } from '../di/ServiceLocator'; + +/** + * 打卡视图模型:加载打卡数据 + 提交打卡状态。 + */ +@ObservedV2 +export class CheckinViewModel { + @Trace record: CheckinRecord = new CheckinRecord(); + @Trace loggedIn: boolean = false; + @Trace loading: boolean = false; + @Trace submitting: boolean = false; + @Trace error: string = ''; + + private readonly repository: CheckinRepository; + private readonly session: SessionRepository; + + constructor(repository: CheckinRepository, session: SessionRepository) { + this.repository = repository; + this.session = session; + } + + static create(): CheckinViewModel { + return new CheckinViewModel( + ServiceLocator.get('checkinRepository') as CheckinRepository, + ServiceLocator.get('sessionRepository') as SessionRepository + ); + } + + async load(): Promise { + this.loading = true; + this.error = ''; + this.loggedIn = this.session.isLoggedIn(); + if (!this.loggedIn) { + this.loading = false; + return; + } + try { + this.record = await this.repository.observeCheckin(); + } catch (err) { + this.error = JSON.stringify(err); + } finally { + this.loading = false; + } + } + + async submit(status: string): Promise { + if (this.submitting) { + return; + } + this.submitting = true; + try { + this.record = await this.repository.submitCheckin(status); + } catch (err) { + this.error = JSON.stringify(err); + } finally { + this.submitting = false; + } + } +} diff --git a/entry/src/main/ets/viewmodel/HomeViewModel.ets b/entry/src/main/ets/viewmodel/HomeViewModel.ets index 864a134..3890e4b 100644 --- a/entry/src/main/ets/viewmodel/HomeViewModel.ets +++ b/entry/src/main/ets/viewmodel/HomeViewModel.ets @@ -1,37 +1,41 @@ -import { User } from '../model/User'; -import { UserRepository } from '../data/repository/UserRepository'; +import { HomeData } from '../model/HomeModels'; +import { HomeRepository } from '../data/repository/HomeRepository'; +import { SessionRepository } from '../data/repository/SessionRepository'; import { ServiceLocator } from '../di/ServiceLocator'; /** * 首页视图模型:@ObservedV2 三态(loading / error / data)。 - * 只依赖 UserRepository 契约,不直接接触网络层。 + * 根据登录态分流到游客首页 / 原生首页。 */ @ObservedV2 export class HomeViewModel { - @Trace users: User[] = []; + @Trace data: HomeData = new HomeData(); + @Trace isGuest: boolean = true; @Trace loading: boolean = false; @Trace error: string = ''; - private readonly repository: UserRepository; + private readonly repository: HomeRepository; + private readonly session: SessionRepository; - constructor(repository: UserRepository) { + constructor(repository: HomeRepository, session: SessionRepository) { this.repository = repository; + this.session = session; } - /** - * 工厂:从 DI 容器解析依赖并装配,避免页面直接触碰 data 层类型。 - */ static create(): HomeViewModel { - return new HomeViewModel(ServiceLocator.get('userRepository') as UserRepository); + return new HomeViewModel( + ServiceLocator.get('homeRepository') as HomeRepository, + ServiceLocator.get('sessionRepository') as SessionRepository + ); } async load(): Promise { this.loading = true; this.error = ''; try { - // 演示:拉取一个示例用户;真实业务可替换为列表接口。 - const user = await this.repository.getUser('demo-user'); - this.users = [user]; + const loggedIn = this.session.isLoggedIn(); + this.isGuest = !loggedIn; + this.data = loggedIn ? await this.repository.observeHome() : await this.repository.observeGuestHome(); } catch (err) { this.error = JSON.stringify(err); } finally { diff --git a/entry/src/main/ets/viewmodel/PlanViewModel.ets b/entry/src/main/ets/viewmodel/PlanViewModel.ets new file mode 100644 index 0000000..1fc8e25 --- /dev/null +++ b/entry/src/main/ets/viewmodel/PlanViewModel.ets @@ -0,0 +1,56 @@ +import { PlanRecord, PlanType } from '../model/PlanModels'; +import { PlanRepository } from '../data/repository/PlanRepository'; +import { SessionRepository } from '../data/repository/SessionRepository'; +import { ServiceLocator } from '../di/ServiceLocator'; + +/** + * 计划视图模型:周/月/年类型切换 + 计划数据加载。 + */ +@ObservedV2 +export class PlanViewModel { + @Trace record: PlanRecord = new PlanRecord(); + @Trace selectedType: string = PlanType.WEEKLY; + @Trace loggedIn: boolean = false; + @Trace loading: boolean = false; + @Trace error: string = ''; + + private readonly repository: PlanRepository; + private readonly session: SessionRepository; + + constructor(repository: PlanRepository, session: SessionRepository) { + this.repository = repository; + this.session = session; + } + + static create(): PlanViewModel { + return new PlanViewModel( + ServiceLocator.get('planRepository') as PlanRepository, + ServiceLocator.get('sessionRepository') as SessionRepository + ); + } + + async load(): Promise { + this.loading = true; + this.error = ''; + this.loggedIn = this.session.isLoggedIn(); + if (!this.loggedIn) { + this.loading = false; + return; + } + try { + this.record = await this.repository.observePlan(this.selectedType); + } catch (err) { + this.error = JSON.stringify(err); + } finally { + this.loading = false; + } + } + + async selectType(type: string): Promise { + if (this.selectedType === type) { + return; + } + this.selectedType = type; + await this.load(); + } +} diff --git a/entry/src/main/ets/viewmodel/ProfileViewModel.ets b/entry/src/main/ets/viewmodel/ProfileViewModel.ets new file mode 100644 index 0000000..f9095d5 --- /dev/null +++ b/entry/src/main/ets/viewmodel/ProfileViewModel.ets @@ -0,0 +1,58 @@ +import { UserProfile } from '../model/ProfileModels'; +import { ProfileRepository } from '../data/repository/ProfileRepository'; +import { SessionRepository } from '../data/repository/SessionRepository'; +import { ServiceLocator } from '../di/ServiceLocator'; + +/** + * 我的视图模型:资料加载 + 模拟登录 / 退出登录。 + */ +@ObservedV2 +export class ProfileViewModel { + @Trace profile: UserProfile = new UserProfile(); + @Trace loggedIn: boolean = false; + @Trace loading: boolean = false; + @Trace error: string = ''; + + private readonly repository: ProfileRepository; + private readonly session: SessionRepository; + + constructor(repository: ProfileRepository, session: SessionRepository) { + this.repository = repository; + this.session = session; + } + + static create(): ProfileViewModel { + return new ProfileViewModel( + ServiceLocator.get('profileRepository') as ProfileRepository, + ServiceLocator.get('sessionRepository') as SessionRepository + ); + } + + async load(): Promise { + this.loading = true; + this.error = ''; + this.loggedIn = this.session.isLoggedIn(); + if (!this.loggedIn) { + this.loading = false; + return; + } + try { + this.profile = await this.repository.observeProfile(); + } catch (err) { + this.error = JSON.stringify(err); + } finally { + this.loading = false; + } + } + + async login(): Promise { + await this.session.login(); + await this.load(); + } + + logout(): void { + this.session.logout(); + this.loggedIn = false; + this.profile = new UserProfile(); + } +}