feat(V0.2): 打卡 / 日历 / 清单模块

- 数据: Habit/CheckIn/CheckList/CheckListItem/CheckListTemplate + 迁移 + 重新生成 client
- 后端: server/checkin/period.js 周期计算(日/周/月/年, 周一起始, Asia/Shanghai)
        /api/checkin/* 打卡项CRUD/打卡/撤销/补打/某日详情/月历
        /api/checklists/* 清单与检查项CRUD/勾选/全选/复制/模板(系统预置出差·回老家)
- 前端: 底部新增「打卡」Tab -> /checkin, 页内三视图
        环形进度 RingProgress + 完成特效(粒子/光晕/触感, 可关闭)
        打卡视图: 待办列表/乐观更新/撤销/新建编辑
        日历视图: 月历网格 + 今天·昨天·明天 + 日期标记/完成率
        清单视图: 场景清单/勾选进度条/模板生成/另存模板/归档
- 文档: docs/V0.2/需求文档.md 补充实现约定(附录B)与接口清单
This commit is contained in:
cheney
2026-10-22 11:37:16 +08:00
parent 54a3224f00
commit 004f8c262d
32 changed files with 11030 additions and 63 deletions
+462 -2
View File
@@ -401,7 +401,12 @@ export const ModelName = {
MihomeHome: 'MihomeHome',
MihomeDevice: 'MihomeDevice',
MihomeEnvSample: 'MihomeEnvSample',
MihomeEnvHour: 'MihomeEnvHour'
MihomeEnvHour: 'MihomeEnvHour',
Habit: 'Habit',
CheckIn: 'CheckIn',
CheckList: 'CheckList',
CheckListItem: 'CheckListItem',
CheckListTemplate: 'CheckListTemplate'
} as const
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
@@ -417,7 +422,7 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
omit: GlobalOmitOptions
}
meta: {
modelProps: "user" | "article" | "strategy" | "indicator" | "indicatorPoint" | "news" | "alert" | "serverNode" | "serverNodeHistory" | "serviceCheck" | "econ_SowInventory" | "scraperCache" | "oilPriceHistory" | "mihomeAccount" | "mihomeHome" | "mihomeDevice" | "mihomeEnvSample" | "mihomeEnvHour"
modelProps: "user" | "article" | "strategy" | "indicator" | "indicatorPoint" | "news" | "alert" | "serverNode" | "serverNodeHistory" | "serviceCheck" | "econ_SowInventory" | "scraperCache" | "oilPriceHistory" | "mihomeAccount" | "mihomeHome" | "mihomeDevice" | "mihomeEnvSample" | "mihomeEnvHour" | "habit" | "checkIn" | "checkList" | "checkListItem" | "checkListTemplate"
txIsolationLevel: TransactionIsolationLevel
}
model: {
@@ -1609,6 +1614,336 @@ export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runt
}
}
}
Habit: {
payload: Prisma.$HabitPayload<ExtArgs>
fields: Prisma.HabitFieldRefs
operations: {
findUnique: {
args: Prisma.HabitFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload> | null
}
findUniqueOrThrow: {
args: Prisma.HabitFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>
}
findFirst: {
args: Prisma.HabitFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload> | null
}
findFirstOrThrow: {
args: Prisma.HabitFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>
}
findMany: {
args: Prisma.HabitFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>[]
}
create: {
args: Prisma.HabitCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>
}
createMany: {
args: Prisma.HabitCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.HabitDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>
}
update: {
args: Prisma.HabitUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>
}
deleteMany: {
args: Prisma.HabitDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.HabitUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.HabitUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$HabitPayload>
}
aggregate: {
args: Prisma.HabitAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateHabit>
}
groupBy: {
args: Prisma.HabitGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.HabitGroupByOutputType>[]
}
count: {
args: Prisma.HabitCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.HabitCountAggregateOutputType> | number
}
}
}
CheckIn: {
payload: Prisma.$CheckInPayload<ExtArgs>
fields: Prisma.CheckInFieldRefs
operations: {
findUnique: {
args: Prisma.CheckInFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload> | null
}
findUniqueOrThrow: {
args: Prisma.CheckInFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>
}
findFirst: {
args: Prisma.CheckInFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload> | null
}
findFirstOrThrow: {
args: Prisma.CheckInFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>
}
findMany: {
args: Prisma.CheckInFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>[]
}
create: {
args: Prisma.CheckInCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>
}
createMany: {
args: Prisma.CheckInCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.CheckInDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>
}
update: {
args: Prisma.CheckInUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>
}
deleteMany: {
args: Prisma.CheckInDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.CheckInUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.CheckInUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckInPayload>
}
aggregate: {
args: Prisma.CheckInAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateCheckIn>
}
groupBy: {
args: Prisma.CheckInGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckInGroupByOutputType>[]
}
count: {
args: Prisma.CheckInCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckInCountAggregateOutputType> | number
}
}
}
CheckList: {
payload: Prisma.$CheckListPayload<ExtArgs>
fields: Prisma.CheckListFieldRefs
operations: {
findUnique: {
args: Prisma.CheckListFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload> | null
}
findUniqueOrThrow: {
args: Prisma.CheckListFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>
}
findFirst: {
args: Prisma.CheckListFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload> | null
}
findFirstOrThrow: {
args: Prisma.CheckListFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>
}
findMany: {
args: Prisma.CheckListFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>[]
}
create: {
args: Prisma.CheckListCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>
}
createMany: {
args: Prisma.CheckListCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.CheckListDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>
}
update: {
args: Prisma.CheckListUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>
}
deleteMany: {
args: Prisma.CheckListDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.CheckListUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.CheckListUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListPayload>
}
aggregate: {
args: Prisma.CheckListAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateCheckList>
}
groupBy: {
args: Prisma.CheckListGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckListGroupByOutputType>[]
}
count: {
args: Prisma.CheckListCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckListCountAggregateOutputType> | number
}
}
}
CheckListItem: {
payload: Prisma.$CheckListItemPayload<ExtArgs>
fields: Prisma.CheckListItemFieldRefs
operations: {
findUnique: {
args: Prisma.CheckListItemFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload> | null
}
findUniqueOrThrow: {
args: Prisma.CheckListItemFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>
}
findFirst: {
args: Prisma.CheckListItemFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload> | null
}
findFirstOrThrow: {
args: Prisma.CheckListItemFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>
}
findMany: {
args: Prisma.CheckListItemFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>[]
}
create: {
args: Prisma.CheckListItemCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>
}
createMany: {
args: Prisma.CheckListItemCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.CheckListItemDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>
}
update: {
args: Prisma.CheckListItemUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>
}
deleteMany: {
args: Prisma.CheckListItemDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.CheckListItemUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.CheckListItemUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListItemPayload>
}
aggregate: {
args: Prisma.CheckListItemAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateCheckListItem>
}
groupBy: {
args: Prisma.CheckListItemGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckListItemGroupByOutputType>[]
}
count: {
args: Prisma.CheckListItemCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckListItemCountAggregateOutputType> | number
}
}
}
CheckListTemplate: {
payload: Prisma.$CheckListTemplatePayload<ExtArgs>
fields: Prisma.CheckListTemplateFieldRefs
operations: {
findUnique: {
args: Prisma.CheckListTemplateFindUniqueArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload> | null
}
findUniqueOrThrow: {
args: Prisma.CheckListTemplateFindUniqueOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>
}
findFirst: {
args: Prisma.CheckListTemplateFindFirstArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload> | null
}
findFirstOrThrow: {
args: Prisma.CheckListTemplateFindFirstOrThrowArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>
}
findMany: {
args: Prisma.CheckListTemplateFindManyArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>[]
}
create: {
args: Prisma.CheckListTemplateCreateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>
}
createMany: {
args: Prisma.CheckListTemplateCreateManyArgs<ExtArgs>
result: BatchPayload
}
delete: {
args: Prisma.CheckListTemplateDeleteArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>
}
update: {
args: Prisma.CheckListTemplateUpdateArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>
}
deleteMany: {
args: Prisma.CheckListTemplateDeleteManyArgs<ExtArgs>
result: BatchPayload
}
updateMany: {
args: Prisma.CheckListTemplateUpdateManyArgs<ExtArgs>
result: BatchPayload
}
upsert: {
args: Prisma.CheckListTemplateUpsertArgs<ExtArgs>
result: runtime.Types.Utils.PayloadToResult<Prisma.$CheckListTemplatePayload>
}
aggregate: {
args: Prisma.CheckListTemplateAggregateArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.AggregateCheckListTemplate>
}
groupBy: {
args: Prisma.CheckListTemplateGroupByArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckListTemplateGroupByOutputType>[]
}
count: {
args: Prisma.CheckListTemplateCountArgs<ExtArgs>
result: runtime.Types.Utils.Optional<Prisma.CheckListTemplateCountAggregateOutputType> | number
}
}
}
}
} & {
other: {
@@ -1924,6 +2259,81 @@ export const MihomeEnvHourScalarFieldEnum = {
export type MihomeEnvHourScalarFieldEnum = (typeof MihomeEnvHourScalarFieldEnum)[keyof typeof MihomeEnvHourScalarFieldEnum]
export const HabitScalarFieldEnum = {
id: 'id',
userId: 'userId',
name: 'name',
period: 'period',
target: 'target',
color: 'color',
icon: 'icon',
note: 'note',
archived: 'archived',
sortOrder: 'sortOrder',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type HabitScalarFieldEnum = (typeof HabitScalarFieldEnum)[keyof typeof HabitScalarFieldEnum]
export const CheckInScalarFieldEnum = {
id: 'id',
habitId: 'habitId',
userId: 'userId',
date: 'date',
seq: 'seq',
note: 'note',
source: 'source',
createdAt: 'createdAt'
} as const
export type CheckInScalarFieldEnum = (typeof CheckInScalarFieldEnum)[keyof typeof CheckInScalarFieldEnum]
export const CheckListScalarFieldEnum = {
id: 'id',
userId: 'userId',
title: 'title',
scene: 'scene',
note: 'note',
archived: 'archived',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type CheckListScalarFieldEnum = (typeof CheckListScalarFieldEnum)[keyof typeof CheckListScalarFieldEnum]
export const CheckListItemScalarFieldEnum = {
id: 'id',
listId: 'listId',
title: 'title',
note: 'note',
done: 'done',
doneAt: 'doneAt',
sortOrder: 'sortOrder',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type CheckListItemScalarFieldEnum = (typeof CheckListItemScalarFieldEnum)[keyof typeof CheckListItemScalarFieldEnum]
export const CheckListTemplateScalarFieldEnum = {
id: 'id',
userId: 'userId',
name: 'name',
scene: 'scene',
items: 'items',
builtin: 'builtin',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type CheckListTemplateScalarFieldEnum = (typeof CheckListTemplateScalarFieldEnum)[keyof typeof CheckListTemplateScalarFieldEnum]
export const SortOrder = {
asc: 'asc',
desc: 'desc'
@@ -2128,6 +2538,51 @@ export const MihomeEnvSampleOrderByRelevanceFieldEnum = {
export type MihomeEnvSampleOrderByRelevanceFieldEnum = (typeof MihomeEnvSampleOrderByRelevanceFieldEnum)[keyof typeof MihomeEnvSampleOrderByRelevanceFieldEnum]
export const HabitOrderByRelevanceFieldEnum = {
name: 'name',
period: 'period',
color: 'color',
icon: 'icon',
note: 'note'
} as const
export type HabitOrderByRelevanceFieldEnum = (typeof HabitOrderByRelevanceFieldEnum)[keyof typeof HabitOrderByRelevanceFieldEnum]
export const CheckInOrderByRelevanceFieldEnum = {
date: 'date',
note: 'note',
source: 'source'
} as const
export type CheckInOrderByRelevanceFieldEnum = (typeof CheckInOrderByRelevanceFieldEnum)[keyof typeof CheckInOrderByRelevanceFieldEnum]
export const CheckListOrderByRelevanceFieldEnum = {
title: 'title',
scene: 'scene',
note: 'note'
} as const
export type CheckListOrderByRelevanceFieldEnum = (typeof CheckListOrderByRelevanceFieldEnum)[keyof typeof CheckListOrderByRelevanceFieldEnum]
export const CheckListItemOrderByRelevanceFieldEnum = {
title: 'title',
note: 'note'
} as const
export type CheckListItemOrderByRelevanceFieldEnum = (typeof CheckListItemOrderByRelevanceFieldEnum)[keyof typeof CheckListItemOrderByRelevanceFieldEnum]
export const CheckListTemplateOrderByRelevanceFieldEnum = {
name: 'name',
scene: 'scene'
} as const
export type CheckListTemplateOrderByRelevanceFieldEnum = (typeof CheckListTemplateOrderByRelevanceFieldEnum)[keyof typeof CheckListTemplateOrderByRelevanceFieldEnum]
/**
* Field references
@@ -2302,6 +2757,11 @@ export type GlobalOmitConfig = {
mihomeDevice?: Prisma.MihomeDeviceOmit
mihomeEnvSample?: Prisma.MihomeEnvSampleOmit
mihomeEnvHour?: Prisma.MihomeEnvHourOmit
habit?: Prisma.HabitOmit
checkIn?: Prisma.CheckInOmit
checkList?: Prisma.CheckListOmit
checkListItem?: Prisma.CheckListItemOmit
checkListTemplate?: Prisma.CheckListTemplateOmit
}
/* Types for Logging */