完成游戏资讯小组件的开发
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 270 B |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 4.7 KiB |
|
@ -71,11 +71,10 @@ export default defineComponent(() => {
|
||||||
return () => (
|
return () => (
|
||||||
<div class={clsx('w-full h-full relative flex', isGame.value && 'bg-[#2c2e3e]')}>
|
<div class={clsx('w-full h-full relative flex', isGame.value && 'bg-[#2c2e3e]')}>
|
||||||
<ThemeProvider dark={isGame.value}>
|
<ThemeProvider dark={isGame.value}>
|
||||||
{isGame.value && <AdderPageBack />}
|
|
||||||
<div
|
<div
|
||||||
class={
|
class={
|
||||||
'w-[200px] h-full relative z-10 pt-[100px] ' +
|
'w-[220px] h-full relative z-10 pt-[100px] ' +
|
||||||
(isGame.value ? 'pl-6 pr-2' : 'bg-white/60 backdrop-blur px-4')
|
(isGame.value ? 'pl-8 pr-2 rounded-xl' : 'bg-white/60 l backdrop-blur px-4')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ItemButton
|
<ItemButton
|
||||||
|
|
|
@ -58,7 +58,7 @@ export default defineComponent(() => {
|
||||||
|
|
||||||
const sortBy = ref<'hotNum' | 'time'>('hotNum')
|
const sortBy = ref<'hotNum' | 'time'>('hotNum')
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
request<BackgroundType[]>('GET', '/api/backgroundTypes').then((res) => {
|
request<BackgroundType[]>('GET', '/api/app/backgroundTypes').then((res) => {
|
||||||
console.log(res)
|
console.log(res)
|
||||||
typeList.value = res
|
typeList.value = res
|
||||||
selectType.value = res[0].id
|
selectType.value = res[0].id
|
||||||
|
@ -69,7 +69,7 @@ export default defineComponent(() => {
|
||||||
(e) => {
|
(e) => {
|
||||||
if (!e[0]) return
|
if (!e[0]) return
|
||||||
wallpaperList.value = []
|
wallpaperList.value = []
|
||||||
request<WallpaperItem[]>('GET', `/api/backgrounds?typeId=${e[0]}&sort=${sortBy.value}`).then(
|
request<WallpaperItem[]>('GET', `/api/app/backgrounds?typeId=${e[0]}&sort=${sortBy.value}`).then(
|
||||||
(res) => {
|
(res) => {
|
||||||
console.log(res)
|
console.log(res)
|
||||||
wallpaperList.value = res
|
wallpaperList.value = res
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent(() => {
|
||||||
|
return () => (
|
||||||
|
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
|
||||||
|
large
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
|
export default defineComponent(() => {
|
||||||
|
|
||||||
|
return () => (
|
||||||
|
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
|
||||||
|
middle
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,12 @@
|
||||||
|
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>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,14 @@
|
||||||
|
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>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,30 @@
|
||||||
|
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
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import useGameNews from './useGameNews'
|
||||||
|
|
||||||
|
export default defineComponent(() => {
|
||||||
|
const store = useGameNews()
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class="w-full h-full grid grid-cols-1 grid-rows-3 p-2 gap-y-1"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(23,33,45,.6)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{store.list
|
||||||
|
.filter((_, index) => index < 3)
|
||||||
|
.map((item) => (
|
||||||
|
<div class={'w-full rounded-xl bg-[#17212d] flex gap-x-2 p-1'}>
|
||||||
|
<img class={'h-full w-[45px] rounded-lg object-cover'} src={item.cover}></img>
|
||||||
|
<div class={'flex flex-col overflow-hidden justify-between py-[2px]'}>
|
||||||
|
<span class={'text-white text-nowrap text-[14px] text-ellipsis overflow-hidden'}>
|
||||||
|
{item.title}
|
||||||
|
</span>
|
||||||
|
<span class={'text-white text-nowrap text-[12px] opacity-60 text-ellipsis overflow-hidden'}>{item.content}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import useGameNews from './useGameNews'
|
||||||
|
|
||||||
|
export default defineComponent(() => {
|
||||||
|
const store = useGameNews()
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class="w-full h-full grid grid-cols-1 grid-rows-3 p-2 gap-y-1"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(23,33,45,.6)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{store.list
|
||||||
|
.filter((_, index) => index < 3)
|
||||||
|
.map((item) => (
|
||||||
|
<div class={'w-full rounded-xl bg-[#17212d] flex gap-x-2 p-1'}>
|
||||||
|
<img class={'h-full w-[45px] rounded-lg object-cover'} src={item.cover}></img>
|
||||||
|
<div class={'flex flex-col overflow-hidden justify-between py-[2px]'}>
|
||||||
|
<span class={'text-white text-nowrap text-[14px] text-ellipsis overflow-hidden'}>
|
||||||
|
{item.title}
|
||||||
|
</span>
|
||||||
|
<span class={'text-white text-nowrap text-[12px] opacity-60 text-ellipsis overflow-hidden'}>{item.content}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,88 @@
|
||||||
|
import { defineComponent, ref, watch, type VNodeRef } from 'vue'
|
||||||
|
import useGameNews from './useGameNews'
|
||||||
|
import { RiTimeLine } from 'oh-vue-icons/icons'
|
||||||
|
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
addIcons(RiTimeLine)
|
||||||
|
export default defineComponent(() => {
|
||||||
|
const store = useGameNews()
|
||||||
|
const containerRef = ref<VNodeRef | null>(null as VNodeRef | null)
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
const container = containerRef.value
|
||||||
|
console.log(container)
|
||||||
|
|
||||||
|
if (container.scrollTop + container.clientHeight >= container.scrollHeight - 50) {
|
||||||
|
console.log('到底了')
|
||||||
|
|
||||||
|
store.getNews()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class="w-full h-full flex flex-col p-5 bg-[#17212d]"
|
||||||
|
style={{
|
||||||
|
background: 'rgba(23,33,45,.6)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class={'flex w-full justify-center pb-5'}>
|
||||||
|
<img class={'h-[20px]'} src="/icons/游戏资讯@2x.png"></img>
|
||||||
|
</div>
|
||||||
|
<div class={'h-0 w-full flex-1'}>
|
||||||
|
<div class={'w-full h-full overflow-y-scroll'} onWheel={handleScroll} ref={containerRef}>
|
||||||
|
<div class={'grid grid-cols-2 gap-4 '}>
|
||||||
|
{store.list.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
class={
|
||||||
|
'flex cursor-pointer items-center h-[110px] rounded-lg relative overflow-hidden'
|
||||||
|
}
|
||||||
|
onClick={()=> {
|
||||||
|
window.open(item.share_url)
|
||||||
|
}}
|
||||||
|
key={index}
|
||||||
|
>
|
||||||
|
<img class={'h-full w-[40%] rounded-xl object-cover'} src={item.cover}></img>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class={
|
||||||
|
' absolute right-0 top-0 w-[70%] h-full rounded-xl flex flex-col justify-between py-4 text-white pl-2 overflow-hidden'
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
backdropFilter: 'blur(16px)',
|
||||||
|
backgroundColor: '#17212d',
|
||||||
|
background: 'rgba(0, 0, 0, .2)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class={'text-nowrap text-ellipsis overflow-hidden text-[14px]'}>
|
||||||
|
{item.title}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class={' text-ellipsis overflow-hidden text-[12px] opacity-60 line-clamp-2'}
|
||||||
|
>
|
||||||
|
{item.content}
|
||||||
|
</span>
|
||||||
|
<div class={'text-[12px] items-center flex opacity-40 gap-x-1'}>
|
||||||
|
<OhVueIcon
|
||||||
|
name={RiTimeLine.name}
|
||||||
|
class={'text-white'}
|
||||||
|
scale={0.7}
|
||||||
|
></OhVueIcon>
|
||||||
|
<span>{dayjs(item.create_time * 1000).format('YYYY-MM-DD')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{store.loading && (
|
||||||
|
<div class={'w-full font-bold flex justify-center text-white py-2'}>加载中...</div>
|
||||||
|
)}
|
||||||
|
{store.noMoreData && (
|
||||||
|
<div class={'w-full font-bold flex justify-center text-white py-2'}>无更多数据</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { defineComponent } from 'vue'
|
||||||
|
import useGameNews from './useGameNews'
|
||||||
|
|
||||||
|
export default defineComponent(() => {
|
||||||
|
const store = useGameNews()
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class="w-full h-full flex items-center px-3"
|
||||||
|
style={{
|
||||||
|
background: `url('/bg/gamenews__back.png')`,
|
||||||
|
backgroundSize: 'cover'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img class={'w-[48px] h-[48px]'} src={'/icons/gamenews__icon.png'}></img>
|
||||||
|
<div class={'flex-1 flex justify-center'}>
|
||||||
|
<div class="flex-col flex">
|
||||||
|
<span class={'text-[16px] text-white'}>游戏资讯</span>
|
||||||
|
<div class={'flex items-center text-[#fffc] text-[12px] '}>
|
||||||
|
立即查看
|
||||||
|
<div>
|
||||||
|
<img src="/icons/gt.png"></img>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,30 @@
|
||||||
|
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
|
|
@ -0,0 +1,58 @@
|
||||||
|
import request from "@/utils/request";
|
||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref, type VNodeRef } from "vue";
|
||||||
|
|
||||||
|
|
||||||
|
export interface GameNews {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
cover: string;
|
||||||
|
image: string;
|
||||||
|
create_time: number;
|
||||||
|
share_url: string;
|
||||||
|
}
|
||||||
|
export default defineStore("gameNews", () => {
|
||||||
|
const list = ref<GameNews[]>([])
|
||||||
|
const page = ref(1)
|
||||||
|
const loading = ref(false)
|
||||||
|
const noMoreData = ref(false)
|
||||||
|
const containerRef = ref<VNodeRef | null>(null)
|
||||||
|
|
||||||
|
const getList = async () => {
|
||||||
|
const res = await request<{
|
||||||
|
data: GameNews[];
|
||||||
|
}>('GET', `/api/gameDes?page=${page.value}&page_size=16`)
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
const getNews = async () => {
|
||||||
|
|
||||||
|
if (loading.value || noMoreData.value) return;
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await getList()
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
noMoreData.value = true;
|
||||||
|
} else {
|
||||||
|
list.value.push(...data);
|
||||||
|
page.value++;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getNews()
|
||||||
|
return {
|
||||||
|
list,
|
||||||
|
loading,
|
||||||
|
noMoreData,
|
||||||
|
getNews,
|
||||||
|
containerRef
|
||||||
|
}
|
||||||
|
})
|
|
@ -2,6 +2,7 @@ import type { Component } from 'vue'
|
||||||
import calendar from './calendar'
|
import calendar from './calendar'
|
||||||
import weather from './weather'
|
import weather from './weather'
|
||||||
import weApply from './weApply'
|
import weApply from './weApply'
|
||||||
|
import gameNews from './gameNews'
|
||||||
export interface Widget {
|
export interface Widget {
|
||||||
name: string // 小组件类型唯一标识
|
name: string // 小组件类型唯一标识
|
||||||
label: string // 小组件名称
|
label: string // 小组件名称
|
||||||
|
@ -16,4 +17,4 @@ export interface Widget {
|
||||||
}[] // 不同尺寸小组件块
|
}[] // 不同尺寸小组件块
|
||||||
}
|
}
|
||||||
|
|
||||||
export default [calendar, weather, weApply] as Widget[]
|
export default [calendar, weather, weApply, gameNews] as Widget[]
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
import { defineComponent, ref, watch, type VNodeRef } from 'vue'
|
||||||
|
import { useWeApplyStore } from './useWeApplyStore'
|
||||||
|
import { addIcons, OhVueIcon } from 'oh-vue-icons'
|
||||||
|
import { HiChevronDown } from 'oh-vue-icons/icons'
|
||||||
|
import clsx from 'clsx'
|
||||||
|
addIcons(HiChevronDown)
|
||||||
|
export default defineComponent(() => {
|
||||||
|
const store = useWeApplyStore()
|
||||||
|
const gameRef = ref<VNodeRef | null>(null)
|
||||||
|
const isGameBottom = ref(false)
|
||||||
|
const isWorkBottom = ref(false)
|
||||||
|
const workRef = ref<VNodeRef | null>(null)
|
||||||
|
const computIsBottom = (ref: any) => {
|
||||||
|
if (ref) {
|
||||||
|
const { scrollTop, clientHeight, scrollHeight } = ref
|
||||||
|
return scrollTop + clientHeight >= scrollHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleGameScroll = () => {
|
||||||
|
const isAtBottom = computIsBottom(gameRef.value)
|
||||||
|
console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。')
|
||||||
|
if (isAtBottom) {
|
||||||
|
isGameBottom.value = true
|
||||||
|
} else {
|
||||||
|
isGameBottom.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleWorkScroll = () => {
|
||||||
|
const isAtBottom = computIsBottom(workRef.value)
|
||||||
|
console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。')
|
||||||
|
if (isAtBottom) {
|
||||||
|
isWorkBottom.value = true
|
||||||
|
} else {
|
||||||
|
isWorkBottom.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watch(gameRef, (val, _, onCleanup) => {
|
||||||
|
console.log(val)
|
||||||
|
if (!val) return
|
||||||
|
val.addEventListener('scroll', handleGameScroll)
|
||||||
|
// if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) {
|
||||||
|
// isGameBottom.value = true
|
||||||
|
// } else {
|
||||||
|
// isGameBottom.value = false
|
||||||
|
// }
|
||||||
|
onCleanup(() => {
|
||||||
|
val.removeEventListener('scroll', handleGameScroll)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
watch(workRef, (val, _, onCleanup) => {
|
||||||
|
console.log(val)
|
||||||
|
if (!val) return
|
||||||
|
|
||||||
|
val.addEventListener('scroll', handleWorkScroll)
|
||||||
|
// if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) {
|
||||||
|
// isGameBottom.value = true
|
||||||
|
// } else {
|
||||||
|
// isGameBottom.value = false
|
||||||
|
// }
|
||||||
|
onCleanup(() => {
|
||||||
|
val.removeEventListener('scroll', handleWorkScroll)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return () => (
|
||||||
|
<div
|
||||||
|
class={'w-full h-full flex p-2 justify-between'}
|
||||||
|
style={{
|
||||||
|
background: 'rgba(23,33,45,.6)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={'w-[49.5%] h-full rounded-xl p-2 relative overflow-hidden'}
|
||||||
|
style={{
|
||||||
|
background: 'rgba(23,33,46,.8)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!isGameBottom.value && (
|
||||||
|
<div
|
||||||
|
class={
|
||||||
|
'w-full absolute bottom-0 left-0 flex justify-center bg-[#17212e] h-[20px] items-center'
|
||||||
|
}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
if (gameRef.value) {
|
||||||
|
gameRef.value.scrollTop += 40
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<OhVueIcon name={HiChevronDown.name} fill="#ddd"></OhVueIcon>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
ref={gameRef}
|
||||||
|
class={clsx('w-full h-full flex flex-col overflow-y-scroll gap-y-2 scrollbar-hide ')}
|
||||||
|
onWheel={() => {
|
||||||
|
console.log('wheel')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{store.state.list
|
||||||
|
.filter((val) => val.type === 'game')
|
||||||
|
.map((item) => (
|
||||||
|
<div class={'flex gap-x-2 items-center'}>
|
||||||
|
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
||||||
|
<div class={'flex-1 flex flex-col overflow-hidden'}>
|
||||||
|
<span class={'text-white text-[14px]'}>{item.name}</span>
|
||||||
|
<span
|
||||||
|
class={
|
||||||
|
'text-[#fff9] text-[12px] whitespace-nowrap text-ellipsis overflow-hidden'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item.des}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class={'w-[49.5%] h-full rounded-xl p-2 relative overflow-hidden'}
|
||||||
|
style={{
|
||||||
|
background: 'rgba(23,33,46,.8)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!isWorkBottom.value && (
|
||||||
|
<div
|
||||||
|
class={
|
||||||
|
'w-full absolute bottom-0 left-0 flex justify-center bg-[#17212e] h-[20px] items-center'
|
||||||
|
}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
if (workRef.value) {
|
||||||
|
workRef.value.scrollTop += 20
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<OhVueIcon name={HiChevronDown.name} fill="#ddd"></OhVueIcon>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
ref={workRef}
|
||||||
|
class={clsx('w-full h-full flex flex-col overflow-y-scroll gap-y-2 scrollbar-hide ')}
|
||||||
|
onWheel={() => {
|
||||||
|
console.log('wheel')
|
||||||
|
handleWorkScroll()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{store.state.list
|
||||||
|
.filter((val) => val.type === 'work')
|
||||||
|
.map((item) => (
|
||||||
|
<div class={'flex gap-x-2 items-center'}>
|
||||||
|
<img src={item.icon} alt="game icon" class={'w-[37px] h-[37px] rounded'}></img>
|
||||||
|
<div class={'flex-1 flex flex-col overflow-hidden'}>
|
||||||
|
<span class={'text-white text-[14px]'}>{item.name}</span>
|
||||||
|
<span
|
||||||
|
class={
|
||||||
|
'text-[#fff9] text-[12px] whitespace-nowrap text-ellipsis overflow-hidden'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item.des}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
|
@ -0,0 +1,18 @@
|
||||||
|
import asyncLoader from '@/utils/asyncLoader'
|
||||||
|
import type { Widget } from '..'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'video',
|
||||||
|
label: '视频',
|
||||||
|
description: '热门视频',
|
||||||
|
icon: '/icons/recommendedIcon.png',
|
||||||
|
modal: null,
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
w: 4,
|
||||||
|
h: 2,
|
||||||
|
label: '大',
|
||||||
|
component: asyncLoader(() => import('./Large'))
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} as Widget
|
|
@ -0,0 +1,29 @@
|
||||||
|
import request from "@/utils/request"
|
||||||
|
import { defineStore } from "pinia"
|
||||||
|
import { reactive } from "vue"
|
||||||
|
type WeApplyType = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
icon: string;
|
||||||
|
des: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
export const useWeApplyStore = defineStore('weApply', () => {
|
||||||
|
const state = reactive({
|
||||||
|
list: [] as WeApplyType[]
|
||||||
|
})
|
||||||
|
const getWeApplyList = async () => {
|
||||||
|
return request<WeApplyType[]>('GET', '/api/app/weApplys').then(res => {
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getList = async () => {
|
||||||
|
state.list = await getWeApplyList()
|
||||||
|
}
|
||||||
|
getList()
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
getList
|
||||||
|
}
|
||||||
|
})
|
|
@ -13,12 +13,11 @@ export default defineComponent(() => {
|
||||||
const computIsBottom = (ref: any) => {
|
const computIsBottom = (ref: any) => {
|
||||||
if (ref) {
|
if (ref) {
|
||||||
const { scrollTop, clientHeight, scrollHeight } = ref
|
const { scrollTop, clientHeight, scrollHeight } = ref
|
||||||
return scrollTop + clientHeight >= scrollHeight
|
return scrollTop + clientHeight >= scrollHeight -8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleGameScroll = () => {
|
const handleGameScroll = () => {
|
||||||
const isAtBottom = computIsBottom(gameRef.value)
|
const isAtBottom = computIsBottom(gameRef.value)
|
||||||
console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。')
|
|
||||||
if (isAtBottom) {
|
if (isAtBottom) {
|
||||||
isGameBottom.value = true
|
isGameBottom.value = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,40 +26,13 @@ export default defineComponent(() => {
|
||||||
}
|
}
|
||||||
const handleWorkScroll = () => {
|
const handleWorkScroll = () => {
|
||||||
const isAtBottom = computIsBottom(workRef.value)
|
const isAtBottom = computIsBottom(workRef.value)
|
||||||
console.log(isAtBottom ? '已滚动到底部!' : '未滚动到底部。')
|
|
||||||
if (isAtBottom) {
|
if (isAtBottom) {
|
||||||
isWorkBottom.value = true
|
isWorkBottom.value = true
|
||||||
} else {
|
} else {
|
||||||
isWorkBottom.value = false
|
isWorkBottom.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
watch(gameRef, (val, _, onCleanup) => {
|
|
||||||
console.log(val)
|
|
||||||
if (!val) return
|
|
||||||
val.addEventListener('scroll', handleGameScroll)
|
|
||||||
// if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) {
|
|
||||||
// isGameBottom.value = true
|
|
||||||
// } else {
|
|
||||||
// isGameBottom.value = false
|
|
||||||
// }
|
|
||||||
onCleanup(() => {
|
|
||||||
val.removeEventListener('scroll', handleGameScroll)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
watch(workRef, (val, _, onCleanup) => {
|
|
||||||
console.log(val)
|
|
||||||
if (!val) return
|
|
||||||
|
|
||||||
val.addEventListener('scroll', handleWorkScroll)
|
|
||||||
// if (val + gameRef.value.clientHeight >= gameRef.value.scrollHeight) {
|
|
||||||
// isGameBottom.value = true
|
|
||||||
// } else {
|
|
||||||
// isGameBottom.value = false
|
|
||||||
// }
|
|
||||||
onCleanup(() => {
|
|
||||||
val.removeEventListener('scroll', handleWorkScroll)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={'w-full h-full flex p-2 justify-between'}
|
class={'w-full h-full flex p-2 justify-between'}
|
||||||
|
@ -84,6 +56,7 @@ export default defineComponent(() => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (gameRef.value) {
|
if (gameRef.value) {
|
||||||
gameRef.value.scrollTop += 40
|
gameRef.value.scrollTop += 40
|
||||||
|
handleGameScroll()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -95,7 +68,7 @@ export default defineComponent(() => {
|
||||||
ref={gameRef}
|
ref={gameRef}
|
||||||
class={clsx('w-full h-full flex flex-col overflow-y-scroll gap-y-2 scrollbar-hide ')}
|
class={clsx('w-full h-full flex flex-col overflow-y-scroll gap-y-2 scrollbar-hide ')}
|
||||||
onWheel={() => {
|
onWheel={() => {
|
||||||
console.log('wheel')
|
handleGameScroll()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{store.state.list
|
{store.state.list
|
||||||
|
@ -133,6 +106,8 @@ export default defineComponent(() => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (workRef.value) {
|
if (workRef.value) {
|
||||||
workRef.value.scrollTop += 20
|
workRef.value.scrollTop += 20
|
||||||
|
handleWorkScroll()
|
||||||
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -144,7 +119,7 @@ export default defineComponent(() => {
|
||||||
ref={workRef}
|
ref={workRef}
|
||||||
class={clsx('w-full h-full flex flex-col overflow-y-scroll gap-y-2 scrollbar-hide ')}
|
class={clsx('w-full h-full flex flex-col overflow-y-scroll gap-y-2 scrollbar-hide ')}
|
||||||
onWheel={() => {
|
onWheel={() => {
|
||||||
console.log('wheel')
|
handleWorkScroll()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{store.state.list
|
{store.state.list
|
||||||
|
|
|
@ -4,7 +4,7 @@ import type { Widget } from '..'
|
||||||
export default {
|
export default {
|
||||||
name: 'weApply',
|
name: 'weApply',
|
||||||
label: '大家都在用',
|
label: '大家都在用',
|
||||||
description: '大家都在用',
|
description: '盘点近期大热的应用软件和热门游戏',
|
||||||
icon: '/icons/recommendedIcon.png',
|
icon: '/icons/recommendedIcon.png',
|
||||||
modal: null,
|
modal: null,
|
||||||
list: [
|
list: [
|
||||||
|
|