Merge commit 'ea1bd25064bfd1e623c5f4bb9173e9112607484d' into tomato

This commit is contained in:
expdsn 2024-11-11 14:15:59 +08:00
commit 3c2b441832
21 changed files with 293 additions and 144 deletions

View File

@ -7,7 +7,7 @@
name="viewport" name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
/> />
<title>Vite App</title> <title>Fatfox 新标签页</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@ -25,7 +25,11 @@ export default defineComponent(() => {
full.value = false full.value = false
}) })
return () => ( return () => (
<div class="fixed left-0 top-0 z-50 w-full"> <div
class="fixed left-0 top-0 z-50 w-full"
onContextmenu={(e) => e.stopPropagation()}
onKeydown={(e) => e.stopPropagation()}
>
{/* 背景遮罩 */} {/* 背景遮罩 */}
<Transition> <Transition>
{show.value && ( {show.value && (

View File

@ -8,6 +8,7 @@ import { defineComponent, onMounted, onUnmounted, ref, watch } from 'vue'
import useRouterStore from '@/useRouterStore' import useRouterStore from '@/useRouterStore'
import useSearchStore from '@/layout/header/search/useSearchStore' import useSearchStore from '@/layout/header/search/useSearchStore'
import useLayoutStore from '@/layout/useLayoutStore' import useLayoutStore from '@/layout/useLayoutStore'
import { sendParent } from '@/utils/parent'
const stageStrList = [ const stageStrList = [
'dazhaohu', 'dazhaohu',
@ -128,6 +129,7 @@ export default defineComponent(() => {
}} }}
onClick={() => { onClick={() => {
run('aixin') run('aixin')
sendParent(['openSide'])
}} }}
/> />
) )

View File

@ -1,12 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div>要什么服务器,直接 oss</div>
<script src="/test.js" />
</body>
</html>

View File

@ -4,6 +4,9 @@ import type { Block } from './layout.types'
import clsx from 'clsx' import clsx from 'clsx'
import useLayoutStore from './useLayoutStore' import useLayoutStore from './useLayoutStore'
import widgetList from '@/widgets' import widgetList from '@/widgets'
import useRouterStore from '@/useRouterStore'
import useAdderPageStore from './adder/useAdderPageStore'
import useSettingsStore from '@/settings/useSettingsStore'
const defaultDisplay = { const defaultDisplay = {
x: 0, x: 0,
@ -26,8 +29,8 @@ export const useMenuStore = defineStore('menu', () => {
window.removeEventListener('mousemove', handle) window.removeEventListener('mousemove', handle)
}) })
const open = (type: (typeof defaultDisplay)['type']) => { const open = (type: (typeof defaultDisplay)['type']) => {
display.x = Math.min(window.innerWidth - 140, mPos.x) display.x = Math.min(window.innerWidth - 180, mPos.x)
display.y = Math.min(window.innerHeight - 240, mPos.y) display.y = Math.min(window.innerHeight - 220, mPos.y)
display.type = type display.type = type
} }
const show = computed(() => display.x > 0 && display.y > 0) const show = computed(() => display.x > 0 && display.y > 0)
@ -49,6 +52,10 @@ const Item = defineComponent({
alert: { alert: {
type: Boolean, type: Boolean,
default: false default: false
},
noStyle: {
type: Boolean,
default: false
} }
}, },
emits: { emits: {
@ -61,9 +68,17 @@ const Item = defineComponent({
'px-4 py-2 text-sm tracking-widest w-full overflow-hidden text-ellipsis whitespace-nowrap break-all transition-all rounded-lg cursor-pointer mb-2', 'px-4 py-2 text-sm tracking-widest w-full overflow-hidden text-ellipsis whitespace-nowrap break-all transition-all rounded-lg cursor-pointer mb-2',
{ {
'bg-red-500/80 hover:bg-red-500 text-white': props.alert, 'bg-red-500/80 hover:bg-red-500 text-white': props.alert,
'bg-white/80 hover:bg-white text-black/80': !props.alert 'bg-white/80 hover:bg-white text-black/80': !props.alert && !props.noStyle,
'bg-transparent text-black/60 hover:text-black/80 hover:bg-white/20': props.noStyle
} }
)} )}
style={
props.noStyle
? {
padding: '6px 10px'
}
: {}
}
onClick={() => { onClick={() => {
ctx.emit('click') ctx.emit('click')
}} }}
@ -76,28 +91,98 @@ const Item = defineComponent({
export default defineComponent(() => { export default defineComponent(() => {
const menu = useMenuStore() const menu = useMenuStore()
const settings = useSettingsStore()
const layout = useLayoutStore() const layout = useLayoutStore()
document.addEventListener('contextmenu', () => {
menu.open('global')
})
const router = useRouterStore()
const adderPage = useAdderPageStore()
return () => return () =>
menu.show && ( menu.show && (
<div <div
v-outside-click={() => { v-outside-click={() => {
menu.dismiss() menu.dismiss()
}} }}
class="fixed px-2 pt-4 pb-2 bg-white/60 backdrop-blur shadow-lg rounded-lg overflow-hidden w-[120px]" class="fixed px-2 pt-4 pb-2 bg-white/60 backdrop-blur shadow-lg rounded-lg overflow-hidden"
style={{ style={{
zIndex: '999', zIndex: '999',
left: menu.display.x + 'px', left: menu.display.x + 'px',
top: menu.display.y + 'px' top: menu.display.y + 'px',
width: menu.display.type === 'global' ? '160px' : '120px'
}} }}
> >
{(() => { {(() => {
if (menu.display.type === 'global') { if (menu.display.type === 'global') {
// 全局菜单 // 全局菜单
return <></> return (
<>
<Item
noStyle
onClick={() => {
router.go('global-adder')
adderPage.type = 1
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
router.go('global-adder')
adderPage.type = 0
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
router.go('global-adder')
adderPage.type = 3
menu.dismiss()
}}
>
</Item>
<Item
noStyle
onClick={() => {
router.go('global-background')
menu.dismiss()
}}
>
</Item>
</>
)
} }
if (menu.display.type === 'dock') { if (menu.display.type === 'dock') {
// dock 栏 // dock 栏
return <></> return (
<>
<Item
noStyle
onClick={() => {
settings.state.disabledShortcut = !settings.state.disabledShortcut
menu.dismiss()
}}
>
{settings.state.disabledShortcut ? '启用' : '禁用'}
</Item>
<Item
noStyle
onClick={() => {
router.go('settings-dock')
menu.dismiss()
}}
>
</Item>
</>
)
} }
const block = menu.display.type const block = menu.display.type
if (!block.link) { if (!block.link) {
@ -190,7 +275,7 @@ export default defineComponent(() => {
// 链接 // 链接
return ( return (
<> <>
<Item></Item> <Item></Item>
<Item <Item
alert alert
onClick={() => { onClick={() => {

View File

@ -1,4 +1,12 @@
import { computed, defineComponent, inject, onMounted, onUnmounted, provide, ref, type InjectionKey, type Ref } from 'vue' import {
computed,
defineComponent,
onUnmounted,
provide,
ref,
type InjectionKey,
type Ref
} from 'vue'
import useLayoutStore from '../useLayoutStore' import useLayoutStore from '../useLayoutStore'
import { OhVueIcon, addIcons } from 'oh-vue-icons' import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { import {
@ -74,7 +82,7 @@ export default defineComponent(() => {
const store = useAdderPageStore() const store = useAdderPageStore()
const addTo = ref(layout.state.currentPage) const addTo = ref(layout.state.currentPage)
provide(AddToToken, addTo) provide(AddToToken, addTo)
onUnmounted(()=> { onUnmounted(() => {
store.type = 1 store.type = 1
}) })
return () => ( return () => (
@ -124,10 +132,7 @@ export default defineComponent(() => {
}} }}
/> />
</div> </div>
<div <div class={'w-0 h-full flex-grow relative z-10 flex flex-col ' + (isGame.value ? '' : '')}>
class={'w-0 h-full flex-grow relative z-10 flex flex-col ' + (isGame.value ? '' : '')}
onContextmenu={(e) => e.stopPropagation()}
>
<Form class="w-full px-4 mt-4" layout="inline"> <Form class="w-full px-4 mt-4" layout="inline">
<Form.Item label="添加到"> <Form.Item label="添加到">
<Select <Select
@ -147,7 +152,7 @@ export default defineComponent(() => {
<div class="w-full h-full relative"> <div class="w-full h-full relative">
{store.type === 0 ? ( {store.type === 0 ? (
<WidgetAdder /> <WidgetAdder />
) : store.type=== 1 ? ( ) : store.type === 1 ? (
<HotAdder /> <HotAdder />
) : store.type === 2 ? ( ) : store.type === 2 ? (
<CustomAdder /> <CustomAdder />

View File

@ -4,6 +4,7 @@ import useSortable, { dragging, resetDragging } from '../grid/useSortable'
import LinkBlock from '../grid/LinkBlock' import LinkBlock from '../grid/LinkBlock'
import useSettingsStore from '@/settings/useSettingsStore' import useSettingsStore from '@/settings/useSettingsStore'
import clsx from 'clsx' import clsx from 'clsx'
import { useMenuStore } from '../GlobalMenu'
export default defineComponent(() => { export default defineComponent(() => {
const layout = useLayoutStore() const layout = useLayoutStore()
@ -13,11 +14,12 @@ export default defineComponent(() => {
computed(() => layout.state.dock), computed(() => layout.state.dock),
ref('dock') ref('dock')
) )
const menu = useMenuStore()
const current = ref(-1) const current = ref(-1)
return () => return () =>
setting.state.showDock !== '' && ( setting.state.showDock !== '' && (
<div <div
onDragover={()=> { onDragover={() => {
show.value = true show.value = true
}} }}
onMouseenter={() => { onMouseenter={() => {
@ -26,9 +28,7 @@ export default defineComponent(() => {
onMouseleave={() => { onMouseleave={() => {
show.value = false show.value = false
}} }}
class={ class={'w-3/5 min-w-[800px] h-[120px] fixed left-1/2 bottom-0 -translate-x-1/2'}
'w-3/5 min-w-[800px] h-[120px] fixed left-1/2 bottom-0 -translate-x-1/2'
}
> >
<div <div
class={clsx( class={clsx(
@ -43,6 +43,11 @@ export default defineComponent(() => {
onMouseleave={() => { onMouseleave={() => {
current.value = -1 current.value = -1
}} }}
onContextmenu={(e) => {
e.stopPropagation()
e.preventDefault()
menu.open('dock')
}}
> >
{layout.state.dockLabels.split('').map((l, i) => { {layout.state.dockLabels.split('').map((l, i) => {
const block = layout.state.dock[i] const block = layout.state.dock[i]
@ -87,12 +92,14 @@ export default defineComponent(() => {
}} }}
> >
{block && <LinkBlock block={block} dock />} {block && <LinkBlock block={block} dock />}
<div {!setting.state.disabledShortcut && (
class="absolute z-10 left-0 bottom-0 w-full bg-black/20 text-[12px] text-white text-center" <div
style={{ boxShadow: block ? 'none' : '0 -4px 14px 0 rgba(0,0,0,.3)' }} class="absolute z-10 left-0 bottom-0 w-full bg-black/20 text-[12px] text-white text-center"
> style={{ boxShadow: block ? 'none' : '0 -4px 14px 0 rgba(0,0,0,.3)' }}
{l} >
</div> {l}
</div>
)}
</div> </div>
) )
})} })}

View File

@ -120,6 +120,10 @@ export default defineComponent({
style={{ style={{
borderRadius: `calc(var(--block-radius) * var(--block-size))` borderRadius: `calc(var(--block-radius) * var(--block-size))`
}} }}
onContextmenu={(e) => {
e.stopPropagation()
e.preventDefault()
}}
> >
{props.block.link ? ( {props.block.link ? (
props.block.link.startsWith('id:') ? ( props.block.link.startsWith('id:') ? (

View File

@ -39,9 +39,8 @@ export default defineComponent({
'grid-rows-3 grid-cols-3 gap-[6%] p-[8%]': props.big, 'grid-rows-3 grid-cols-3 gap-[6%] p-[8%]': props.big,
'grid-rows-2 grid-cols-2 gap-[8%] p-[10%]': !props.big 'grid-rows-2 grid-cols-2 gap-[8%] p-[10%]': !props.big
})} })}
onContextmenu={(e) => { onContextmenu={() => {
e.preventDefault() menu.open('dock')
menu.open(props.block)
}} }}
> >
{selectedDir.value.list {selectedDir.value.list

View File

@ -37,8 +37,15 @@ export default defineComponent(() => {
<input <input
class="relative h-[40px] mb-2 w-[240px] bg-transparent outline-none border-none text-center text-white" class="relative h-[40px] mb-2 w-[240px] bg-transparent outline-none border-none text-center text-white"
v-model={dir.value.label} v-model={dir.value.label}
onKeydown={(e) => e.stopPropagation()}
/> />
<div class="relative w-[50%] min-h-[280px] max-h-[60vh] overflow-y-auto bg-white/60 backdrop-blur rounded-lg shadow-lg p-2"> <div
class="relative w-[50%] min-h-[280px] max-h-[60vh] overflow-y-auto bg-white/60 backdrop-blur rounded-lg shadow-lg p-2"
onContextmenu={(e) => {
e.stopPropagation()
e.preventDefault()
}}
>
<div <div
class="w-full grid justify-center grid-flow-row-dense pb-[200px]" class="w-full grid justify-center grid-flow-row-dense pb-[200px]"
style="grid-template-columns:repeat(auto-fill, var(--block-size));grid-auto-rows:var(--block-size)" style="grid-template-columns:repeat(auto-fill, var(--block-size));grid-auto-rows:var(--block-size)"

View File

@ -1,6 +1,7 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import type { Block } from '../layout.types' import type { Block } from '../layout.types'
import { useMenuStore } from '../GlobalMenu' import { useMenuStore } from '../GlobalMenu'
import jump from '@/utils/jump'
export default defineComponent({ export default defineComponent({
props: { props: {
@ -23,12 +24,11 @@ export default defineComponent({
return () => ( return () => (
<div <div
class="w-full h-full flex justify-center items-center font-bold bg-cover bg-center bg-no-repeat" class="w-full h-full flex justify-center items-center font-bold bg-cover bg-center bg-no-repeat"
onContextmenu={(e) => { onContextmenu={() => {
e.preventDefault()
menu.open(props.block) menu.open(props.block)
}} }}
onClick={() => { onClick={() => {
window.open(props.block.link, '_blank') jump(props.block.link)
}} }}
style={{ style={{
backgroundColor: props.block.background || 'white', backgroundColor: props.block.background || 'white',
@ -44,8 +44,7 @@ export default defineComponent({
return () => ( return () => (
<div <div
class="w-full h-full flex justify-between px-3 items-center font-bold bg-cover bg-center bg-no-repeat" class="w-full h-full flex justify-between px-3 items-center font-bold bg-cover bg-center bg-no-repeat"
onContextmenu={(e) => { onContextmenu={() => {
e.preventDefault()
menu.open(props.block) menu.open(props.block)
}} }}
onClick={() => { onClick={() => {
@ -61,7 +60,11 @@ export default defineComponent({
{props.block.label} {props.block.label}
</span> </span>
</div> </div>
<img src="/tab/icons/gameicon.webp" alt="game_icon" class={'absolute right-0 bottom-0 w-[36px]'} /> <img
src="/tab/icons/gameicon.webp"
alt="game_icon"
class={'absolute right-0 bottom-0 w-[36px]'}
/>
</div> </div>
) )
} }

View File

@ -4,6 +4,7 @@ import DivBgImg from '~/icons/welcome/back.png'
import startUseImg from '~/icons/welcome/startUse.png' import startUseImg from '~/icons/welcome/startUse.png'
import useBackgroundStore from '../background/useBackgroundStore' import useBackgroundStore from '../background/useBackgroundStore'
import useLayoutStore from '../useLayoutStore' import useLayoutStore from '../useLayoutStore'
import request from '@/utils/request'
export const DefaultPageSetting = [ export const DefaultPageSetting = [
{ {
name: '游戏', name: '游戏',
@ -43,7 +44,6 @@ export default defineComponent(() => {
if (!visited) { if (!visited) {
// 如果没有记录,说明是第一次访问 // 如果没有记录,说明是第一次访问
isFirst.value = true isFirst.value = true
// 设置标记,后续访问不会再次显示
} }
}) })
return () => return () =>
@ -123,7 +123,14 @@ export default defineComponent(() => {
onClick={() => { onClick={() => {
localStorage.setItem('hasVisited', 'true') localStorage.setItem('hasVisited', 'true')
isFirst.value = false isFirst.value = false
layout.changeBackground(DefaultPageSetting[selectMode.value].backgroundUrl)
// 设置标记,后续访问不会再次显示
// 获取默认界面
request('GET', '/api/app/desktop').then((res: any) => {
if (!res) return
layout.state.dir = res.dir
layout.state.content = res.content
})
}} }}
style={{ style={{
backgroundImage: `url('${startUseImg}')`, backgroundImage: `url('${startUseImg}')`,

View File

@ -16,10 +16,14 @@ export default defineComponent({
const router = useRouterStore() const router = useRouterStore()
return () => { return () => {
const placeholder = ( const placeholder = (
<div class="w-full h-full flex justify-center items-center text-black/60" onContextmenu={(e) => { <div
e.preventDefault() class="w-full h-full flex justify-center items-center text-black/60"
menu.open(props.block) onContextmenu={() => {
}}></div> menu.open(props.block)
}}
>
</div>
) )
const selected = widgetList.find((el) => el.name === props.block.name) const selected = widgetList.find((el) => el.name === props.block.name)
if (!selected) return placeholder if (!selected) return placeholder
@ -30,8 +34,7 @@ export default defineComponent({
return ( return (
<div <div
class="w-full h-full relative" class="w-full h-full relative"
onContextmenu={(e) => { onContextmenu={() => {
e.preventDefault()
menu.open(props.block) menu.open(props.block)
}} }}
onClick={() => { onClick={() => {

View File

@ -116,10 +116,7 @@ export default defineComponent(() => {
const searchConfig = useSearchConfigStore() const searchConfig = useSearchConfigStore()
const showAdder = ref<{ [key: string]: any } | null | undefined>(undefined) const showAdder = ref<{ [key: string]: any } | null | undefined>(undefined)
return () => ( return () => (
<div <div class="w-full h-full bg-white/80 backdrop-blur p-4 flex flex-col select-text">
class="w-full h-full bg-white/80 backdrop-blur p-4 flex flex-col select-text"
onContextmenu={(e) => e.stopPropagation()}
>
<ThemeProvider> <ThemeProvider>
<h2 class="text-center tracking-widest font-bold text-xl text-black/80"></h2> <h2 class="text-center tracking-widest font-bold text-xl text-black/80"></h2>
<div class="grid grid-cols-2 gap-4"> <div class="grid grid-cols-2 gap-4">

View File

@ -8,68 +8,73 @@ import SearchSuggestion from './SearchSuggestion'
import useLayoutStore from '@/layout/useLayoutStore' import useLayoutStore from '@/layout/useLayoutStore'
import clsx from 'clsx' import clsx from 'clsx'
export default defineComponent((props: { export default defineComponent(
isMini?: boolean (props: { isMini?: boolean }) => {
}) => { const settings = useSettingsStore()
const settings = useSettingsStore() const search = useSearchStore()
const search = useSearchStore() const searchConfig = useSearchConfigStore()
const searchConfig = useSearchConfigStore() const layout = useLayoutStore()
const layout = useLayoutStore() return () => (
return () => (
<div
class={clsx(!props?.isMini ? "absolute left-1/2 -translate-x-1/2 z-20 transition-all" : "w-full")}
style={
props.isMini ? {
} :
{
top: layout.isCompact ? '40px' : layout.state.simple ? '230px' : '172px',
width: settings.state.searchWidth + 'rem'
}}
>
<div <div
class={ class={clsx(
clsx( !props?.isMini ? 'absolute left-1/2 -translate-x-1/2 z-20 transition-all' : 'w-full'
'w-full h-11 shadow-content overflow-hidden px-1 transition-all flex justify-between items-center gap-4 ', )}
(search.focus ? 'bg-white/60' : 'bg-white/40 hover:bg-white/60'), style={
props.isMini ? "" : "max-w-[90vw] w-full") props.isMini
? {}
: {
top: layout.isCompact ? '40px' : layout.state.simple ? '230px' : '172px',
width: settings.state.searchWidth + 'rem'
}
} }
style={{
borderRadius: settings.state.searchRadius + 'px'
}}
> >
<div <div
class="w-9 h-11 flex justify-center items-center cursor-pointer" class={clsx(
onClick={() => { 'w-full h-11 shadow-content overflow-hidden px-1 transition-all flex justify-between items-center gap-4 ',
search.showSearchConfig = true search.focus ? 'bg-white/60' : 'bg-white/40 hover:bg-white/60',
props.isMini ? '' : 'max-w-[90vw] w-full'
)}
style={{
borderRadius: settings.state.searchRadius + 'px'
}} }}
> >
<div <div
class="w-[26px] h-[26px] bg-center bg-contain bg-no-repeat" class="w-9 h-11 flex justify-center items-center cursor-pointer"
style={{ onClick={() => {
backgroundImage: `url('${searchConfig.current.icon}')`, search.showSearchConfig = true
borderRadius: settings.state.searchRadius - 4 + 'px'
}} }}
>
<div
class="w-[26px] h-[26px] bg-center bg-contain bg-no-repeat"
style={{
backgroundImage: `url('${searchConfig.current.icon}')`,
borderRadius: settings.state.searchRadius - 4 + 'px'
}}
/>
</div>
<input
v-model={search.searchStr}
ref={(el) => (search.searchRef = el as any)}
onContextmenu={(e) => e.stopPropagation()}
onKeydown={(e) => e.stopPropagation()}
class="flex-1 h-full outline-none bg-transparent placeholder:text-slate-600 placeholder:tracking-widest text-slate-800 pr-4"
placeholder={`输入搜索 ${searchConfig.current.name}`}
/> />
</div> </div>
<input <Transition name="searchContent">{search.showSearchConfig && <SearchConfig />}</Transition>
v-model={search.searchStr} <Transition name="searchContent">
ref={(el) => (search.searchRef = el as any)} {search.focus && !search.searchStr && searchConfig.history.length > 0 && (
onContextmenu={(e) => e.stopPropagation()} <SearchHistory />
class="flex-1 h-full outline-none bg-transparent placeholder:text-slate-600 placeholder:tracking-widest text-slate-800 pr-4" )}
placeholder={`输入搜索 ${searchConfig.current.name}`} </Transition>
/> <Transition name="searchContent">
{search.focus && search.searchStr && <SearchSuggestion />}
</Transition>
</div> </div>
<Transition name="searchContent">{search.showSearchConfig && <SearchConfig />}</Transition> )
<Transition name="searchContent"> },
{search.focus && !search.searchStr && searchConfig.history.length > 0 && <SearchHistory />} {
</Transition> name: 'SearchComponent',
<Transition name="searchContent"> props: ['isMini']
{search.focus && search.searchStr && <SearchSuggestion />} }
</Transition> )
</div>
)
}, {
name: 'SearchComponent',
props: ['isMini']
})

View File

@ -4,6 +4,8 @@ import { computed, reactive, ref, toRaw, watch } from 'vue'
import db from '@/db' import db from '@/db'
import useResource from './background/useResource' import useResource from './background/useResource'
import { globalToast } from '@/main' import { globalToast } from '@/main'
import jump from '@/utils/jump'
import useSettingsStore from '@/settings/useSettingsStore'
const defaultLayout: Layout = { const defaultLayout: Layout = {
content: [ content: [
@ -20,6 +22,7 @@ const defaultLayout: Layout = {
} }
export default defineStore('layout', () => { export default defineStore('layout', () => {
const settings = useSettingsStore()
const state = reactive(defaultLayout) const state = reactive(defaultLayout)
const ready = ref(false) const ready = ref(false)
@ -86,6 +89,12 @@ export default defineStore('layout', () => {
if (openDir.value === id) { if (openDir.value === id) {
openDir.value = '' openDir.value = ''
} }
} else if (dir && dir.list.length === 0) {
const idx = currentPage.value.list.findIndex((el) => el.link === 'id:' + id)
if (idx < 0) return
currentPage.value.list.splice(idx, 1)
delete state.dir[id]
openDir.value = ''
} }
} }
@ -96,7 +105,6 @@ export default defineStore('layout', () => {
} }
// 处理不同的组件的名称 // 处理不同的组件的名称
if (block.name === 'gameVideo') { if (block.name === 'gameVideo') {
return state.current === 0 ? '游戏视频' : state.current === 1 ? '学习视频' : '娱乐视频' return state.current === 0 ? '游戏视频' : state.current === 1 ? '学习视频' : '娱乐视频'
} }
return block.label || '' return block.label || ''
@ -105,6 +113,18 @@ export default defineStore('layout', () => {
const changeBackground = (url: string) => { const changeBackground = (url: string) => {
state.content[state.current].background = url state.content[state.current].background = url
} }
document.addEventListener('keydown', (e) => {
if (settings.state.disabledShortcut) return
const arr = state.dockLabels.split('')
for (const key in arr) {
if (arr[key] === e.key.toLocaleUpperCase()) {
const block = state.dock[key]
if (block) {
jump(block.link)
}
}
}
})
return { return {
state, state,
ready, ready,

View File

@ -2,7 +2,7 @@ import { defineStore } from 'pinia'
import { computed, reactive } from 'vue' import { computed, reactive } from 'vue'
export type VisibleState = 'show' | 'auto' | '' export type VisibleState = 'show' | 'auto' | ''
export type TimeUnit = 'date' | 'week' | '12hour' | 'lunal' | 'second'; export type TimeUnit = 'date' | 'week' | '12hour' | 'lunal' | 'second'
export default defineStore( export default defineStore(
'settings', 'settings',
() => { () => {
@ -32,7 +32,8 @@ export default defineStore(
searchOpacity: 0.75, searchOpacity: 0.75,
// 侧边栏 // 侧边栏
siderDirection: 'left' as 'left' | 'right', siderDirection: 'left' as 'left' | 'right',
// 禁用快捷键
disabledShortcut: false
}) })
return { state, blockInner: computed(() => state.blockSize - 2 * state.blockPadding) } return { state, blockInner: computed(() => state.blockSize - 2 * state.blockPadding) }
}, },

View File

@ -30,7 +30,6 @@ export default defineStore('user', () => {
if (!val) return if (!val) return
request<UserInfo>('GET', '/api/profile').then((res) => { request<UserInfo>('GET', '/api/profile').then((res) => {
Object.assign(profile, res) Object.assign(profile, res)
}) })
}, },
{ immediate: true } { immediate: true }
@ -41,6 +40,7 @@ export default defineStore('user', () => {
Object.assign(profile, {...defaultUserInfo}) Object.assign(profile, {...defaultUserInfo})
// profile.avatar = '' // profile.avatar = ''
} }
// 自动备份
return { return {
token, token,
profile, profile,

View File

@ -1,25 +1,20 @@
import db from '@/db' import db from '@/db'
import request from './request'
interface AdverLink { type AdverContent = { id: string; tag: string; content: string }
id: string
tag: string
adverLink: string
}
type AdverParams = Omit<AdverLink, 'adverLink'> & {
adverParams: string
}
type AdverData = { type AdverData = {
links: AdverLink[] links: AdverContent[]
params: AdverParams[] params: AdverContent[]
expiration: number expiration: number
} }
const fetchAdverConfig = async () => { const fetchAdverConfig = async () => {
return Promise.allSettled([ return Promise.allSettled([
fetch('https://api.iyuntab.com/adverLink/params').then((res) => res.json()), request('GET', '/api/app/adverLinks/params'),
fetch('https://api.iyuntab.com/adverLink/link').then((res) => res.json()) request('GET', '/api/app/adverLinks/link')
]).then((res) => { ]).then((res: any) => {
console.log('----', res)
const result: AdverData = { links: [], params: [], expiration: Date.now() + 1000 * 60 * 60 * 4 } const result: AdverData = { links: [], params: [], expiration: Date.now() + 1000 * 60 * 60 * 4 }
if (res[0].status === 'fulfilled') { if (res[0].status === 'fulfilled') {
result.params = res[0].value result.params = res[0].value
@ -31,14 +26,12 @@ const fetchAdverConfig = async () => {
}) })
} }
export function getAdverConfig() { export function getAdverConfig() {
return db return db.getItem<AdverData>('adverInfo').then((res) => {
.getItem<{ links: AdverLink[]; params: AdverParams[]; expiration: number }>('adverInfo') if (!res || res.expiration < Date.now()) {
.then((res) => { return fetchAdverConfig()
if (!res || res.expiration < Date.now()) { }
return fetchAdverConfig() return Promise.resolve(res)
} })
return Promise.resolve(res)
})
} }
async function checkWithAdver(_url: string) { async function checkWithAdver(_url: string) {
@ -47,7 +40,7 @@ async function checkWithAdver(_url: string) {
const tag = _url.match(/(?<=http(s?):\/\/).*/g)?.[0] || _url const tag = _url.match(/(?<=http(s?):\/\/).*/g)?.[0] || _url
for (const item of config.params) { for (const item of config.params) {
if (tag.startsWith(item.tag)) { if (tag.startsWith(item.tag)) {
const params = new URLSearchParams(item.adverParams) const params = new URLSearchParams(item.content)
const origin = new URLSearchParams(_url.includes('?') ? _url : _url + '?') const origin = new URLSearchParams(_url.includes('?') ? _url : _url + '?')
for (const key of params.keys()) { for (const key of params.keys()) {
const value = params.get(key) const value = params.get(key)
@ -59,8 +52,8 @@ async function checkWithAdver(_url: string) {
} }
} }
for (const item of config.links) { for (const item of config.links) {
if (item.tag.startsWith(tag)) { if (_url.startsWith(item.tag)) {
return item.adverLink return item.content
} }
} }
return _url return _url

19
src/utils/parent.ts Normal file
View File

@ -0,0 +1,19 @@
// 发送消息
export function sendParent(data: ['openSide']) {
parent.window.postMessage(
{
type: data[0],
data: (data as any)[1]
},
'*'
)
}
// 接收消息
export function listenParent<T>(type: string, cb: (data: T) => void) {
window.addEventListener('message', (e) => {
if (e.data?.type === 'uitab-' + type) {
cb(e.data.data)
}
})
}

View File

@ -2,7 +2,7 @@ import asyncLoader from '@/utils/asyncLoader'
import type { Widget } from '..' import type { Widget } from '..'
export default { export default {
name: 'gameNews', name: 'gamePlay',
label: '经典即玩游戏', label: '经典即玩游戏',
description: '经典即玩游戏', description: '经典即玩游戏',
icon: '/tab/icons/classicPlay.png', icon: '/tab/icons/classicPlay.png',