This commit is contained in:
plightfield 2024-11-15 21:01:19 +08:00
parent 47d9efd677
commit 56a9c28ec1
5 changed files with 223 additions and 155 deletions

View File

@ -13,7 +13,6 @@ import CustomWallpaper from './CustomWallpaper'
addIcons(BiChevronLeft, BiChevronDown) addIcons(BiChevronLeft, BiChevronDown)
const wallpaperAttrList = ['动态壁纸', '静态壁纸', '自定义壁纸'] const wallpaperAttrList = ['动态壁纸', '静态壁纸', '自定义壁纸']
export type BackgroundType = { export type BackgroundType = {
id: string id: string
@ -51,11 +50,12 @@ export default defineComponent(() => {
(e) => { (e) => {
if (!e[0]) return if (!e[0]) return
wallpaperList.value = [] wallpaperList.value = []
request<WallpaperItem[]>('GET', `/api/app/backgrounds?typeId=${e[0]}&sort=${sortBy.value}`).then( request<WallpaperItem[]>(
(res) => { 'GET',
wallpaperList.value = res `/api/app/backgrounds?typeId=${e[0]}&sort=${sortBy.value}`
} ).then((res) => {
) wallpaperList.value = res
})
}, },
{ {
immediate: true immediate: true
@ -166,10 +166,6 @@ export default defineComponent(() => {
<div <div
onClick={() => { onClick={() => {
layout.changeBackground(item.url) layout.changeBackground(item.url)
background.bgTrriger = false
setTimeout(() => {
background.bgTrriger = true
}, 0)
}} }}
class="h-[156px] relative cursor-pointer group w-full flex-grow-0 rounded-xl overflow-hidden" class="h-[156px] relative cursor-pointer group w-full flex-grow-0 rounded-xl overflow-hidden"
> >
@ -201,7 +197,6 @@ export default defineComponent(() => {
<div <div
key={index} key={index}
onClick={() => { onClick={() => {
if (index === 2) { if (index === 2) {
if (!userStore.isLogin) { if (!userStore.isLogin) {
router.go('global-login') router.go('global-login')

View File

@ -1,31 +1,103 @@
import { defineComponent, Transition } from 'vue' import { defineComponent, nextTick, reactive, ref, Transition, watch } from 'vue'
import useLayoutStore from '../useLayoutStore' import useLayoutStore from '../useLayoutStore'
import useSettingsStore from '@/settings/useSettingsStore' import useSettingsStore from '@/settings/useSettingsStore'
import useBackgroundStore from './useBackgroundStore'
const BgContent = defineComponent({
props: {
image: {
type: String,
required: false,
default: ''
},
video: {
type: String,
required: false,
default: ''
},
zIndex: {
type: Number,
required: false,
default: 0
}
},
setup(props) {
return () => (
<div
class="absolute left-0 top-0 w-full h-full"
style={{
zIndex: props.zIndex
}}
>
{props.video ? (
<video src={props.video} class="w-full h-full" muted />
) : (
<div
class="w-full h-full bg-center bg-cover bg-no-repeat"
style={{
backgroundImage: `url('${props.image}')`
}}
></div>
)}
</div>
)
}
})
export default defineComponent({ export default defineComponent({
name: 'BackgroundPage', name: 'BackgroundPage',
setup() { setup() {
const layout = useLayoutStore() const layout = useLayoutStore()
const background = useBackgroundStore()
const settings = useSettingsStore() const settings = useSettingsStore()
const animate = ref(false)
const pair = reactive<{
front: typeof layout.background | null
back: typeof layout.background | null
}>({ front: { ...layout.background }, back: null })
let first = false
watch(layout.background, (val) => {
if (!first) {
first = true
pair.front = { ...val } as any
pair.back = null
return
}
animate.value = true
nextTick(() => {
// 让前面的消失,后面的显式
pair.front = null
pair.back = { ...val }
})
})
watch(
() => pair.front,
(val) => {
if (val === null) {
setTimeout(() => {
animate.value = false
nextTick(() => {
pair.front = { ...pair.back } as any
pair.back = null
})
}, 600)
}
}
)
watch(pair, console.log)
return () => ( return () => (
<div class="absolute left-0 top-0 w-full h-screen z-0"> <div class="absolute left-0 top-0 w-full h-screen z-0">
<Transition name="background"> <Transition name={animate.value ? 'background' : ''}>
{background.bgTrriger && ( {pair.front ? (
<> <div class="absolute left-0 top-0 w-full h-full">
{layout.background.video ? ( <BgContent image={pair.front.image} video={pair.front.video} zIndex={1} />
<video src={layout.background.video} class="w-full h-full" /> </div>
) : ( ) : null}
<div </Transition>
class="w-full h-full bg-center bg-cover bg-no-repeat" <Transition name={animate.value ? 'background' : ''}>
style={{ {pair.back && (
backgroundImage: `url('${layout.background.image}')` <div class="absolute left-0 top-0 w-full h-full">
}} <BgContent image={pair.back.image} video={pair.back.video} zIndex={0} />
></div> </div>
)}
</>
)} )}
</Transition> </Transition>
<div <div
@ -35,9 +107,7 @@ export default defineComponent({
backgroundColor: `rgba(0,0,0,${settings.state.maskOpacity})`, backgroundColor: `rgba(0,0,0,${settings.state.maskOpacity})`,
backdropFilter: `blur(${settings.state.maskFilter}px)` backdropFilter: `blur(${settings.state.maskFilter}px)`
}} }}
> ></div>
</div>
</div> </div>
) )
} }

View File

@ -3,7 +3,6 @@ import { reactive, ref, watch } from 'vue'
export default defineStore('background', () => { export default defineStore('background', () => {
const tag = ref(localStorage.getItem('backgroundTag') || '') const tag = ref(localStorage.getItem('backgroundTag') || '')
const bgTrriger = ref(true)
const resource = reactive({ const resource = reactive({
type: 'image', type: 'image',
brief: '', brief: '',
@ -30,7 +29,6 @@ export default defineStore('background', () => {
) )
return { return {
tag, tag,
resource, resource
bgTrriger
} }
}) })

View File

@ -1,16 +1,15 @@
import { computed, defineComponent, onMounted, ref, Transition, watch } from 'vue' import { defineComponent, onMounted, ref, Transition } from 'vue'
import returnImg from "~/icons/work/return.png" import returnImg from '~/icons/work/return.png'
import endImg from "~/icons/work/tomotoIconEnd.png" import endImg from '~/icons/work/tomotoIconEnd.png'
import playWaveGif from "~/icons/work/playMusicIcon.gif" import playWaveGif from '~/icons/work/playMusicIcon.gif'
import PlayStartImg from "~/icons/work/start.png" import PlayStartImg from '~/icons/work/start.png'
import musicIcon from "~/icons/work/musicIcon.png" import musicIcon from '~/icons/work/musicIcon.png'
import useBackgroundStore from '../background/useBackgroundStore'
import useLayoutStore from '../useLayoutStore'
import useTomatoStore, { musicList } from '@/widgets/work/useTomatoStore' import useTomatoStore, { musicList } from '@/widgets/work/useTomatoStore'
import Search from '../header/search' import Search from '../header/search'
import { Modal, Tooltip } from 'ant-design-vue' import { Modal, Tooltip } from 'ant-design-vue'
import { formatSeconds } from '@/utils/tool' import { formatSeconds } from '@/utils/tool'
import clsx from 'clsx' import clsx from 'clsx'
import Background from '../background'
export const DefaultPageSetting = [ export const DefaultPageSetting = [
{ {
name: '游戏', name: '游戏',
@ -38,8 +37,6 @@ export const DefaultPageSetting = [
} }
] ]
export default defineComponent(() => { export default defineComponent(() => {
const background = useBackgroundStore()
const layout = useLayoutStore()
const store = useTomatoStore() const store = useTomatoStore()
const isFirst = ref(false) const isFirst = ref(false)
const showSelectModal = ref(false) const showSelectModal = ref(false)
@ -57,129 +54,135 @@ export default defineComponent(() => {
return () => return () =>
store.openFullscreen && ( store.openFullscreen && (
<div class="fixed left-0 top-0 z-50 w-full "> <div class="fixed left-0 top-0 z-50 w-full ">
<Background />
<Transition name="background"> <div class="w-full h-screen" />
{background.bgTrriger && (
<>
{layout.background.video ? (
<video src={layout.background.video} class="w-full h-screen" />
) : (
<div
class="w-full h-screen bg-center bg-cover bg-no-repeat"
style={{
backgroundImage: `url('${layout.background.image}')`
}}
></div>
)}
</>
)}
</Transition>
<Transition name="modal"> <Transition name="modal">
<div
<div class={"w-[500px] h-[500px] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 "}> class={
'w-[500px] h-[500px] absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 '
<Modal open={showSelectModal.value} footer={null} class={'bg-white p-0 rounded-lg'} }
>
<Modal
open={showSelectModal.value}
footer={null}
class={'bg-white p-0 rounded-lg'}
destroyOnClose destroyOnClose
centered centered
onCancel={() => { onCancel={() => {
showSelectModal.value = false showSelectModal.value = false
}}> }}
<div class={"flex flex-col items-center px-4"}> >
<span class={"text-[#333] font-bold text-[16px] mb-5"}></span> <div class={'flex flex-col items-center px-4'}>
<div class={"flex flex-col w-full gap-y-1"}> <span class={'text-[#333] font-bold text-[16px] mb-5'}></span>
{ <div class={'flex flex-col w-full gap-y-1'}>
musicList.map((item, idx) => ( {musicList.map((item, idx) => (
<div <div
onClick={() => { onClick={() => {
store.state.selectMusic = idx store.state.selectMusic = idx
store.setTrack(idx) store.setTrack(idx)
}} }}
class={"bg-black/[0.05] cursor-pointer rounded-lg text-[#333] text-[14px] py-2 pl-10 border-[1px] relative border-transparent hover:border-[#5955FB]"}> class={
{ 'bg-black/[0.05] cursor-pointer rounded-lg text-[#333] text-[14px] py-2 pl-10 border-[1px] relative border-transparent hover:border-[#5955FB]'
store.state.selectMusic === idx && }
<img src={playWaveGif} class={" absolute left-2 top-1/2 -translate-y-1/2"}></img> >
{store.state.selectMusic === idx && (
} <img
<span>{item.name}</span> src={playWaveGif}
</div> class={' absolute left-2 top-1/2 -translate-y-1/2'}
)) ></img>
} )}
<span>{item.name}</span>
</div>
))}
</div> </div>
<button <button
onClick={() => { onClick={() => {
showSelectModal.value = false showSelectModal.value = false
}} }}
class={"px-10 py-2 mt-7 font-bold text-[16px] text-white rounded-lg flex items-center justify-center cursor-pointer hover:opacity-90 duration-150"} style={{ class={
'px-10 py-2 mt-7 font-bold text-[16px] text-white rounded-lg flex items-center justify-center cursor-pointer hover:opacity-90 duration-150'
}
style={{
background: 'linear-gradient(225deg,#642FFF 0%,#5162FF 100%)', background: 'linear-gradient(225deg,#642FFF 0%,#5162FF 100%)',
boxShadow: '0 2px 6px #00000026' boxShadow: '0 2px 6px #00000026'
}}></button> }}
>
</button>
</div> </div>
</Modal> </Modal>
<div class={"w-full h-full absolute z-0 rotate-90"}> <div class={'w-full h-full absolute z-0 rotate-90'}>
{ {Array.from({ length: 60 }).map((_, idx) => (
Array.from({ length: 60 }).map((_, idx) => ( <div
<div class={clsx(" w-[30px] h-[5px] absolute mt-[-2.5px] top-1/2", class={clsx(
(((60 * 15 - store.remainingTime) / 15) >= idx) ? "bg-white" : "bg-white/50" ' w-[30px] h-[5px] absolute mt-[-2.5px] top-1/2',
)} style={{ (60 * 15 - store.remainingTime) / 15 >= idx ? 'bg-white' : 'bg-white/50'
)}
style={{
transformOrigin: '250px', transformOrigin: '250px',
borderRadius: '3px', borderRadius: '3px',
transform: `rotateZ(${idx * 6}deg)` transform: `rotateZ(${idx * 6}deg)`
}}
}}> ></div>
))}
</div>
))
}
</div> </div>
<div class={"w-[500px] flex justify-center flex-col items-center gap-y-3 h-full text-white "}> <div
<span class={"text-[24px] leading-[36px]"}></span> class={
<span class={"font-din text-[82px] font-bold leading-[115px]"}>{!store.state.isStart ? '15:00' : formatSeconds(store.remainingTime)}</span> 'w-[500px] flex justify-center flex-col items-center gap-y-3 h-full text-white '
<div class={"relative"}> }
<div class={"aboslute w-[370px] z-10"}> >
<span class={'text-[24px] leading-[36px]'}></span>
<span class={'font-din text-[82px] font-bold leading-[115px]'}>
{!store.state.isStart ? '15:00' : formatSeconds(store.remainingTime)}
</span>
<div class={'relative'}>
<div class={'aboslute w-[370px] z-10'}>
<Search isMini></Search> <Search isMini></Search>
</div> </div>
</div> </div>
<div class={"w-full flex gap-x-4 justify-center z-[1] mt-5"}> <div class={'w-full flex gap-x-4 justify-center z-[1] mt-5'}>
<Tooltip title={"返回工作模式"}> <Tooltip title={'返回工作模式'}>
<div <div
onClick={() => { onClick={() => {
store.openFullscreen = false store.openFullscreen = false
}} }}
class={"w-[44px] h-[44px] flex items-center justify-center rounded-lg cursor-pointer hover:opacity-90"} class={
'w-[44px] h-[44px] flex items-center justify-center rounded-lg cursor-pointer hover:opacity-90'
}
style={{ style={{
background: 'linear-gradient(225deg,#707eff 0%,#6b97ff 100%)', background: 'linear-gradient(225deg,#707eff 0%,#6b97ff 100%)',
boxShadow: '0 2px 4px #0003' boxShadow: '0 2px 4px #0003'
}}> }}
<img src={returnImg} alt='return' class={"w-[18px] h-[18px]"}></img> >
<img src={returnImg} alt="return" class={'w-[18px] h-[18px]'}></img>
</div> </div>
</Tooltip> </Tooltip>
<Tooltip title={store.state.isStart ? "停止" : '开始'}> <Tooltip title={store.state.isStart ? '停止' : '开始'}>
<div <div
onClick={() => { onClick={() => {
store.state.isStart ? store.state.isStart ? store.stopTomatoTime() : store.beginTomatoTime()
store.stopTomatoTime() :
store.beginTomatoTime()
}} }}
class={"w-[44px] h-[44px] flex items-center justify-center rounded-lg cursor-pointer hover:opacity-90"} class={
'w-[44px] h-[44px] flex items-center justify-center rounded-lg cursor-pointer hover:opacity-90'
}
style={{ style={{
background: 'linear-gradient(225deg,#707eff 0%,#6b97ff 100%)', background: 'linear-gradient(225deg,#707eff 0%,#6b97ff 100%)',
boxShadow: '0 2px 4px #0003' boxShadow: '0 2px 4px #0003'
}}> }}
{ >
store.state.isStart ? {store.state.isStart ? (
<img src={endImg} alt='return' class={"w-[18px] h-[18px]"}></img> <img src={endImg} alt="return" class={'w-[18px] h-[18px]'}></img>
: ) : (
<img src={PlayStartImg} alt="start" class={"w-[18px] h-[18px]"} /> <img src={PlayStartImg} alt="start" class={'w-[18px] h-[18px]'} />
)}
}
</div> </div>
</Tooltip> </Tooltip>
<div class={"w-[140px] h-[44px] relative bg-[#f0f0f0] rounded-lg flex px-3 gap-x-2 items-center justify-between cursor-pointer hover:opacity-90"} <div
class={
'w-[140px] h-[44px] relative bg-[#f0f0f0] rounded-lg flex px-3 gap-x-2 items-center justify-between cursor-pointer hover:opacity-90'
}
style={{ style={{
boxShadow: '0 2px 4px #0003' boxShadow: '0 2px 4px #0003'
}} }}
@ -187,33 +190,33 @@ export default defineComponent(() => {
showSelectModal.value = true showSelectModal.value = true
}} }}
> >
{store.state.isPlaying ? (
{ <img src={playWaveGif} alt="return" class={'w-[18px] h-[18px] '}></img>
store.state.isPlaying ? ) : (
<img src={playWaveGif} alt='return' class={"w-[18px] h-[18px] "}></img> <img src={musicIcon} alt="return" class={'w-[18px] h-[18px] '}></img>
: )}
<img src={musicIcon} alt='return' class={"w-[18px] h-[18px] "}></img> <span class={'whitespace-nowrap text-ellipsis overflow-hidden text-[#333]'}>
} {musicList[store.state.selectMusic].name}
<span class={"whitespace-nowrap text-ellipsis overflow-hidden text-[#333]"}>{musicList[store.state.selectMusic].name}</span> </span>
<div <div
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
store.togglePlay() store.togglePlay()
}} }}
class={"w-[26px] h-[26px] right-[-14px] rounded-full bg-[#c0c0c0] absolute flex items-center justify-center"}> class={
{ 'w-[26px] h-[26px] right-[-14px] rounded-full bg-[#c0c0c0] absolute flex items-center justify-center'
store.state.isPlaying ?
<img src={endImg} alt='start ' class={"w-[12px] h-[12px]"}></img>
:
<img src={PlayStartImg} alt='start ' class={"w-[12px] h-[12px]"}></img>
} }
>
{store.state.isPlaying ? (
<img src={endImg} alt="start " class={'w-[12px] h-[12px]'}></img>
) : (
<img src={PlayStartImg} alt="start " class={'w-[12px] h-[12px]'}></img>
)}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</Transition> </Transition>
</div> </div>
) )

View File

@ -262,18 +262,20 @@ body {
} }
} }
.background-enter-active { .background-enter-active,
animation: bounce-in 0.8s; .background-leave-active {
transform: scale(1);
opacity: 1;
transition:
transform 0.6s cubic-bezier(0.47, 1.64, 0.41, 0.8),
opacity 0.6s ease-out;
} }
@keyframes bounce-in { .background-enter-from {
0% { transform: scale(1.25);
transform: scale(1); opacity: 0;
} }
50% { .background-leave-to {
transform: scale(1.25); transform: scale(1);
} opacity: 0;
100% {
transform: scale(1);
}
} }