完成视频小组件

This commit is contained in:
expdsn 2024-10-23 14:57:27 +08:00
parent c1ac61c3fd
commit 56429b19a4
14 changed files with 181 additions and 140 deletions

BIN
public/icons/game_video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -34,7 +34,13 @@ export const WidgetItem = defineComponent({
'text-black/80': !isGame.value 'text-black/80': !isGame.value
})} })}
> >
{props.content.label} {props.content.name === 'gameVideo'
? useLayoutStore().state.current === 0
? '游戏视频'
: useLayoutStore().state.current === 1
? '学习视频'
: '娱乐视频'
: props.content.label}
</div> </div>
<div <div
class={clsx('text-[12px]', { class={clsx('text-[12px]', {
@ -42,7 +48,13 @@ export const WidgetItem = defineComponent({
'text-black/60': !isGame.value 'text-black/60': !isGame.value
})} })}
> >
{props.content.description} {props.content.description === 'gameVideoDesc'
? useLayoutStore().state.current === 0
? '热门游戏视频'
: useLayoutStore().state.current === 1
? '热门学习视频'
: '热门娱乐视频'
: props.content.description}
</div> </div>
</div> </div>
</div> </div>

View File

@ -111,9 +111,8 @@ export default defineComponent({
} }
}} }}
> >
<div class={'w-full h-full relative'}>
<div <div
class="w-full h-full overflow-hidden relative cursor-pointer shadow-lg" class="w-full h-full overflow-hidden relative cursor-pointer shadow-lg hover-move"
style={{ style={{
borderRadius: `calc(var(--block-radius) * var(--block-size))` borderRadius: `calc(var(--block-radius) * var(--block-size))`
}} }}
@ -133,14 +132,13 @@ export default defineComponent({
</div> </div>
{settings.state.showBlockLabel && ( {settings.state.showBlockLabel && (
<div <div
class="absolute left-0 -bottom-7 text-sm text-white text-center w-full overflow-hidden text-ellipsis whitespace-nowrap break-all font-bold" class="absolute left-0 -bottom-3 text-sm text-white text-center w-full overflow-hidden text-ellipsis whitespace-nowrap break-all font-bold"
style="text-shadow: 0 0 4px rgba(0,0,0,.6)" style="text-shadow: 0 0 4px rgba(0,0,0,.6)"
> >
{layout.getLabel(props.block)} {layout.getLabel(props.block)}
</div> </div>
)} )}
</div> </div>
</div>
) )
} }
}) })

View File

@ -22,6 +22,7 @@ const defaultLayout: Layout = {
export default defineStore('layout', () => { export default defineStore('layout', () => {
const state = reactive(defaultLayout) const state = reactive(defaultLayout)
const ready = ref(false) const ready = ref(false)
db.getItem<Layout>('layout').then((res) => { db.getItem<Layout>('layout').then((res) => {
if (res) { if (res) {
Object.assign(state, res) Object.assign(state, res)
@ -96,8 +97,16 @@ export default defineStore('layout', () => {
const dir = state.dir[block.link.slice(3)] const dir = state.dir[block.link.slice(3)]
if (dir) return dir.label if (dir) return dir.label
} }
// 处理不同的组件的名称
if (block.name === 'gameVideo') {
console.log(state.currentPage);
console.log(block);
return state.current === 0 ? '游戏视频' : state.current === 1 ? '学习视频' : '娱乐视频'
}
return block.label || '' return block.label || ''
} }
const changeBackground = (url: string) => { const changeBackground = (url: string) => {
state.content[state.current].background = url state.content[state.current].background = url
} }

9
src/utils/tool.ts Normal file
View File

@ -0,0 +1,9 @@
/**
*
* @param min
* @param max
* @returns
*/
export function randomNum(min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}

View File

@ -0,0 +1,103 @@
import useLayoutStore from '@/layout/useLayoutStore'
import request from '@/utils/request'
import { addIcons, OhVueIcon } from 'oh-vue-icons'
import { computed, defineComponent, onMounted, ref, watch, type CSSProperties } from 'vue'
import { FaChevronLeft } from 'oh-vue-icons/icons'
import type { CarouselRef } from 'ant-design-vue/es/carousel'
import { randomNum } from '@/utils/tool'
addIcons(FaChevronLeft)
interface Owner {
face: string
mid: number
name: string
}
interface GameData {
_id: string
aid: number
ctime: number
duration: number
owner: Owner
pic: string
rid: string
time: string
title: string
type: string
}
export default defineComponent(() => {
const list = ref<GameData[]>([])
const currentIndex = ref(-1)
const current = computed(() => {
if (currentIndex.value === -1) {
return null
} else {
return list.value[currentIndex.value]
}
})
watch(
() => useLayoutStore().state.current,
(val) => {
const type = val === 0 ? 'game' : val === 1 ? 'study' : 'entertainment'
request<GameData[]>('GET', `/api/hotVideo?type=${type}`).then((res) => {
list.value = res
currentIndex.value = randomNum(0, list.value.length)
})
},
{
immediate: true
}
)
onMounted(() => {
setInterval(() => {
currentIndex.value = currentIndex.value === list.value.length - 1 ? 0 : currentIndex.value + 1
}, 5000)
})
return () => (
<div class="w-full h-full p-2 bg-[#17212d] ">
{
<div
class={'w-full h-full rounded-xl relative group'}
style={{
backgroundImage: `url('https://uetab.com/countdown-img/pic2.jpg')`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat'
}}
>
<div
class={
'absolute bottom-0 left-1/2 -translate-x-1/2 pb-2 w-[300px] flex flex-col text-white '
}
>
<span class="text-[14px] text-ellipsis overflow-hidden whitespace-nowrap">
{current.value?.title}
</span>
<span class="text-[12px] opacity-60">{current.value?.owner.name}</span>
</div>
<div
onClick={(e) => {
e.stopPropagation()
currentIndex.value =
currentIndex.value === 0 ? list.value.length - 1 : currentIndex.value - 1
}}
class="absolute hidden bottom-[20px] group-hover:flex items-center justify-center left-[0px] w-[22px] h-[22px] bg-white/30 rounded"
>
<OhVueIcon name={FaChevronLeft.name} class={'text-white/80'}></OhVueIcon>
</div>
<div
onClick={(e) => {
e.stopPropagation()
currentIndex.value =
currentIndex.value === list.value.length - 1 ? 0 : currentIndex.value + 1
}}
class="absolute hidden bottom-[20px] group-hover:flex items-center justify-center right-[0px] rotate-180 w-[22px] h-[22px] bg-white/30 rounded"
>
<OhVueIcon name={FaChevronLeft.name} class={'text-white/80'}></OhVueIcon>
</div>
</div>
}
</div>
)
})

View File

@ -0,0 +1,18 @@
import asyncLoader from '@/utils/asyncLoader'
import type { Widget } from '..'
export default {
name: 'gameVideo',
label: 'gameVideo',
description: 'gameVideoDesc',
icon: '/icons/game_video.png',
modal: null,
list: [
{
w: 4,
h: 2,
label: '大',
component: asyncLoader(() => import('./Large'))
}
]
} as Widget

View File

@ -7,6 +7,7 @@ import eat from './eat'
import discount from './discount' import discount from './discount'
import hotspot from './hotspot' import hotspot from './hotspot'
import constellation from './constellation' import constellation from './constellation'
import gameVideo from './gameVideo'
export interface Widget { export interface Widget {
name: string // 小组件类型唯一标识 name: string // 小组件类型唯一标识
label: string // 小组件名称 label: string // 小组件名称
@ -21,4 +22,4 @@ export interface Widget {
}[] // 不同尺寸小组件块 }[] // 不同尺寸小组件块
} }
export default [calendar, weather, weApply, gameNews, eat, discount, hotspot, constellation] as Widget[] export default [calendar, weather, weApply, gameNews, eat, discount, hotspot, constellation, gameVideo] as Widget[]

View File

@ -1,9 +0,0 @@
import { defineComponent } from 'vue'
export default defineComponent(() => {
return () => (
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
large
</div>
)
})

View File

@ -1,10 +0,0 @@
import { defineComponent } from 'vue'
export default defineComponent(() => {
return () => (
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
middle
</div>
)
})

View File

@ -1,12 +0,0 @@
import { defineComponent } from 'vue'
export default defineComponent(() => {
return () => (
<div
class="w-full h-full bg-red-50 flex "
style={{
background: 'linear-gradient(180deg,#dcefff 0%,#e7ecff 100%)'
}}
></div>
)
})

View File

@ -1,14 +0,0 @@
import { defineComponent } from 'vue'
export default defineComponent(() => {
return () => (
<div
class="w-full h-full items-center pl-3 gap-x-2 flex py-3 text-white"
style={{
background: 'linear-gradient(135deg,#5996ff 0%,#4862ff 100%)'
}}
>
</div>
)
})

View File

@ -1,30 +0,0 @@
import asyncLoader from '@/utils/asyncLoader'
import type { Widget } from '..'
export default {
name: 'gameNews',
label: '游戏资讯',
description: '游戏资讯',
icon: '/icons/game_news_icon.png',
modal: asyncLoader(() => import('./Modal')),
list: [
{
w: 2,
h: 1,
label: '小',
component: asyncLoader(() => import('./Small'))
},
{
w: 2,
h: 2,
label: '中',
component: asyncLoader(() => import('./Middle'))
},
{
w: 4,
h: 2,
label: '大',
component: asyncLoader(() => import('./Large'))
}
]
} as Widget

View File

@ -1,34 +0,0 @@
import useLayoutStore from '@/layout/useLayoutStore'
import request from '@/utils/request'
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'
type HotType = {
desc: string
hotScore: string
index: number
picurl: string
title: string
url: string
}
export const PlatformList = new Map<string, string>([
['baidu', '百度'],
['weibo', '微博'],
['bilibili', 'B站']
] as const)
export default defineStore('video', () => {
const videoList = ref([])
const layout = useLayoutStore()
const type = ref('baidu')
const getNews = async (type: string) => {
const res = request('GET', `/api/hotList?type=${type}`)
}
watch(
() => layout.state.current,
(val) => {
console.log('videoList', val)
}
)
return {}
})