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)
const wallpaperAttrList = ['动态壁纸', '静态壁纸', '自定义壁纸']
export type BackgroundType = {
id: string
@ -51,11 +50,12 @@ export default defineComponent(() => {
(e) => {
if (!e[0]) return
wallpaperList.value = []
request<WallpaperItem[]>('GET', `/api/app/backgrounds?typeId=${e[0]}&sort=${sortBy.value}`).then(
(res) => {
wallpaperList.value = res
}
)
request<WallpaperItem[]>(
'GET',
`/api/app/backgrounds?typeId=${e[0]}&sort=${sortBy.value}`
).then((res) => {
wallpaperList.value = res
})
},
{
immediate: true
@ -166,10 +166,6 @@ export default defineComponent(() => {
<div
onClick={() => {
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"
>
@ -201,7 +197,6 @@ export default defineComponent(() => {
<div
key={index}
onClick={() => {
if (index === 2) {
if (!userStore.isLogin) {
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 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({
name: 'BackgroundPage',
setup() {
const layout = useLayoutStore()
const background = useBackgroundStore()
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 () => (
<div class="absolute left-0 top-0 w-full h-screen z-0">
<Transition name="background">
{background.bgTrriger && (
<>
{layout.background.video ? (
<video src={layout.background.video} class="w-full h-full" />
) : (
<div
class="w-full h-full bg-center bg-cover bg-no-repeat"
style={{
backgroundImage: `url('${layout.background.image}')`
}}
></div>
)}
</>
<Transition name={animate.value ? 'background' : ''}>
{pair.front ? (
<div class="absolute left-0 top-0 w-full h-full">
<BgContent image={pair.front.image} video={pair.front.video} zIndex={1} />
</div>
) : null}
</Transition>
<Transition name={animate.value ? 'background' : ''}>
{pair.back && (
<div class="absolute left-0 top-0 w-full h-full">
<BgContent image={pair.back.image} video={pair.back.video} zIndex={0} />
</div>
)}
</Transition>
<div
@ -35,9 +107,7 @@ export default defineComponent({
backgroundColor: `rgba(0,0,0,${settings.state.maskOpacity})`,
backdropFilter: `blur(${settings.state.maskFilter}px)`
}}
>
</div>
></div>
</div>
)
}

View File

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

View File

@ -1,16 +1,15 @@
import { computed, defineComponent, onMounted, ref, Transition, watch } from 'vue'
import returnImg from "~/icons/work/return.png"
import endImg from "~/icons/work/tomotoIconEnd.png"
import playWaveGif from "~/icons/work/playMusicIcon.gif"
import PlayStartImg from "~/icons/work/start.png"
import musicIcon from "~/icons/work/musicIcon.png"
import useBackgroundStore from '../background/useBackgroundStore'
import useLayoutStore from '../useLayoutStore'
import { defineComponent, onMounted, ref, Transition } from 'vue'
import returnImg from '~/icons/work/return.png'
import endImg from '~/icons/work/tomotoIconEnd.png'
import playWaveGif from '~/icons/work/playMusicIcon.gif'
import PlayStartImg from '~/icons/work/start.png'
import musicIcon from '~/icons/work/musicIcon.png'
import useTomatoStore, { musicList } from '@/widgets/work/useTomatoStore'
import Search from '../header/search'
import { Modal, Tooltip } from 'ant-design-vue'
import { formatSeconds } from '@/utils/tool'
import clsx from 'clsx'
import Background from '../background'
export const DefaultPageSetting = [
{
name: '游戏',
@ -38,8 +37,6 @@ export const DefaultPageSetting = [
}
]
export default defineComponent(() => {
const background = useBackgroundStore()
const layout = useLayoutStore()
const store = useTomatoStore()
const isFirst = ref(false)
const showSelectModal = ref(false)
@ -57,129 +54,135 @@ export default defineComponent(() => {
return () =>
store.openFullscreen && (
<div class="fixed left-0 top-0 z-50 w-full ">
<Transition name="background">
{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>
<Background />
<div class="w-full h-screen" />
<Transition name="modal">
<div 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'}
<div
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'}
destroyOnClose
centered
onCancel={() => {
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 w-full gap-y-1"}>
{
musicList.map((item, idx) => (
<div
onClick={() => {
store.state.selectMusic = 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]"}>
{
store.state.selectMusic === idx &&
<img src={playWaveGif} class={" absolute left-2 top-1/2 -translate-y-1/2"}></img>
}
<span>{item.name}</span>
</div>
))
}
}}
>
<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 w-full gap-y-1'}>
{musicList.map((item, idx) => (
<div
onClick={() => {
store.state.selectMusic = 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]'
}
>
{store.state.selectMusic === idx && (
<img
src={playWaveGif}
class={' absolute left-2 top-1/2 -translate-y-1/2'}
></img>
)}
<span>{item.name}</span>
</div>
))}
</div>
<button
onClick={() => {
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%)',
boxShadow: '0 2px 6px #00000026'
}}></button>
}}
>
</button>
</div>
</Modal>
<div class={"w-full h-full absolute z-0 rotate-90"}>
{
Array.from({ length: 60 }).map((_, idx) => (
<div class={clsx(" w-[30px] h-[5px] absolute mt-[-2.5px] top-1/2",
(((60 * 15 - store.remainingTime) / 15) >= idx) ? "bg-white" : "bg-white/50"
)} style={{
<div class={'w-full h-full absolute z-0 rotate-90'}>
{Array.from({ length: 60 }).map((_, idx) => (
<div
class={clsx(
' w-[30px] h-[5px] absolute mt-[-2.5px] top-1/2',
(60 * 15 - store.remainingTime) / 15 >= idx ? 'bg-white' : 'bg-white/50'
)}
style={{
transformOrigin: '250px',
borderRadius: '3px',
transform: `rotateZ(${idx * 6}deg)`
}}>
</div>
))
}
}}
></div>
))}
</div>
<div class={"w-[500px] flex justify-center flex-col items-center gap-y-3 h-full text-white "}>
<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"}>
<div
class={
'w-[500px] flex justify-center flex-col items-center gap-y-3 h-full text-white '
}
>
<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>
</div>
</div>
<div class={"w-full flex gap-x-4 justify-center z-[1] mt-5"}>
<Tooltip title={"返回工作模式"}>
<div class={'w-full flex gap-x-4 justify-center z-[1] mt-5'}>
<Tooltip title={'返回工作模式'}>
<div
onClick={() => {
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={{
background: 'linear-gradient(225deg,#707eff 0%,#6b97ff 100%)',
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>
</Tooltip>
<Tooltip title={store.state.isStart ? "停止" : '开始'}>
<Tooltip title={store.state.isStart ? '停止' : '开始'}>
<div
onClick={() => {
store.state.isStart ?
store.stopTomatoTime() :
store.beginTomatoTime()
store.state.isStart ? 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={{
background: 'linear-gradient(225deg,#707eff 0%,#6b97ff 100%)',
boxShadow: '0 2px 4px #0003'
}}>
{
store.state.isStart ?
<img src={endImg} alt='return' class={"w-[18px] h-[18px]"}></img>
:
<img src={PlayStartImg} alt="start" class={"w-[18px] h-[18px]"} />
}
}}
>
{store.state.isStart ? (
<img src={endImg} alt="return" class={'w-[18px] h-[18px]'}></img>
) : (
<img src={PlayStartImg} alt="start" class={'w-[18px] h-[18px]'} />
)}
</div>
</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={{
boxShadow: '0 2px 4px #0003'
}}
@ -187,33 +190,33 @@ export default defineComponent(() => {
showSelectModal.value = true
}}
>
{
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>
}
<span class={"whitespace-nowrap text-ellipsis overflow-hidden text-[#333]"}>{musicList[store.state.selectMusic].name}</span>
{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>
)}
<span class={'whitespace-nowrap text-ellipsis overflow-hidden text-[#333]'}>
{musicList[store.state.selectMusic].name}
</span>
<div
onClick={(e) => {
e.stopPropagation()
store.togglePlay()
}}
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>
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>
)}
</div>
</div>
</div>
</div>
</div>
</Transition>
</div>
)

View File

@ -262,18 +262,20 @@ body {
}
}
.background-enter-active {
animation: bounce-in 0.8s;
.background-enter-active,
.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 {
0% {
transform: scale(1);
}
50% {
transform: scale(1.25);
}
100% {
transform: scale(1);
}
.background-enter-from {
transform: scale(1.25);
opacity: 0;
}
.background-leave-to {
transform: scale(1);
opacity: 0;
}