添加ping检测时间,智能根据内网情况打开网页

This commit is contained in:
wintsa 2024-03-18 17:45:13 +08:00
parent 76c26f3e28
commit 51df420c01
5 changed files with 198 additions and 124 deletions

View File

@ -13,6 +13,7 @@ declare namespace Panel {
description?: string description?: string
openMethod: number openMethod: number
itemIconGroupId ?:number itemIconGroupId ?:number
time ?:number|string|null
} }
interface ItemIconGroup extends Common.InfoBase { interface ItemIconGroup extends Common.InfoBase {

View File

@ -0,0 +1,21 @@
export function ping(url:string) {
return new Promise((resolve, reject) => {
var start = new Date().getTime();
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
var end = new Date().getTime();
var time = end - start;
resolve(time);
}
};
xhr.onerror = function () {
reject(new Error('请求失败'));
};
xhr.open("GET", url, true);
xhr.send();
});
}

View File

@ -53,3 +53,36 @@ export function isMap<T extends Map<any, any>>(value: T | unknown): value is T {
export function isFile<T extends File>(value: T | unknown): value is T { export function isFile<T extends File>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object File]' return Object.prototype.toString.call(value) === '[object File]'
} }
/**
* @Author: wintsa
* @Date: 2024-03-18 16:32:53
* @LastEditors: wintsa
* @Description: ip是否为局域网
* @return {*}
*/
export function isLocalUrl(url:string) {
// 创建一个 <a> 元素
var anchor = document.createElement('a');
// 设置其 href 属性为所检查的 URL
anchor.href = url;
// 获取主机名
var hostname = anchor.hostname;
// 检查主机名是否是局域网的
// 这里假设局域网主机名的特征
var ip = hostname.split('.');
if (
// 检查是否为localhost
hostname === 'localhost' ||
// 检查是否为私有IP地址
(ip.length === 4 && (
ip[0] === '10' ||
(ip[0] === '172' && parseInt(ip[1]) >= 16 && parseInt(ip[1]) <= 31) ||
(ip[0] === '192' && ip[1] === '168')
))
) {
return true;
} else {
return false;
}
}

View File

@ -37,21 +37,25 @@ const textColor = computed(() => {
<template> <template>
<div class="app-icon w-full"> <div class="app-icon w-full">
<!-- 详情图标 --> <!-- 详情图标 -->
<div <div v-if="style === PanelPanelConfigStyleEnum.info"
v-if="style === PanelPanelConfigStyleEnum.info"
class="app-icon-info w-full rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)] flex" class="app-icon-info w-full rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)] flex"
:style="{ background: itemInfo?.icon?.backgroundColor || defaultBackground }" :style="{ background: itemInfo?.icon?.backgroundColor || defaultBackground }">
>
<!-- 图标 --> <!-- 图标 -->
<div class="app-icon-info-icon w-[70px] h-[70px]"> <div class="app-icon-info-icon w-[70px] h-[70px]">
<div class="w-[70px] h-full flex items-center justify-center "> <div class="w-[70px] h-full flex items-center justify-center ">
<ItemIcon :item-icon="itemInfo?.icon" force-background="transparent" :size="50" class="overflow-hidden rounded-xl" /> <ItemIcon :item-icon="itemInfo?.icon" force-background="transparent" :size="50"
class="overflow-hidden rounded-xl" />
</div> </div>
</div> </div>
<!-- 文字 --> <!-- 文字 -->
<!-- 如果为纯白色将自动根据背景的明暗计算字体的黑白色 --> <!-- 如果为纯白色将自动根据背景的明暗计算字体的黑白色 -->
<div class="text-white flex items-center" :style="{ color: (iconTextColor === '#ffffff') ? textColor : iconTextColor, maxWidth: 'calc(100% - 80px)' }"> <div class="text-white flex items-center"
:style="{ color: (iconTextColor === '#ffffff') ? textColor : iconTextColor, maxWidth: 'calc(100% - 80px)', flex: 1,position: 'relative' }">
<transition name="fade">
<div class="badge" v-if="itemInfo?.time">{{ itemInfo?.time }}</div> <!-- 这里的数字表示未读数 -->
</transition>
<div class="app-icon-info-text-box w-full"> <div class="app-icon-info-text-box w-full">
<div class="app-icon-info-text-box-title font-semibold w-full"> <div class="app-icon-info-text-box-title font-semibold w-full">
<NEllipsis> <NEllipsis>
@ -71,17 +75,40 @@ const textColor = computed(() => {
<div v-if="style === PanelPanelConfigStyleEnum.icon" class="app-icon-small"> <div v-if="style === PanelPanelConfigStyleEnum.icon" class="app-icon-small">
<div <div
class="app-icon-small-icon overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)]" class="app-icon-small-icon overflow-hidden rounded-2xl sunpanel w-[70px] h-[70px] mx-auto rounded-2xl transition-all duration-200 hover:shadow-[0_0_20px_10px_rgba(0,0,0,0.2)]"
:title="itemInfo?.description" :title="itemInfo?.description">
>
<ItemIcon :item-icon="itemInfo?.icon" /> <ItemIcon :item-icon="itemInfo?.icon" />
</div> </div>
<div <div v-if="!iconTextIconHideTitle"
v-if="!iconTextIconHideTitle"
class="app-icon-small-title text-center app-icon-text-shadow cursor-pointer mt-[2px]" class="app-icon-small-title text-center app-icon-text-shadow cursor-pointer mt-[2px]"
:style="{ color: iconTextColor }" :style="{ color: iconTextColor }">
>
<span>{{ itemInfo?.title }}</span> <span>{{ itemInfo?.title }}</span>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<style scoped>
.badge {
position: absolute;
top: 0;
right: 0;
color: white;
width: 20px;
/* 设置徽章的宽度 */
height: 20px;
/* 设置徽章的高度 */
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
mix-blend-mode: difference; /* 设置文字与背景色反色 */
/* 设置徽章内文本的大小 */
}
.fade-enter-active, .fade-leave-active {
transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>

View File

@ -14,6 +14,8 @@ import { PanelPanelConfigStyleEnum, PanelStateNetworkModeEnum } from '@/enums'
import { VisitMode } from '@/enums/auth' import { VisitMode } from '@/enums/auth'
import { router } from '@/router' import { router } from '@/router'
import { t } from '@/locales' import { t } from '@/locales'
import { isLocalUrl } from '@/utils/is'
import { ping } from '@/utils/functions/ping'
interface ItemGroup extends Panel.ItemIconGroup { interface ItemGroup extends Panel.ItemIconGroup {
sortStatus?: boolean sortStatus?: boolean
@ -76,10 +78,20 @@ function handleItemClick(itemGroupIndex: number, item: Panel.ItemInfo) {
let jumpUrl = '' let jumpUrl = ''
if (item) // if (item)
jumpUrl = (panelState.networkMode === PanelStateNetworkModeEnum.lan ? item.lanUrl : item.url) as string // jumpUrl = (panelState.networkMode === PanelStateNetworkModeEnum.lan ? item.lanUrl : item.url) as string
if (item.lanUrl === '') // if (item.lanUrl === '')
// jumpUrl = item.url
///
const isflag = isLocalUrl(window.location.origin)
if (isflag && item.lanUrl) {
jumpUrl = item.lanUrl as string
} else {
jumpUrl = item.url jumpUrl = item.url
}
openPage(item.openMethod, jumpUrl, item.title) openPage(item.openMethod, jumpUrl, item.title)
} }
@ -184,6 +196,7 @@ function handleEditSuccess(item: Panel.ItemInfo) {
function handleChangeNetwork(mode: PanelStateNetworkModeEnum) { function handleChangeNetwork(mode: PanelStateNetworkModeEnum) {
panelState.setNetworkMode(mode) panelState.setNetworkMode(mode)
if (mode === PanelStateNetworkModeEnum.lan) if (mode === PanelStateNetworkModeEnum.lan)
ms.success(t('panelHome.changeToLanModelSuccess')) ms.success(t('panelHome.changeToLanModelSuccess'))
else else
@ -307,8 +320,26 @@ function handleSetSortStatus(groupIndex: number, sortStatus: boolean) {
updateItemIconGroupByNet(groupIndex, items.value[groupIndex].id as number) updateItemIconGroupByNet(groupIndex, items.value[groupIndex].id as number)
} }
} }
function ping(params: any) { async function usePing(params: any, itemGroupIndex: any) {
return params const isflag = isLocalUrl(window.location.origin)
const promises = params.items.map(async (e: any) => {
if (isflag && e.lanUrl) {
return ping(e.lanUrl)
} else {
return ping(e.url)
}
})
const result = await Promise.all(promises)
items.value[itemGroupIndex].items?.forEach((e: any, i) => {
e['time'] = result[i]
})
setTimeout(() => {
items.value[itemGroupIndex].items?.forEach((e: any) => {
delete e['time']
})
}, 5000);
} }
function handleEditItem(item: Panel.ItemInfo) { function handleEditItem(item: Panel.ItemInfo) {
editItemInfoData.value = item editItemInfoData.value = item
@ -326,24 +357,19 @@ function handleAddItem(itemIconGroupId?: number) {
<template> <template>
<div class="w-full h-full sun-main"> <div class="w-full h-full sun-main">
<div <div class="cover wallpaper" :style="{
class="cover wallpaper" :style="{ filter: `blur(${panelState.panelConfig.backgroundBlur}px)`,
filter: `blur(${panelState.panelConfig.backgroundBlur}px)`, background: `url(${panelState.panelConfig.backgroundImageSrc}) no-repeat`,
background: `url(${panelState.panelConfig.backgroundImageSrc}) no-repeat`, backgroundSize: 'cover',
backgroundSize: 'cover', backgroundPosition: 'center',
backgroundPosition: 'center', }" />
}"
/>
<div class="mask" :style="{ backgroundColor: `rgba(0,0,0,${panelState.panelConfig.backgroundMaskNumber})` }" /> <div class="mask" :style="{ backgroundColor: `rgba(0,0,0,${panelState.panelConfig.backgroundMaskNumber})` }" />
<div ref="scrollContainerRef" class="absolute w-full h-full overflow-auto"> <div ref="scrollContainerRef" class="absolute w-full h-full overflow-auto">
<div <div class="p-2.5 mx-auto" :style="{
class="p-2.5 mx-auto" marginTop: `${panelState.panelConfig.marginTop}%`,
:style="{ marginBottom: `${panelState.panelConfig.marginBottom}%`,
marginTop: `${panelState.panelConfig.marginTop}%`, maxWidth: (panelState.panelConfig.maxWidth ?? '1200') + panelState.panelConfig.maxWidthUnit,
marginBottom: `${panelState.panelConfig.marginBottom}%`, }">
maxWidth: (panelState.panelConfig.maxWidth ?? '1200') + panelState.panelConfig.maxWidthUnit,
}"
>
<!-- --> <!-- -->
<div class="mx-[auto] w-[80%]"> <div class="mx-[auto] w-[80%]">
<div class="flex mx-[auto] items-center justify-center text-white"> <div class="flex mx-[auto] items-center justify-center text-white">
@ -365,45 +391,38 @@ function handleAddItem(itemIconGroupId?: number) {
</div> </div>
<!-- 应用盒子 --> <!-- 应用盒子 -->
<div :style="{ marginLeft: `${panelState.panelConfig.marginX}px`, marginRight: `${panelState.panelConfig.marginX}px` }"> <div
:style="{ marginLeft: `${panelState.panelConfig.marginX}px`, marginRight: `${panelState.panelConfig.marginX}px` }">
<!-- 系统监控状态 --> <!-- 系统监控状态 -->
<div <div v-if="panelState.panelConfig.systemMonitorShow
v-if="panelState.panelConfig.systemMonitorShow && ((panelState.panelConfig.systemMonitorPublicVisitModeShow && authStore.visitMode === VisitMode.VISIT_MODE_PUBLIC)
&& ((panelState.panelConfig.systemMonitorPublicVisitModeShow && authStore.visitMode === VisitMode.VISIT_MODE_PUBLIC) || authStore.visitMode === VisitMode.VISIT_MODE_LOGIN)" class="flex mx-auto">
|| authStore.visitMode === VisitMode.VISIT_MODE_LOGIN)" <SystemMonitor :allow-edit="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN"
class="flex mx-auto" :show-title="panelState.panelConfig.systemMonitorShowTitle" />
>
<SystemMonitor
:allow-edit="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN"
:show-title="panelState.panelConfig.systemMonitorShowTitle"
/>
</div> </div>
<!-- 组纵向排列 --> <!-- 组纵向排列 -->
<div <div v-for="(itemGroup, itemGroupIndex) in filterItems" :key="itemGroupIndex" class="item-list mt-[50px]"
v-for="(itemGroup, itemGroupIndex) in filterItems" :key="itemGroupIndex"
class="item-list mt-[50px]"
:class="itemGroup.sortStatus ? 'shadow-2xl border shadow-[0_0_30px_10px_rgba(0,0,0,0.3)] p-[10px] rounded-2xl' : ''" :class="itemGroup.sortStatus ? 'shadow-2xl border shadow-[0_0_30px_10px_rgba(0,0,0,0.3)] p-[10px] rounded-2xl' : ''"
@mouseenter="handleSetHoverStatus(itemGroupIndex, true)" @mouseenter="handleSetHoverStatus(itemGroupIndex, true)"
@mouseleave="handleSetHoverStatus(itemGroupIndex, false)" @mouseleave="handleSetHoverStatus(itemGroupIndex, false)">
>
<!-- 分组标题 --> <!-- 分组标题 -->
<div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center"> <div class="text-white text-xl font-extrabold mb-[20px] ml-[10px] flex items-center">
<span class="group-title text-shadow"> <span class="group-title text-shadow">
{{ itemGroup.title }} {{ itemGroup.title }}
</span> </span>
<div <div v-if="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN"
v-if="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN"
class="group-buttons ml-2 delay-100 transition-opacity flex" class="group-buttons ml-2 delay-100 transition-opacity flex"
:class="itemGroup.hoverStatus ? 'opacity-100' : 'opacity-0'" :class="itemGroup.hoverStatus ? 'opacity-100' : 'opacity-0'">
>
<span class="mr-2 cursor-pointer" :title="t('common.add')" @click="handleAddItem(itemGroup.id)"> <span class="mr-2 cursor-pointer" :title="t('common.add')" @click="handleAddItem(itemGroup.id)">
<SvgIcon class="text-white font-xl" icon="typcn:plus" /> <SvgIcon class="text-white font-xl" icon="typcn:plus" />
</span> </span>
<span class="mr-2 cursor-pointer " :title="t('common.sort')" @click="handleSetSortStatus(itemGroupIndex, !itemGroup.sortStatus)"> <span class="mr-2 cursor-pointer " :title="t('common.sort')"
@click="handleSetSortStatus(itemGroupIndex, !itemGroup.sortStatus)">
<SvgIcon class="text-white font-xl" icon="ri:drag-drop-line" /> <SvgIcon class="text-white font-xl" icon="ri:drag-drop-line" />
</span> </span>
<span class="mr-2 cursor-pointer " :title="t('panelHome.ping')" @click="ping(itemGroupIndex)"> <span class="mr-2 cursor-pointer " :title="t('panelHome.ping')"
@click="usePing(itemGroup, itemGroupIndex)">
<SvgIcon class="text-white font-xl" icon="mdi-wan" /> <SvgIcon class="text-white font-xl" icon="mdi-wan" />
</span> </span>
</div> </div>
@ -412,34 +431,24 @@ function handleAddItem(itemIconGroupId?: number) {
<!-- 详情图标 --> <!-- 详情图标 -->
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info"> <div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.info">
<div v-if="itemGroup.items"> <div v-if="itemGroup.items">
<VueDraggable <VueDraggable v-model="itemGroup.items" item-key="sort" :animation="300" class="icon-info-box"
v-model="itemGroup.items" item-key="sort" :animation="300" filter=".not-drag" :disabled="!itemGroup.sortStatus">
class="icon-info-box" <div v-for="item, index in itemGroup.items" :key="index" :title="item.description"
filter=".not-drag" @contextmenu="(e) => handleContextMenu(e, itemGroupIndex, item)">
:disabled="!itemGroup.sortStatus" <AppIcon :class="itemGroup.sortStatus ? 'cursor-move' : 'cursor-pointer'" :item-info="item"
>
<div v-for="item, index in itemGroup.items" :key="index" :title="item.description" @contextmenu="(e) => handleContextMenu(e, itemGroupIndex, item)">
<AppIcon
:class="itemGroup.sortStatus ? 'cursor-move' : 'cursor-pointer'"
:item-info="item"
:icon-text-color="panelState.panelConfig.iconTextColor" :icon-text-color="panelState.panelConfig.iconTextColor"
:icon-text-info-hide-description="panelState.panelConfig.iconTextInfoHideDescription || false" :icon-text-info-hide-description="panelState.panelConfig.iconTextInfoHideDescription || false"
:icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :style="0"
:style="0" @click="handleItemClick(itemGroupIndex, item)" />
@click="handleItemClick(itemGroupIndex, item)"
/>
</div> </div>
<div v-if="itemGroup.items.length === 0" class="not-drag"> <div v-if="itemGroup.items.length === 0" class="not-drag">
<AppIcon <AppIcon :class="itemGroup.sortStatus ? 'cursor-move' : 'cursor-pointer'"
:class="itemGroup.sortStatus ? 'cursor-move' : 'cursor-pointer'"
:item-info="{ icon: { itemType: 3, text: 'subway:add' }, title: t('common.add'), url: '', openMethod: 0 }" :item-info="{ icon: { itemType: 3, text: 'subway:add' }, title: t('common.add'), url: '', openMethod: 0 }"
:icon-text-color="panelState.panelConfig.iconTextColor" :icon-text-color="panelState.panelConfig.iconTextColor"
:icon-text-info-hide-description="panelState.panelConfig.iconTextInfoHideDescription || false" :icon-text-info-hide-description="panelState.panelConfig.iconTextInfoHideDescription || false"
:icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :style="0"
:style="0" @click="handleAddItem(itemGroup.id)" />
@click="handleAddItem(itemGroup.id)"
/>
</div> </div>
</VueDraggable> </VueDraggable>
</div> </div>
@ -448,35 +457,24 @@ function handleAddItem(itemIconGroupId?: number) {
<!-- APP图标宫型盒子 --> <!-- APP图标宫型盒子 -->
<div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon"> <div v-if="panelState.panelConfig.iconStyle === PanelPanelConfigStyleEnum.icon">
<div v-if="itemGroup.items"> <div v-if="itemGroup.items">
<VueDraggable <VueDraggable v-model="itemGroup.items" item-key="sort" :animation="300" class="icon-small-box"
v-model="itemGroup.items" item-key="sort" :animation="300" filter=".not-drag" :disabled="!itemGroup.sortStatus">
class="icon-small-box" <div v-for="item, index in itemGroup.items" :key="index" :title="item.description"
@contextmenu="(e) => handleContextMenu(e, itemGroupIndex, item)">
filter=".not-drag" <AppIcon :class="itemGroup.sortStatus ? 'cursor-move' : 'cursor-pointer'" :item-info="item"
:disabled="!itemGroup.sortStatus"
>
<div v-for="item, index in itemGroup.items" :key="index" :title="item.description" @contextmenu="(e) => handleContextMenu(e, itemGroupIndex, item)">
<AppIcon
:class="itemGroup.sortStatus ? 'cursor-move' : 'cursor-pointer'"
:item-info="item"
:icon-text-color="panelState.panelConfig.iconTextColor" :icon-text-color="panelState.panelConfig.iconTextColor"
:icon-text-info-hide-description="!panelState.panelConfig.iconTextInfoHideDescription" :icon-text-info-hide-description="!panelState.panelConfig.iconTextInfoHideDescription"
:icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :style="1"
:style="1" @click="handleItemClick(itemGroupIndex, item)" />
@click="handleItemClick(itemGroupIndex, item)"
/>
</div> </div>
<div v-if="itemGroup.items.length === 0" class="not-drag"> <div v-if="itemGroup.items.length === 0" class="not-drag">
<AppIcon <AppIcon class="cursor-pointer"
class="cursor-pointer"
:item-info="{ icon: { itemType: 3, text: 'subway:add' }, title: $t('common.add'), url: '', openMethod: 0 }" :item-info="{ icon: { itemType: 3, text: 'subway:add' }, title: $t('common.add'), url: '', openMethod: 0 }"
:icon-text-color="panelState.panelConfig.iconTextColor" :icon-text-color="panelState.panelConfig.iconTextColor"
:icon-text-info-hide-description="!panelState.panelConfig.iconTextInfoHideDescription" :icon-text-info-hide-description="!panelState.panelConfig.iconTextInfoHideDescription"
:icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :icon-text-icon-hide-title="panelState.panelConfig.iconTextIconHideTitle || false" :style="1"
:style="1" @click="handleAddItem(itemGroup.id)" />
@click="handleAddItem(itemGroup.id)"
/>
</div> </div>
</vuedraggable> </vuedraggable>
</div> </div>
@ -502,40 +500,41 @@ function handleAddItem(itemIconGroupId?: number) {
</div> </div>
<!-- 右键菜单 --> <!-- 右键菜单 -->
<NDropdown <NDropdown placement="bottom-start" trigger="manual" :x="dropdownMenuX" :y="dropdownMenuY"
placement="bottom-start" trigger="manual" :x="dropdownMenuX" :y="dropdownMenuY" :options="getDropdownMenuOptions()" :show="dropdownShow" :on-clickoutside="onClickoutside"
:options="getDropdownMenuOptions()" :show="dropdownShow" :on-clickoutside="onClickoutside" @select="handleRightMenuSelect" @select="handleRightMenuSelect" />
/>
<!-- 悬浮按钮 --> <!-- 悬浮按钮 -->
<div class="fixed-element shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]"> <div class="fixed-element shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]">
<NButtonGroup vertical> <NButtonGroup vertical>
<!-- 网络模式切换按钮组 --> <!-- 网络模式切换按钮组 -->
<NButton <NButton
v-if="panelState.networkMode === PanelStateNetworkModeEnum.lan && panelState.panelConfig.netModeChangeButtonShow" color="#2a2a2a6b" v-if="panelState.networkMode === PanelStateNetworkModeEnum.lan && panelState.panelConfig.netModeChangeButtonShow"
:title="t('panelHome.changeToWanModel')" @click="handleChangeNetwork(PanelStateNetworkModeEnum.wan)" color="#2a2a2a6b" :title="t('panelHome.changeToWanModel')"
> @click="handleChangeNetwork(PanelStateNetworkModeEnum.wan)">
<template #icon> <template #icon>
<SvgIcon class="text-white font-xl" icon="material-symbols:lan-outline-rounded" /> <SvgIcon class="text-white font-xl" icon="material-symbols:lan-outline-rounded" />
</template> </template>
</NButton> </NButton>
<NButton <NButton
v-if="panelState.networkMode === PanelStateNetworkModeEnum.wan && panelState.panelConfig.netModeChangeButtonShow" color="#2a2a2a6b" v-if="panelState.networkMode === PanelStateNetworkModeEnum.wan && panelState.panelConfig.netModeChangeButtonShow"
:title="t('panelHome.changeToLanModel')" @click="handleChangeNetwork(PanelStateNetworkModeEnum.lan)" color="#2a2a2a6b" :title="t('panelHome.changeToLanModel')"
> @click="handleChangeNetwork(PanelStateNetworkModeEnum.lan)">
<template #icon> <template #icon>
<SvgIcon class="text-white font-xl" icon="mdi:wan" /> <SvgIcon class="text-white font-xl" icon="mdi:wan" />
</template> </template>
</NButton> </NButton>
<NButton v-if="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN" color="#2a2a2a6b" @click="settingModalShow = !settingModalShow"> <NButton v-if="authStore.visitMode === VisitMode.VISIT_MODE_LOGIN" color="#2a2a2a6b"
@click="settingModalShow = !settingModalShow">
<template #icon> <template #icon>
<SvgIcon class="text-white font-xl" icon="majesticons-applications" /> <SvgIcon class="text-white font-xl" icon="majesticons-applications" />
</template> </template>
</NButton> </NButton>
<NButton v-if="authStore.visitMode === VisitMode.VISIT_MODE_PUBLIC" color="#2a2a2a6b" :title="$t('panelHome.goToLogin')" @click="router.push('/login')"> <NButton v-if="authStore.visitMode === VisitMode.VISIT_MODE_PUBLIC" color="#2a2a2a6b"
:title="$t('panelHome.goToLogin')" @click="router.push('/login')">
<template #icon> <template #icon>
<SvgIcon class="text-white font-xl" icon="material-symbols:account-circle" /> <SvgIcon class="text-white font-xl" icon="material-symbols:account-circle" />
</template> </template>
@ -546,12 +545,8 @@ function handleAddItem(itemIconGroupId?: number) {
<!-- <Setting v-model:visible="settingModalShow" /> --> <!-- <Setting v-model:visible="settingModalShow" /> -->
</div> </div>
<NBackTop <NBackTop :listen-to="() => scrollContainerRef" :right="10" :bottom="10"
:listen-to="() => scrollContainerRef" style="background-color:transparent;border: none;box-shadow: none;">
:right="10"
:bottom="10"
style="background-color:transparent;border: none;box-shadow: none;"
>
<div class="shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]"> <div class="shadow-[0_0_10px_2px_rgba(0,0,0,0.2)]">
<NButton color="#2a2a2a6b"> <NButton color="#2a2a2a6b">
<template #icon> <template #icon>
@ -561,14 +556,13 @@ function handleAddItem(itemIconGroupId?: number) {
</div> </div>
</NBackTop> </NBackTop>
<EditItem v-model:visible="editItemInfoShow" :item-info="editItemInfoData" :item-group-id="currentAddItenIconGroupId" @done="handleEditSuccess" /> <EditItem v-model:visible="editItemInfoShow" :item-info="editItemInfoData"
:item-group-id="currentAddItenIconGroupId" @done="handleEditSuccess" />
<!-- 弹窗 --> <!-- 弹窗 -->
<NModal <NModal v-model:show="windowShow" :mask-closable="false" preset="card"
v-model:show="windowShow" :mask-closable="false" preset="card"
style="max-width: 1000px;height: 600px;border-radius: 1rem;" :bordered="true" size="small" role="dialog" style="max-width: 1000px;height: 600px;border-radius: 1rem;" :bordered="true" size="small" role="dialog"
aria-modal="true" aria-modal="true">
>
<template #header> <template #header>
<div class="flex items-center"> <div class="flex items-center">
<span class="mr-[20px]"> <span class="mr-[20px]">
@ -584,10 +578,8 @@ function handleAddItem(itemIconGroupId?: number) {
<NSkeleton height="180px" width="100%" class="mt-[20px] rounded-lg" /> <NSkeleton height="180px" width="100%" class="mt-[20px] rounded-lg" />
<NSkeleton height="180px" width="100%" class="mt-[20px] rounded-lg" /> <NSkeleton height="180px" width="100%" class="mt-[20px] rounded-lg" />
</div> </div>
<iframe <iframe v-show="!windowIframeIsLoad" id="windowIframeId" ref="windowIframeRef" :src="windowSrc"
v-show="!windowIframeIsLoad" id="windowIframeId" ref="windowIframeRef" :src="windowSrc" class="w-full h-full" frameborder="0" @load="handWindowIframeIdLoad" />
class="w-full h-full" frameborder="0" @load="handWindowIframeIdLoad"
/>
</div> </div>
</NModal> </NModal>
</div> </div>
@ -658,7 +650,7 @@ html {
} }
@media (max-width: 500px) { @media (max-width: 500px) {
.icon-info-box{ .icon-info-box {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
} }
} }