完成经典即玩小游戏
This commit is contained in:
parent
775ba48259
commit
d0ed386313
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
|
@ -34,7 +34,7 @@ const layout = useLayoutStore()
|
||||||
<SettingsOverlay />
|
<SettingsOverlay />
|
||||||
<SettingsButton />
|
<SettingsButton />
|
||||||
<Sider />
|
<Sider />
|
||||||
<LoginModal v-if="router.path !== 'global-login'"/>
|
<LoginModal v-if="router.path === 'global-login'"/>
|
||||||
<Grid v-if="layout.ready" />
|
<Grid v-if="layout.ready" />
|
||||||
<Dock />
|
<Dock />
|
||||||
<div class="fixed z-40 right-[14%] top-8">
|
<div class="fixed z-40 right-[14%] top-8">
|
||||||
|
|
|
@ -9,9 +9,9 @@ import { frontAddress, ossBase } from '@/config'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { generateRandomString } from '@/utils/tool'
|
import { generateRandomString } from '@/utils/tool'
|
||||||
import MD5 from 'crypto-js/md5'
|
import MD5 from 'crypto-js/md5'
|
||||||
const SECRET = 'A1Cv12olxT12dOE3xA1vPA=='
|
export const SECRET = 'A1Cv12olxT12dOE3xA1vPA=='
|
||||||
const URL_ADDRESS = 'http://newfatfox.oss-cn-beijing.aliyuncs.com'
|
export const URL_ADDRESS = 'http://newfatfox.oss-cn-beijing.aliyuncs.com'
|
||||||
interface GameType {
|
export interface GameType {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
rom: string
|
rom: string
|
||||||
|
@ -21,7 +21,7 @@ interface GameType {
|
||||||
despt: string
|
despt: string
|
||||||
icon: string
|
icon: string
|
||||||
}
|
}
|
||||||
interface OtherGame {
|
export interface OtherGame {
|
||||||
id: number // 游戏ID
|
id: number // 游戏ID
|
||||||
category_ids: number[] // 分类ID数组
|
category_ids: number[] // 分类ID数组
|
||||||
rank: number // 排名
|
rank: number // 排名
|
||||||
|
@ -33,6 +33,32 @@ interface OtherGame {
|
||||||
cover_url: string // 封面URL
|
cover_url: string // 封面URL
|
||||||
corner_mark: number // 角标标识
|
corner_mark: number // 角标标识
|
||||||
}
|
}
|
||||||
|
export const DefautGameTypeList = [
|
||||||
|
{
|
||||||
|
id: 'fc',
|
||||||
|
type: '经典红白机',
|
||||||
|
attr: 0,
|
||||||
|
oridinal: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'md',
|
||||||
|
type: '经典世嘉',
|
||||||
|
attr: 1,
|
||||||
|
oridinal: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'yiqiyoo',
|
||||||
|
type: '休闲游戏',
|
||||||
|
attr: 1,
|
||||||
|
oridinal: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'gba',
|
||||||
|
type: '经典GBA',
|
||||||
|
attr: 3,
|
||||||
|
oridinal: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
export const GameItem = defineComponent({
|
export const GameItem = defineComponent({
|
||||||
props: {
|
props: {
|
||||||
content: {
|
content: {
|
||||||
|
@ -188,32 +214,7 @@ export default defineComponent(() => {
|
||||||
<div class={'w-full h-full flex flex-col gap-y-4'}>
|
<div class={'w-full h-full flex flex-col gap-y-4'}>
|
||||||
<div class={'w-full '}>
|
<div class={'w-full '}>
|
||||||
<CategoryTab
|
<CategoryTab
|
||||||
list={[
|
list={DefautGameTypeList}
|
||||||
{
|
|
||||||
id: 'fc',
|
|
||||||
type: '经典红白机',
|
|
||||||
attr: 0,
|
|
||||||
oridinal: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'md',
|
|
||||||
type: '经典世嘉',
|
|
||||||
attr: 1,
|
|
||||||
oridinal: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'yiqiyoo',
|
|
||||||
type: '休闲游戏',
|
|
||||||
attr: 1,
|
|
||||||
oridinal: 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'gba',
|
|
||||||
type: '经典GBA',
|
|
||||||
attr: 3,
|
|
||||||
oridinal: 3
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
selectType={selectType.value}
|
selectType={selectType.value}
|
||||||
onUpdate:type={(e) => {
|
onUpdate:type={(e) => {
|
||||||
selectType.value = e
|
selectType.value = e
|
||||||
|
|
|
@ -10,6 +10,7 @@ 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'
|
||||||
export const DefaultPageSetting = [
|
export const DefaultPageSetting = [
|
||||||
{
|
{
|
||||||
name: '游戏',
|
name: '游戏',
|
||||||
|
@ -55,7 +56,6 @@ export default defineComponent(() => {
|
||||||
watch(() =>
|
watch(() =>
|
||||||
store.remainingTime
|
store.remainingTime
|
||||||
, (val) => {
|
, (val) => {
|
||||||
console.log(val);
|
|
||||||
|
|
||||||
if (val <= 0) {
|
if (val <= 0) {
|
||||||
store.stopTomatoTime()
|
store.stopTomatoTime()
|
||||||
|
@ -123,9 +123,12 @@ export default defineComponent(() => {
|
||||||
}}>确定</button>
|
}}>确定</button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<div class={"w-full h-full absolute z-0 rotate-90"}>
|
||||||
{
|
{
|
||||||
Array.from({ length: 60 }).map((_, idx) => (
|
Array.from({ length: 60 }).map((_, idx) => (
|
||||||
<div class={"bg-white w-[30px] h-[5px] absolute mt-[-2.5px] top-1/2"} style={{
|
<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',
|
transformOrigin: '250px',
|
||||||
borderRadius: '3px',
|
borderRadius: '3px',
|
||||||
transform: `rotateZ(${idx * 6}deg)`
|
transform: `rotateZ(${idx * 6}deg)`
|
||||||
|
@ -135,16 +138,18 @@ export default defineComponent(() => {
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class={"w-[500px] flex justify-center flex-col items-center gap-y-3 h-full text-white "}>
|
<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={"text-[24px] leading-[36px]"}>专注中</span>
|
||||||
<span class={"font-din text-[82px] font-bold leading-[115px]"}>{!store.state.isStart ? '15:00' : formatSeconds(store.remainingTime)}</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={"relative"}>
|
||||||
<div class={"aboslute w-[370px]"}>
|
<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 mt-5"}>
|
<div class={"w-full flex gap-x-4 justify-center z-[1] mt-5"}>
|
||||||
<Tooltip title={"返回工作模式"}>
|
<Tooltip title={"返回工作模式"}>
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|
|
@ -14,7 +14,7 @@ export default defineComponent({
|
||||||
const router = useRouterStore()
|
const router = useRouterStore()
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class="absolute left-0 -bottom-2 translate-y-full w-full rounded-lg bg-white/60 backdrop-blur shadow-lg p-4 flex flex-wrap gap-4"
|
class="absolute left-0 -bottom-2 z-10 translate-y-full w-full rounded-lg bg-white/60 backdrop-blur shadow-lg p-4 flex flex-wrap gap-4"
|
||||||
v-outside-click={() => {
|
v-outside-click={() => {
|
||||||
search.showSearchConfig = false
|
search.showSearchConfig = false
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default defineComponent(() => {
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
return () =>
|
return () =>
|
||||||
settings.state.showHistory && (
|
settings.state.showHistory && (
|
||||||
<div class="absolute left-0 -bottom-2 translate-y-full w-full rounded-lg bg-white/60 backdrop-blur shadow-lg p-4">
|
<div class="absolute left-0 -bottom-2 translate-y-full w-full rounded-lg z-10 bg-white/60 backdrop-blur shadow-lg p-4">
|
||||||
{searchConfig.history.map((item, idx) => (
|
{searchConfig.history.map((item, idx) => (
|
||||||
<div
|
<div
|
||||||
key={idx}
|
key={idx}
|
||||||
|
|
|
@ -1,9 +1,167 @@
|
||||||
|
import { frontAddress, ossBase } from '@/config'
|
||||||
|
import { DefautGameTypeList, SECRET, type GameType, type OtherGame } from '@/layout/adder/GameAdder'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import { generateRandomString } from '@/utils/tool'
|
||||||
|
import clsx from 'clsx'
|
||||||
|
import { MD5 } from 'crypto-js'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export default defineComponent(() => {
|
export default defineComponent(() => {
|
||||||
|
const selectType = ref('fc')
|
||||||
|
const appList = ref<GameType[]>([])
|
||||||
|
const hoverId = ref(0)
|
||||||
|
const loading = ref(false)
|
||||||
|
const fetchGame = async (page: number) => {
|
||||||
|
const parems = `nonce=${generateRandomString(8)}&pid=PIDc8uT24mpo×tamp=${dayjs().unix()}`
|
||||||
|
const sign = MD5(parems + SECRET).toString()
|
||||||
|
const response = await fetch(
|
||||||
|
`https://ge.yiqiyoo.com/game/v2/third-part/games?${parems}&sign=${sign}&paginate.limit=99&paginate.page=${page}`
|
||||||
|
)
|
||||||
|
const res = await response.json()
|
||||||
|
return res.data.items
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
selectType,
|
||||||
|
(val) => {
|
||||||
|
console.log(val);
|
||||||
|
appList.value = []
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
if (val !== 'yiqiyoo') {
|
||||||
|
request<GameType[]>('GET', `/api/games?type=${val}`)
|
||||||
|
.then((res) => {
|
||||||
|
appList.value = res
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Promise.all([fetchGame(1)]).then((res) => {
|
||||||
|
const resData = res.flat() as OtherGame[]
|
||||||
|
appList.value = resData.map((el) => ({
|
||||||
|
id: el.id.toString(),
|
||||||
|
name: el.name,
|
||||||
|
despt: el.short_description,
|
||||||
|
icon: el.icon,
|
||||||
|
rom: el.url,
|
||||||
|
playstation: el.url,
|
||||||
|
hot: el.rank,
|
||||||
|
category: el.category_ids[0].toString()
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
return () => (
|
return () => (
|
||||||
<div class="w-full h-full bg-[#ecfbff] flex flex-col">
|
<div class="w-full h-full bg-[#ecfbff] flex flex-col backdrop-blur-sm p-[8px]" style={{
|
||||||
large
|
background: 'rgba(23,33,45,.6)'
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class={"w-full h-full rounded-2xl backdrop-blur-lg px-4 flex flex-col"} style={{
|
||||||
|
background: 'rgba(23,33,46,.8)'
|
||||||
|
}}>
|
||||||
|
<div class={"w-full flex justify-between items-center"}>
|
||||||
|
<div class={"flex gap-x-2 h-[36px]"}>
|
||||||
|
{
|
||||||
|
DefautGameTypeList.map(item => (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
selectType.value = item.id
|
||||||
|
}}
|
||||||
|
class={clsx("flex items-center jusitfy-center relative py-4 text-[13px]",
|
||||||
|
selectType.value === item.id ? "text-[#589fff]" : " text-[#589fffcc]"
|
||||||
|
)} >
|
||||||
|
{item.type}
|
||||||
|
{
|
||||||
|
selectType.value === item.id &&
|
||||||
|
<div class={"bg-[#589fff] w-[22px] h-[4px] absolute top-0 left-1/2 -translate-x-1/2"} style={{
|
||||||
|
borderRadius: '0 0 12px 12px',
|
||||||
|
|
||||||
|
}}></div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<span class={"text-[#ddd]/70 text-[14px]"}>查看更多</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
!loading.value &&
|
||||||
|
|
||||||
|
<div class={"flex-1 h-0 w-full overflow-y-auto scrollbar-hide"}>
|
||||||
|
<div class={"w-full flex flex-col"}>
|
||||||
|
{
|
||||||
|
appList.value.filter((_, index) => index < 10).map((item, idx) => (
|
||||||
|
<div class={"flex items-center gap-x-2 pl-[8px] py-[4px] rounded-lg"}
|
||||||
|
onMouseenter={() => {
|
||||||
|
hoverId.value = idx
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
background: hoverId.value === idx ? "rgba(61,80,105,.8)" : "transparent"
|
||||||
|
}}>
|
||||||
|
<div class={clsx("w-[22px] h-[22px] bg-white/10 flex items-center justify-center rounded",
|
||||||
|
idx === 0 ? "text-red-500" : idx === 1 ? "text-orange-500" : idx === 2 ? "text-yellow-400" : "text-white"
|
||||||
|
)}>{idx + 1}</div>
|
||||||
|
<div class={"flex flex-1"}>
|
||||||
|
{
|
||||||
|
hoverId.value === idx ?
|
||||||
|
<div class={"w-full h-full flex justify-between pr-4 items-center"}>
|
||||||
|
<div class={"flex gap-x-3"}>
|
||||||
|
<img
|
||||||
|
class={"w-[36px] h-[36px] rounded "}
|
||||||
|
src={item.icon.startsWith('http')
|
||||||
|
? item.icon
|
||||||
|
: ossBase + '/' + item.icon}></img>
|
||||||
|
<div class={"flex flex-col"}>
|
||||||
|
<span class={"w-[150px] text-[13px] text-white text-ellipsis whitespace-nowrap overflow-hidden"}>{item.name}</span>
|
||||||
|
<span class={"w-[150px] text-[13px] text-white/50 text-ellipsis whitespace-nowrap overflow-hidden"}>{item.despt}</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
!item.rom.startsWith('http')
|
||||||
|
? `${frontAddress}/emu/#/home?params=${JSON.stringify({
|
||||||
|
...item,
|
||||||
|
rom: ossBase + '/' + item.rom
|
||||||
|
})}`
|
||||||
|
: item.rom,
|
||||||
|
)
|
||||||
|
|
||||||
|
}}
|
||||||
|
class={"bg-[#317aff] w-[76px] h-[26px] rounded text-white text-[12px]"}>立即游玩</button>
|
||||||
|
</div> :
|
||||||
|
<div class={"w-full h-full flex gap-x-4"}>
|
||||||
|
<span class={"w-[80px] text-[13px] text-white text-ellipsis whitespace-nowrap overflow-hidden"}>{item.name}</span>
|
||||||
|
<span class={"w-[180px] text-[13px] text-white/50 text-ellipsis whitespace-nowrap overflow-hidden"}>{item.despt}</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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>
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -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>
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -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>
|
|
||||||
)
|
|
||||||
})
|
|
|
@ -3,23 +3,11 @@ import type { Widget } from '..'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'gameNews',
|
name: 'gameNews',
|
||||||
label: '游戏资讯',
|
label: '经典即玩游戏',
|
||||||
description: '游戏资讯',
|
description: '经典即玩游戏',
|
||||||
icon: '/tab/icons/game_news_icon.png',
|
icon: '/tab/icons/classicPlay.png',
|
||||||
modal: asyncLoader(() => import('./Modal')),
|
modal: null,
|
||||||
list: [
|
list: [
|
||||||
{
|
|
||||||
w: 2,
|
|
||||||
h: 1,
|
|
||||||
label: '小',
|
|
||||||
component: asyncLoader(() => import('./Small'))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
w: 2,
|
|
||||||
h: 2,
|
|
||||||
label: '中',
|
|
||||||
component: asyncLoader(() => import('./Middle'))
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
w: 4,
|
w: 4,
|
||||||
h: 2,
|
h: 2,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import hotspot from './hotspot'
|
||||||
import constellation from './constellation'
|
import constellation from './constellation'
|
||||||
import gameVideo from './gameVideo'
|
import gameVideo from './gameVideo'
|
||||||
import work from './work'
|
import work from './work'
|
||||||
|
import game from './game'
|
||||||
export interface Widget {
|
export interface Widget {
|
||||||
name: string // 小组件类型唯一标识
|
name: string // 小组件类型唯一标识
|
||||||
label: string // 小组件名称
|
label: string // 小组件名称
|
||||||
|
@ -23,4 +24,4 @@ export interface Widget {
|
||||||
}[] // 不同尺寸小组件块
|
}[] // 不同尺寸小组件块
|
||||||
}
|
}
|
||||||
|
|
||||||
export default [calendar, weather, weApply, gameNews, eat, discount, hotspot, constellation, gameVideo, work] as Widget[]
|
export default [game, calendar, weather, weApply, gameNews, eat, discount, hotspot, constellation, gameVideo, work] as Widget[]
|
||||||
|
|
|
@ -8,17 +8,18 @@ export default {
|
||||||
icon: '/tab/icons/work/tomato_work_icon.png',
|
icon: '/tab/icons/work/tomato_work_icon.png',
|
||||||
modal: asyncLoader(() => import('./Modal')),
|
modal: asyncLoader(() => import('./Modal')),
|
||||||
list: [
|
list: [
|
||||||
|
{
|
||||||
|
w: 4,
|
||||||
|
h: 2,
|
||||||
|
label: '大',
|
||||||
|
component: asyncLoader(() => import('./Large'))
|
||||||
|
},
|
||||||
{
|
{
|
||||||
w: 2,
|
w: 2,
|
||||||
h: 1,
|
h: 1,
|
||||||
label: '小',
|
label: '小',
|
||||||
component: asyncLoader(() => import('./Small'))
|
component: asyncLoader(() => import('./Small'))
|
||||||
},
|
},
|
||||||
{
|
|
||||||
w: 4,
|
|
||||||
h: 2,
|
|
||||||
label: '大',
|
|
||||||
component: asyncLoader(() => import('./Large'))
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
} as Widget
|
} as Widget
|
||||||
|
|
Loading…
Reference in New Issue