Browse Source

add:移动端适配

master
tiantian 6 months ago
parent
commit
8fad22cbea
  1. 1
      frontend/package.json
  2. 973
      frontend/src/components/computer/Computer.vue
  3. 57
      frontend/src/components/desktop/DeskItem.vue
  4. 141
      frontend/src/components/desktop/Desktop.vue
  5. 4
      frontend/src/components/window/WindowNode.vue
  6. 702
      frontend/src/components/window/WindowTemplate.vue
  7. 26
      frontend/src/main.ts

1
frontend/package.json

@ -23,6 +23,7 @@
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",
"swiper": "^11.1.15",
"vant": "^4.9.15",
"vue": "^3.4.31",
"vue-i18n": "^9.13.1",
"vue-router": "^4.4.0",

973
frontend/src/components/computer/Computer.vue

File diff suppressed because it is too large

57
frontend/src/components/desktop/DeskItem.vue

@ -8,17 +8,30 @@
<swiper-slide class="swiper-slide">
<FileList :on-chosen="props.onChosen" :on-open="openapp" :file-list="appList"></FileList>
</swiper-slide>
<swiper-slide></swiper-slide>
<swiper-slide>
<div @click.stop="handle(item)" class="magnet-item" :style="{
animationDelay: `${Math.floor(index / 4) * 0.02}s`,
animationDuration: `${Math.floor(index / 4) * 0.04 + 0.1}s`,
}" v-for="(item, index) in menulist" v-glowing :key="basename(item.path)">
<FileIcon class="magnet-item_img" :file="item" />
<span class="magnet-item_title">{{ getName(item) }}</span>
</div>
</swiper-slide>
</swiper>
</div>
</template>
<script lang="ts" setup>
import { mountEvent } from "@/system/event";
import { useSystem } from "@/system/index.ts";
import { useSystem, BrowserWindow } from "@/system/index.ts";
import { useAppOpen } from "@/hook/useAppOpen";
import { onMounted } from "vue";
import { isMobileDevice } from "@/util/device";
import { Swiper, SwiperSlide } from 'swiper/vue'
import { basename } from "@/system/core/Path";
import { emitEvent } from "@/system/event";
import { t } from "@/i18n";
// swiper
import 'swiper/swiper-bundle.css';
// swiper
@ -26,6 +39,7 @@ import { Pagination } from 'swiper/modules'
// modules使
const modules = [Pagination]
const { openapp, appList } = useAppOpen("apps");
const { appList: menulist } = useAppOpen("menulist")
const props = defineProps({
onChosen: {
type: Function,
@ -37,6 +51,31 @@ onMounted(() => {
useSystem().initAppList();
});
});
function handle(item: any) {
emitEvent("magnet.item.click", item);
const sys = useSystem();
const winopt = sys._rootState.windowMap["Menulist"].get(item.title);
if (winopt) {
if (winopt._hasShow) {
return;
} else {
winopt._hasShow = true;
const win = new BrowserWindow(winopt.window);
win.show();
win.on("close", () => {
winopt._hasShow = false;
});
}
}
}
function getName(item: any) {
const name = basename(item.path);
if (name.endsWith(".exe")) {
return t(name.replace(".exe", ""));
} else {
return name;
}
}
</script>
<style lang="scss" scoped>
.desk-group {
@ -62,7 +101,7 @@ onMounted(() => {
.swiperBox {
width: 100vw;
padding-top: vh(20);
padding-top: vh(10);
// position: absolute;
// top:0;
// left: 0;
@ -74,4 +113,16 @@ onMounted(() => {
grid-template-rows: repeat(5, vh(100))
}
}
.magnet-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.magnet-item_img {
width: vw(40);
height: vh(40);
}
}
</style>

141
frontend/src/components/desktop/Desktop.vue

@ -19,6 +19,15 @@
<div class="bottom">
<Taskbar></Taskbar>
</div>
<div class="bottom-bar" v-if="isMobileDevice()">
<div @click.stop="handle(item)" class="magnet-item" :style="{
animationDelay: `${Math.floor(index / 4) * 0.02}s`,
animationDuration: `${Math.floor(index / 4) * 0.04 + 0.1}s`,
}" v-for="(item, index) in bottomApp" v-glowing :key="basename(item.path)">
<FileIcon class="magnet-item_img" :file="item" />
<span class="magnet-item_title">{{ getName(item) }}</span>
</div>
</div>
<ContextMenu></ContextMenu>
</div>
</template>
@ -27,10 +36,113 @@ import { emitEvent } from "@/system/event";
import { useContextMenu } from "@/hook/useContextMenu";
import { useFileDrag } from "@/hook/useFileDrag";
import { Rect, useRectChosen } from "@/hook/useRectChosen";
import { useSystem } from "@/system";
import { useSystem, BrowserWindow } from "@/system";
import { onErrorCaptured } from "vue";
import { useUpgradeStore } from '@/stores/upgrade';
import { isMobileDevice } from "@/util/device";
import { basename } from "@/system/core/Path";
import { t } from "@/i18n";
import { useAppOpen } from "@/hook/useAppOpen";
const { openapp } = useAppOpen("menulist");
function handle(item: any) {
if (item.name.includes('localchat')) {
openapp(item);
emitEvent("desktop.app.open");
} else {
emitEvent("magnet.item.click", item);
}
const sys = useSystem();
const winopt = sys._rootState.windowMap["Menulist"].get(item.title);
if (winopt) {
if (winopt._hasShow) {
return;
} else {
winopt._hasShow = true;
winopt.window.fullscreen = true
const win = new BrowserWindow(winopt.window);
win.show();
win.on("close", () => {
winopt._hasShow = false;
});
}
}
}
function getName(item: any) {
const name = basename(item.path);
if (name.endsWith(".exe")) {
return t(name.replace(".exe", ""));
} else {
return name;
}
}
const bottomApp = [
{
"isFile": true,
"isDirectory": false,
"isSymlink": false,
"size": 32,
"modTime": "2024-12-16T09:17:18.7214789+08:00",
"atime": "2024-12-16T09:17:18.7214789+08:00",
"birthtime": "2024-12-16T09:17:18.7214789+08:00",
"mtime": "2024-12-16T09:17:18.7214789+08:00",
"rdev": 0,
"mode": 511,
"name": "computer.exe",
"path": "/C/Users/Menulist/computer.exe",
"oldPath": "/C/Users/Menulist/computer.exe",
"parentPath": "/C/Users/Menulist",
"content": "link::Desktop::computer::diannao",
"ext": "exe",
"title": "computer",
"id": 1,
"isPwd": false
},
{
"isFile": true,
"isDirectory": false,
"isSymlink": false,
"size": 31,
"modTime": "2024-12-16T09:17:18.7214789+08:00",
"atime": "2024-12-16T09:17:18.7214789+08:00",
"birthtime": "2024-12-16T09:17:18.7214789+08:00",
"mtime": "2024-12-16T09:17:18.7214789+08:00",
"rdev": 0,
"mode": 511,
"name": "setting.exe",
"path": "/C/Users/Menulist/setting.exe",
"oldPath": "/C/Users/Menulist/setting.exe",
"parentPath": "/C/Users/Menulist",
"content": "link::Desktop::setting::setting",
"ext": "exe",
"title": "setting",
"id": 15,
"isPwd": false
},
{
"isFile": true,
"isDirectory": false,
"isSymlink": false,
"size": 30,
"modTime": "2024-12-16T09:17:18.7214789+08:00",
"atime": "2024-12-16T09:17:18.7214789+08:00",
"birthtime": "2024-12-16T09:17:18.7214789+08:00",
"mtime": "2024-12-16T09:17:18.7214789+08:00",
"rdev": 0,
"mode": 511,
"name": "localchat.exe",
"path": "/C/Users/Desktop/localchat.exe",
"oldPath": "/C/Users/Desktop/localchat.exe",
"parentPath": "/C/Users/Desktop",
"content": "link::Desktop::localchat::chat",
"ext": "exe",
"title": "localchat",
"id": 3,
"isPwd": false
}
];
const { createDesktopContextMenu } = useContextMenu();
const { choseStart, chosing, choseEnd, getRect, Chosen } = useRectChosen();
const system = useSystem();
@ -119,5 +231,32 @@ onErrorCaptured((err) => {
.bottom {
display: none;
}
.bottom-bar {
display: flex;
justify-content: space-evenly;
position: absolute;
width: vw(340);
left: 50%;
transform: translateX(-50%);
bottom: vh(15);
height: vh(80);
border-radius: vw(50);
color: #e5e3e3d5;
background-color: rgba(255, 255, 255, .2);
backdrop-filter: blur(15px);
.magnet-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.magnet-item_img {
width: vw(40);
height: vh(40);
}
}
}
}
</style>

4
frontend/src/components/window/WindowNode.vue

@ -1,13 +1,11 @@
<template>
<Transition name="windowanimate" appear>
<WindowTemplate v-if="window.windowInfo.isCreated && !isMobileDevice()" :browser-window="window"></WindowTemplate>
<MobileTemplate v-else></MobileTemplate>
<WindowTemplate v-if="window.windowInfo.isCreated" :browser-window="window"></WindowTemplate>
</Transition>
<WindowNode v-for="node in window.children" :key="node.id" :window="node" />
</template>
<script lang="ts" setup>
import { BrowserWindow } from "@/system/window/BrowserWindow";
import { isMobileDevice } from "@/util/device";
import { UnwrapNestedRefs } from "vue";
defineProps<{
window: UnwrapNestedRefs<BrowserWindow>;

702
frontend/src/components/window/WindowTemplate.vue

@ -1,399 +1,419 @@
<template>
<div
class="wintmp_outer dragwin"
:class="{
topwin: istop,
max: windowInfo.state == WindowStateEnum.maximize,
min: windowInfo.state == WindowStateEnum.minimize,
fullscreen: windowInfo.state == WindowStateEnum.fullscreen,
noframe: !windowInfo.frame,
disable: windowInfo.disable,
}"
:style="customerStyle"
@touchstart.passive="onFocus"
@mousedown="onFocus"
ref="$win_outer"
v-dragable
>
<div class="wintmp_outer dragwin" :class="{
topwin: istop,
max: windowInfo.state == WindowStateEnum.maximize,
min: windowInfo.state == WindowStateEnum.minimize,
fullscreen: windowInfo.state == WindowStateEnum.fullscreen,
noframe: !windowInfo.frame,
disable: windowInfo.disable,
}" :style="customerStyle" @touchstart.passive="onFocus" @mousedown="onFocus" ref="$win_outer" v-dragable>
<!-- 窗口标题栏 -->
<div
class="wintmp_uper"
@contextmenu.prevent
>
<div class="wintmp_uper" @contextmenu.prevent v-if="!isMobileDevice()">
<MenuBar :browser-window="browserWindow"></MenuBar>
</div>
<van-nav-bar v-else left-text="返回" left-arrow @click-left="onClickLeft" fixed>
<template #title>
<div class="title">
<FileIcon :icon="browserWindow.windowInfo.icon" />
{{ browserWindow.windowInfo.title }}
</div>
</template>
</van-nav-bar>
<div
class="wintmp_main"
:class="{ resizeing: resizemode != 'null', 'saveFileMain':browserWindow.windowInfo.footer}"
@mousedown.stop="predown"
@touchstart.stop.passive="predown"
@contextmenu.stop.prevent
>
<div
class="content-mask"
v-if="!istop && typeof browserWindow.content === 'string'"
></div>
<div class="wintmp_main"
:class="{ resizeing: resizemode != 'null', 'saveFileMain': browserWindow.windowInfo.footer }"
@mousedown.stop="predown" @touchstart.stop.passive="predown" @contextmenu.stop.prevent>
<div class="content-mask" v-if="!istop && typeof browserWindow.content === 'string'"></div>
<WindowInner :win="browserWindow"></WindowInner>
</div>
<!-- 使用 v-for 生成拖拽边界 -->
<div
v-for="border in dragBorders"
:key="border.type"
:class="[
border.class,
'win_drag_border',
{ isChoseMode: resizemode == border.type },
border.cursorClass,
]"
v-if="resizable"
draggable="false"
@mousedown.stop.prevent="startScale($event, border.type)"
@touchstart.stop.passive="startScale($event, border.type)"
></div>
<div class="wintmp_footer" v-if="browserWindow.windowInfo.footer">
<MenuFooter :browser-window="browserWindow" @translateSavePath="translateSavePath"></MenuFooter>
</div>
<div v-for="border in dragBorders" :key="border.type" :class="[
border.class,
'win_drag_border',
{ isChoseMode: resizemode == border.type },
border.cursorClass,
]" v-if="resizable" draggable="false" @mousedown.stop.prevent="startScale($event, border.type)"
@touchstart.stop.passive="startScale($event, border.type)"></div>
<div class="wintmp_footer" v-if="browserWindow.windowInfo.footer">
<MenuFooter :browser-window="browserWindow" @translateSavePath="translateSavePath"></MenuFooter>
</div>
</div>
</template>
<script lang="ts" setup>
import { useSystem } from "@/system";
import { emitEvent } from "@/system/event";""
import {
BrowserWindow,
WindowStateEnum,
} from "@/system/window/BrowserWindow";
import { ScaleElement } from "@/system/window/dom/ScaleElement";
import { vDragable } from "@/system/window/MakeDragable";
import {
computed,
onMounted,
onUnmounted,
provide,
ref,
UnwrapNestedRefs,
} from "vue";
import { useChooseStore } from "@/stores/choose";
import eventBus from '@/system/event/eventBus'
const sys = useSystem();
const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>;
}>();
const browserWindow = props.browserWindow;
const windowInfo = browserWindow.windowInfo;
// const temp = reactive(browserWindow)
provide("browserWindow", browserWindow);
provide("system", sys);
const choose = useChooseStore()
function translateSavePath (path: string, name?: string) {
if (browserWindow.windowInfo.footer) {
const pos = choose.saveFileContent.findIndex((item: any) => {
return item.componentID == browserWindow.windowInfo.componentID
})
if (pos == -1) return
if (path && path !== '') {
choose.saveFileContent[pos].filePath = path
} else if (name && name !== '') {
choose.saveFileContent[pos].fileName = name
eventBus.emit('saveFile', choose.saveFileContent[pos] )
}
}
}
provide('translateSavePath', translateSavePath)
function predown() {
browserWindow.moveTop();
emitEvent("window.content.click", browserWindow);
import { useSystem } from "@/system";
import { emitEvent } from "@/system/event"; ""
import {
BrowserWindow,
WindowStateEnum,
} from "@/system/window/BrowserWindow";
import { ScaleElement } from "@/system/window/dom/ScaleElement";
import { vDragable } from "@/system/window/MakeDragable";
import {
computed,
onMounted,
onUnmounted,
provide,
ref,
UnwrapNestedRefs,
} from "vue";
import { useChooseStore } from "@/stores/choose";
import eventBus from '@/system/event/eventBus'
import { isMobileDevice } from "@/util/device";
const onClickLeft = () => {
if (choose.isExist(props.browserWindow.windowInfo.componentID)) {
choose.closeSaveFile(props.browserWindow.windowInfo.componentID)
}
props.browserWindow.destroy();
}
const customerStyle = ref<NonNullable<unknown>>({});
const sys = useSystem();
const props = defineProps<{
browserWindow: UnwrapNestedRefs<BrowserWindow>;
}>();
function onFocus(e: MouseEvent | TouchEvent): void {
browserWindow?.moveTop();
if (windowInfo.state === WindowStateEnum.maximize) {
if (e instanceof MouseEvent) {
e.preventDefault();
e.stopPropagation();
}
const browserWindow = props.browserWindow;
if (isMobileDevice()) browserWindow.maximize()
const windowInfo = browserWindow.windowInfo;
console.log(windowInfo, 'windowInfo')
// const temp = reactive(browserWindow)
provide("browserWindow", browserWindow);
provide("system", sys);
const choose = useChooseStore()
function translateSavePath(path: string, name?: string) {
if (browserWindow.windowInfo.footer) {
const pos = choose.saveFileContent.findIndex((item: any) => {
return item.componentID == browserWindow.windowInfo.componentID
})
if (pos == -1) return
if (path && path !== '') {
choose.saveFileContent[pos].filePath = path
} else if (name && name !== '') {
choose.saveFileContent[pos].fileName = name
eventBus.emit('saveFile', choose.saveFileContent[pos])
}
}
}
provide('translateSavePath', translateSavePath)
function predown() {
browserWindow.moveTop();
emitEvent("window.content.click", browserWindow);
}
const customerStyle = ref<NonNullable<unknown>>({});
function onFocus(e: MouseEvent | TouchEvent): void {
browserWindow?.moveTop();
if (windowInfo.state === WindowStateEnum.maximize) {
if (e instanceof MouseEvent) {
e.preventDefault();
e.stopPropagation();
}
}
}
const istop = computed(() => windowInfo.istop);
onMounted(() => {
customerStyle.value = {
width: computed(() => windowInfo.width + "px"),
height: computed(() => windowInfo.height + "px"),
left: computed(() => windowInfo.x + "px"),
top: computed(() => windowInfo.y + "px"),
zIndex: computed(() => {
if (windowInfo.alwaysOnTop) {
return 9999;
}
return windowInfo.zindex;
}),
backgroundColor: computed(() => windowInfo.backgroundColor),
};
});
const resizable = ref(windowInfo.resizable);
const resizemode = ref("null");
let scaleAble: ScaleElement;
onMounted(() => {
scaleAble = new ScaleElement(
resizemode,
windowInfo.width,
windowInfo.height,
windowInfo.x,
windowInfo.y
);
scaleAble.onResize(
(width: number, height: number, x: number, y: number) => {
windowInfo.width = width || windowInfo.width;
windowInfo.height = height || windowInfo.height;
windowInfo.x = x || windowInfo.x;
windowInfo.y = y || windowInfo.y;
browserWindow.emit(
"resize",
windowInfo.width,
windowInfo.height
);
const istop = computed(() => windowInfo.istop);
onMounted(() => {
customerStyle.value = {
width: computed(() => windowInfo.width + "px"),
height: computed(() => windowInfo.height + "px"),
left: computed(() => windowInfo.x + "px"),
top: computed(() => windowInfo.y + "px"),
zIndex: computed(() => {
if (windowInfo.alwaysOnTop) {
return 9999;
}
);
});
return windowInfo.zindex;
}),
backgroundColor: computed(() => windowInfo.backgroundColor),
};
});
const resizable = ref(windowInfo.resizable);
const resizemode = ref("null");
let scaleAble: ScaleElement;
function startScale(e: MouseEvent | TouchEvent, dire: string) {
console.log(e);
if (windowInfo.disable) {
return;
onMounted(() => {
scaleAble = new ScaleElement(
resizemode,
windowInfo.width,
windowInfo.height,
windowInfo.x,
windowInfo.y
);
scaleAble.onResize(
(width: number, height: number, x: number, y: number) => {
windowInfo.width = width || windowInfo.width;
windowInfo.height = height || windowInfo.height;
windowInfo.x = x || windowInfo.x;
windowInfo.y = y || windowInfo.y;
browserWindow.emit(
"resize",
windowInfo.width,
windowInfo.height
);
}
scaleAble?.startScale(
e,
dire,
windowInfo.x,
windowInfo.y,
windowInfo.width,
windowInfo.height
);
);
});
function startScale(e: MouseEvent | TouchEvent, dire: string) {
console.log(e);
if (windowInfo.disable) {
return;
}
scaleAble?.startScale(
e,
dire,
windowInfo.x,
windowInfo.y,
windowInfo.width,
windowInfo.height
);
}
onUnmounted(() => {
scaleAble.unMount();
});
onUnmounted(() => {
scaleAble.unMount();
});
const dragBorders = [
{ type: "r", class: "right_border", cursorClass: "ew-resize" },
{ type: "b", class: "bottom_border", cursorClass: "ns-resize" },
{ type: "l", class: "left_border", cursorClass: "ew-resize" },
{ type: "t", class: "top_border", cursorClass: "ns-resize" },
{
type: "rb",
class: "right_bottom_border",
cursorClass: "nwse-resize",
},
{ type: "lb", class: "left_bottom_border", cursorClass: "nesw-resize" },
{ type: "lt", class: "left_top_border", cursorClass: "nwse-resize" },
{ type: "rt", class: "right_top_border", cursorClass: "nesw-resize" },
];
const dragBorders = [
{ type: "r", class: "right_border", cursorClass: "ew-resize" },
{ type: "b", class: "bottom_border", cursorClass: "ns-resize" },
{ type: "l", class: "left_border", cursorClass: "ew-resize" },
{ type: "t", class: "top_border", cursorClass: "ns-resize" },
{
type: "rb",
class: "right_bottom_border",
cursorClass: "nwse-resize",
},
{ type: "lb", class: "left_bottom_border", cursorClass: "nesw-resize" },
{ type: "lt", class: "left_top_border", cursorClass: "nwse-resize" },
{ type: "rt", class: "right_top_border", cursorClass: "nesw-resize" },
];
</script>
<style>
.dragwin {
position: absolute;
width: 100%;
height: 100%;
}
.dragwin {
position: absolute;
width: 100%;
height: 100%;
}
</style>
<style scoped lang="scss">
.wintmp_outer {
position: absolute;
padding: 0;
margin: 0;
// left: 0;
// top: 0;
// min-width: 800px;
width: max-content;
height: max-content;
// min-height: 650px;
border-radius: 10px;
.wintmp_outer {
position: absolute;
padding: 0;
margin: 0;
// left: 0;
// top: 0;
// min-width: 800px;
width: max-content;
height: max-content;
// min-height: 650px;
border-radius: 10px;
overflow: hidden;
background-color: #fff;
border: var(--window-border);
display: flex;
flex-direction: column;
// box-shadow: var(--window-box-shadow);
// border-radius: var(--window-border-radius);
.wintmp_main {
position: relative;
width: 100%;
height: 100%;
// background-color: rgb(255, 255, 255);
overflow: hidden;
background-color: #fff;
border: var(--window-border);
display: flex;
flex-direction: column;
// box-shadow: var(--window-box-shadow);
// border-radius: var(--window-border-radius);
.wintmp_main {
position: relative;
width: 100%;
height: 100%;
// background-color: rgb(255, 255, 255);
overflow: hidden;
contain: content;
}
.wintmp_footer {
position: relative;
}
}
.saveFileMain {
:deep(.main) {
height: calc(100% - 60px);
}
}
.topwin {
// border: 1px solid #0078d7;
// box-shadow: var(--window-top-box-shadow);
contain: content;
}
.icon {
width: 12px;
height: 12px;
.wintmp_footer {
position: relative;
}
}
.max {
position: absolute;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
transition: left 0.1s ease-in-out, top 0.1s ease-in-out,
width 0.1s ease-in-out, height 0.1s ease-in-out;
}
.disable {
.wintmp_footer,
.wintmp_uper,
.wintmp_main {
pointer-events: none;
user-select: none;
box-shadow: none;
}
}
.min {
visibility: hidden;
display: none;
.saveFileMain {
:deep(.main) {
height: calc(100% - 60px);
}
}
.fullscreen {
//
position: fixed;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
z-index: 205 !important;
border: none;
.wintmp_uper {
display: none;
}
}
.topwin {
// border: 1px solid #0078d7;
// box-shadow: var(--window-top-box-shadow);
}
.icon {
width: 12px;
height: 12px;
}
.max {
position: absolute;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
transition: left 0.1s ease-in-out, top 0.1s ease-in-out,
width 0.1s ease-in-out, height 0.1s ease-in-out;
}
.noframe {
border: none;
.disable {
.wintmp_footer,
.wintmp_uper,
.wintmp_main {
pointer-events: none;
user-select: none;
box-shadow: none;
.wintmp_uper {
display: none;
}
}
}
.transparent {
background-color: transparent;
.min {
visibility: hidden;
display: none;
}
.wintmp_main {
background-color: transparent;
}
.fullscreen {
//
position: fixed;
left: 0 !important;
top: 0 !important;
width: 100% !important;
height: 100% !important;
z-index: 205 !important;
border: none;
.wintmp_uper {
background-color: rgba(255, 255, 255, 0.774);
}
.wintmp_uper {
display: none;
}
}
.win_drag_border {
position: absolute;
background-color: rgba(0, 0, 0, 0);
}
.noframe {
border: none;
box-shadow: none;
.right_border {
cursor: ew-resize;
right: -12px;
width: 16px;
height: calc(100% - 4px);
.wintmp_uper {
display: none;
}
}
.bottom_border {
cursor: ns-resize;
bottom: -12px;
width: calc(100% - 4px);
height: 16px;
}
.transparent {
background-color: transparent;
.left_border {
cursor: ew-resize;
left: -12px;
width: 16px;
height: calc(100% - 4px);
.wintmp_main {
background-color: transparent;
}
.top_border {
cursor: ns-resize;
top: -12px;
width: calc(100% - 4px);
height: 16px;
.wintmp_uper {
background-color: rgba(255, 255, 255, 0.774);
}
}
.left_top_border {
cursor: nwse-resize;
left: -12px;
top: -12px;
width: 16px;
height: 16px;
}
.win_drag_border {
position: absolute;
background-color: rgba(0, 0, 0, 0);
}
.right_top_border {
cursor: nesw-resize;
right: -12px;
top: -12px;
width: 16px;
height: 16px;
}
.right_border {
cursor: ew-resize;
right: -12px;
width: 16px;
height: calc(100% - 4px);
}
.left_bottom_border {
cursor: nesw-resize;
left: -12px;
bottom: -12px;
width: 16px;
height: 16px;
}
.bottom_border {
cursor: ns-resize;
bottom: -12px;
width: calc(100% - 4px);
height: 16px;
}
.right_bottom_border {
cursor: nwse-resize;
right: -12px;
bottom: -12px;
width: 16px;
height: 16px;
}
.left_border {
cursor: ew-resize;
left: -12px;
width: 16px;
height: calc(100% - 4px);
}
.isChoseMode {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
.top_border {
cursor: ns-resize;
top: -12px;
width: calc(100% - 4px);
height: 16px;
}
.resizeing {
user-select: none;
pointer-events: none;
.left_top_border {
cursor: nwse-resize;
left: -12px;
top: -12px;
width: 16px;
height: 16px;
}
.right_top_border {
cursor: nesw-resize;
right: -12px;
top: -12px;
width: 16px;
height: 16px;
}
.left_bottom_border {
cursor: nesw-resize;
left: -12px;
bottom: -12px;
width: 16px;
height: 16px;
}
.right_bottom_border {
cursor: nwse-resize;
right: -12px;
bottom: -12px;
width: 16px;
height: 16px;
}
.isChoseMode {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
}
.resizeing {
user-select: none;
pointer-events: none;
}
.content-mask {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0);
z-index: 100;
}
@media screen and (max-width: 768px) {
.wintmp_outer {
height: vh(100);
padding-top: vh(40);
}
.content-mask {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0);
z-index: 100;
.title {
height: vh(46);
display: flex;
align-items: center;
.icon {
width: 1em;
height: 1em;
}
}
}
</style>

26
frontend/src/main.ts

@ -1,24 +1,26 @@
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
import * as ElementPlusIconsVue from "@element-plus/icons-vue"
//svg插件需要配置代码
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import { createApp } from "vue";
import screenShort from "vue-web-screen-shot";
import App from "./App.vue";
import './assets/windows10.scss';
import { i18n } from './i18n/index.ts';
import pinia from './stores/index.ts';
import router from './system/router';
import ElementPlus from "element-plus"
import "element-plus/dist/index.css"
import { createApp } from "vue"
import screenShort from "vue-web-screen-shot"
import App from "./App.vue"
import "./assets/windows10.scss"
import { i18n } from "./i18n/index.ts"
import pinia from "./stores/index.ts"
import router from "./system/router"
import { NavBar } from "vant"
import "vant/lib/index.css"
const app = createApp(App)
app.use(router)
app.use(ElementPlus)
app.use(pinia)
app.use(i18n)
app.use(NavBar)
app.use(screenShort, { enableWebRtc: true })
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.mount("#app");
app.mount("#app")

Loading…
Cancel
Save