保存一下
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
/**
|
||||
* 桌面应用图标信息
|
||||
*/
|
||||
export interface IDesktopAppIcon {
|
||||
/** 图标name */
|
||||
name: string;
|
||||
/** 图标 */
|
||||
icon: string;
|
||||
/** 图标路径 */
|
||||
path: string;
|
||||
col: number;
|
||||
row: number;
|
||||
/** 图标在grid布局中的列 */
|
||||
x: number;
|
||||
/** 图标在grid布局中的行 */
|
||||
y: number;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
*/
|
||||
export interface IGridTemplateParams {
|
||||
/** 单元格预设宽度 */
|
||||
cellExpectWidth: number
|
||||
readonly cellExpectWidth: number
|
||||
/** 单元格预设高度 */
|
||||
cellExpectHeight: number
|
||||
readonly cellExpectHeight: number
|
||||
/** 单元格实际宽度 */
|
||||
cellRealWidth: number
|
||||
/** 单元格实际高度 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
BIN
src/core/desktop/ui/imgs/desktop-bg-1.jpeg
Normal file
BIN
src/core/desktop/ui/imgs/desktop-bg-1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
BIN
src/core/desktop/ui/imgs/desktop-bg-2.jpeg
Normal file
BIN
src/core/desktop/ui/imgs/desktop-bg-2.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
@@ -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 {}
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
"noUnusedParameters": false, // 检查未使用的参数
|
||||
"noImplicitReturns": true, // 检查函数所有路径是否都有返回值
|
||||
"noImplicitOverride": true, // 检查子类是否正确覆盖了父类方法
|
||||
"allowSyntheticDefaultImports": true // 允许使用默认导入
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user