feat: 重做灵动岛编辑器与课表档案时间表编辑
灵动岛 - 重构自定义方案编辑器:组件库常驻、拖拽添加与排序、方案切换/新建/复制/删除、编辑模式预览与缩放,容器在编辑时展开全部子组件。 - 新增天气简报组件:主进程固定请求 Open-Meteo,只接受数值经纬度,失败退避并保留本次运行缓存;冒烟模式不访问外网。 - 倒计时支持目标名称与日期;课程表组件新增「今日时间点」,按时间点类型折叠/展开,课中不再常驻倒计时。 - preload 暴露 getIslandWeather 与时间点订阅,契约同步 desktop.d.ts。 课表档案 - 时间点默认课程:布局返回 defaultCourse,日课表没有条目时回退;新增 apply-default 覆盖所有引用课表;全校时间表不携带默认课程。 - 新增 ClassIsland 式时间表编辑器(列表/时间轴视图、拖动把柄、按类型添加、默认时长与缩放)与「课表信息」表单。 - 课表页默认进入单表编辑,底部保留列表/周/月视图;时间表支持新路由删除。 - 「课间」统一改称「课间休息」。 验证 - pnpm typecheck、pnpm lint 通过。 - verify:e2e 隔离验收 248/248 项通过(含默认课程回退、覆盖写入与时间表删除)。 - ui-smoke 覆盖单表编辑、课表信息与时间轴视图,并更新回归截图。
This commit is contained in:
1 parent
938285bb9c
commit
682818dd4a
41 files changed
+4349
-1095
No files matched your search
@@ -1,5 +1,7 @@
|
||||
import type {
|
||||
IslandLayoutSettings as ContractIslandLayoutSettings,
|
||||
IslandTimePointDto as ContractIslandTimePointDto,
|
||||
IslandWeather,
|
||||
ScheduleDto as ContractScheduleDto,
|
||||
} from '@classhelper/shared';
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
@@ -10,6 +12,7 @@ import type { IslandAppearance, IslandState } from '@classhelper/shared';
|
||||
* 只暴露「订阅状态/外观」与「发送用户操作」两件事,渲染进程不接触任何 Node 能力。
|
||||
*/
|
||||
export interface IslandBridge {
|
||||
getIslandWeather(coordinates: { latitude: number; longitude: number }): Promise<IslandWeather>;
|
||||
getLayout(): Promise<ContractIslandLayoutSettings>;
|
||||
saveLayout(value: ContractIslandLayoutSettings): Promise<ContractIslandLayoutSettings>;
|
||||
onLayout(handler: (value: ContractIslandLayoutSettings) => void): void;
|
||||
@@ -24,6 +27,8 @@ export interface IslandBridge {
|
||||
onViewport(handler: (value: { width: number; height: number }) => void): () => void;
|
||||
getSchedules(): Promise<ContractScheduleDto[]>;
|
||||
onSchedules(handler: (value: ContractScheduleDto[]) => void): void;
|
||||
getTimePoints(): Promise<ContractIslandTimePointDto[]>;
|
||||
onTimePoints(handler: (value: ContractIslandTimePointDto[]) => void): void;
|
||||
|
||||
onState(handler: (state: IslandState) => void): void;
|
||||
sendAction(
|
||||
@@ -57,6 +62,7 @@ export interface IslandBridge {
|
||||
}
|
||||
|
||||
const bridge: IslandBridge = {
|
||||
getIslandWeather: (coordinates) => ipcRenderer.invoke('island:weather', coordinates),
|
||||
getLayout: () => ipcRenderer.invoke('island:get-layout'),
|
||||
saveLayout: (value) => ipcRenderer.invoke('island:save-layout', value),
|
||||
onLayout: (handler) => {
|
||||
@@ -84,6 +90,10 @@ const bridge: IslandBridge = {
|
||||
onSchedules: (handler) => {
|
||||
ipcRenderer.on('island:schedules', (_event, value) => handler(value));
|
||||
},
|
||||
getTimePoints: () => ipcRenderer.invoke('island:get-time-points'),
|
||||
onTimePoints: (handler) => {
|
||||
ipcRenderer.on('island:time-points', (_event, value) => handler(value));
|
||||
},
|
||||
|
||||
onState: (handler) => {
|
||||
ipcRenderer.on('island:state', (_event, state: IslandState) => handler(state));
|
||||
|
||||
Reference in new issue
Block a user