Browse Source

add:兼容移动端静态样式

master
tiantian 6 months ago
parent
commit
8e50f0717d
  1. 7
      frontend/components.d.ts
  2. 4
      frontend/index.html
  3. 20
      frontend/package-lock.json
  4. 1
      frontend/package.json
  5. 10
      frontend/src/App.vue
  6. 47
      frontend/src/components/desktop/mobile/BottomBar.vue
  7. 105
      frontend/src/components/desktop/mobile/Mobile.vue
  8. 43
      frontend/src/components/desktop/mobile/MobileApp.vue
  9. 16
      frontend/src/components/desktop/mobile/util.scss
  10. 10
      frontend/src/util/device.ts
  11. 8
      frontend/vite.config.ts

7
frontend/components.d.ts

@ -25,6 +25,7 @@ declare module 'vue' {
AssistantAdd: typeof import('./src/components/ai/AssistantAdd.vue')['default']
Battery: typeof import('./src/components/taskbar/Battery.vue')['default']
BatteryPop: typeof import('./src/components/taskbar/BatteryPop.vue')['default']
BottomBar: typeof import('./src/components/desktop/mobile/BottomBar.vue')['default']
Browser: typeof import('./src/components/builtin/Browser.vue')['default']
Calendar: typeof import('./src/components/builtin/Calendar.vue')['default']
Chat: typeof import('./src/components/chat/Chat.vue')['default']
@ -73,13 +74,9 @@ declare module 'vue' {
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTag: typeof import('element-plus/es')['ElTag']
Error: typeof import('./src/components/taskbar/Error.vue')['default']
FileIcon: typeof import('./src/components/builtin/FileIcon.vue')['default']
FileIconImg: typeof import('./src/components/builtin/FileIconImg.vue')['default']
@ -103,6 +100,8 @@ declare module 'vue' {
MenuList: typeof import('./src/components/taskbar/MenuList.vue')['default']
MessageCenterPop: typeof import('./src/components/taskbar/MessageCenterPop.vue')['default']
MessageIcon: typeof import('./src/components/taskbar/MessageIcon.vue')['default']
Mobile: typeof import('./src/components/desktop/mobile/Mobile.vue')['default']
MobileApp: typeof import('./src/components/desktop/mobile/MobileApp.vue')['default']
MusicStore: typeof import('./src/components/builtin/MusicStore.vue')['default']
MusicViewer: typeof import('./src/components/builtin/MusicViewer.vue')['default']
NetWork: typeof import('./src/components/taskbar/NetWork.vue')['default']

4
frontend/index.html

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>GodoOS</title>
<script src="/font/iconfont.js"></script>
<style>
@ -14,7 +14,7 @@
fill: currentColor;
overflow: hidden;
}
</style>
</head>

20
frontend/package-lock.json

@ -21,6 +21,7 @@
"moment": "^2.30.1",
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",
"swiper": "^11.1.15",
"vue": "^3.4.31",
"vue-i18n": "^9.13.1",
"vue-router": "^4.4.0",
@ -3436,6 +3437,25 @@
"integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==",
"optional": true
},
"node_modules/swiper": {
"version": "11.1.15",
"resolved": "https://registry.npmmirror.com/swiper/-/swiper-11.1.15.tgz",
"integrity": "sha512-IzWeU34WwC7gbhjKsjkImTuCRf+lRbO6cnxMGs88iVNKDwV+xQpBCJxZ4bNH6gSrIbbyVJ1kuGzo3JTtz//CBw==",
"funding": [
{
"type": "patreon",
"url": "https://www.patreon.com/swiperjs"
},
{
"type": "open_collective",
"url": "http://opencollective.com/swiper"
}
],
"license": "MIT",
"engines": {
"node": ">= 4.7.0"
}
},
"node_modules/symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz",

1
frontend/package.json

@ -22,6 +22,7 @@
"moment": "^2.30.1",
"pinia": "^2.1.7",
"pinia-plugin-persist": "^1.0.0",
"swiper": "^11.1.15",
"vue": "^3.4.31",
"vue-i18n": "^9.13.1",
"vue-router": "^4.4.0",

10
frontend/src/App.vue

@ -1,12 +1,18 @@
<script setup lang="ts">
import { System } from "@/system/index.ts";
import { onMounted } from "vue";
import { onMounted} from "vue";
import { isMobileDevice } from "@/util/device";
onMounted(() => {
new System();
isMobile.value = isMobileDevice();
console.log(isMobile.value);
});
const isMobile = ref<boolean>(false);
</script>
<template>
<screen />
<screen v-if="!isMobile"/>
<mobile v-else></Mobile>
</template>

47
frontend/src/components/desktop/mobile/BottomBar.vue

@ -0,0 +1,47 @@
<template>
<div class="bottom-bar">
<MobileApp v-for="item in bottomBarList" :key="item.name" :item="item"></MobileApp>
</div>
</template>
<script setup lang="ts">
import { ref,watch } from 'vue';
const props = defineProps(['list']);
const bottomBarList = ref<any[]>([]);
watch(props.list,() => {
console.log(props.list, '~~~~~~~');
if (Array.isArray(props.list) && props.list.length > 0) {
props.list.forEach((item: any) => {
console.log(item.name.includes('computer'), 'item.name=======');
if (item.name.includes('computer') || item.name.includes('localchat')) {
bottomBarList.value.push(item);
}
});
console.log(bottomBarList.value, 'bottomBarList============================================');
} else {
console.log('props.list is empty or not an array');
}
},{
immediate:true
});
</script>
<style lang="scss" scoped>
.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);
}
</style>

105
frontend/src/components/desktop/mobile/Mobile.vue

@ -0,0 +1,105 @@
<template>
<div class="desktop" :style="{ backgroundColor: background }">
<DesktopBackground class="userarea-upper"></DesktopBackground>
<template v-if="backgroundType == 'image'">
</template>
<div class="dest-item userarea-upper">
<!-- Swiper -->
<swiper :modules="modules" :loop="true" :slides-per-view="1" :space-between="20"
:pagination="{ type: 'bullets', clickable: true }" class="swiperBox" @swiper="onSwiper"
@slideChange="onSlideChange">
<swiper-slide class="swiper-slide">
<MobileApp v-for="item in appList" :key="item.name" :item="item" class="item"></MobileApp>
</swiper-slide>
<swiper-slide></swiper-slide>
<swiper-slide></swiper-slide>
</swiper>
</div>
<BottomBar :list="appList"></BottomBar>
</div>
</template>
<script lang="ts" setup>
import { Bios, System, useSystem } from '@/system';
import { ref, onMounted } from 'vue';
import { RootState } from '@/system/root.ts';
import { Swiper, SwiperSlide } from 'swiper/vue'
// swiper
import 'swiper/swiper-bundle.css';
// swiper
import { Pagination } from 'swiper/modules'
import { useAppOpen } from "@/hook/useAppOpen";
const { openapp, appList } = useAppOpen("apps");
console.log(appList,'appList======')
console.log(openapp,'openapp=======')
// modules使
const modules = [Pagination]
const onSwiper = (swiper: any) => {
console.log(swiper);
};
// swiper
const onSlideChange = (swiper: any) => {
// swiperswiperactiveIndex
console.log(swiper.activeIndex)
}
const mobileref = ref();
const rootState = ref<RootState | undefined>(useSystem()?._rootState);
const backgroundType = ref("color");
const background: any = ref('#3A98CE');
// const
onMounted(() => {
refershBack(rootState.value?.options.background);
});
function refershBack(val: string | undefined) {
background.value = val || "#3A98CE";
if (background.value || background.value.startsWith("/image/")) {
backgroundType.value = "image";
} else {
backgroundType.value = "color";
}
}
Bios.onOpen((system: System) => {
rootState.value = system._rootState;
system.rootRef = mobileref.value;
});
</script>
<style lang="scss" scoped>
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
.desktop {
position: relative;
background-color: #3A98CE;
background: url('@/pubic/image/bg/bg6.jpg');
height: 100vh;
overflow: hidden;
.userarea-upper {
position: absolute;
top: 0;
left: 0;
}
.dest-item{
z-index: 2;
.swiperBox {
width: 100vw;
padding:vw(20);
// position: absolute;
// top:0;
// left: 0;
height: vh(560);
.swiper-slide{
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(4,vh(100))
}
}
}
}
</style>

43
frontend/src/components/desktop/mobile/MobileApp.vue

@ -0,0 +1,43 @@
<template>
<div class="file-item">
<FileIcon :file="item" class="icon"</FileIcon>
<span class="title">{{ getName(item) }}</span>
</div>
</template>
<script setup lang="ts">
import {
basename,
} from "@/system/index.ts";
import { dealSystemName, t } from "@/i18n";
defineProps(['item'])
function getName(item: any) {
const name = dealSystemName(basename(item.path));
// console.log(name)
// console.log(item.path)
if (name.endsWith(".exe")) {
return t(name.replace(".exe", ""));
} else {
return name;
}
}
</script>
<style lang="scss" scoped>
.file-item{
height: vh(70);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
.icon{
width: vw(40);
height: vh(40);
}
.title{
font-size: vw(12);
text-align: center;
}
}
</style>

16
frontend/src/components/desktop/mobile/util.scss

@ -0,0 +1,16 @@
@use "sass:math";
// 默认设计稿的宽度
$designWidth: 375;
// 默认设计稿的高度
$designHeight: 667;
// px 转为 vw 的函数
@function vw($px) {
@return math.div($px, $designWidth) * 100vw;
}
// px 转为 vh 的函数
@function vh($px) {
@return math.div($px, $designHeight) * 100vh;
}

10
frontend/src/util/device.ts

@ -0,0 +1,10 @@
export const isMobileDevice=() =>{
const userAgent = navigator.userAgent.toLowerCase();
const mobileKeywords = ['iphone', 'android', 'mobile', 'blackberry', 'iemobile', 'opera mini'];
for (const keyword of mobileKeywords) {
if (userAgent.includes(keyword)) {
return true;
}
}
return false;
}

8
frontend/vite.config.ts

@ -21,7 +21,13 @@ export default defineConfig(async () => ({
resolvers: [ElementPlusResolver()],
}),
],
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "./src/components/desktop/mobile/util.scss";`
}
}
},
clearScreen: false,
server: {
host: '0.0.0.0',

Loading…
Cancel
Save