Compare commits

..

No commits in common. "3a07dae8b38a37d112a0f248779e0fade2b1579e" and "b3f1ed6f346607d7436ea97dde57a0985548d5e9" have entirely different histories.

19 changed files with 130 additions and 402 deletions

View File

@ -16,7 +16,6 @@ import useLayoutStore from './layout/useLayoutStore'
import WelcomePage from './layout/grid/WelcomePage' import WelcomePage from './layout/grid/WelcomePage'
import TomatoPage from './layout/grid/TomatoPage' import TomatoPage from './layout/grid/TomatoPage'
import useRouterStore from './useRouterStore' import useRouterStore from './useRouterStore'
import BackupRecovery from './user/BackupRecovery'
const Grid = asyncLoader(() => import('./layout/grid')) const Grid = asyncLoader(() => import('./layout/grid'))
const Fox = asyncLoader(() => import('./fox')) const Fox = asyncLoader(() => import('./fox'))
const settings = useSettingsStore() const settings = useSettingsStore()
@ -30,13 +29,7 @@ const layout = useLayoutStore()
<template> <template>
<div class="fixed left-0 top-0 w-full h-screen style-root" @contextmenu.prevent> <div class="fixed left-0 top-0 w-full h-screen style-root" @contextmenu.prevent>
<Header /> <Header />
<Background <Background />
@dblclick="
() => {
layout.state.simple = !layout.state.simple
}
"
/>
<GLobalModal /> <GLobalModal />
<SettingsOverlay /> <SettingsOverlay />
<SettingsButton /> <SettingsButton />
@ -57,21 +50,14 @@ const layout = useLayoutStore()
(layout.state.simple && settings.state.simpleModeShowString.includes('showDock')) (layout.state.simple && settings.state.simpleModeShowString.includes('showDock'))
" "
/> />
<div <div class="fixed z-40 right-[14%] top-8" v-if="!layout.state.simple ||
class="fixed z-40 right-[14%] top-8" (layout.state.simple && settings.state.simpleModeShowString.includes('showPet'))">
v-if="
!layout.state.simple ||
(layout.state.simple && settings.state.simpleModeShowString.includes('showPet'))
"
>
<Fox /> <Fox />
</div> </div>
<DirModal /> <DirModal />
<GlobalMenu /> <GlobalMenu />
<WelcomePage></WelcomePage> <WelcomePage></WelcomePage>
<TomatoPage></TomatoPage> <TomatoPage></TomatoPage>
<BackupRecovery v-if="router.path === 'global-backup'"></BackupRecovery>
</div> </div>
</template> </template>

View File

@ -18,7 +18,7 @@ export default defineComponent(() => {
router.path.startsWith('widget-') || router.path.startsWith('widget-') ||
router.path === 'global-search' || router.path === 'global-search' ||
router.path === 'global-adder' || router.path === 'global-adder' ||
router.path === 'global-background' router.path === 'global-background'
) )
const full = ref(false) const full = ref(false)
watch(router, () => { watch(router, () => {
@ -93,21 +93,20 @@ export default defineComponent(() => {
<AdderPage /> <AdderPage />
) : router.path === 'global-background' ? ( ) : router.path === 'global-background' ? (
<BackgroundSwtich /> <BackgroundSwtich />
) : ) : router.path.startsWith('widget-') ? (
router.path.startsWith('widget-') ? ( (() => {
(() => { const name = router.path.split('-')[1]
const name = router.path.split('-')[1] const selected = widgetList.find((el) => el.name === name)
const selected = widgetList.find((el) => el.name === name) if (!selected)
if (!selected) return (
return ( <div class="w-full h-full flex justify-center items-center text-black/80">
<div class="w-full h-full flex justify-center items-center text-black/80">
</div>
</div> )
) const compo = selected.modal
const compo = selected.modal return <compo />
return <compo /> })()
})() ) : null}
) : null}
</Transition> </Transition>
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@ export const apiBase = import.meta.env.PROD
// 后端 cdn 加速地址 // 后端 cdn 加速地址
export const cdnBase = import.meta.env.PROD ? apiBase : apiBase export const cdnBase = import.meta.env.PROD ? apiBase : apiBase
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NzJkYjg5OGUxMjY5NDc1ODYwMmYwMTgifQ.8fpdr_HPgxyU0yr-8f6nGdbHYjsFRlBa2lvjc0Zhe-A
// 图片后缀名 // 图片后缀名
export const imgArr = [ export const imgArr = [
'bmp', 'bmp',

View File

@ -1,6 +1,6 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { computed, defineComponent, onUnmounted, reactive, ref } from 'vue' import { computed, defineComponent, onUnmounted, reactive } from 'vue'
import type { Block, LayoutPages } from './layout.types' 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'
@ -11,17 +11,11 @@ import useSettingsStore from '@/settings/useSettingsStore'
const defaultDisplay = { const defaultDisplay = {
x: 0, x: 0,
y: 0, y: 0,
type: 'global' as Block | 'global' | 'dock' | 'page' type: 'global' as Block | 'global' | 'dock'
} }
export const useMenuStore = defineStore('menu', () => { export const useMenuStore = defineStore('menu', () => {
const display = reactive(defaultDisplay) const display = reactive(defaultDisplay)
const selectPage = ref<{
id: string,
label: string,
name: string,
}>()
const showEditPage = ref(false)
const mPos = { const mPos = {
x: 0, x: 0,
y: 0 y: 0
@ -49,9 +43,7 @@ export const useMenuStore = defineStore('menu', () => {
display, display,
open, open,
dismiss, dismiss,
show, show
selectPage,
showEditPage
} }
}) })
@ -83,8 +75,8 @@ const Item = defineComponent({
style={ style={
props.noStyle props.noStyle
? { ? {
padding: '6px 10px' padding: '6px 10px'
} }
: {} : {}
} }
onClick={() => { onClick={() => {
@ -192,32 +184,6 @@ export default defineComponent(() => {
</> </>
) )
} }
if (menu.display.type === 'page') {
return (
<>
<Item
onClick={() => {
menu.showEditPage = true
menu.dismiss()
}}
>
</Item>
<Item
alert
onClick={() => {
// 删除链接
const idx = layout.currentPage.list.findIndex((el) => el.id === block.id)
if (idx < 0) return
layout.currentPage.list.splice(idx, 1)
menu.dismiss()
}}
>
</Item>
</>
)
}
const block = menu.display.type const block = menu.display.type
if (!block.link) { if (!block.link) {
// 小组件 // 小组件

View File

@ -2,9 +2,9 @@ import { computed, defineComponent, onMounted, ref, Transition } from 'vue'
import WelcomeImg from '~/icons/welcome/welcomeTitle.png' import WelcomeImg from '~/icons/welcome/welcomeTitle.png'
import DivBgImg from '~/icons/welcome/back.png' 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 useLayoutStore from '../useLayoutStore' import useLayoutStore from '../useLayoutStore'
import request from '@/utils/request' import request from '@/utils/request'
import useStatisticStore from '@/utils/useStatisticStore'
export const DefaultPageSetting = [ export const DefaultPageSetting = [
{ {
name: '游戏', name: '游戏',
@ -12,7 +12,7 @@ export const DefaultPageSetting = [
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/831a4d4c-61ff-4bae-ad31-9c0f4fa2db1c.webp', 'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/831a4d4c-61ff-4bae-ad31-9c0f4fa2db1c.webp',
contentUrl: contentUrl:
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/b2f3ed2f-f550-499b-8ea1-dfd192cfd388.webp', 'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/b2f3ed2f-f550-499b-8ea1-dfd192cfd388.webp',
desct: '聚合多类游戏工具,以及 资讯、排行榜' desct: '聚合多类游戏工具,以及 资讯、排行榜'
}, },
{ {
name: '工作台', name: '工作台',
@ -28,7 +28,7 @@ export const DefaultPageSetting = [
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/73164094-cb0d-4366-8d1a-afc84ac119cc.webp', 'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/73164094-cb0d-4366-8d1a-afc84ac119cc.webp',
contentUrl: contentUrl:
'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/bcbbffc6-c8a4-4c8e-8ba5-36fa1fbad4f9.webp', 'https://newfatfox.oss-cn-beijing.aliyuncs.com/000/user_upload/1/resource/bcbbffc6-c8a4-4c8e-8ba5-36fa1fbad4f9.webp',
desct: '综合办公、学习、游戏等 属性,功能较为均' desct: '综合办公、学习、游戏等 属性,功能较为均'
} }
] ]
export default defineComponent(() => { export default defineComponent(() => {
@ -44,11 +44,6 @@ export default defineComponent(() => {
if (!visited) { if (!visited) {
// 如果没有记录,说明是第一次访问 // 如果没有记录,说明是第一次访问
isFirst.value = true isFirst.value = true
useStatisticStore().send({
widget: 'WELCOME',
action: 'OPEN',
space: 'TAB',
})
} }
}) })
return () => return () =>
@ -58,7 +53,7 @@ export default defineComponent(() => {
{show.value && ( {show.value && (
<div <div
class="w-full h-screen bg-black/60 " class="w-full h-screen bg-black/60 "
onClick={() => { }} onClick={() => {}}
style={{ style={{
backgroundImage: `url('${DefaultPageSetting[selectMode.value].backgroundUrl}')`, backgroundImage: `url('${DefaultPageSetting[selectMode.value].backgroundUrl}')`,
backgroundSize: '100% 100%', backgroundSize: '100% 100%',
@ -66,7 +61,7 @@ export default defineComponent(() => {
backgroundRepeat: 'no-repeat' backgroundRepeat: 'no-repeat'
}} }}
> >
<div class="w-full h-screen bg-black/60 " onClick={() => { }}></div> <div class="w-full h-screen bg-black/60 " onClick={() => {}}></div>
</div> </div>
)} )}
</Transition> </Transition>
@ -93,11 +88,11 @@ export default defineComponent(() => {
} }
onClick={() => { onClick={() => {
selectMode.value = idx selectMode.value = idx
}} }}
style={{ style={{
transform: `translate(${idx === selectMode.value ? 80 : (((selectMode.value === 2 && idx === 0) || (selectMode.value + 1 === idx)) ? 219 : -52)}px) scale(${idx === selectMode.value ? 1 : 0.85 transform: `translate(${idx === selectMode.value ? 80 : idx === (selectMode.value + 1) % 2 ? 219 : -52}px) scale(${
})`, idx === selectMode.value ? 1 : 0.85
})`,
backgroundImage: `url('${DivBgImg}')`, backgroundImage: `url('${DivBgImg}')`,
backgroundSize: '100% 100%', backgroundSize: '100% 100%',
zIndex: selectMode.value === idx ? 10 : 0 zIndex: selectMode.value === idx ? 10 : 0
@ -135,13 +130,6 @@ export default defineComponent(() => {
if (!res) return if (!res) return
layout.state.dir = res.dir layout.state.dir = res.dir
layout.state.content = res.content layout.state.content = res.content
})
layout.state.current = selectMode.value as 0 | 1 | 2
useStatisticStore().send({
widget: selectMode.value === 0 ? "WELCOME_GAME" : selectMode.value === 1 ? "WELCOME_WORK" : "WELCOME_RELAX",
action: 'CLICK',
space: 'TAB',
}) })
}} }}
style={{ style={{

View File

@ -21,8 +21,6 @@ export default defineComponent(() => {
return () => ( return () => (
<div <div
class="absolute left-0 top-0 w-full h-screen overflow-y-auto no-scrollbar pt-[240px] px-[calc((100%_-_var(--main-width))_/_2)]" class="absolute left-0 top-0 w-full h-screen overflow-y-auto no-scrollbar pt-[240px] px-[calc((100%_-_var(--main-width))_/_2)]"
onScroll={(e) => { onScroll={(e) => {
const h = (e.target as any).scrollTop const h = (e.target as any).scrollTop
@ -59,7 +57,6 @@ export default defineComponent(() => {
}} }}
> >
<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)"
ref={container} ref={container}

View File

@ -4,7 +4,6 @@ import useSearchStore from './useSearchStore'
import { OhVueIcon, addIcons } from 'oh-vue-icons' import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { FaPlus } from 'oh-vue-icons/icons' import { FaPlus } from 'oh-vue-icons/icons'
import useRouterStore from '@/useRouterStore' import useRouterStore from '@/useRouterStore'
import useStatisticStore from '@/utils/useStatisticStore'
addIcons(FaPlus) addIcons(FaPlus)
@ -35,13 +34,6 @@ export default defineComponent({
onClick={() => { onClick={() => {
searchConfig.current = { ...item } searchConfig.current = { ...item }
search.showSearchConfig = false search.showSearchConfig = false
useStatisticStore().send({
widget: 'search',
action: 'search',
key: `key=${item.name}`
})
}} }}
> >
<div <div

View File

@ -1,10 +1,9 @@
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { OhVueIcon, addIcons } from 'oh-vue-icons' import { OhVueIcon, addIcons } from 'oh-vue-icons'
import { MdHistory, RiCloseCircleLine } from 'oh-vue-icons/icons' import { MdHistory, MdRemove, RiCloseCircleLine } from 'oh-vue-icons/icons'
import useSearchConfigStore from './useSearchConfigStore' import useSearchConfigStore from './useSearchConfigStore'
import jump from '@/utils/jump' import jump from '@/utils/jump'
import useSettingsStore from '@/settings/useSettingsStore' import useSettingsStore from '@/settings/useSettingsStore'
import useStatisticStore from '@/utils/useStatisticStore'
addIcons(MdHistory, RiCloseCircleLine) addIcons(MdHistory, RiCloseCircleLine)
export default defineComponent(() => { export default defineComponent(() => {
const searchConfig = useSearchConfigStore() const searchConfig = useSearchConfigStore()
@ -18,12 +17,6 @@ export default defineComponent(() => {
class="flex justify-between hover:pl-[20px] duration-300 items-center text-black/80 cursor-pointer hover:bg-white/40 py-1 px-2 rounded transition-all" class="flex justify-between hover:pl-[20px] duration-300 items-center text-black/80 cursor-pointer hover:bg-white/40 py-1 px-2 rounded transition-all"
onMousedown={() => { onMousedown={() => {
jump(searchConfig.current.url + item) jump(searchConfig.current.url + item)
useStatisticStore().send({
widget: 'search',
action: 'search',
key: `key=${item}&engine=${searchConfig.current.name}&type=直接搜索`
})
}} }}
> >
<div class="flex items-center w-0 flex-grow"> <div class="flex items-center w-0 flex-grow">

View File

@ -41,7 +41,50 @@ const defaultCustomSearchList: SearchInfo[] = [
] ]
// const defaultCustomSearchList: SearchInfo[] = [
// {
// name: '知乎',
// url: 'https://www.zhihu.com/search?type=content&q=',
// icon: 'searchIcons/zhihu.svg',
// show: true
// },
// {
// name: 'GitHub',
// url: 'https://github.com/search?q=',
// icon: 'searchIcons/GitHub.svg',
// show: true
// },
// {
// name: 'F搜',
// url: 'https://fsoufsou.com/search?q=',
// icon: 'searchIcons/F.svg',
// show: true
// },
// {
// name: '豆瓣',
// url: 'https://www.douban.com/search?q=',
// icon: 'searchIcons/douban.svg',
// show: true
// },
// {
// name: 'Yandex',
// url: 'https://yandex.com/search/?text=',
// icon: 'searchIcons/yandex.svg',
// show: true
// },
// {
// name: '开发者',
// url: 'https://kaifa.baidu.com/searchPage?wd=',
// icon: 'searchIcons/kaifa.svg',
// show: true
// },
// {
// name: 'B站',
// url: 'https://search.bilibili.com/all?keyword=',
// icon: 'searchIcons/bilibili.svg',
// show: true
// }
// ]
export default defineStore( export default defineStore(
'searchConfig', 'searchConfig',
() => { () => {

View File

@ -5,7 +5,6 @@ import jump from '@/utils/jump'
import debounce from 'lodash/debounce' import debounce from 'lodash/debounce'
import { aIUrl, translateUrl } from '@/config' import { aIUrl, translateUrl } from '@/config'
import request from '@/utils/request' import request from '@/utils/request'
import useStatisticStore from '@/utils/useStatisticStore'
export type SearchAdType = { export type SearchAdType = {
name: string name: string
icon: string icon: string
@ -82,12 +81,6 @@ export default defineStore('search', () => {
searchConfig.addHistory(str) searchConfig.addHistory(str)
searchStr.value = '' searchStr.value = ''
jump(searchConfig.current.url + str) jump(searchConfig.current.url + str)
useStatisticStore().send({
widget: 'search',
action: 'search',
key: `key=${str}&engine=${searchConfig.current.name}&type=直接搜索`
})
return return
} }
if (current.value <= 1) { if (current.value <= 1) {

View File

@ -26,7 +26,7 @@ export interface Block {
extra?: any extra?: any
} }
export type LayoutPages = { list: Block[]; label: string; name: string; id: string }[] export type LayoutPages = { list: Block[]; label: string; name: string }[]
export interface Layout { export interface Layout {
content: [ content: [
@ -52,4 +52,3 @@ export interface Layout {
dockLabels: string dockLabels: string
simple: boolean simple: boolean
} }

View File

@ -16,12 +16,9 @@ export default defineComponent(() => {
() => layout.state.current, () => layout.state.current,
(val) => { (val) => {
selected.value = val selected.value = val
hover.value = false
}, },
{ immediate: true } { immediate: true }
) )
return () => ( return () => (
<div <div
class="w-[56px] h-[56px] relative cursor-pointer" class="w-[56px] h-[56px] relative cursor-pointer"

View File

@ -9,8 +9,7 @@ import useUserStore from '@/user/useUserStore'
import AvatarCircle from '@/user/AvatarCircle' import AvatarCircle from '@/user/AvatarCircle'
import clsx from 'clsx' import clsx from 'clsx'
import useSettingsStore from '@/settings/useSettingsStore' import useSettingsStore from '@/settings/useSettingsStore'
import { useMenuStore } from '../GlobalMenu'
import { v4 as uuid } from 'uuid'
initIcons() initIcons()
addIcons(PxHeadset, PxAddBox, PxCheck) addIcons(PxHeadset, PxAddBox, PxCheck)
const Item = defineComponent({ const Item = defineComponent({
@ -30,10 +29,6 @@ const Item = defineComponent({
active: { active: {
type: Boolean, type: Boolean,
default: false default: false
},
id: {
type: String,
default: ''
} }
}, },
emits: ['click'], emits: ['click'],
@ -41,16 +36,6 @@ const Item = defineComponent({
const hover = ref(false) const hover = ref(false)
return () => ( return () => (
<div <div
onContextmenu={(e) => {
useMenuStore().open('page')
useMenuStore().selectPage = {
id: props.id,
label: props.label,
name: props.name,
}
e.stopPropagation()
e.preventDefault()
}}
class={ class={
'relative z-10 w-full h-[56px] flex flex-col justify-center items-center text-[13px] cursor-pointer transition-all font-bold ' + 'relative z-10 w-full h-[56px] flex flex-col justify-center items-center text-[13px] cursor-pointer transition-all font-bold ' +
(props.active ? 'text-white' : hover.value ? 'text-white' : 'text-white/80') (props.active ? 'text-white' : hover.value ? 'text-white' : 'text-white/80')
@ -72,7 +57,7 @@ const Item = defineComponent({
} }
}) })
export default defineComponent(() => { export default defineComponent(() => {
const menu = useMenuStore() const showEdit = ref(false)
const selected = ref(icons[0]) const selected = ref(icons[0])
const router = useRouterStore() const router = useRouterStore()
const layout = useLayoutStore() const layout = useLayoutStore()
@ -87,21 +72,6 @@ export default defineComponent(() => {
}, },
{ immediate: true } { immediate: true }
) )
watch(
() => menu.selectPage,
(val) => {
if (val) {
selected.value = {
name: val.name,
label: val.label
}
label.value = val.label
} else {
selected.value = icons[0]
label.value = ''
}
}
)
return () => ( return () => (
<Transition> <Transition>
{layout.ready && ( {layout.ready && (
@ -142,7 +112,6 @@ export default defineComponent(() => {
key={idx} key={idx}
name={el.name} name={el.name}
label={el.label} label={el.label}
id={el.id}
idx={idx} idx={idx}
active={layout.state.currentPage === idx} active={layout.state.currentPage === idx}
onClick={() => { onClick={() => {
@ -168,7 +137,7 @@ export default defineComponent(() => {
name="px-add-box" name="px-add-box"
label="添加" label="添加"
onClick={() => { onClick={() => {
menu.showEditPage = true showEdit.value = true
}} }}
/> />
<Item <Item
@ -192,14 +161,14 @@ export default defineComponent(() => {
</div> </div>
</div> </div>
{/* 添加页面 */} {/* 添加页面 */}
{menu.showEditPage && ( {showEdit.value && (
<div <div
class={clsx( class={clsx(
'absolute bottom-0 w-56 rounded-lg p-4 bg-white/40 backdrop-blur shadow-lg', 'absolute bottom-0 w-56 rounded-lg p-4 bg-white/40 backdrop-blur shadow-lg',
settings.state.siderDirection === 'left' ? 'left-[70px]' : 'right-[70px]' settings.state.siderDirection === 'left' ? 'left-[70px]' : 'right-[70px]'
)} )}
v-outside-click={() => { v-outside-click={() => {
menu.showEditPage = false showEdit.value = false
}} }}
> >
<input <input
@ -227,25 +196,15 @@ export default defineComponent(() => {
<div <div
class="w-full mt-2 py-1 rounded-lg bg-white text-center text-sm shadow hover:shadow-lg transition-all cursor-pointer" class="w-full mt-2 py-1 rounded-lg bg-white text-center text-sm shadow hover:shadow-lg transition-all cursor-pointer"
onClick={() => { onClick={() => {
if (menu.selectPage) { layout.currentMode.pages.push({
menu.selectPage.name = selected.value.name list: [],
menu.selectPage.label = label.value label: label.value,
name: selected.value.name
} else { })
layout.currentMode.pages.push({
list: [],
label: label.value,
name: selected.value.name,
id: uuid()
})
}
menu.showEditPage = false
}} }}
> >
<OhVueIcon name="px-check" /> <OhVueIcon name="px-check" />
{menu.selectPage ? "修改页面" : "添加页面"}
</div> </div>
</div> </div>
)} )}

View File

@ -1,7 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
export type GlobalStr = 'search' | 'block' | 'adder' | 'login' | 'background' | 'backup' export type GlobalStr = 'search' | 'block' | 'adder' | 'login' | 'background'
export type SettingStr = export type SettingStr =
| 'user' | 'user'
| 'background' | 'background'

View File

@ -1,49 +0,0 @@
import { defineComponent, ref, Transition } from 'vue'
import useRouterStore from '@/useRouterStore'
import { Radio, RadioGroup } from 'ant-design-vue'
import useUserStore from './useUserStore'
export default defineComponent(() => {
const router = useRouterStore()
const userStore = useUserStore()
const select = ref(1)
return () => (
<div class="fixed left-0 top-0 z-50 w-full">
<Transition>
<div
class="w-full h-screen bg-black/50"
></div>
</Transition>
<Transition name="modal">
<div class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 overflow-hidden transition-all w-[400px] h-[240px] rounded-lg bg-white/30 ">
<div class="w-full h-full flex flex-col justify-between p-4 px-6 rounded-lg bg-white overflow-hidden relative">
<div class={"text-center border-b-[#ddd] border-b-[1px] pb-2 "}></div>
<span class={"text-[#666] text-[14px]"}></span>
<RadioGroup value={select.value} onChange={(e) => {
select.value = e.target.value
}} class={"flex flex-col text-[#333] gap-y-3"}>
<Radio value={1} class={"text-[#333]"}></Radio>
<Radio value={2} class={"text-[#333]"}></Radio>
</RadioGroup>
<div class={"flex justify-end "}
onClick={() => {
if (select.value === 1) {
userStore.comineData()
} else {
userStore.coverageData()
}
router.replace('')
}}
>
<button class={"px-10 py-1 hover:opacity-80 duration-150 bg-[#4a7aff] text-white rounded-lg"}></button>
</div>
</div>
</div>
</Transition>
</div>
)
})

View File

@ -39,13 +39,12 @@ export default defineComponent(() => {
</div> </div>
<div class="flex py-2"> <div class="flex py-2">
<div class={labelStyle}>:</div> <div class={labelStyle}>:</div>
<Tag color={user.profile.gender === 1 ? 'blue' : user.profile.gender === 2 ? 'red' : 'gray'}> <Tag color={user.profile.gender === 1 ? 'blue' : 'red'}>
{user.profile.gender === 1 ? '男' : user.profile.gender === 2 ? '女' : '未知'} {user.profile.gender === 1 ? '男' : '女'}
</Tag> </Tag>
</div> </div>
</div> </div>
) )}
}
<div class="flex justify-around items-center my-10"> <div class="flex justify-around items-center my-10">
{user.isLogin ? ( {user.isLogin ? (
@ -91,6 +90,6 @@ export default defineComponent(() => {
</Button> </Button>
)} )}
</div> </div>
</div > </div>
) )
}) })

View File

@ -1,6 +1,5 @@
import type { Block, Layout } from '@/layout/layout.types' import type { Block, Layout } from '@/layout/layout.types'
import useLayoutStore from '@/layout/useLayoutStore' import useLayoutStore from '@/layout/useLayoutStore'
import useRouterStore from '@/useRouterStore'
import request from '@/utils/request' import request from '@/utils/request'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { computed, reactive, ref, watch } from 'vue' import { computed, reactive, ref, watch } from 'vue'
@ -22,130 +21,64 @@ const defaultUserInfo: UserInfo = {
openId: '' openId: ''
} }
function getLinkList(data: Layout) {
function areArraysEqualById(arr1: Block[], arr2: Block[]): boolean { const list = [] as Block[]
if (arr1.length !== arr2.length) { for (const mode of data.content) {
return false; for (const page of mode.pages) {
} for (const item of page.list) {
if (!item.link || item.link.startsWith('id:')) break
// 将 arr2 转换为一个以 id 为键的映射 list.push(item)
}
// 检查 arr1 中的每个 item 是否在 arr2 中存在,并且值是否相同
for (let i = 0; i < arr1.length; i++) {
console.log(arr1[i].id);
console.log(arr2[i].id);
if (arr1[i].id !== arr2[i].id) {
return false
} }
} }
for (const item of data.dock) {
return true; if (item) list.push(item)
}
for (const dirItem of Object.values(data.dir)) {
for (const item of dirItem.list) {
list.push(item)
}
}
return list
} }
export default defineStore('user', () => { export default defineStore('user', () => {
const token = ref(localStorage.getItem('token') || '') const token = ref(localStorage.getItem('token') || '')
const remoteData = ref<Layout | null>(null) watch(token, (val) => {
const remoteAddList = ref<Block[]>([]) localStorage.setItem('token', val)
})
const profile = reactive({ ...defaultUserInfo }) const profile = reactive({ ...defaultUserInfo })
const layout = useLayoutStore() const layout = useLayoutStore()
const isLogin = computed(() => !!token.value && !!profile.id)
function getLinkList(data: Layout) {
const list = [] as Block[]
for (const mode of data.content) {
for (const page of mode.pages) {
for (const item of page.list) {
list.push(item)
}
}
}
for (const item of data.dock) {
if (item) list.push(item)
}
for (const dirItem of Object.values(data.dir)) {
for (const item of dirItem.list) {
list.push(item)
}
}
return list
}
watch( watch(
token, token,
async (val) => { async (val) => {
localStorage.setItem('token', val)
if (!val) return if (!val) return
const res = await request<UserInfo>('GET', '/api/profile') const res = await request<UserInfo>('GET', '/api/profile')
Object.assign(profile, res) Object.assign(profile, res)
const data = await request<Layout>('GET', '/api/backup')
const remoteList = getLinkList(data)
const localList = getLinkList(layout.state)
const addList: Block[] = []
for (const item of remoteList) {
if (!localList.some((el) => el.id !== item.id)) {
addList.push(item)
}
}
if (addList.length > 0) {
// TODO: 交给张阳
}
}, },
{ immediate: true } { immediate: true }
) )
const isLogin = computed(() => !!token.value && !!profile.id)
watch(
token,
async (val) => {
if (!val) return
console.log(val);
const data = await request<Layout>('GET', '/api/backup')
if (!data) {
useRouterStore().replace('')
return
}
const remoteList = getLinkList(data)
const localList = getLinkList(layout.state)
remoteAddList.value = []
for (const item of remoteList) {
// if (!localList.some((el) => el.id !== item.id)) {
// // addList.push(item)
// remoteAddList.value.push(item)
// }
if (localList.findIndex(val => val.id === item.id) === -1) {
remoteAddList.value.push({ ...item })
}
}
if (remoteAddList.value.length > 0 || !areArraysEqualById(remoteList, localList)) {
// TODO: 交给张阳
// remoteAddList.value = addList
remoteData.value = data
useRouterStore().go('global-backup')
}
},
)
const logout = () => { const logout = () => {
token.value = '' token.value = ''
Object.assign(profile, { ...defaultUserInfo }) Object.assign(profile, { ...defaultUserInfo })
} }
const comineData = () => {
if (!remoteAddList.value) return
console.log({ ...remoteAddList.value });
remoteAddList.value.map(item => {
layout.state.content[layout.state.current].pages[layout.state.currentPage].list.push(item)
})
}
const coverageData = () => {
if (!remoteData.value) return
Object.assign(layout.state.content, remoteData.value.content)
Object.assign(layout.state.dock, remoteData.value.dock)
Object.assign(layout.state.dir, remoteData.value.dir)
}
return { return {
token, token,
profile, profile,
isLogin, isLogin,
logout, logout
coverageData,
comineData
} }
}) })

View File

@ -1,5 +1,3 @@
import useLayoutStore from "@/layout/useLayoutStore";
import request from "./request";
/** /**
* *
* @param min * @param min
@ -35,25 +33,7 @@ export function formatSeconds(seconds: number): string {
const minutes = Math.floor(seconds / 60); const minutes = Math.floor(seconds / 60);
// 计算剩余的秒数 // 计算剩余的秒数
const remainingSeconds = seconds % 60; const remainingSeconds = seconds % 60;
// 返回格式化后的字符串,确保分钟和秒数都是两位数 // 返回格式化后的字符串,确保分钟和秒数都是两位数
return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`; return `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;
} }
export function sendEvent(list: {
widget: string;
space?: string;
action: string;
key: string;
}[]) {
const store = useLayoutStore()
request('POST', '/api/app/statistics', {
data: list.map((item) => ({
widget: item.widget,
space: item.space || store.state.current === 0 ? 'TAB_GAME' : store.state.current === 1 ? 'TAB_WORK' : 'TAB_EAZY',
action: item.action,
key: item.key
}))
})
}

View File

@ -1,47 +0,0 @@
import { debounce } from "lodash";
import { defineStore } from "pinia"
import { ref, watch, type Ref } from "vue"
import request from "./request";
import { message } from "ant-design-vue";
import useLayoutStore from "@/layout/useLayoutStore";
export type StatisticType = {
widget: string;
space?: string;
action: string;
key?: string;
}
export default defineStore('statistic', () => {
const list = ref([] as StatisticType[])
const store = useLayoutStore()
const send = (item: StatisticType) => {
list.value.push(item)
}
const debouncedHandler = debounce((newValue: StatisticType[]) => {
console.log('数值改变并已防抖处理:', newValue)
if (newValue.length === 0) return
request("POST", `/api/app/statistics`, {
data: newValue.map((item) => ({
widget: item.widget,
space: item.space || store.state.current === 0 ? 'TAB_GAME' : store.state.current === 1 ? 'TAB_WORK' : 'TAB_EAZY',
action: item.action,
key: item.key
})),
returnType: 'text'
}).then(() => {
list.value = []
message.success('发送统计成功')
})
}, 2500) //
watch(list, (newValue) => {
console.log(list);
debouncedHandler(newValue)
}, {
deep: true
})
return {
list,
send
}
})