diff --git a/index.html b/index.html index 9e5fc8f..57d1891 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Vite App + vue-desktop
diff --git a/src/core/desktop/types/IDesktopAppIcon.ts b/src/core/desktop/types/IDesktopAppIcon.ts index e3952ab..5550409 100644 --- a/src/core/desktop/types/IDesktopAppIcon.ts +++ b/src/core/desktop/types/IDesktopAppIcon.ts @@ -1,7 +1,15 @@ +/** + * 桌面应用图标信息 + */ export interface IDesktopAppIcon { + /** 图标name */ name: string; + /** 图标 */ icon: string; + /** 图标路径 */ path: string; - col: number; - row: number; + /** 图标在grid布局中的列 */ + x: number; + /** 图标在grid布局中的行 */ + y: number; } diff --git a/src/core/desktop/types/IGridTemplateParams.ts b/src/core/desktop/types/IGridTemplateParams.ts index 4de2283..ccda108 100644 --- a/src/core/desktop/types/IGridTemplateParams.ts +++ b/src/core/desktop/types/IGridTemplateParams.ts @@ -3,9 +3,9 @@ */ export interface IGridTemplateParams { /** 单元格预设宽度 */ - cellExpectWidth: number + readonly cellExpectWidth: number /** 单元格预设高度 */ - cellExpectHeight: number + readonly cellExpectHeight: number /** 单元格实际宽度 */ cellRealWidth: number /** 单元格实际高度 */ diff --git a/src/core/desktop/ui/DesktopComponent.vue b/src/core/desktop/ui/DesktopComponent.vue index 0a1cfd2..245bf62 100644 --- a/src/core/desktop/ui/DesktopComponent.vue +++ b/src/core/desktop/ui/DesktopComponent.vue @@ -4,11 +4,11 @@ class="w-full h-full pos-relative" >
-
+
+ :iconInfo="appIcon" :gridTemplate="gridTemplate" />
@@ -22,8 +22,9 @@ import XSystem from '@/core/XSystem.ts' import { notificationApi } from '@/core/common/naive-ui/discrete-api.ts' import { configProviderProps } from '@/core/common/naive-ui/theme.ts' import { DesktopEventEnum } from '@/core/events/EventTypes.ts' -import { useDesktopInit } from '@/core/desktop/ui/useDesktopInit.ts' +import { useDesktopInit } from '@/core/desktop/ui/hooks/useDesktopInit.ts' import AppIcon from '@/core/desktop/ui/components/AppIcon.vue' +import { watch } from 'vue' const props = defineProps<{ process: DesktopProcess }>() @@ -47,15 +48,25 @@ const onContextMenu = (e: MouseEvent) => { diff --git a/src/core/desktop/ui/useDesktopInit.ts b/src/core/desktop/ui/hooks/useDesktopInit.ts similarity index 55% rename from src/core/desktop/ui/useDesktopInit.ts rename to src/core/desktop/ui/hooks/useDesktopInit.ts index bb5bc46..03da16c 100644 --- a/src/core/desktop/ui/useDesktopInit.ts +++ b/src/core/desktop/ui/hooks/useDesktopInit.ts @@ -6,7 +6,10 @@ import { onMounted, onUnmounted, reactive, + ref, + toRaw, toRefs, + toValue, useTemplateRef, watch, watchEffect, @@ -58,27 +61,32 @@ export function useDesktopInit(containerStr: string) { // 有桌面图标的app const appInfos = XSystem.instance.processManages.processInfos.filter(processInfo => !processInfo.isJustProcess) + const oldAppIcons: IDesktopAppIcon[] = JSON.parse(localStorage.getItem('desktopAppIconInfo') || '[]') const appIcons: IDesktopAppIcon[] = appInfos.map((processInfo, index) => { + const oldAppIcon = oldAppIcons.find(oldAppIcon => oldAppIcon.name === processInfo.name) + // 左上角坐标原点,从上到下从左到右 索引从1开始 const x = Math.floor(index / gridTemplate.rowCount) + 1 const y = index % gridTemplate.rowCount + 1 + return { name: processInfo.name, icon: processInfo.icon, path: processInfo.startName, - col: x, - row: y + x: oldAppIcon ? oldAppIcon.x : x, + y: oldAppIcon ? oldAppIcon.y : y } }) - const appIconsRef = reactive(appIcons) - watch(() => [gridTemplate.rowCount, gridTemplate.colCount], () => { - appIconsRef.forEach((appIcon, index) => { - const x = Math.floor(index / gridTemplate.rowCount) + 1 - const y = index % gridTemplate.rowCount + 1 - appIcon.col = x - appIcon.row = y - }) + const appIconsRef = ref(appIcons) + + watch(() => [gridTemplate.rowCount, gridTemplate.colCount], ([nRows, nCols], [oRows, oCols]) => { + if (oCols == 1 && oRows == 1) return + appIconsRef.value = rearrangeIcons(toRaw(appIconsRef.value), nCols, nRows, oCols, oRows) + }) + + XSystem.instance.eventManages.addEventListener(DesktopEventEnum.onDesktopAppIconPos, (iconInfo) => { + localStorage.setItem('desktopAppIconInfo', JSON.stringify(toValue(appIconsRef.value))) }) return { @@ -86,4 +94,63 @@ export function useDesktopInit(containerStr: string) { appIconsRef, gridStyle } -} \ No newline at end of file +} + +/** + * 重新安排图标位置 + * @param appIcons 图标信息 + * @param newCols 新的列数 + * @param newRows 新的行数 + * @param oldCols 旧的列数 + * @param oldRows 旧的行数 + */ +function rearrangeIcons( + appIcons: IDesktopAppIcon[], + newCols: number, + newRows: number, + oldCols: number, + oldRows: number +): IDesktopAppIcon[] { + if (oldCols === newCols && oldRows === newRows) { + return appIcons; + } + const occupied = new Set(); + + function key(x: number, y: number) { + return `${x},${y}`; + } + + const result: IDesktopAppIcon[] = [] + const exceed: IDesktopAppIcon[] = [] + + for (const appIcon of appIcons) { + const { x, y } = appIcon; + + if (x <= newCols && y <= newRows) { + if (!occupied.has(key(x, y))) { + occupied.add(key(x, y)) + result.push({ ...appIcon, x, y }) + } + } else { + exceed.push(appIcon) + } + } + + for (const appIcon of exceed) { + // 最后格子也被占 → 从 (1,1) 开始找空位 + let placed = false; + for (let c = 1; c <= newCols; c++) { + for (let r = 1; r <= newRows; r++) { + if (!occupied.has(key(c, r))) { + occupied.add(key(c, r)); + result.push({ ...appIcon, x: c, y: r }); + placed = true; + break; + } + } + if (placed) break; + } + } + + return result; +} diff --git a/src/core/desktop/ui/imgs/desktop-bg-1.jpeg b/src/core/desktop/ui/imgs/desktop-bg-1.jpeg new file mode 100644 index 0000000..719e22c Binary files /dev/null and b/src/core/desktop/ui/imgs/desktop-bg-1.jpeg differ diff --git a/src/core/desktop/ui/imgs/desktop-bg-2.jpeg b/src/core/desktop/ui/imgs/desktop-bg-2.jpeg new file mode 100644 index 0000000..4e0e791 Binary files /dev/null and b/src/core/desktop/ui/imgs/desktop-bg-2.jpeg differ diff --git a/src/core/events/EventTypes.ts b/src/core/events/EventTypes.ts index 014c78d..da80ade 100644 --- a/src/core/events/EventTypes.ts +++ b/src/core/events/EventTypes.ts @@ -1,17 +1,5 @@ import type { IEventMap } from '@/core/events/IEventBuilder.ts' - -/** - * 桌面进程事件枚举 - * @description - *

onDesktopRootDomResize - 桌面根dom尺寸改变

- *

onDesktopProcessInitialize - 桌面进程初始化完成

- */ -export enum DesktopEventEnum { - /** 桌面进程初始化完成 */ - onDesktopRootDomResize = 'onDesktopRootDomResize', - /** 桌面进程初始化完成 */ - onDesktopProcessInitialize = 'onDesktopProcessInitialize' -} +import type { IDesktopAppIcon } from '@/core/desktop/types/IDesktopAppIcon.ts' /** * 基础系统进程事件枚举 @@ -28,19 +16,6 @@ export enum BasicSystemEventEnum { onThemeChange = 'onThemeChange' } -/** - * 桌面进程的事件 - * @description - *

onDesktopRootDomResize - 桌面根dom尺寸改变

- *

onDesktopProcessInitialize - 桌面进程初始化完成

- */ -export interface IDesktopEvent extends IEventMap { - /** 桌面根dom尺寸改变 */ - [DesktopEventEnum.onDesktopRootDomResize]: (width: number, height: number) => void - /** 桌面进程初始化完成 */ - [DesktopEventEnum.onDesktopProcessInitialize]: () => void -} - /** * 系统进程的事件 * @description @@ -54,4 +29,35 @@ export interface IBasicSystemEvent extends IEventMap { [BasicSystemEventEnum.onThemeChange]: (theme: string) => void } +/** + * 桌面进程事件枚举 + * @description + *

onDesktopRootDomResize - 桌面根dom尺寸改变

+ *

onDesktopProcessInitialize - 桌面进程初始化完成

+ */ +export enum DesktopEventEnum { + /** 桌面进程初始化完成 */ + onDesktopRootDomResize = 'onDesktopRootDomResize', + /** 桌面进程初始化完成 */ + onDesktopProcessInitialize = 'onDesktopProcessInitialize', + /** 桌面应用图标位置改变 */ + onDesktopAppIconPos = 'onDesktopAppIconPos' +} + + +/** + * 桌面进程的事件 + * @description + *

onDesktopRootDomResize - 桌面根dom尺寸改变

+ *

onDesktopProcessInitialize - 桌面进程初始化完成

+ */ +export interface IDesktopEvent extends IEventMap { + /** 桌面根dom尺寸改变 */ + [DesktopEventEnum.onDesktopRootDomResize]: (width: number, height: number) => void + /** 桌面进程初始化完成 */ + [DesktopEventEnum.onDesktopProcessInitialize]: () => void + /** 桌面应用图标位置改变 */ + [DesktopEventEnum.onDesktopAppIconPos]: (iconInfo: IDesktopAppIcon) => void +} + export interface IAllEvent extends IDesktopEvent, IBasicSystemEvent {} diff --git a/tsconfig.app.json b/tsconfig.app.json index 68e330a..60fcea2 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -16,5 +16,6 @@ "noUnusedParameters": false, // 检查未使用的参数 "noImplicitReturns": true, // 检查函数所有路径是否都有返回值 "noImplicitOverride": true, // 检查子类是否正确覆盖了父类方法 + "allowSyntheticDefaultImports": true // 允许使用默认导入 } }