Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
fc-minigame
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
陈冲
fc-minigame
Commits
2f5cc1aa
Commit
2f5cc1aa
authored
Jun 09, 2026
by
董政锦
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: game3 第一页完成;
parent
8f17f3eb
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
1473 additions
and
0 deletions
+1473
-0
bg.webp
frontend-large/src/assets/images/game3/bg.webp
+0
-0
left.webp
frontend-large/src/assets/images/game3/left.webp
+0
-0
qrcode.png
frontend-large/src/assets/images/game3/qrcode.png
+0
-0
right.webp
frontend-large/src/assets/images/game3/right.webp
+0
-0
title.webp
frontend-large/src/assets/images/game3/title.webp
+0
-0
Game3.vue
frontend-large/src/pages/game3/Game3.vue
+212
-0
LoadingView.vue
frontend-large/src/pages/game3/views/LoadingView.vue
+288
-0
Rank1View.vue
frontend-large/src/pages/game3/views/Rank1View.vue
+627
-0
Rank2View.vue
frontend-large/src/pages/game3/views/Rank2View.vue
+337
-0
index.ts
frontend-large/src/router/index.ts
+9
-0
No files found.
frontend-large/src/assets/images/game3/bg.webp
0 → 100644
View file @
2f5cc1aa
File added
frontend-large/src/assets/images/game3/left.webp
0 → 100644
View file @
2f5cc1aa
File added
frontend-large/src/assets/images/game3/qrcode.png
0 → 100644
View file @
2f5cc1aa
7.66 KB
frontend-large/src/assets/images/game3/right.webp
0 → 100644
View file @
2f5cc1aa
File added
frontend-large/src/assets/images/game3/title.webp
0 → 100644
View file @
2f5cc1aa
File added
frontend-large/src/pages/game3/Game3.vue
0 → 100644
View file @
2f5cc1aa
<
script
setup
lang=
"ts"
>
import
{
nextTick
,
onMounted
,
onUnmounted
,
ref
,
watch
}
from
'vue'
import
{
useRouter
}
from
'vue-router'
import
Loading
from
'./views/LoadingView.vue'
import
Rank1
from
'./views/Rank1View.vue'
import
Rank2
from
'./views/Rank2View.vue'
import
{
useAdminGameSocket
}
from
'@/composables/useAdminGameSocket'
import
type
Player
from
'@/commons/player.ts'
import
{
playApplauseMusic
,
playGame6Music
,
stopAllMusic
,
stopGame6Music
}
from
'@/commons/music'
import
{
$confirm
,
$remove_socket_storage
,
$toast
}
from
'@/commons/utils.ts'
const
router
=
useRouter
()
type
GameScreen
=
'loading'
|
'rank1'
|
'rank2'
const
PLAYER_LIMIT
=
20
const
RANK_LIMIT
=
10
const
emptyLoadingPlayer
=
()
=>
({
score
:
'-'
,
telephone
:
''
,
userid
:
''
,
wechat_id
:
''
,
nickname
:
'虚位以待'
,
avatar
:
''
,
})
const
emptyRankPlayer
=
(
index
:
number
):
Player
=>
({
wechat_id
:
`empty-
${
index
}
`
,
nickname
:
'虚位以待'
,
avatar
:
''
,
score
:
'-'
,
})
const
screen
=
ref
<
GameScreen
>
(
'loading'
)
const
loadingPlayers
=
ref
<
any
[]
>
(
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
))
const
playerCount
=
ref
(
0
)
const
rankPlayers
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
)))
const
rank1Ref
=
ref
<
InstanceType
<
typeof
Rank1
>
|
null
>
(
null
)
let
isPlayingStartAnimation
=
false
const
confirmRefresh
=
(
event
:
BeforeUnloadEvent
)
=>
{
event
.
preventDefault
()
event
.
returnValue
=
''
}
const
renderPlayers
=
(
data
:
any
)
=>
{
const
players
=
Array
.
isArray
(
data
?.
list
)
?
data
.
list
:
[]
playerCount
.
value
=
Number
(
data
?.
count
??
players
.
length
)
loadingPlayers
.
value
=
Array
.
from
(
{
length
:
PLAYER_LIMIT
},
(
_
,
index
)
=>
players
[
index
]
??
emptyLoadingPlayer
(),
)
}
const
updateRankPlayers
=
(
data
:
any
)
=>
{
if
(
!
Array
.
isArray
(
data
))
return
rankPlayers
.
value
=
Array
.
from
(
{
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
data
[
index
]
??
emptyRankPlayer
(
index
),
)
}
const
playerToRankPlayer
=
(
player
:
any
,
index
:
number
):
Player
=>
({
telephone
:
player
?.
telephone
??
''
,
userid
:
player
?.
userid
??
''
,
wechat_id
:
player
?.
wechat_id
||
`empty-
${
index
}
`
,
nickname
:
player
?.
nickname
||
'虚位以待'
,
avatar
:
player
?.
avatar
||
''
,
score
:
player
?.
score
??
'-'
,
})
const
seedRankPlayersFromLoading
=
()
=>
{
rankPlayers
.
value
=
Array
.
from
(
{
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
{
const
player
=
loadingPlayers
.
value
[
index
]
if
(
!
player
?.
userid
&&
!
player
?.
wechat_id
)
{
return
emptyRankPlayer
(
index
)
}
return
playerToRankPlayer
(
player
,
index
)
},
)
}
const
resetRoundState
=
()
=>
{
playerCount
.
value
=
0
loadingPlayers
.
value
=
Array
.
from
({
length
:
PLAYER_LIMIT
},
emptyLoadingPlayer
)
rankPlayers
.
value
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyRankPlayer
(
index
))
isPlayingStartAnimation
=
false
}
const
gotoLoading
=
(
reset
=
false
)
=>
{
if
(
reset
)
{
resetRoundState
()
}
screen
.
value
=
'loading'
}
const
gotoRank1WithIntro
=
async
()
=>
{
if
(
isPlayingStartAnimation
)
return
isPlayingStartAnimation
=
true
seedRankPlayersFromLoading
()
screen
.
value
=
'rank1'
await
nextTick
()
await
rank1Ref
.
value
?.
startIntro
()
screen
.
value
=
'rank2'
isPlayingStartAnimation
=
false
}
function
handleRoomState
(
data
:
any
)
{
if
(
Array
.
isArray
(
data
?.
list
))
{
renderPlayers
(
data
)
}
switch
(
data
?.
status
)
{
case
0
:
gotoLoading
(
true
)
createRoom
(
6
)
break
case
1
:
gotoLoading
()
break
case
2
:
seedRankPlayersFromLoading
()
screen
.
value
=
'rank1'
break
case
3
:
screen
.
value
=
'rank2'
break
}
}
const
gameId
=
'game6'
const
{
startGame
,
createRoom
,
backRoom
,
closeRoom
}
=
useAdminGameSocket
({
gameId
,
onRoomState
:
handleRoomState
,
onRoomJoin
:
(
data
)
=>
{
renderPlayers
(
data
)
gotoLoading
()
},
onGameStart
:
gotoRank1WithIntro
,
onRoomRank
:
updateRankPlayers
,
onRelogin
:
async
()
=>
{
$remove_socket_storage
();
await
router
.
replace
(
'/'
)
}
})
const
startGameWithMusic
=
()
=>
{
if
(
playerCount
.
value
==
0
)
{
// alert('房间中没有玩家')
$toast
(
'房间中没有玩家'
);
return
;
}
startGame
()
}
const
nextRound
=
()
=>
{
gotoLoading
(
true
)
//重开房间
backRoom
(
6
)
}
const
nextRoundWithMusic
=
()
=>
{
nextRound
()
}
const
backHandler
=
async
()
=>
{
const
ok
=
await
$confirm
({
title
:
'提示'
,
message
:
'是否关闭当前房间回到首页'
,
confirmText
:
'确定'
,
cancelText
:
'取消'
,
})
if
(
ok
)
{
closeRoom
();
stopAllMusic
()
router
.
replace
(
'/main'
);
}
}
onMounted
(()
=>
{
window
.
addEventListener
(
'beforeunload'
,
confirmRefresh
)
playGame6Music
()
})
onUnmounted
(()
=>
{
stopAllMusic
();
window
.
removeEventListener
(
'beforeunload'
,
confirmRefresh
)
})
watch
(
screen
,
(
value
)
=>
{
// console.log(value);
if
(
value
==
'rank2'
){
playApplauseMusic
();
}
else
if
(
value
==
'loading'
){
playGame6Music
();
}
})
</
script
>
<
template
>
<Loading
v-if=
"screen === 'loading'"
:players=
"loadingPlayers"
:player-count=
"playerCount"
@
start=
"startGameWithMusic"
@
back=
"backHandler"
/>
<Rank1
v-else-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
@
start=
"startGameWithMusic"
/>
<Rank2
v-else
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
</
template
>
frontend-large/src/pages/game3/views/LoadingView.vue
0 → 100644
View file @
2f5cc1aa
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
import
router
from
'@/router'
;
import
{
$format_str
}
from
'@/commons/utils.ts'
;
import
DesignStage
from
'@/components/DesignStage.vue'
import
{
assetUrl
,
cssAssetUrl
}
from
'@/commons/assets.ts'
;
defineProps
<
{
players
:
any
[];
playerCount
:
number
;
}
>
();
const
emit
=
defineEmits
<
{
start
:
[];
back
:[];
}
>
();
const
imageUrls
=
{
bg
:
cssAssetUrl
(
'game3/bg.webp'
),
logo
:
cssAssetUrl
(
'game1/logo.png'
),
title1
:
cssAssetUrl
(
'game3/title.webp'
),
title2
:
cssAssetUrl
(
'game1/title2.png'
),
qrcode
:
assetUrl
(
'game3/qrcode.png'
),
// gu: cssAssetUrl('game1/gu.png'),
// bg: cssAssetUrl('game1/bg.png'),
// logo: cssAssetUrl('game1/logo.png'),
// title1: cssAssetUrl('game1/title1.png'),
// title2: cssAssetUrl('game1/title2.png'),
// qrcode: assetUrl('game1/qrcode.png'),
// gu: cssAssetUrl('game1/gu.png'),
imgMole
:
cssAssetUrl
(
'game3/left.webp'
),
imgRabbit
:
cssAssetUrl
(
'game3/right.webp'
),
bottomLayers
:
cssAssetUrl
(
'game1/bottom-layers.png'
),
avatarAnimation
:
cssAssetUrl
(
'avatar-red_animation.png'
),
avatar
:
cssAssetUrl
(
'avatar-red.png'
),
line
:
cssAssetUrl
(
'game1/line.png'
),
// start1: cssAssetUrl('game1/start-1.png'),
// start2: cssAssetUrl('game1/start-2.png'),
start
:
cssAssetUrl
(
'game1/start.png'
),
back
:
cssAssetUrl
(
'game1/back.png'
),
};
const
isStartPressed
=
ref
(
false
);
const
pressStartButton
=
()
=>
{
isStartPressed
.
value
=
true
;
emit
(
'start'
);
};
const
releaseStartButton
=
()
=>
{
isStartPressed
.
value
=
false
;
};
const
renderAvatar
=
(
item
:
any
|
null
)
=>
{
if
(
item
&&
item
.
avatar
)
{
return
`background: url("
${
String
(
item
.
avatar
).
replace
(
/"/g
,
'
\\
"'
)}
") center / cover no-repeat;`
}
return
`background:
${
imageUrls
.
avatar
}
center / cover no-repeat;`
}
</
script
>
<
template
>
<DesignStage>
<div
class=
"bg"
>
<div
class=
"img-logo"
></div>
<div
class=
"img-title1"
></div>
<!--
<div
class=
"img-title2"
></div>
-->
<div
class=
"img-qrcode-container"
>
<div
class=
"img-qrcode"
><img
:src=
"imageUrls.qrcode"
/></div>
<div
class=
"txt-qrcode"
>
微信扫码参与
</div>
</div>
<div
class=
"img-mole"
></div>
<div
class=
"img-rabbit"
></div>
<div
class=
"list-container"
>
<div
class=
"txt-count"
>
当前在线人数
<span>
{{
playerCount
}}
</span></div>
<div
class=
"list-container-left"
>
<div
v-for=
"(item, index) in players"
:key=
"item.userid || item.wechat_id || `empty-$
{index}`">
<div>
<div
class=
"img-avatar-container"
>
<div
class=
"img-avatar"
:style=
"`$
{renderAvatar(item)}`">
</div>
</div>
<div
class=
"txt-nickname"
>
{{
$format_str
(
item
.
nickname
,
12
)
}}
</div>
</div>
</div>
</div>
<div
class=
"list-container-line"
></div>
<div
class=
"list-container-right"
>
<!--
<div
class=
"btn-start"
:class=
"
{ pressed: isStartPressed }" @pointerdown="pressStartButton"
@pointerup="releaseStartButton" @pointerleave="releaseStartButton"
@pointercancel="releaseStartButton">
</div>
-->
<div
class=
"btn-start"
@
click=
"pressStartButton"
></div>
<div
class=
"btn-back"
@
click=
"emit('back')"
></div>
</div>
</div>
</div>
</DesignStage>
</
template
>
<
style
scoped
>
.bg
{
width
:
1920px
;
height
:
1080px
;
background
:
v-bind
(
'imageUrls.bg'
)
center
/
cover
no-repeat
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
position
:
relative
;
}
.img-logo
{
background
:
v-bind
(
'imageUrls.logo'
);
background-size
:
cover
;
width
:
428px
;
height
:
77px
;
position
:
absolute
;
left
:
37px
;
top
:
82px
;
}
.img-title1
{
background
:
v-bind
(
'imageUrls.title1'
);
width
:
910px
;
height
:
437px
;
/* margin: 0 auto; */
position
:
absolute
;
left
:
511px
;
top
:
0
;
}
.img-title2
{
background
:
v-bind
(
'imageUrls.title2'
);
width
:
643px
;
height
:
140px
;
margin
:
0
auto
;
position
:
relative
;
top
:
80px
;
}
.img-qrcode-container
{
width
:
144px
;
height
:
177px
;
position
:
absolute
;
z-index
:
1
;
top
:
40px
;
right
:
40px
;
.img-qrcode
{
width
:
100%
;
height
:
144px
;
border-radius
:
10px
;
img
{
width
:
147px
;
height
:
147px
;
}
}
.txt-qrcode
{
font-size
:
24px
;
color
:
white
;
}
}
.img-mole
{
background
:
v-bind
(
'imageUrls.imgMole'
)
center
/
cover
no-repeat
;
width
:
344px
;
height
:
354px
;
position
:
absolute
;
top
:
311px
;
left
:
144px
;
}
.img-rabbit
{
background
:
v-bind
(
'imageUrls.imgRabbit'
)
center
/
cover
no-repeat
;
width
:
633px
;
height
:
367px
;
position
:
absolute
;
top
:
293px
;
left
:
1260px
;
}
.list-container
{
background
:
v-bind
(
'imageUrls.bottomLayers'
);
width
:
1800px
;
height
:
397px
;
position
:
absolute
;
left
:
60px
;
bottom
:
60px
;
border
:
3px
solid
#AA0000
;
border-radius
:
10px
;
.txt-count
{
font-size
:
36px
;
margin-left
:
30px
;
margin-top
:
20px
;
color
:
#AA0000
;
font-weight
:
bold
;
>span
{
margin-left
:
20px
;
font-size
:
48px
;
position
:
relative
;
top
:
5px
;
}
}
.list-container-left
{
float
:
left
;
display
:
grid
;
grid-template-columns
:
repeat
(
10
,
1
fr
);
row-gap
:
20px
;
width
:
73%
;
margin-top
:
30px
;
height
:
250px
;
align-content
:
center
;
.img-avatar-container
{
position
:
relative
;
margin
:
0
auto
;
width
:
72px
;
height
:
72px
;
border-radius
:
36px
;
}
.img-avatar-container
::before
{
content
:
""
;
position
:
absolute
;
inset
:
0
;
border-radius
:
inherit
;
background
:
v-bind
(
'imageUrls.avatarAnimation'
)
center
/
cover
no-repeat
;
animation
:
avatar-rotate
10s
linear
infinite
;
}
.img-avatar
{
position
:
relative
;
top
:
6px
;
z-index
:
1
;
margin
:
0
auto
;
width
:
60px
;
height
:
60px
;
border-radius
:
30px
;
/* background: v-bind('imageUrls.avatar'); */
}
.txt-nickname
{
color
:
#666
;
font-size
:
20px
;
text-align
:
center
;
}
}
.list-container-line
{
float
:
left
;
width
:
1px
;
height
:
281px
;
margin-left
:
50px
;
background
:
v-bind
(
'imageUrls.line'
)
center
no-repeat
;
}
.list-container-right
{
float
:
left
;
.btn-start
{
width
:
316px
;
height
:
105px
;
margin-left
:
60px
;
margin-top
:
10px
;
background
:
v-bind
(
'imageUrls.start'
);
cursor
:
pointer
;
}
/* .btn-start.pressed {
background: v-bind('imageUrls.start2');
} */
.btn-back
{
width
:
316px
;
height
:
105px
;
margin-left
:
60px
;
margin-top
:
30px
;
background
:
v-bind
(
'imageUrls.back'
);
cursor
:
pointer
;
}
}
}
</
style
>
frontend-large/src/pages/game3/views/Rank1View.vue
0 → 100644
View file @
2f5cc1aa
<
script
setup
lang=
"ts"
>
import
{
onBeforeUnmount
,
onMounted
,
ref
,
watch
}
from
'vue'
import
DesignStage
from
'../../../components/DesignStage.vue'
import
type
Player
from
'../../../commons/player.ts'
import
{
$format_str
,
$is_run_local
}
from
'@/commons/utils.ts'
;
import
{
assetUrl
,
cssAssetUrl
}
from
'@/commons/assets.ts'
;
const
props
=
defineProps
<
{
rankList
:
Player
[];
}
>
();
const
emit
=
defineEmits
<
{
start
:
[];
}
>
();
const
RANK_LIMIT
=
10
;
const
START_COUNTDOWN_SECONDS
=
3
;
const
GU_FRAME_DURATION
=
300
;
const
GU_LOOP_DELAY
=
1000
;
const
MOLE_CELL_COUNT
=
9
;
const
MOLE_LAND_DURATION
=
5000
;
const
MOLE_SHOW_DURATION
=
1200
;
const
MOLE_HIDE_DURATION
=
650
;
const
designStage
=
ref
<
InstanceType
<
typeof
DesignStage
>
|
null
>
(
null
);
const
rankEffects
=
ref
<
Record
<
string
,
"up"
|
"down"
|
"new"
>>
({});
const
guFrameIndex
=
ref
(
0
);
const
guBurstVisible
=
ref
(
false
);
const
guBurstKey
=
ref
(
0
);
let
guFramesReady
:
Promise
<
void
>
|
undefined
;
let
guTimer
:
ReturnType
<
typeof
setTimeout
>
|
undefined
;
let
guBurstTimer
:
ReturnType
<
typeof
setTimeout
>
|
undefined
;
// const loadGuFrames = (dir: string) => Array.from(
// { length: 10 },
// (_, index) => assetUrl(`${dir}/${String(index + 1).padStart(2, '0')}.png`),
// );
// const guFrames = [
// loadGuFrames('game1/gu'),
// loadGuFrames('game1/gu2'),
// ];
const
imageUrls
=
{
bg
:
cssAssetUrl
(
'game6/bg2.png'
),
logo
:
cssAssetUrl
(
'game1/logo.png'
),
title
:
cssAssetUrl
(
'game6/title2.png'
),
fireworks
:
cssAssetUrl
(
'game1/fireworks.png'
),
// fireworks: cssAssetUrl('game1/fireworks.png'),
// titleRank: cssAssetUrl('game1/title-rank.png'),
rankNo4
:
cssAssetUrl
(
'game6/no4.png'
),
rankNo1
:
cssAssetUrl
(
'game6/no1.png'
),
rankNo2
:
cssAssetUrl
(
'game6/no2.png'
),
rankNo3
:
cssAssetUrl
(
'game6/no3.png'
),
// rankIcon: cssAssetUrl('game1/no-icon.png'),
// rankNo1Icon: cssAssetUrl('game1/no1-icon.png'),
// rankNo2Icon: cssAssetUrl('game1/no2-icon.png'),
// rankNo3Icon: cssAssetUrl('game1/no3-icon.png'),
avatar
:
cssAssetUrl
(
'avatar-yellow.png'
),
avatarAnimation
:
cssAssetUrl
(
'avatar-yellow_animation.png'
),
mole2
:
cssAssetUrl
(
'game6/mole2.png'
),
rankContainer
:
cssAssetUrl
(
'game6/rank-container.png'
),
land
:
cssAssetUrl
(
'game6/land.png'
),
moleShow
:
cssAssetUrl
(
'game6/mole_show.png'
),
moleHide
:
cssAssetUrl
(
'game6/mole_hide.png'
),
rabbitShow
:
cssAssetUrl
(
'game6/rabbit_show.png'
),
rabbitHide
:
cssAssetUrl
(
'game6/rabbit_hide.png'
),
};
const
emptyPlayer
=
(
index
:
number
):
Player
=>
({
wechat_id
:
`empty-
${
index
}
`
,
nickname
:
'-'
,
avatar
:
''
,
score
:
0
,
});
const
list
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
emptyPlayer
(
index
)));
const
playerKey
=
(
player
:
Player
,
index
=
0
)
=>
player
.
userid
||
player
.
wechat_id
||
`empty-
${
index
}
`
;
const
mockRankStep
=
ref
(
0
);
type
MoleKind
=
"land"
|
"mole"
|
"rabbit"
;
type
MolePhase
=
"land"
|
"show"
|
"hide"
;
type
MoleCell
=
{
kind
:
MoleKind
;
phase
:
MolePhase
;
animationKey
:
number
;
};
const
moleCells
=
ref
<
MoleCell
[]
>
(
Array
.
from
({
length
:
MOLE_CELL_COUNT
},
()
=>
({
kind
:
"land"
,
phase
:
"land"
,
animationKey
:
0
,
})),
);
const
moleTimers
:
Array
<
ReturnType
<
typeof
setTimeout
>
|
undefined
>
=
[];
const
makeMockPlayer
=
(
id
:
number
,
score
:
number
):
Player
=>
({
wechat_id
:
`mock-
${
id
}
`
,
nickname
:
`Player
${
id
}
`
,
avatar
:
''
,
score
,
});
const
mockRankRounds
:
Player
[][]
=
[
[
makeMockPlayer
(
1
,
980
),
makeMockPlayer
(
2
,
900
),
makeMockPlayer
(
3
,
860
),
makeMockPlayer
(
4
,
820
),
makeMockPlayer
(
5
,
780
),
makeMockPlayer
(
6
,
720
),
makeMockPlayer
(
7
,
680
),
makeMockPlayer
(
8
,
640
),
makeMockPlayer
(
9
,
600
),
makeMockPlayer
(
10
,
560
),
],
[
makeMockPlayer
(
4
,
1040
),
makeMockPlayer
(
1
,
1010
),
makeMockPlayer
(
7
,
960
),
makeMockPlayer
(
2
,
940
),
makeMockPlayer
(
11
,
880
),
makeMockPlayer
(
3
,
850
),
makeMockPlayer
(
5
,
830
),
makeMockPlayer
(
8
,
790
),
makeMockPlayer
(
6
,
760
),
makeMockPlayer
(
10
,
700
),
],
[
makeMockPlayer
(
7
,
1180
),
makeMockPlayer
(
11
,
1090
),
makeMockPlayer
(
4
,
1060
),
makeMockPlayer
(
12
,
1000
),
makeMockPlayer
(
1
,
980
),
makeMockPlayer
(
8
,
930
),
makeMockPlayer
(
2
,
890
),
makeMockPlayer
(
5
,
850
),
makeMockPlayer
(
13
,
810
),
makeMockPlayer
(
3
,
780
),
],
];
const
updateRankList
=
(
rankList
:
Player
[])
=>
{
const
oldRanks
=
new
Map
(
list
.
value
.
map
((
player
,
index
)
=>
[
playerKey
(
player
,
index
),
index
]));
const
next
=
Array
.
from
({
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
rankList
[
index
]
??
emptyPlayer
(
index
));
const
effects
:
Record
<
string
,
"up"
|
"down"
|
"new"
>
=
{};
next
.
forEach
((
player
,
index
)
=>
{
const
key
=
playerKey
(
player
,
index
);
if
(
!
key
||
key
.
startsWith
(
"empty-"
))
return
;
const
oldIndex
=
oldRanks
.
get
(
key
);
if
(
oldIndex
===
undefined
)
effects
[
key
]
=
"new"
;
else
if
(
oldIndex
>
index
)
effects
[
key
]
=
"up"
;
else
if
(
oldIndex
<
index
)
effects
[
key
]
=
"down"
;
});
list
.
value
=
next
;
rankEffects
.
value
=
{};
requestAnimationFrame
(()
=>
{
rankEffects
.
value
=
effects
;
});
};
watch
(
()
=>
props
.
rankList
,
(
rankList
)
=>
updateRankList
(
rankList
),
{
immediate
:
true
,
deep
:
true
},
);
const
playMockRankAnimation
=
()
=>
{
if
(
$is_run_local
())
{
updateRankList
(
mockRankRounds
[
mockRankStep
.
value
]
??
mockRankRounds
[
0
]
??
[]);
mockRankStep
.
value
=
(
mockRankStep
.
value
+
1
)
%
mockRankRounds
.
length
;
}
};
const
startGame
=
()
=>
{
if
(
$is_run_local
())
{
emit
(
'start'
);
}
};
const
randomMoleKind
=
(
includeLand
=
true
):
MoleKind
=>
{
const
kinds
:
MoleKind
[]
=
includeLand
?
[
"land"
,
"mole"
,
"rabbit"
]
:
[
"mole"
,
"rabbit"
];
return
kinds
[
Math
.
floor
(
Math
.
random
()
*
kinds
.
length
)]
??
"land"
;
};
const
clearMoleTimer
=
(
index
:
number
)
=>
{
const
timer
=
moleTimers
[
index
];
if
(
timer
)
{
clearTimeout
(
timer
);
moleTimers
[
index
]
=
undefined
;
}
};
const
setMoleCell
=
(
index
:
number
,
kind
:
MoleKind
,
phase
:
MolePhase
)
=>
{
const
next
=
[...
moleCells
.
value
];
const
current
=
next
[
index
];
next
[
index
]
=
{
kind
,
phase
,
animationKey
:
(
current
?.
animationKey
??
0
)
+
1
,
};
moleCells
.
value
=
next
;
};
const
scheduleMoleCell
=
(
index
:
number
,
kind
=
randomMoleKind
())
=>
{
clearMoleTimer
(
index
);
if
(
kind
===
"land"
)
{
setMoleCell
(
index
,
"land"
,
"land"
);
moleTimers
[
index
]
=
setTimeout
(()
=>
scheduleMoleCell
(
index
,
randomMoleKind
(
false
)),
MOLE_LAND_DURATION
);
return
;
}
setMoleCell
(
index
,
kind
,
"show"
);
moleTimers
[
index
]
=
setTimeout
(()
=>
{
setMoleCell
(
index
,
kind
,
"hide"
);
moleTimers
[
index
]
=
setTimeout
(()
=>
scheduleMoleCell
(
index
,
"land"
),
MOLE_HIDE_DURATION
);
},
MOLE_SHOW_DURATION
);
};
const
moleCellClass
=
(
cell
:
MoleCell
)
=>
[
`mole-
${
cell
.
kind
}
`
,
`mole-
${
cell
.
phase
}
`
,
];
onMounted
(()
=>
{
moleCells
.
value
.
forEach
((
_
,
index
)
=>
{
moleTimers
[
index
]
=
setTimeout
(
()
=>
scheduleMoleCell
(
index
,
randomMoleKind
()),
Math
.
floor
(
Math
.
random
()
*
MOLE_LAND_DURATION
),
);
});
});
onBeforeUnmount
(()
=>
{
moleTimers
.
forEach
((
_
,
index
)
=>
clearMoleTimer
(
index
));
});
// const stopPlayerGu = () => {
// if (guTimer) {
// clearTimeout(guTimer);
// guTimer = undefined;
// }
// if (guBurstTimer) {
// clearTimeout(guBurstTimer);
// guBurstTimer = undefined;
// }
// guBurstVisible.value = false;
// guFrameIndex.value = 0;
// }
// const preloadGuFrames = () => {
// if (!guFramesReady) {
// guFramesReady = Promise.all(guFrames.flat().map((src) => {
// const img = new Image();
// img.src = src;
// return img.decode
// ? img.decode().catch(() => undefined)
// : new Promise
<
void
>
((
resolve
)
=>
{
// img.onload = () => resolve();
// img.onerror = () => resolve();
// });
// })).then(() => undefined);
// }
// return guFramesReady;
// }
// const playGuLoopDelayAnimation = () => {
// if (guBurstTimer) {
// clearTimeout(guBurstTimer);
// guBurstTimer = undefined;
// }
// guBurstVisible.value = false;
// requestAnimationFrame(() => {
// guBurstKey.value += 1;
// guBurstVisible.value = true;
// guBurstTimer = setTimeout(() => {
// guBurstVisible.value = false;
// guBurstTimer = undefined;
// }, GU_LOOP_DELAY);
// });
// }
// const playerGu = async () => {
// stopPlayerGu();
// const frameCount = Math.min(...guFrames.map((frames) => frames.length));
// if (frameCount
<=
0
)
return
;
// await preloadGuFrames();
// let frameIndex = 0;
// const tick = () => {
// guFrameIndex.value = frameIndex;
// if (frameIndex >= frameCount - 1) {
// frameIndex = 0;
// playGuLoopDelayAnimation();
// guTimer = setTimeout(tick, GU_LOOP_DELAY);
// return;
// }
// frameIndex += 1;
// guTimer = setTimeout(tick, GU_FRAME_DURATION);
// }
// tick();
// }
const
startIntro
=
async
()
=>
{
// playerGu();
await
designStage
.
value
?.
startCountdown
(
START_COUNTDOWN_SECONDS
,
60
);
// stopPlayerGu();
};
defineExpose
({
startIntro
,
});
const
renderAvatar
=
(
item
:
any
|
null
)
=>
{
if
(
item
&&
item
.
avatar
)
{
return
`background: url("
${
String
(
item
.
avatar
).
replace
(
/"/g
,
'
\\
"'
)}
") center / cover no-repeat;`
}
return
`background:
${
imageUrls
.
avatar
}
center / cover no-repeat;`
}
const
rankIcon
=
(
index
:
number
)
=>
{
const
icons
=
[
imageUrls
.
rankNo1
,
imageUrls
.
rankNo2
,
imageUrls
.
rankNo3
,
];
let
w
=
42
;
let
h
=
47
;
let
l
=
-
20
;
let
t
=
-
20
;
if
(
index
<=
2
)
{
w
=
65
;
h
=
48
;
l
=
-
30
;
t
=
-
20
;
}
return
{
background
:
`
${
icons
[
index
]
??
imageUrls
.
rankNo4
}
center
/
cover
no
-
repeat
`,
width: w + 'px',
height: h + 'px',
left: l + 'px',
top: t + 'px',
lineHeight: h + 'px',
color: index <= 2 ? 'white' : '#CC7F36',
};
}
</
script
>
<
template
>
<DesignStage
ref=
"designStage"
>
<div
class=
"bg"
>
<div
class=
"img-logo"
></div>
<div
class=
"img-title"
></div>
<div
class=
"img-mole"
></div>
<div
class=
"rank-container"
>
<div
v-for=
"(item, index) in list"
:key=
"playerKey(item, index)"
>
<div>
<div
class=
"rank-icon"
:style=
"rankIcon(index)"
>
{{
index
+
1
}}
</div>
<div
class=
"rank-item"
>
<div>
<div
class=
"img-avatar-container"
>
<div
class=
"img-avatar"
:style=
"`$
{renderAvatar(item)}`">
</div>
</div>
<div
class=
"txt-nickname"
>
{{
$format_str
(
item
.
nickname
,
12
)
}}
</div>
<div
class=
"txt-score"
>
{{
item
.
score
}}
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"mole-container"
>
<div
v-for=
"(cell, index) in moleCells"
:key=
"index"
class=
"mole-hole"
:class=
"moleCellClass(cell)"
>
<div
:key=
"cell.animationKey"
class=
"mole-sprite"
></div>
</div>
</div>
</div>
</DesignStage>
</
template
>
<
style
scoped
>
.bg
{
width
:
1920px
;
height
:
1080px
;
background
:
v-bind
(
'imageUrls.bg'
)
center
/
cover
no-repeat
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
position
:
relative
;
}
.img-logo
{
background
:
v-bind
(
'imageUrls.logo'
);
background-size
:
cover
;
width
:
428px
;
height
:
77px
;
position
:
absolute
;
left
:
37px
;
top
:
82px
;
}
.img-title
{
background
:
v-bind
(
'imageUrls.title'
)
center
/
cover
no-repeat
;
width
:
675px
;
height
:
281px
;
margin
:
0
auto
;
margin-top
:
37px
;
}
.img-mole
{
background
:
v-bind
(
'imageUrls.mole2'
)
center
/
cover
no-repeat
;
width
:
189px
;
height
:
228px
;
position
:
absolute
;
left
:
144px
;
top
:
141px
;
}
.rank-container
{
background
:
v-bind
(
'imageUrls.rankContainer'
)
center
/
cover
no-repeat
;
display
:
grid
;
grid-template-columns
:
repeat
(
10
,
minmax
(
0
,
1
fr
));
align-items
:
center
;
column-gap
:
42px
;
box-sizing
:
border-box
;
padding
:
30px
;
width
:
1832px
;
height
:
244px
;
position
:
absolute
;
left
:
44px
;
top
:
348px
;
>div
{
box-sizing
:
border-box
;
text-align
:
center
;
width
:
100%
;
height
:
100%
;
>div
{
box-sizing
:
border-box
;
width
:
100%
;
height
:
100%
;
background
:
#A10A06
;
border-radius
:
5px
;
position
:
relative
;
.rank-icon
{
position
:
absolute
;
color
:
#CC7F36
;
font-weight
:
bold
;
}
.rank-icon
:nth-child
(
1
),
.rank-icon
:nth-child
(
2
),
.rank-icon
:nth-child
(
3
)
{
color
:
white
;
}
}
}
.img-avatar-container
{
position
:
relative
;
margin
:
0
auto
;
width
:
90px
;
height
:
90px
;
border-radius
:
36px
;
/* transform: scale(1.3); */
top
:
18px
}
.img-avatar-container
::before
{
content
:
""
;
position
:
absolute
;
inset
:
0
;
border-radius
:
inherit
;
background
:
v-bind
(
'imageUrls.avatarAnimation'
);
animation
:
avatar-rotate
10s
linear
infinite
;
}
.img-avatar
{
width
:
80px
;
height
:
80px
;
border-radius
:
40px
;
position
:
absolute
;
left
:
6px
;
top
:
5px
;
}
.txt-nickname
{
position
:
absolute
;
bottom
:
40px
;
text-align
:
center
;
width
:
100%
;
color
:
#F9EBCB
;
}
.txt-score
{
position
:
absolute
;
bottom
:
5px
;
text-align
:
center
;
width
:
100%
;
color
:
#F9EBCB
;
}
}
.mole-container
{
position
:
absolute
;
top
:
200px
;
/* inset: 0; */
pointer-events
:
none
;
.mole-hole
{
position
:
absolute
;
width
:
500px
;
height
:
500px
;
transform
:
translate
(
-125px
,
-125px
);
overflow
:
hidden
;
.mole-sprite
{
width
:
500px
;
height
:
500px
;
background-repeat
:
no-repeat
;
background-position
:
0
0
;
background-size
:
auto
500px
;
}
&
.mole-land
.mole-sprite
{
background
:
v-bind
(
'imageUrls.land'
)
center
/
cover
no-repeat
;
}
&
.mole-mole.mole-show
.mole-sprite
{
background-image
:
v-bind
(
'imageUrls.moleShow'
);
animation
:
mole-show
1.2s
steps
(
30
)
both
;
}
&
.mole-mole.mole-hide
.mole-sprite
{
background-image
:
v-bind
(
'imageUrls.moleHide'
);
animation
:
mole-hide
0.65s
steps
(
15
)
both
;
}
&
.mole-rabbit.mole-show
.mole-sprite
{
background-image
:
v-bind
(
'imageUrls.rabbitShow'
);
animation
:
mole-show
1.2s
steps
(
30
)
both
;
}
&
.mole-rabbit.mole-hide
.mole-sprite
{
background-image
:
v-bind
(
'imageUrls.rabbitHide'
);
animation
:
mole-hide
0.65s
steps
(
15
)
both
;
}
&
:nth-child
(
1
)
{
left
:
247px
;
top
:
312px
;
}
&
:nth-child
(
2
)
{
left
:
547px
;
top
:
300px
;
}
&
:nth-child
(
3
)
{
left
:
847px
;
top
:
312px
;
}
&
:nth-child
(
4
)
{
left
:
1147px
;
top
:
300px
;
}
&
:nth-child
(
5
)
{
left
:
1447px
;
top
:
312px
;
}
&
:nth-child
(
6
)
{
left
:
397px
;
top
:
480px
;
}
&
:nth-child
(
7
)
{
left
:
697px
;
top
:
460px
;
}
&
:nth-child
(
8
)
{
left
:
997px
;
top
:
460px
;
}
&
:nth-child
(
9
)
{
left
:
1297px
;
top
:
480px
;
}
}
}
@keyframes
mole-show
{
from
{
background-position-x
:
0
;
}
to
{
background-position-x
:
-15000px
;
}
}
@keyframes
mole-hide
{
from
{
background-position-x
:
0
;
}
to
{
background-position-x
:
-7500px
;
}
}
</
style
>
frontend-large/src/pages/game3/views/Rank2View.vue
0 → 100644
View file @
2f5cc1aa
<
script
setup
lang=
"ts"
>
import
{
ref
,
watch
}
from
'vue'
import
DesignStage
from
'../../../components/DesignStage.vue'
import
type
Player
from
'../../../commons/player.ts'
import
{
cssAssetUrl
}
from
'@/commons/assets.ts'
;
const
props
=
defineProps
<
{
rankList
:
Player
[];
}
>
();
const
emit
=
defineEmits
<
{
next
:
[];
back
:
[];
}
>
();
const
FINAL_RANK_LIMIT
=
10
;
const
imageUrls
=
{
bg
:
cssAssetUrl
(
'game6/bg3.png'
),
logo
:
cssAssetUrl
(
'game1/logo.png'
),
title
:
cssAssetUrl
(
'game6/title3.png'
),
podium
:
cssAssetUrl
(
'game6/podium.png'
),
vip
:
cssAssetUrl
(
'game6/vip.png'
),
avatar
:
cssAssetUrl
(
'avatar-yellow.png'
),
avatarAnimation
:
cssAssetUrl
(
'avatar-yellow_animation.png'
),
rankIcon
:
cssAssetUrl
(
'game6/no4.png'
),
next
:
cssAssetUrl
(
'game1/next.png'
),
back
:
cssAssetUrl
(
'game1/back.png'
),
};
const
emptyPlayer
=
(
index
:
number
):
Player
=>
({
active
:
false
,
wechat_id
:
`empty-
${
index
}
`
,
nickname
:
'虚位以待'
,
avatar
:
''
,
score
:
0
,
});
const
list
=
ref
<
Player
[]
>
(
Array
.
from
({
length
:
FINAL_RANK_LIMIT
},
(
_
,
index
)
=>
emptyPlayer
(
index
)));
const
updateFinalRank
=
(
rankList
:
Player
[])
=>
{
list
.
value
=
Array
.
from
(
{
length
:
FINAL_RANK_LIMIT
},
(
_
,
index
)
=>
rankList
[
index
]
??
emptyPlayer
(
index
),
);
};
watch
(
()
=>
props
.
rankList
,
(
rankList
)
=>
updateFinalRank
(
rankList
),
{
immediate
:
true
,
deep
:
true
},
);
const
renderAvatar
=
(
item
:
any
|
null
)
=>
{
if
(
item
&&
item
.
avatar
)
{
return
`background: url('
${
item
.
avatar
}
') center / cover no-repeat;`
}
return
`background:
${
imageUrls
.
avatar
}
center / cover no-repeat;`
}
</
script
>
<
template
>
<DesignStage>
<div
class=
"bg"
>
<div
class=
"img-logo"
></div>
<div
class=
"img-title"
></div>
<div
class=
"img-title2"
></div>
<div
class=
"podium"
>
<div
class=
"img-vip"
></div>
<div
class=
"rank-no1"
>
<div
class=
"avatar"
:style=
"`$
{renderAvatar(list[0])}`">
</div>
<div
class=
"nickname"
>
{{
list
[
0
]?.
nickname
}}
</div>
</div>
<div
class=
"rank-no2"
>
<div
class=
"avatar"
:style=
"`$
{renderAvatar(list[1])}`">
</div>
<div
class=
"nickname"
>
{{
list
[
1
]?.
nickname
}}
</div>
</div>
<div
class=
"rank-no3"
>
<div
class=
"avatar"
:style=
"`$
{renderAvatar(list[2])}`">
</div>
<div
class=
"nickname"
>
{{
list
[
2
]?.
nickname
}}
</div>
</div>
</div>
<div
class=
"rank-container"
>
<div
v-for=
"(item, index) in list.slice(3)"
:key=
"item.userid || item.wechat_id || `rank-$
{index}`">
<div
class=
"no-icon"
>
{{
index
+
4
}}
</div>
<div>
<div
class=
"img-avatar-container"
>
<div
class=
"img-avatar"
:style=
"`$
{renderAvatar(list[index + 3])}`">
</div>
</div>
<div
class=
"txt-nickname"
>
{{
item
.
nickname
}}
</div>
</div>
</div>
</div>
<div
class=
"btn-next"
@
click=
"emit('next')"
></div>
<div
class=
"btn-back"
@
click=
"emit('back')"
></div>
</div>
</DesignStage>
</
template
>
<
style
scoped
>
.bg
{
width
:
1920px
;
height
:
1080px
;
background
:
v-bind
(
'imageUrls.bg'
)
center
/
cover
no-repeat
;
display
:
flex
;
flex-direction
:
column
;
overflow
:
hidden
;
position
:
relative
;
}
.img-logo
{
background
:
v-bind
(
'imageUrls.logo'
);
background-size
:
cover
;
width
:
428px
;
height
:
77px
;
position
:
absolute
;
left
:
37px
;
top
:
82px
;
}
.img-title
{
background
:
v-bind
(
'imageUrls.title'
)
center
/
cover
no-repeat
;
width
:
831px
;
height
:
120px
;
margin
:
0
auto
;
margin-top
:
64px
;
}
/* .img-title2 {
background: v-bind('imageUrls.title2') no-repeat center;
width: 457px;
height: 57px;
margin: 0 auto;
margin-top: 37px;
} */
.podium
{
background
:
v-bind
(
'imageUrls.podium'
)
no-repeat
center
;
width
:
1920px
;
height
:
740px
;
position
:
absolute
;
bottom
:
0
;
left
:
0
;
.img-vip
{
width
:
969px
;
height
:
238px
;
position
:
absolute
;
left
:
480px
;
top
:
-60px
;
background
:
v-bind
(
'imageUrls.vip'
)
center
/
cover
no-repeat
;
}
.rank-no1
{
position
:
relative
;
.avatar
{
width
:
160px
;
height
:
160px
;
border-radius
:
80px
;
position
:
absolute
;
left
:
884px
;
top
:
-7px
;
}
.nickname
{
width
:
220px
;
height
:
52px
;
background
:
linear-gradient
(
0deg
,
#FFBF5A
0%
,
#FFE47A
100%
);
border
:
1px
solid
#FFF9DC
;
text-align
:
center
;
line-height
:
46px
;
position
:
absolute
;
left
:
850px
;
top
:
136px
;
z-index
:
1
;
border-radius
:
26px
;
font-size
:
30px
;
color
:
#4B1A14
;
}
}
.rank-no2
{
position
:
relative
;
.avatar
{
width
:
144px
;
height
:
144px
;
border-radius
:
72px
;
position
:
absolute
;
left
:
488px
;
top
:
27px
;
/* border: 1px solid red; */
}
.nickname
{
width
:
220px
;
height
:
52px
;
background
:
linear-gradient
(
0deg
,
#AEA6A7
0%
,
#EAE4DF
100%
);
border
:
1px
solid
white
;
color
:
#383636
;
text-align
:
center
;
line-height
:
52px
;
position
:
absolute
;
left
:
447px
;
top
:
160px
;
z-index
:
1
;
border-radius
:
23px
;
font-size
:
30px
;
}
}
.rank-no3
{
position
:
relative
;
.avatar
{
width
:
144px
;
height
:
144px
;
border-radius
:
72px
;
position
:
absolute
;
left
:
1297px
;
top
:
26px
;
}
.nickname
{
width
:
220px
;
height
:
52px
;
background
:
linear-gradient
(
0deg
,
#F3AE76
0%
,
#F9CDA3
100%
);
color
:
#6F3A0E
;
text-align
:
center
;
line-height
:
46px
;
position
:
absolute
;
left
:
1255px
;
top
:
160px
;
z-index
:
1
;
border-radius
:
26px
;
font-size
:
30px
;
border
:
1px
solid
#FEFEFD
;
}
}
}
.rank-container
{
display
:
flex
;
align-items
:
center
;
width
:
1570px
;
height
:
115px
;
position
:
absolute
;
bottom
:
263px
;
left
:
200px
;
>div
{
flex
:
1
;
display
:
grid
;
width
:
100px
;
height
:
100%
;
.no-icon
{
background
:
v-bind
(
'imageUrls.rankIcon'
)
no-repeat
center
;
width
:
42px
;
height
:
47px
;
position
:
absolute
;
text-align
:
center
;
line-height
:
42px
;
color
:
#CC7F36
;
font-weight
:
bold
;
top
:
50px
;
}
.img-avatar-container
{
position
:
relative
;
margin
:
0
auto
;
margin-top
:
10px
;
width
:
72px
;
height
:
72px
;
border-radius
:
36px
;
transform
:
scale
(
1.6
);
top
:
50px
;
}
.img-avatar-container
::before
{
content
:
""
;
position
:
absolute
;
inset
:
0
;
border-radius
:
inherit
;
background
:
v-bind
(
'imageUrls.avatarAnimation'
)
center
/
cover
no-repeat
;
animation
:
avatar-rotate
10s
linear
infinite
;
}
.img-avatar
{
position
:
relative
;
top
:
6px
;
z-index
:
1
;
margin
:
0
auto
;
width
:
60px
;
height
:
60px
;
border-radius
:
30px
;
background
:
v-bind
(
'imageUrls.avatar'
)
center
/
cover
no-repeat
;
}
.txt-nickname
{
color
:
#F9EBCB
;
font-size
:
22px
;
text-align
:
center
;
position
:
absolute
;
top
:
170px
;
text-align
:
center
;
/* left:10px; */
margin-left
:
68px
;
}
}
}
.btn-next
{
position
:
absolute
;
bottom
:
50px
;
left
:
620px
;
width
:
316px
;
height
:
105px
;
cursor
:
pointer
;
background
:
v-bind
(
'imageUrls.next'
)
center
/
cover
no-repeat
;
}
.btn-back
{
position
:
absolute
;
bottom
:
50px
;
left
:
1020px
;
width
:
316px
;
height
:
105px
;
cursor
:
pointer
;
background
:
v-bind
(
'imageUrls.back'
)
center
/
cover
no-repeat
;
}
</
style
>
frontend-large/src/router/index.ts
View file @
2f5cc1aa
...
@@ -4,6 +4,7 @@ import { $read } from '@/commons/utils'
...
@@ -4,6 +4,7 @@ import { $read } from '@/commons/utils'
import
Login
from
'@/pages/Login.vue'
import
Login
from
'@/pages/Login.vue'
import
Main
from
'@/pages/Main.vue'
import
Main
from
'@/pages/Main.vue'
import
Game1
from
'@/pages/game1/Game.vue'
import
Game1
from
'@/pages/game1/Game.vue'
import
Game3
from
'@/pages/game3/Game3.vue'
import
Game4
from
'@/pages/game4/Game4.vue'
import
Game4
from
'@/pages/game4/Game4.vue'
import
Game5
from
'@/pages/game5/Game5.vue'
import
Game5
from
'@/pages/game5/Game5.vue'
import
Game6
from
'@/pages/game6/Game.vue'
import
Game6
from
'@/pages/game6/Game.vue'
...
@@ -37,6 +38,14 @@ const router = createRouter({
...
@@ -37,6 +38,14 @@ const router = createRouter({
},
},
},
},
{
{
path
:
'/game3'
,
name
:
'Game3'
,
component
:
Game3
,
meta
:
{
requiresAuth
:
true
,
},
},
{
path
:
'/game4'
,
path
:
'/game4'
,
name
:
'Game4'
,
name
:
'Game4'
,
component
:
Game4
,
component
:
Game4
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment