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
7405af15
Commit
7405af15
authored
Jun 12, 2026
by
陈冲
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'main' of
http://git.ruanyiit.com/chenchong/fc-minigame
parents
28863a1a
82fe3ea6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
155 additions
and
63 deletions
+155
-63
MobileStage.vue
frontend-h5/src/components/MobileStage.vue
+7
-3
Game3.vue
frontend-h5/src/pages/game3/Game3.vue
+0
-0
PlayingView.vue
frontend-h5/src/pages/game3/views/PlayingView.vue
+46
-14
Game3.vue
frontend-large/src/pages/game3/Game3.vue
+102
-46
Rank1View.vue
frontend-large/src/pages/game3/views/Rank1View.vue
+0
-0
No files found.
frontend-h5/src/components/MobileStage.vue
View file @
7405af15
...
@@ -193,14 +193,18 @@ defineExpose({
...
@@ -193,14 +193,18 @@ defineExpose({
}
}
.modal-container
{
.modal-container
{
position
:
absolute
;
/* position:fixed + 显式 100vw/100vh 确保在 iOS Safari 中全屏蒙层,
inset
:
0
;
避免因父级 overflow:hidden / transform:scale 导致 inset:0 计算异常 */
position
:
fixed
;
top
:
0
;
left
:
0
;
width
:
100vw
;
height
:
100vh
;
z-index
:
10
;
z-index
:
10
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
center
;
justify-content
:
center
;
background-color
:
rgba
(
0
,
0
,
0
,
0.6
);
background-color
:
rgba
(
0
,
0
,
0
,
0.6
);
/* pointer-events: none; */
}
}
.game-rule-fade-enter-active
,
.game-rule-fade-enter-active
,
...
...
frontend-h5/src/pages/game3/Game3.vue
View file @
7405af15
This diff is collapsed.
Click to expand it.
frontend-h5/src/pages/game3/views/PlayingView.vue
View file @
7405af15
...
@@ -26,8 +26,26 @@ const HORSE_BOTTOM_PCT = 19.11;
...
@@ -26,8 +26,26 @@ const HORSE_BOTTOM_PCT = 19.11;
const
ITEM_SIZE
=
80
;
const
ITEM_SIZE
=
80
;
const
GAME_DURATION
=
60
;
const
GAME_DURATION
=
60
;
const
LEFT_LANE_X
=
170
;
// 设计基准跑道 X 位置(750px 设计稿下的值,窄屏设备上会自动居中偏移)
const
RIGHT_LANE_X
=
470
;
const
DESIGN_LEFT_LANE_X
=
150
;
const
DESIGN_RIGHT_LANE_X
=
500
;
// 运行时根据视口计算的真实 X 位置(适配不同屏幕宽度)
const
leftLaneX
=
ref
(
DESIGN_LEFT_LANE_X
);
const
rightLaneX
=
ref
(
DESIGN_RIGHT_LANE_X
);
/** 按视口宽度计算 750px 设计区域在 content-bg 中的居中偏移 */
const
updateLanePositions
=
()
=>
{
const
vw
=
window
.
visualViewport
?.
width
??
window
.
innerWidth
;
const
vh
=
window
.
visualViewport
?.
height
??
window
.
innerHeight
;
// MobileStage contain 模式下 scale = min(scaleX, scaleY),手机通常由高度决定
const
scaleY
=
vh
/
1624
;
if
(
!
scaleY
||
scaleY
<=
0
)
return
;
const
stageViewportWidth
=
vw
/
scaleY
;
const
offset
=
Math
.
max
(
0
,
(
stageViewportWidth
-
750
)
/
2
);
leftLaneX
.
value
=
DESIGN_LEFT_LANE_X
+
offset
;
rightLaneX
.
value
=
DESIGN_RIGHT_LANE_X
+
offset
;
};
// ========== 马帧 ==========
// ========== 马帧 ==========
const
HORSE_FRAME_COUNT
=
21
;
const
HORSE_FRAME_COUNT
=
21
;
...
@@ -63,20 +81,20 @@ preloadFrames(bomFrames);
...
@@ -63,20 +81,20 @@ preloadFrames(bomFrames);
const
horseLane
=
ref
<
'left'
|
'right'
>
(
'left'
);
const
horseLane
=
ref
<
'left'
|
'right'
>
(
'left'
);
const
horseFrameIndex
=
ref
(
0
);
const
horseFrameIndex
=
ref
(
0
);
const
horseX
=
ref
(
LEFT_LANE_X
);
const
horseX
=
ref
(
leftLaneX
.
value
);
const
horseTargetX
=
ref
(
LEFT_LANE_X
);
const
horseTargetX
=
ref
(
leftLaneX
.
value
);
const
switchToLeft
=
()
=>
{
const
switchToLeft
=
()
=>
{
if
(
horseLane
.
value
!==
'left'
)
{
if
(
horseLane
.
value
!==
'left'
)
{
horseLane
.
value
=
'left'
;
horseLane
.
value
=
'left'
;
horseTargetX
.
value
=
LEFT_LANE_X
;
horseTargetX
.
value
=
leftLaneX
.
value
;
}
}
};
};
const
switchToRight
=
()
=>
{
const
switchToRight
=
()
=>
{
if
(
horseLane
.
value
!==
'right'
)
{
if
(
horseLane
.
value
!==
'right'
)
{
horseLane
.
value
=
'right'
;
horseLane
.
value
=
'right'
;
horseTargetX
.
value
=
RIGHT_LANE_X
;
horseTargetX
.
value
=
rightLaneX
.
value
;
}
}
};
};
...
@@ -183,7 +201,7 @@ function generateNewItem() {
...
@@ -183,7 +201,7 @@ function generateNewItem() {
if
(
!
props
.
isDivDescVisible
)
return
;
if
(
!
props
.
isDivDescVisible
)
return
;
const
seed
=
Date
.
now
()
+
itemIdCounter
;
const
seed
=
Date
.
now
()
+
itemIdCounter
;
const
kind
:
ItemKind
=
seededRandom
(
seed
)
<
0.
5
5
?
'coin'
:
'bomb'
;
const
kind
:
ItemKind
=
seededRandom
(
seed
)
<
0.
7
5
?
'coin'
:
'bomb'
;
// 概率分配车道,但避免与前一个同车道道具太近
// 概率分配车道,但避免与前一个同车道道具太近
let
lane
:
'left'
|
'right'
=
seededRandom
(
seed
+
1000
)
<
0.5
?
'left'
:
'right'
;
let
lane
:
'left'
|
'right'
=
seededRandom
(
seed
+
1000
)
<
0.5
?
'left'
:
'right'
;
...
@@ -244,7 +262,7 @@ const checkCollisions = () => {
...
@@ -244,7 +262,7 @@ const checkCollisions = () => {
for
(
const
item
of
roadItems
.
value
)
{
for
(
const
item
of
roadItems
.
value
)
{
if
(
item
.
collected
||
item
.
colliding
)
continue
;
if
(
item
.
collected
||
item
.
colliding
)
continue
;
const
itemX
=
item
.
lane
===
'left'
?
LEFT_LANE_X
:
RIGHT_LANE_X
;
const
itemX
=
item
.
lane
===
'left'
?
leftLaneX
.
value
:
rightLaneX
.
value
;
// item.y 已经是屏幕坐标(content-bg 内),无需加 roadOffset
// item.y 已经是屏幕坐标(content-bg 内),无需加 roadOffset
const
itemCenterX
=
itemX
+
ITEM_SIZE
/
2
;
const
itemCenterX
=
itemX
+
ITEM_SIZE
/
2
;
const
itemCenterY
=
item
.
y
+
ITEM_SIZE
/
2
;
const
itemCenterY
=
item
.
y
+
ITEM_SIZE
/
2
;
...
@@ -278,7 +296,7 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
...
@@ -278,7 +296,7 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
const
frameDuration
=
1000
/
totalFrames
;
const
frameDuration
=
1000
/
totalFrames
;
// 碰撞动画(大幅放大尺寸,x 往右偏移让动画居中于视觉碰撞点)
// 碰撞动画(大幅放大尺寸,x 往右偏移让动画居中于视觉碰撞点)
effectAnims
.
value
.
push
({
id
:
animId
,
kind
:
item
.
kind
,
frame
:
0
,
x
:
x
+
40
,
y
});
effectAnims
.
value
.
push
({
id
:
animId
,
kind
:
item
.
kind
,
frame
:
0
,
x
:
x
+
65
,
y
});
let
frameIdx
=
0
;
let
frameIdx
=
0
;
const
tick
=
()
=>
{
const
tick
=
()
=>
{
...
@@ -297,7 +315,7 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
...
@@ -297,7 +315,7 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
const
effectId
=
++
scoreEffectIdSeq
;
const
effectId
=
++
scoreEffectIdSeq
;
scoreEffects
.
value
.
push
({
scoreEffects
.
value
.
push
({
id
:
effectId
,
id
:
effectId
,
x
:
x
+
ITEM_SIZE
/
2
,
x
:
x
+
ITEM_SIZE
/
2
+
25
,
y
:
y
,
y
:
y
,
score
:
delta
,
score
:
delta
,
});
});
...
@@ -377,6 +395,12 @@ const stopMainLoop = () => {
...
@@ -377,6 +395,12 @@ const stopMainLoop = () => {
// ========== 生命周期 ==========
// ========== 生命周期 ==========
onMounted
(()
=>
{
onMounted
(()
=>
{
window
.
addEventListener
(
'keydown'
,
handleKeydown
);
window
.
addEventListener
(
'keydown'
,
handleKeydown
);
window
.
addEventListener
(
'resize'
,
updateLanePositions
);
window
.
visualViewport
?.
addEventListener
(
'resize'
,
updateLanePositions
);
updateLanePositions
();
// 初始化马匹在左侧跑道(使用计算后的实际 X 位置)
horseX
.
value
=
leftLaneX
.
value
;
horseTargetX
.
value
=
leftLaneX
.
value
;
nextTick
(()
=>
{
nextTick
(()
=>
{
startRoadScroll
();
startRoadScroll
();
startMainLoop
();
startMainLoop
();
...
@@ -386,6 +410,8 @@ onMounted(() => {
...
@@ -386,6 +410,8 @@ onMounted(() => {
onBeforeUnmount
(()
=>
{
onBeforeUnmount
(()
=>
{
window
.
removeEventListener
(
'keydown'
,
handleKeydown
);
window
.
removeEventListener
(
'keydown'
,
handleKeydown
);
window
.
removeEventListener
(
'resize'
,
updateLanePositions
);
window
.
visualViewport
?.
removeEventListener
(
'resize'
,
updateLanePositions
);
stopRoadScroll
();
stopRoadScroll
();
stopMainLoop
();
stopMainLoop
();
stopItemGen
();
stopItemGen
();
...
@@ -405,6 +431,9 @@ watch(() => props.isDivDescVisible, (visible) => {
...
@@ -405,6 +431,9 @@ watch(() => props.isDivDescVisible, (visible) => {
scoreEffects
.
value
=
[];
scoreEffects
.
value
=
[];
roadOffset
.
value
=
0
;
roadOffset
.
value
=
0
;
gameElapsed
.
value
=
0
;
gameElapsed
.
value
=
0
;
updateLanePositions
();
horseX
.
value
=
leftLaneX
.
value
;
horseTargetX
.
value
=
leftLaneX
.
value
;
startRoadScroll
();
startRoadScroll
();
startMainLoop
();
startMainLoop
();
scheduleNextItem
();
scheduleNextItem
();
...
@@ -582,18 +611,21 @@ watch(() => props.isDivDescVisible, (visible) => {
...
@@ -582,18 +611,21 @@ watch(() => props.isDivDescVisible, (visible) => {
.road-item
{
.road-item
{
position
:
absolute
;
position
:
absolute
;
width
:
80px
;
/* width: 80px;
height
:
80px
;
height: 80px; */
width
:
77px
;
height
:
96px
;
z-index
:
5
;
z-index
:
5
;
pointer-events
:
none
;
pointer-events
:
none
;
}
}
.item-lane-left
{
.item-lane-left
{
left
:
170px
;
/* 当 content-bg 宽于 750px 设计稿时,自动居中 750px 游戏区域 */
left
:
calc
((
var
(
--stage-viewport-width
,
750px
)
-
750px
)
/
2
+
170px
);
}
}
.item-lane-right
{
.item-lane-right
{
left
:
470px
;
left
:
calc
((
var
(
--stage-viewport-width
,
750px
)
-
750px
)
/
2
+
520px
)
;
}
}
.effect-anim
{
.effect-anim
{
...
...
frontend-large/src/pages/game3/Game3.vue
View file @
7405af15
...
@@ -55,36 +55,48 @@ const renderPlayers = (data: any) => {
...
@@ -55,36 +55,48 @@ const renderPlayers = (data: any) => {
}
}
const
updateRankPlayers
=
(
data
:
any
)
=>
{
const
updateRankPlayers
=
(
data
:
any
)
=>
{
if
(
!
Array
.
isArray
(
data
))
return
// 兼容多种数据格式:纯数组 / {list:[]} / {players:[]} / {data:[]}
let
arr
:
any
[]
|
null
=
null
;
if
(
Array
.
isArray
(
data
))
{
arr
=
data
;
}
else
if
(
Array
.
isArray
(
data
?.
list
))
{
arr
=
data
.
list
;
}
else
if
(
Array
.
isArray
(
data
?.
players
))
{
arr
=
data
.
players
;
}
else
if
(
Array
.
isArray
(
data
?.
data
))
{
arr
=
data
.
data
;
}
rankPlayers
.
value
=
Array
.
from
(
if
(
!
arr
||
arr
.
length
===
0
)
{
{
length
:
RANK_LIMIT
},
console
.
warn
(
'[game3] updateRankPlayers: 无法解析排行数据'
,
data
);
(
_
,
index
)
=>
data
[
index
]
??
emptyRankPlayer
(
index
),
return
;
)
}
}
const
playerToRankPlayer
=
(
player
:
any
,
index
:
number
):
Player
=>
({
// 打印第一条原始数据的所有字段名,用于排查字段不匹配问题
telephone
:
player
?.
telephone
??
''
,
console
.
log
(
'[game3] updateRankPlayers: 收到排行数据'
,
arr
.
length
,
'条, 第1条字段:'
,
Object
.
keys
(
arr
[
0
]
||
{}),
', 第1条值:'
,
JSON
.
parse
(
JSON
.
stringify
(
arr
[
0
])));
userid
:
player
?.
userid
??
''
,
wechat_id
:
player
?.
wechat_id
||
`empty-
${
index
}
`
,
// 将 WS 数据标准化为 Player 格式(同时保留 userid / wechat_id)
nickname
:
player
?.
nickname
||
'虚位以待'
,
// ⚠️ 当 WS 返回的数据没有 userid/openid/wechat_id 等ID字段时,用 avatar 作为唯一标识
avatar
:
player
?.
avatar
||
''
,
const
normalized
=
arr
.
map
((
item
:
any
,
i
:
number
)
=>
{
score
:
player
?.
score
??
'-'
,
const
hasId
=
item
.
userid
||
item
.
openid
||
item
.
user_id
||
item
.
wechat_id
;
})
const
avatar
=
item
.
avatar
||
item
.
headimgurl
||
''
;
const
nickname
=
item
.
nickname
||
item
.
name
||
'虚位以待'
;
const
isRealPlayer
=
nickname
&&
nickname
!==
'-'
&&
nickname
!==
'虚位以待'
;
const
wechat_id
=
hasId
||
(
isRealPlayer
&&
avatar
?
`avt:
${
avatar
}
`
:
`empty-
${
i
}
`
);
return
{
...
item
,
userid
:
hasId
||
(
isRealPlayer
&&
avatar
?
`avt:
${
avatar
}
`
:
''
),
wechat_id
,
nickname
,
avatar
,
score
:
item
.
score
??
0
,
};
});
const
seedRankPlayersFromLoading
=
()
=>
{
rankPlayers
.
value
=
Array
.
from
(
rankPlayers
.
value
=
Array
.
from
(
{
length
:
RANK_LIMIT
},
{
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
{
(
_
,
index
)
=>
normalized
[
index
]
??
emptyRankPlayer
(
index
),
const
player
=
loadingPlayers
.
value
[
index
]
);
if
(
!
player
?.
userid
&&
!
player
?.
wechat_id
)
{
return
emptyRankPlayer
(
index
)
}
return
playerToRankPlayer
(
player
,
index
)
},
)
}
}
const
resetRoundState
=
()
=>
{
const
resetRoundState
=
()
=>
{
...
@@ -107,7 +119,7 @@ const gotoRank1WithIntro = async () => {
...
@@ -107,7 +119,7 @@ const gotoRank1WithIntro = async () => {
if
(
isPlayingStartAnimation
)
return
if
(
isPlayingStartAnimation
)
return
isPlayingStartAnimation
=
true
isPlayingStartAnimation
=
true
seedRankPlayersFromLoading
()
// ⚠️ 不要用 seedRankPlayersFromLoading,由 WS room_rank_result 驱动马匹数据
screen
.
value
=
'rank1'
screen
.
value
=
'rank1'
await
nextTick
()
await
nextTick
()
await
rank1Ref
.
value
?.
startIntro
()
await
rank1Ref
.
value
?.
startIntro
()
...
@@ -129,8 +141,16 @@ function handleRoomState(data: any) {
...
@@ -129,8 +141,16 @@ function handleRoomState(data: any) {
gotoLoading
()
gotoLoading
()
break
break
case
2
:
case
2
:
seedRankPlayersFromLoading
()
// 重连/中途进房时游戏已在运行,直接进入赛马画面
if
(
isPlayingStartAnimation
)
break
;
isPlayingStartAnimation
=
true
;
screen
.
value
=
'rank1'
screen
.
value
=
'rank1'
console
.
log
(
'[game3] handleRoomState: status=2, 直接启动赛马动画'
);
nextTick
(()
=>
{
rank1Ref
.
value
?.
startIntro
().
finally
(()
=>
{
isPlayingStartAnimation
=
false
;
});
});
break
break
case
3
:
case
3
:
screen
.
value
=
'rank2'
screen
.
value
=
'rank2'
...
@@ -143,24 +163,58 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
...
@@ -143,24 +163,58 @@ const { startGame, createRoom, backRoom, closeRoom } = useAdminGameSocket({
onAny
:
(
evt
,
payload
)
=>
{
onAny
:
(
evt
,
payload
)
=>
{
// 兜底处理所有非标准事件,解析玩家实时分数(对齐 game4)
// 兜底处理所有非标准事件,解析玩家实时分数(对齐 game4)
const
data
=
payload
?.
data
??
payload
;
const
data
=
payload
?.
data
??
payload
;
if
(
!
Array
.
isArray
(
data
))
return
;
// 尝试从 data 中提取数组
const
boosts
:
Record
<
string
,
number
>
=
{};
let
arr
:
any
[]
|
null
=
null
;
let
hasBoost
=
false
;
if
(
Array
.
isArray
(
data
))
{
arr
=
data
;
data
.
forEach
((
item
:
any
)
=>
{
}
else
if
(
Array
.
isArray
(
data
?.
list
))
{
const
id
=
item
.
userid
||
item
.
wechat_id
||
item
.
avatar
||
""
;
arr
=
data
.
list
;
if
(
!
id
)
return
;
}
else
if
(
Array
.
isArray
(
data
?.
data
))
{
const
raw
=
item
.
score
??
item
.
boost
??
item
.
acceleration
??
item
.
speed
??
item
.
progress
;
arr
=
data
.
data
;
if
(
raw
===
undefined
||
raw
===
null
)
return
;
}
const
val
=
Number
(
raw
);
if
(
isNaN
(
val
))
return
;
if
(
arr
&&
arr
.
length
>
0
)
{
boosts
[
id
]
=
Math
.
max
(
0
,
val
);
const
boosts
:
Record
<
string
,
number
>
=
{};
hasBoost
=
true
;
const
normalized
=
arr
.
map
((
item
:
any
,
i
:
number
)
=>
{
});
const
hasId
=
item
.
userid
||
item
.
openid
||
item
.
user_id
||
item
.
wechat_id
;
const
avatar
=
item
.
avatar
||
item
.
headimgurl
||
''
;
if
(
hasBoost
)
{
const
nickname
=
item
.
nickname
||
item
.
name
||
'虚位以待'
;
horseBoosts
.
value
=
{
...
boosts
};
const
isRealPlayer
=
nickname
&&
nickname
!==
'-'
&&
nickname
!==
'虚位以待'
;
const
wechat_id
=
hasId
||
(
isRealPlayer
&&
avatar
?
`avt:
${
avatar
}
`
:
`empty-
${
i
}
`
);
return
{
...
item
,
userid
:
hasId
||
(
isRealPlayer
&&
avatar
?
`avt:
${
avatar
}
`
:
''
),
wechat_id
,
};
});
const
hasAnyPlayer
=
normalized
.
some
((
item
:
any
)
=>
{
const
id
=
item
.
userid
||
item
.
wechat_id
||
''
;
return
!!
id
&&
!
id
.
startsWith
(
'empty-'
);
});
if
(
hasAnyPlayer
)
{
// 同时更新 rankPlayers(确保马匹列表有真实玩家)
rankPlayers
.
value
=
Array
.
from
(
{
length
:
RANK_LIMIT
},
(
_
,
index
)
=>
normalized
[
index
]
??
emptyRankPlayer
(
index
),
);
}
normalized
.
forEach
((
item
:
any
)
=>
{
const
id
=
item
.
userid
||
item
.
wechat_id
||
''
;
if
(
!
id
||
id
.
startsWith
(
'empty-'
))
return
;
const
raw
=
item
.
score
??
item
.
boost
??
item
.
acceleration
??
item
.
speed
??
item
.
progress
;
if
(
raw
===
undefined
||
raw
===
null
)
return
;
const
val
=
Number
(
raw
);
if
(
isNaN
(
val
))
return
;
boosts
[
id
]
=
Math
.
max
(
0
,
val
);
});
if
(
Object
.
keys
(
boosts
).
length
>
0
)
{
horseBoosts
.
value
=
{
...
horseBoosts
.
value
,
...
boosts
};
}
}
}
},
},
onRoomState
:
handleRoomState
,
onRoomState
:
handleRoomState
,
...
@@ -232,5 +286,7 @@ watch(screen, (value) => {
...
@@ -232,5 +286,7 @@ watch(screen, (value) => {
<
template
>
<
template
>
<Loading
v-if=
"screen === 'loading'"
:players=
"loadingPlayers"
:player-count=
"playerCount"
<Loading
v-if=
"screen === 'loading'"
:players=
"loadingPlayers"
:player-count=
"playerCount"
@
start=
"startGameWithMusic"
@
back=
"backHandler"
/>
@
start=
"startGameWithMusic"
@
back=
"backHandler"
/>
<Rank1
v-else
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
:horse-boosts=
"horseBoosts"
@
start=
"startGameWithMusic"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<Rank1
v-if=
"screen === 'rank1'"
ref=
"rank1Ref"
:rank-list=
"rankPlayers"
:horse-boosts=
"horseBoosts"
@
start=
"startGameWithMusic"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
<Rank2
v-if=
"screen === 'rank2'"
:rank-list=
"rankPlayers"
@
next=
"nextRoundWithMusic"
@
back=
"backHandler"
/>
</
template
>
</
template
>
frontend-large/src/pages/game3/views/Rank1View.vue
View file @
7405af15
This diff is collapsed.
Click to expand it.
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