保存一下

This commit is contained in:
2025-08-25 16:42:07 +08:00
parent 50a06568d4
commit 95a73ef524
10 changed files with 149 additions and 52 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<title>vue-desktop</title>
</head>
<body>
<div id="app"></div>

View File

@@ -1,7 +1,15 @@
/**
* 桌面应用图标信息
*/
export interface IDesktopAppIcon {
/** 图标name */
name: string;
/** 图标 */
icon: string;
/** 图标路径 */
path: string;
col: number;
row: number;
/** 图标在grid布局中的列 */
x: number;
/** 图标在grid布局中的行 */
y: number;
}

View File

@@ -3,9 +3,9 @@
*/
export interface IGridTemplateParams {
/** 单元格预设宽度 */
cellExpectWidth: number
readonly cellExpectWidth: number
/** 单元格预设高度 */
cellExpectHeight: number
readonly cellExpectHeight: number
/** 单元格实际宽度 */
cellRealWidth: number
/** 单元格实际高度 */

View File

@@ -4,11 +4,11 @@
class="w-full h-full pos-relative"
>
<div class="desktop-root" @contextmenu="onContextMenu">
<div class="w-full h-full flex-1 p-2 pos-relative">
<div class="desktop-bg">
<div class="desktop-container"
:style="gridStyle">
<AppIcon v-for="(appIcon, i) in appIconsRef" :key="i"
:icon="appIcon" :gridTemplate="gridTemplate" />
:iconInfo="appIcon" :gridTemplate="gridTemplate" />
</div>
</div>
<div class="task-bar"></div>
@@ -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) => {
</script>
<style lang="scss" scoped>
$taskBarHeight: 40px;
.desktop-root {
@apply w-full h-full flex flex-col;
.desktop-bg {
@apply w-full h-full flex-1 p-2 pos-relative;
background-image: url("imgs/desktop-bg-2.jpeg");
background-repeat: no-repeat;
background-size: cover;
height: calc(100% - #{$taskBarHeight});
}
.desktop-container {
@apply w-full h-full flex-1 grid grid-auto-flow-col pos-relative;
}
.task-bar {
@apply w-full h-[40px] bg-gray-200;
@apply w-full bg-gray-200;
height: $taskBarHeight;
flex-shrink: 0;
}
}

View File

@@ -1,20 +1,22 @@
<template>
<div
class="icon-container"
:style="`grid-column: ${icon.col}/${icon.col + 1};grid-row: ${icon.row}/${icon.row + 1};`"
:style="`grid-column: ${iconInfo.x}/${iconInfo.x + 1};grid-row: ${iconInfo.y}/${iconInfo.y + 1};`"
draggable="true"
@dragstart="onDragStart"
@dragend="onDragEnd"
>
{{ icon.name }}
{{ iconInfo.name }}
</div>
</template>
<script setup lang="ts">
import type { IDesktopAppIcon } from '@/core/desktop/types/IDesktopAppIcon.ts'
import type { IGridTemplateParams } from '@/core/desktop/types/IGridTemplateParams.ts'
import XSystem from '@/core/XSystem.ts'
import { DesktopEventEnum } from '@/core/events/EventTypes.ts'
const { icon, gridTemplate } = defineProps<{ icon: IDesktopAppIcon, gridTemplate: IGridTemplateParams }>()
const { iconInfo, gridTemplate } = defineProps<{ iconInfo: IDesktopAppIcon, gridTemplate: IGridTemplateParams }>()
const onDragStart = (e: DragEvent) => {}
@@ -38,8 +40,10 @@ const onDragEnd = (e: DragEvent) => {
const gridX = Math.ceil(mouseX / gridTemplate.cellRealWidth)
const gridY = Math.ceil(mouseY / gridTemplate.cellRealHeight)
icon.col = gridX
icon.row = gridY
iconInfo.x = gridX
iconInfo.y = gridY
XSystem.instance.eventManages.notifyEvent(DesktopEventEnum.onDesktopAppIconPos, iconInfo)
}
</script>
@@ -47,6 +51,6 @@ const onDragEnd = (e: DragEvent) => {
.icon-container {
width: 100%;
height: 100%;
@apply flex flex-col items-center justify-center rounded bg-gray-200;
@apply flex flex-col items-center justify-center bg-gray-200;
}
</style>

View File

@@ -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 {
@@ -87,3 +95,62 @@ export function useDesktopInit(containerStr: string) {
gridStyle
}
}
/**
*
* @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<string>();
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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -1,17 +1,5 @@
import type { IEventMap } from '@/core/events/IEventBuilder.ts'
/**
* 桌面进程事件枚举
* @description
* <p>onDesktopRootDomResize - 桌面根dom尺寸改变</p>
* <p>onDesktopProcessInitialize - 桌面进程初始化完成</p>
*/
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
* <p>onDesktopRootDomResize - 桌面根dom尺寸改变</p>
* <p>onDesktopProcessInitialize - 桌面进程初始化完成</p>
*/
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
* <p>onDesktopRootDomResize - 桌面根dom尺寸改变</p>
* <p>onDesktopProcessInitialize - 桌面进程初始化完成</p>
*/
export enum DesktopEventEnum {
/** 桌面进程初始化完成 */
onDesktopRootDomResize = 'onDesktopRootDomResize',
/** 桌面进程初始化完成 */
onDesktopProcessInitialize = 'onDesktopProcessInitialize',
/** 桌面应用图标位置改变 */
onDesktopAppIconPos = 'onDesktopAppIconPos'
}
/**
* 桌面进程的事件
* @description
* <p>onDesktopRootDomResize - 桌面根dom尺寸改变</p>
* <p>onDesktopProcessInitialize - 桌面进程初始化完成</p>
*/
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 {}

View File

@@ -16,5 +16,6 @@
"noUnusedParameters": false, // 检查未使用的参数
"noImplicitReturns": true, // 检查函数所有路径是否都有返回值
"noImplicitOverride": true, // 检查子类是否正确覆盖了父类方法
"allowSyntheticDefaultImports": true // 允许使用默认导入
}
}