mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 22:18:07 +08:00
feat: 应用商店兼容移动端 (#1119)
#### What this PR does / why we need it? #### Summary of your change #### Please indicate you've done the following: - [ ] Made sure tests are passing and test coverage is added if needed. - [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/). - [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
This commit is contained in:
parent
13abe8cb66
commit
f7c76c012f
@ -1,82 +0,0 @@
|
|||||||
<template>
|
|
||||||
<Layout v-loading="loading" :element-loading-text="loadinText" fullscreen>
|
|
||||||
<template #menu v-if="!globalStore.isFullScreen">
|
|
||||||
<Menu></Menu>
|
|
||||||
</template>
|
|
||||||
<template #footer v-if="!globalStore.isFullScreen">
|
|
||||||
<Footer></Footer>
|
|
||||||
</template>
|
|
||||||
</Layout>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import Layout from '@/layout/index.vue';
|
|
||||||
import Footer from './footer/index.vue';
|
|
||||||
import Menu from './menu/index.vue';
|
|
||||||
import { onMounted, computed, ref, watch, onBeforeUnmount } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import { GlobalStore } from '@/store';
|
|
||||||
import { useTheme } from '@/hooks/use-theme';
|
|
||||||
import { getSettingInfo, getSystemAvailable } from '@/api/modules/setting';
|
|
||||||
|
|
||||||
const i18n = useI18n();
|
|
||||||
const loading = ref(false);
|
|
||||||
const loadinText = ref();
|
|
||||||
const globalStore = GlobalStore();
|
|
||||||
const themeConfig = computed(() => globalStore.themeConfig);
|
|
||||||
const { switchDark } = useTheme();
|
|
||||||
|
|
||||||
let timer: NodeJS.Timer | null = null;
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => globalStore.isLoading,
|
|
||||||
() => {
|
|
||||||
if (globalStore.isLoading) {
|
|
||||||
loadStatus();
|
|
||||||
} else {
|
|
||||||
loading.value = globalStore.isLoading;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const loadDataFromDB = async () => {
|
|
||||||
const res = await getSettingInfo();
|
|
||||||
document.title = res.data.panelName;
|
|
||||||
i18n.locale.value = res.data.language;
|
|
||||||
i18n.warnHtmlMessage = false;
|
|
||||||
globalStore.updateLanguage(res.data.language);
|
|
||||||
globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme });
|
|
||||||
globalStore.setThemeConfig({ ...themeConfig.value, panelName: res.data.panelName });
|
|
||||||
switchDark();
|
|
||||||
};
|
|
||||||
|
|
||||||
const loadStatus = async () => {
|
|
||||||
loading.value = globalStore.isLoading;
|
|
||||||
loadinText.value = globalStore.loadingText;
|
|
||||||
if (loading.value) {
|
|
||||||
timer = setInterval(async () => {
|
|
||||||
await getSystemAvailable()
|
|
||||||
.then((res) => {
|
|
||||||
if (res) {
|
|
||||||
location.reload();
|
|
||||||
clearInterval(Number(timer));
|
|
||||||
timer = null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
location.reload();
|
|
||||||
clearInterval(Number(timer));
|
|
||||||
timer = null;
|
|
||||||
});
|
|
||||||
}, 1000 * 10);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
clearInterval(Number(timer));
|
|
||||||
timer = null;
|
|
||||||
});
|
|
||||||
onMounted(() => {
|
|
||||||
loadStatus();
|
|
||||||
loadDataFromDB();
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="classObj" class="app-wrapper">
|
<div :class="classObj" class="app-wrapper" v-loading="loading" :element-loading-text="loadinText" fullscreen>
|
||||||
<div v-if="classObj.mobile && classObj.openSidebar" class="drawer-bg" @click="handleClickOutside" />
|
<div v-if="classObj.mobile && classObj.openSidebar" class="drawer-bg" @click="handleClickOutside" />
|
||||||
<div class="app-sidebar">
|
<div class="app-sidebar" v-if="!globalStore.isFullScreen">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -9,23 +9,34 @@
|
|||||||
<mobile-header v-if="classObj.mobile" />
|
<mobile-header v-if="classObj.mobile" />
|
||||||
<app-main class="app-main" />
|
<app-main class="app-main" />
|
||||||
|
|
||||||
<Footer class="app-footer" />
|
<Footer class="app-footer" v-if="!globalStore.isFullScreen" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { onMounted, computed, ref, watch, onBeforeUnmount } from 'vue';
|
||||||
import { Sidebar, Footer, AppMain, MobileHeader } from './components';
|
import { Sidebar, Footer, AppMain, MobileHeader } from './components';
|
||||||
import useResize from './hooks/useResize';
|
import useResize from './hooks/useResize';
|
||||||
import { GlobalStore } from '@/store';
|
import { GlobalStore } from '@/store';
|
||||||
import { MenuStore } from '@/store/modules/menu';
|
import { MenuStore } from '@/store/modules/menu';
|
||||||
import { DeviceType } from '@/enums/app';
|
import { DeviceType } from '@/enums/app';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useTheme } from '@/hooks/use-theme';
|
||||||
|
import { getSettingInfo, getSystemAvailable } from '@/api/modules/setting';
|
||||||
useResize();
|
useResize();
|
||||||
|
|
||||||
const menuStore = MenuStore();
|
const menuStore = MenuStore();
|
||||||
const globalStore = GlobalStore();
|
const globalStore = GlobalStore();
|
||||||
|
|
||||||
|
const i18n = useI18n();
|
||||||
|
const loading = ref(false);
|
||||||
|
const loadinText = ref();
|
||||||
|
const themeConfig = computed(() => globalStore.themeConfig);
|
||||||
|
const { switchDark } = useTheme();
|
||||||
|
|
||||||
|
let timer: NodeJS.Timer | null = null;
|
||||||
|
|
||||||
const classObj = computed(() => {
|
const classObj = computed(() => {
|
||||||
return {
|
return {
|
||||||
hideSidebar: menuStore.isCollapse,
|
hideSidebar: menuStore.isCollapse,
|
||||||
@ -37,6 +48,58 @@ const classObj = computed(() => {
|
|||||||
const handleClickOutside = () => {
|
const handleClickOutside = () => {
|
||||||
menuStore.closeSidebar(false);
|
menuStore.closeSidebar(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => globalStore.isLoading,
|
||||||
|
() => {
|
||||||
|
if (globalStore.isLoading) {
|
||||||
|
loadStatus();
|
||||||
|
} else {
|
||||||
|
loading.value = globalStore.isLoading;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const loadDataFromDB = async () => {
|
||||||
|
const res = await getSettingInfo();
|
||||||
|
document.title = res.data.panelName;
|
||||||
|
i18n.locale.value = res.data.language;
|
||||||
|
i18n.warnHtmlMessage = false;
|
||||||
|
globalStore.updateLanguage(res.data.language);
|
||||||
|
globalStore.setThemeConfig({ ...themeConfig.value, theme: res.data.theme });
|
||||||
|
globalStore.setThemeConfig({ ...themeConfig.value, panelName: res.data.panelName });
|
||||||
|
switchDark();
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadStatus = async () => {
|
||||||
|
loading.value = globalStore.isLoading;
|
||||||
|
loadinText.value = globalStore.loadingText;
|
||||||
|
if (loading.value) {
|
||||||
|
timer = setInterval(async () => {
|
||||||
|
await getSystemAvailable()
|
||||||
|
.then((res) => {
|
||||||
|
if (res) {
|
||||||
|
location.reload();
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
location.reload();
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
|
});
|
||||||
|
}, 1000 * 10);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
|
});
|
||||||
|
onMounted(() => {
|
||||||
|
loadStatus();
|
||||||
|
loadDataFromDB();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@ -6,4 +6,32 @@
|
|||||||
.mobile-monitor-chart {
|
.mobile-monitor-chart {
|
||||||
margin-top: 20px !important;
|
margin-top: 20px !important;
|
||||||
}
|
}
|
||||||
|
.search-button {
|
||||||
|
float: none !important;
|
||||||
|
.table-button {
|
||||||
|
display: inline-flex !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-card {
|
||||||
|
.app-button {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.install-card .a-detail {
|
||||||
|
.d-name {
|
||||||
|
height: auto !important;
|
||||||
|
.h-button {
|
||||||
|
float: none !important;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.d-button {
|
||||||
|
min-width: auto !important;
|
||||||
|
}
|
||||||
|
.d-description {
|
||||||
|
display: block !important;
|
||||||
|
overflow: inherit !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<LayoutContent v-loading="loading" v-if="!showDetail" :title="$t('app.app')">
|
<LayoutContent v-loading="loading" v-if="!showDetail" :title="$t('app.app')">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
<el-col :span="20">
|
<el-col :xs="24" :sm="24" :md="20" :lg="20" :xl="20">
|
||||||
<el-button
|
<el-button
|
||||||
class="tag-button"
|
class="tag-button"
|
||||||
:class="activeTag === 'all' ? '' : 'no-active'"
|
:class="activeTag === 'all' ? '' : 'no-active'"
|
||||||
@ -24,7 +24,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :xs="24" :sm="24" :md="4" :lg="4" :xl="4">
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="req.name"
|
v-model="req.name"
|
||||||
@ -45,11 +45,11 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #main>
|
<template #main>
|
||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
<el-col v-for="(app, index) in apps" :key="index" :xs="12" :sm="12" :md="8" :lg="8" :xl="8">
|
<el-col v-for="(app, index) in apps" :key="index" :xs="24" :sm="12" :md="8" :lg="8" :xl="8">
|
||||||
<div class="app-card">
|
<div class="app-card">
|
||||||
<el-card class="e-card">
|
<el-card class="e-card">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="5" :sm="5" :md="6" :lg="6" :xl="5">
|
<el-col :xs="8" :sm="5" :md="6" :lg="6" :xl="5">
|
||||||
<div class="app-icon">
|
<div class="app-icon">
|
||||||
<el-avatar
|
<el-avatar
|
||||||
shape="square"
|
shape="square"
|
||||||
@ -58,7 +58,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="19" :sm="19" :md="18" :lg="18" :xl="19">
|
<el-col :xs="16" :sm="19" :md="18" :lg="18" :xl="19">
|
||||||
<div class="app-content">
|
<div class="app-content">
|
||||||
<div class="app-header">
|
<div class="app-header">
|
||||||
<span class="app-title">{{ app.name }}</span>
|
<span class="app-title">{{ app.name }}</span>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<LayoutContent v-loading="loading || syncLoading" :title="activeName">
|
<LayoutContent v-loading="loading || syncLoading" :title="activeName">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
<el-col :span="20">
|
<el-col :xs="24" :sm="24" :md="20" :lg="20" :xl="20">
|
||||||
<div>
|
<div>
|
||||||
<el-button
|
<el-button
|
||||||
class="tag-button"
|
class="tag-button"
|
||||||
@ -26,7 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :xs="24" :sm="24" :md="4" :lg="4" :xl="4">
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
class="table-button"
|
class="table-button"
|
||||||
@ -68,7 +68,7 @@
|
|||||||
>
|
>
|
||||||
<div class="install-card">
|
<div class="install-card">
|
||||||
<el-card class="e-card">
|
<el-card class="e-card">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="20">
|
||||||
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
|
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<el-avatar
|
<el-avatar
|
||||||
@ -78,7 +78,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="21" :sm="21" :md="21" :lg="20" :xl="20">
|
<el-col :xs="24" :sm="21" :md="21" :lg="20" :xl="20">
|
||||||
<div class="a-detail">
|
<div class="a-detail">
|
||||||
<div class="d-name">
|
<div class="d-name">
|
||||||
<el-button link type="info">
|
<el-button link type="info">
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-if="nginxIsExist && !openNginxConfig" #toolbar>
|
<template v-if="nginxIsExist && !openNginxConfig" #toolbar>
|
||||||
<el-row :class="{ mask: nginxStatus != 'Running' }">
|
<el-row :class="{ mask: nginxStatus != 'Running' }">
|
||||||
<el-col :span="20">
|
<el-col :xs="24" :sm="24" :md="20" :lg="20" :xl="20">
|
||||||
<el-button type="primary" @click="openCreate">
|
<el-button type="primary" @click="openCreate">
|
||||||
{{ $t('website.create') }}
|
{{ $t('website.create') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
{{ $t('website.defaultServer') }}
|
{{ $t('website.defaultServer') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :xs="24" :sm="24" :md="4" :lg="4" :xl="4">
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="req.name"
|
v-model="req.name"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user