保存一下
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Vite App</title>
|
<title>vue-desktop</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* 桌面应用图标信息
|
||||||
|
*/
|
||||||
export interface IDesktopAppIcon {
|
export interface IDesktopAppIcon {
|
||||||
|
/** 图标name */
|
||||||
name: string;
|
name: string;
|
||||||
|
/** 图标 */
|
||||||
icon: string;
|
icon: string;
|
||||||
|
/** 图标路径 */
|
||||||
path: string;
|
path: string;
|
||||||
col: number;
|
/** 图标在grid布局中的列 */
|
||||||
row: number;
|
x: number;
|
||||||
|
/** 图标在grid布局中的行 */
|
||||||
|
y: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
*/
|
*/
|
||||||
export interface IGridTemplateParams {
|
export interface IGridTemplateParams {
|
||||||
/** 单元格预设宽度 */
|
/** 单元格预设宽度 */
|
||||||
cellExpectWidth: number
|
readonly cellExpectWidth: number
|
||||||
/** 单元格预设高度 */
|
/** 单元格预设高度 */
|
||||||
cellExpectHeight: number
|
readonly cellExpectHeight: number
|
||||||
/** 单元格实际宽度 */
|
/** 单元格实际宽度 */
|
||||||
cellRealWidth: number
|
cellRealWidth: number
|
||||||
/** 单元格实际高度 */
|
/** 单元格实际高度 */
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
class="w-full h-full pos-relative"
|
class="w-full h-full pos-relative"
|
||||||
>
|
>
|
||||||
<div class="desktop-root" @contextmenu="onContextMenu">
|
<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"
|
<div class="desktop-container"
|
||||||
:style="gridStyle">
|
:style="gridStyle">
|
||||||
<AppIcon v-for="(appIcon, i) in appIconsRef" :key="i"
|
<AppIcon v-for="(appIcon, i) in appIconsRef" :key="i"
|
||||||
:icon="appIcon" :gridTemplate="gridTemplate" />
|
:iconInfo="appIcon" :gridTemplate="gridTemplate" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="task-bar"></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 { notificationApi } from '@/core/common/naive-ui/discrete-api.ts'
|
||||||
import { configProviderProps } from '@/core/common/naive-ui/theme.ts'
|
import { configProviderProps } from '@/core/common/naive-ui/theme.ts'
|
||||||
import { DesktopEventEnum } from '@/core/events/EventTypes.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 AppIcon from '@/core/desktop/ui/components/AppIcon.vue'
|
||||||
|
import { watch } from 'vue'
|
||||||
|
|
||||||
const props = defineProps<{ process: DesktopProcess }>()
|
const props = defineProps<{ process: DesktopProcess }>()
|
||||||
|
|
||||||
@@ -47,15 +48,25 @@ const onContextMenu = (e: MouseEvent) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
$taskBarHeight: 40px;
|
||||||
.desktop-root {
|
.desktop-root {
|
||||||
@apply w-full h-full flex flex-col;
|
@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 {
|
.desktop-container {
|
||||||
@apply w-full h-full flex-1 grid grid-auto-flow-col pos-relative;
|
@apply w-full h-full flex-1 grid grid-auto-flow-col pos-relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-bar {
|
.task-bar {
|
||||||
@apply w-full h-[40px] bg-gray-200;
|
@apply w-full bg-gray-200;
|
||||||
|
height: $taskBarHeight;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="icon-container"
|
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"
|
draggable="true"
|
||||||
@dragstart="onDragStart"
|
@dragstart="onDragStart"
|
||||||
@dragend="onDragEnd"
|
@dragend="onDragEnd"
|
||||||
>
|
>
|
||||||
{{ icon.name }}
|
{{ iconInfo.name }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { IDesktopAppIcon } from '@/core/desktop/types/IDesktopAppIcon.ts'
|
import type { IDesktopAppIcon } from '@/core/desktop/types/IDesktopAppIcon.ts'
|
||||||
import type { IGridTemplateParams } from '@/core/desktop/types/IGridTemplateParams.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) => {}
|
const onDragStart = (e: DragEvent) => {}
|
||||||
|
|
||||||
@@ -38,8 +40,10 @@ const onDragEnd = (e: DragEvent) => {
|
|||||||
const gridX = Math.ceil(mouseX / gridTemplate.cellRealWidth)
|
const gridX = Math.ceil(mouseX / gridTemplate.cellRealWidth)
|
||||||
const gridY = Math.ceil(mouseY / gridTemplate.cellRealHeight)
|
const gridY = Math.ceil(mouseY / gridTemplate.cellRealHeight)
|
||||||
|
|
||||||
icon.col = gridX
|
iconInfo.x = gridX
|
||||||
icon.row = gridY
|
iconInfo.y = gridY
|
||||||
|
|
||||||
|
XSystem.instance.eventManages.notifyEvent(DesktopEventEnum.onDesktopAppIconPos, iconInfo)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -47,6 +51,6 @@ const onDragEnd = (e: DragEvent) => {
|
|||||||
.icon-container {
|
.icon-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 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>
|
</style>
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import {
|
|||||||
onMounted,
|
onMounted,
|
||||||
onUnmounted,
|
onUnmounted,
|
||||||
reactive,
|
reactive,
|
||||||
|
ref,
|
||||||
|
toRaw,
|
||||||
toRefs,
|
toRefs,
|
||||||
|
toValue,
|
||||||
useTemplateRef,
|
useTemplateRef,
|
||||||
watch,
|
watch,
|
||||||
watchEffect,
|
watchEffect,
|
||||||
@@ -58,27 +61,32 @@ export function useDesktopInit(containerStr: string) {
|
|||||||
|
|
||||||
// 有桌面图标的app
|
// 有桌面图标的app
|
||||||
const appInfos = XSystem.instance.processManages.processInfos.filter(processInfo => !processInfo.isJustProcess)
|
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 appIcons: IDesktopAppIcon[] = appInfos.map((processInfo, index) => {
|
||||||
|
const oldAppIcon = oldAppIcons.find(oldAppIcon => oldAppIcon.name === processInfo.name)
|
||||||
|
|
||||||
// 左上角坐标原点,从上到下从左到右 索引从1开始
|
// 左上角坐标原点,从上到下从左到右 索引从1开始
|
||||||
const x = Math.floor(index / gridTemplate.rowCount) + 1
|
const x = Math.floor(index / gridTemplate.rowCount) + 1
|
||||||
const y = index % gridTemplate.rowCount + 1
|
const y = index % gridTemplate.rowCount + 1
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: processInfo.name,
|
name: processInfo.name,
|
||||||
icon: processInfo.icon,
|
icon: processInfo.icon,
|
||||||
path: processInfo.startName,
|
path: processInfo.startName,
|
||||||
col: x,
|
x: oldAppIcon ? oldAppIcon.x : x,
|
||||||
row: y
|
y: oldAppIcon ? oldAppIcon.y : y
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const appIconsRef = reactive(appIcons)
|
|
||||||
|
|
||||||
watch(() => [gridTemplate.rowCount, gridTemplate.colCount], () => {
|
const appIconsRef = ref(appIcons)
|
||||||
appIconsRef.forEach((appIcon, index) => {
|
|
||||||
const x = Math.floor(index / gridTemplate.rowCount) + 1
|
watch(() => [gridTemplate.rowCount, gridTemplate.colCount], ([nRows, nCols], [oRows, oCols]) => {
|
||||||
const y = index % gridTemplate.rowCount + 1
|
if (oCols == 1 && oRows == 1) return
|
||||||
appIcon.col = x
|
appIconsRef.value = rearrangeIcons(toRaw(appIconsRef.value), nCols, nRows, oCols, oRows)
|
||||||
appIcon.row = y
|
})
|
||||||
})
|
|
||||||
|
XSystem.instance.eventManages.addEventListener(DesktopEventEnum.onDesktopAppIconPos, (iconInfo) => {
|
||||||
|
localStorage.setItem('desktopAppIconInfo', JSON.stringify(toValue(appIconsRef.value)))
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -86,4 +94,63 @@ export function useDesktopInit(containerStr: string) {
|
|||||||
appIconsRef,
|
appIconsRef,
|
||||||
gridStyle
|
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'
|
import type { IEventMap } from '@/core/events/IEventBuilder.ts'
|
||||||
|
import type { IDesktopAppIcon } from '@/core/desktop/types/IDesktopAppIcon.ts'
|
||||||
/**
|
|
||||||
* 桌面进程事件枚举
|
|
||||||
* @description
|
|
||||||
* <p>onDesktopRootDomResize - 桌面根dom尺寸改变</p>
|
|
||||||
* <p>onDesktopProcessInitialize - 桌面进程初始化完成</p>
|
|
||||||
*/
|
|
||||||
export enum DesktopEventEnum {
|
|
||||||
/** 桌面进程初始化完成 */
|
|
||||||
onDesktopRootDomResize = 'onDesktopRootDomResize',
|
|
||||||
/** 桌面进程初始化完成 */
|
|
||||||
onDesktopProcessInitialize = 'onDesktopProcessInitialize'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础系统进程事件枚举
|
* 基础系统进程事件枚举
|
||||||
@@ -28,19 +16,6 @@ export enum BasicSystemEventEnum {
|
|||||||
onThemeChange = 'onThemeChange'
|
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
|
* @description
|
||||||
@@ -54,4 +29,35 @@ export interface IBasicSystemEvent extends IEventMap {
|
|||||||
[BasicSystemEventEnum.onThemeChange]: (theme: string) => void
|
[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 {}
|
export interface IAllEvent extends IDesktopEvent, IBasicSystemEvent {}
|
||||||
|
|||||||
@@ -16,5 +16,6 @@
|
|||||||
"noUnusedParameters": false, // 检查未使用的参数
|
"noUnusedParameters": false, // 检查未使用的参数
|
||||||
"noImplicitReturns": true, // 检查函数所有路径是否都有返回值
|
"noImplicitReturns": true, // 检查函数所有路径是否都有返回值
|
||||||
"noImplicitOverride": true, // 检查子类是否正确覆盖了父类方法
|
"noImplicitOverride": true, // 检查子类是否正确覆盖了父类方法
|
||||||
|
"allowSyntheticDefaultImports": true // 允许使用默认导入
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user