Commit e103caf8 authored by 陈冲's avatar 陈冲

fix: 修复已上榜玩家不再显示

parent 82ea5e29
......@@ -7,7 +7,8 @@ create table tb_game
game_rank int, -- 排名
item_num int not null check (item_num between 1 and 6), -- 游戏项目(1到6)
score int not null default 0 check (score >= 0), -- 得分
create_date timestamptz -- 创建时间
create_date timestamptz, -- 创建时间
batch_no VARCHAR(50) --批次
);
SELECT * FROM tb_game
......
......@@ -7,7 +7,8 @@ CREATE TABLE tb_game
game_rank INT NOT NULL,
item_num INT NOT NULL,
score INT NOT NULL DEFAULT 0,
create_date DATETIME
create_date DATETIME,
batch_no VARCHAR(50)
);
DROP TABLE IF EXISTS tb_log;
......
......@@ -14,6 +14,7 @@ pub struct Game {
pub score: i32,
/// 创建时间
pub create_date: Option<DateTime<Utc>>,
pub batch_no: String,
}
impl Game {
......@@ -23,7 +24,7 @@ impl Game {
return true;
};
let res = crate::db::db_query(
r#"insert into tb_game(wechat_id,nickname,avatar,item_num,game_rank,score,create_date) values(?,?,?,?,?,?,now());"#,
r#"insert into tb_game(wechat_id,nickname,avatar,item_num,game_rank,score,create_date,batch_no) values(?,?,?,?,?,?,now(),?);"#,
vec![
json!(&self.wechat_id),
json!(&self.nickname),
......@@ -31,6 +32,7 @@ impl Game {
json!(&self.item_num),
json!(&self.game_rank),
json!(&self.score),
json!(&self.batch_no),
],
)
.await;
......
......@@ -95,6 +95,7 @@ struct RoomState {
players: HashMap<String, RoomPlayer>, // 玩家列表,key 是 userid
next_entry_order: usize,
current_game_id: Option<String>,
batch_no: String,
round_started_at: Option<Instant>,
}
......@@ -519,7 +520,8 @@ fn push_room_score_ranking() -> bool {
});
if player.already_top_ranked {
result["alreadyTopRanked"] = json!(true);
result["message"] = json!("一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧");
result["message"] =
json!("一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧");
}
(player.wechat, result)
})
......@@ -787,10 +789,14 @@ async fn handle_room_command(
if let Some(mut player) = CLIENT_PLAYER_MAP.get_mut(userid) {
player.0 = 1;
}
emit_msgpack(&socket, evt, &ok_resp(Some(json!({
"gameId":gameId,//当前游戏
"alreadyTopRanked": already_top_ranked,//是否上过前十榜
}))));
emit_msgpack(
&socket,
evt,
&ok_resp(Some(json!({
"gameId":gameId,//当前游戏
"alreadyTopRanked": already_top_ranked,//是否上过前十榜
}))),
);
// 给所有管理员广播房间状态更新
broadcast_msgpack_all_admin(
evt,
......@@ -820,6 +826,10 @@ async fn handle_room_command(
state.round_started_at = Some(Instant::now());
let round_id = GAME_ROUND_ID.fetch_add(1, Ordering::SeqCst) + 1;
// let snapshot = state.snapshot();
let play_len = state.players.len();
//每次开始房间时记录当前批次
let batch_no = format!("{}-{}", utils::get_current_timestamp(), play_len);
state.batch_no = batch_no.clone();
drop(state);
//通知所有玩家倒计时60秒,实际上还有3秒倒计时,以前2秒统计结果,所以是65
......@@ -827,11 +837,14 @@ async fn handle_room_command(
round_id,
GAME_START_COUNTDOWN_SECS + GAME_RUNNING_SECS + GAME_RESULT_WAIT_SECS,
);
// broadcast_msgpack_all_player(evt, &ok_resp(Some(json!({
// "index":game_index,
// ""
// }))));
broadcast_msgpack_all_player(evt, &ok_resp(Some(json!(game_index))));
//utils::get_current_timestamp()
broadcast_msgpack_all_player(
evt,
&ok_resp(Some(json!({
"index":game_index,
"batch_no":batch_no
}))),
);
//通知管理员
emit_msgpack(&socket, evt, &ok_resp(Some(json!(game_index))));
}
......@@ -881,7 +894,8 @@ async fn handle_room_command(
});
if already_top_ranked {
result["alreadyTopRanked"] = json!(true);
result["message"] = json!("一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧s");
result["message"] =
json!("一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧s");
}
emit_msgpack(&socket, evt, &ok_resp(Some(result)));
return;
......@@ -914,8 +928,10 @@ async fn handle_room_command(
if wechat.is_empty() {
return;
}
let (score, rank, ranking, already_top_ranked) =
let (score, rank, ranking, already_top_ranked, batch_no) =
if let Ok(state) = ROOM_STATE.lock() {
let batch_no = state.batch_no.clone();
//防止客户端提交的状态还在Running中
if !matches!(state.status, RoomStatus::Submit | RoomStatus::Running) {
drop(state);
......@@ -949,27 +965,16 @@ async fn handle_room_command(
.unwrap_or(rank)
};
drop(state);
(server_score, server_rank, ranking, already_top_ranked)
(
server_score,
server_rank,
ranking,
already_top_ranked,
batch_no,
)
} else {
(score, rank, Vec::new(), false)
(score, rank, Vec::new(), false, "".to_string())
};
let action = async |msg: &str| {
let log = Log {
id: 0,
msg: msg.to_string(),
params: json!({
"wechat_id": &wechat.to_string(),
"nickname": &nickname.to_string(),
"avatar": &avatar.to_string(),
"item_num": item_num as i32,
"game_rank": rank as i32,
"score": score as i32,
}),
create_date: None,
};
return log.insert().await;
};
let game = Game {
wechat_id: wechat.to_string(),
nickname: nickname.to_string(),
......@@ -978,23 +983,13 @@ async fn handle_room_command(
game_rank: rank as i32,
score: score as i32,
create_date: None,
batch_no: batch_no,
};
if game.insert().await {
if !already_top_ranked && (1..=ROOM_SCORE_RANK_LIMIT as i64).contains(&rank) {
CLIENT_TOP_RANKED_MAP.insert(userid.to_string(), true);
}
//还需要提交给后台
// match utils::post(wechat, item_num).await {
// Ok(res) => {
// if let Some(msg) = res {
// // action(&msg).await;
// }
// }
// Err(err) => {
// dbg!("err", &err);
// }
// };
let mut payload = json!({
"list": ranking,
......@@ -1002,7 +997,8 @@ async fn handle_room_command(
});
if already_top_ranked {
payload["alreadyTopRanked"] = json!(true);
payload["message"] = json!("一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧");
payload["message"] =
json!("一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧");
}
emit_msgpack(&socket, evt, &ok_resp(Some(payload)));
} else {
......
......@@ -349,7 +349,7 @@ export function $getWechat(): any | null {
return null;
}
export async function postScreenGameScore(gameCode: string, score: number) {
export async function postScreenGameScore(data:any) {
try {
const resp = await fetch('https://api.guocai365.org.cn/api/offline_clearance/user/screen_game_score', {
method: 'POST',
......@@ -358,8 +358,10 @@ export async function postScreenGameScore(gameCode: string, score: number) {
'Content-Type': 'application/json',
},
body: JSON.stringify({
game_code: gameCode,
score,
game_code: data.code,
score:data.score,
batch_no:data.batch_no,
rank_no:data.rank_no,
}),
});
......
......@@ -2,7 +2,7 @@ import { ref } from 'vue'
import { useRouter } from 'vue-router'
import type { Socket } from 'socket.io-client'
import { initSocket, onSocketMessage, sendSocketMessage } from '@/commons/ws'
import { $getWechat, $read, $toast, postScreenGameScore } from '@/commons/utils'
import { $getWechat, $read, $save, $toast, postScreenGameScore } from '@/commons/utils'
type SocketPayload = {
msg?: string
......@@ -12,7 +12,8 @@ type SocketPayload = {
type SubmittedGameScore = {
code: string
score: number
score: number,
rank_no: number,
}
type GameSocketOptions = {
......@@ -150,7 +151,8 @@ export function useGameSocket(options: GameSocketOptions) {
break
}
case 'game_start_result': {
if (data === options.gameId) {
if (data.index === options.gameId) {
$save('batch_no', data.batch_no);
options.onGameStart?.(data)
}
break
......@@ -160,13 +162,19 @@ export function useGameSocket(options: GameSocketOptions) {
break
}
case 'submit_score_save_result': {
if (!userTop10RankStatus) {
const submittedScore = options.onScoreSubmitted?.(true, data)
const token_origin = $getWechat()?.token_origin
if (token_origin && submittedScore && Number.isFinite(submittedScore.score)) {
void postScreenGameScore(submittedScore.code, submittedScore.score)
}
//if (!userTop10RankStatus) {//保证每一轮玩家数据完整性, 暂时不需要这个条件
const submittedScore = options.onScoreSubmitted?.(true, data)
const token_origin = $getWechat()?.token_origin
if (token_origin && submittedScore && Number.isFinite(submittedScore.score)) {
let batch_no = $read('batch_no')
void postScreenGameScore({
code: submittedScore.code,
score: submittedScore.score,
batch_no: batch_no,
rank_no: submittedScore.rank_no,
})
}
//}
break
}
case 'room_back_result': {
......
......@@ -2,7 +2,7 @@
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { cssAssetUrl } from '@/commons/assets.ts'
import MobileStage from '@/components/MobileStage.vue'
import { useGameSocket, sendGameMessage, userJoinStatus,userTop10RankStatus, joinSharedRoom } from '@/composables/useGameSocket'
import { useGameSocket, sendGameMessage, userJoinStatus, userTop10RankStatus, joinSharedRoom } from '@/composables/useGameSocket'
import LoadingView from './views/LoadingView.vue'
import PlayingView from './views/PlayingView.vue'
import ScoreView from './views/ScoreView.vue'
......@@ -143,11 +143,11 @@ function showScoreView() {
showGameRule.value = false;
stopGameCountdown()
setDivDescVisible(false)
if(userTop10RankStatus.value){
if (userTop10RankStatus.value) {
currentView.value = 'loading'
userJoinStatus.value = false;
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧',30000)
}else{
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧', 30000)
} else {
currentView.value = 'score'
}
}
......@@ -218,7 +218,7 @@ if (wechat) {
syncGameCountdown(remainingSeconds)
}
}
return { code: 'JGQF', score: tick.value }
return { code: 'JGQF', score: tick.value, rank_no: rank.value }
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
......@@ -295,8 +295,8 @@ const showGameRuleHandler = () => {
<LoadingView v-if="currentView === 'loading'" :image-urls="imageUrls" :user-join-status="userJoinStatus"
@touchGameRule="showGameRuleHandler" />
<PlayingView v-else-if="currentView === 'playing'" :image-urls="imageUrls" :tick="tick" :rank="rank"
:current-gu-frame="currentGuFrame" :countdown-interval="countdownInterval" :is-div-desc-visible="isDivDescVisible"
@touch="touchHandler" :userTop10RankStatus="userTop10RankStatus" />
:current-gu-frame="currentGuFrame" :countdown-interval="countdownInterval"
:is-div-desc-visible="isDivDescVisible" @touch="touchHandler" :userTop10RankStatus="userTop10RankStatus" />
<ScoreView v-else :image-urls="imageUrls" :rank="rank" :tick="tick" />
</MobileStage>
<div v-else style="text-align: center; width: 100vw; height: 100vh; line-height: 30; font-size: 20px;">
......@@ -333,7 +333,7 @@ const showGameRuleHandler = () => {
width: 57px;
height: 57px;
background: v-bind('imageUrls.close') center / cover no-repeat;
transform: translateX(-50%) scale(1.5);
transform: translateX(-50%) scale(1.5);
position: absolute;
top: -73px;
left: 100%;
......
......@@ -116,14 +116,15 @@ function startGameCountdown(seconds = 60) {
if (countdownInterval.value <= 0) {
countdownInterval.value = 0
gameCountdownTimer = undefined
currentView.value === 'loading'
currentView.value = 'loading'
setDivDescVisible(false)
submitScore(true)
if (userTop10RankStatus.value) {
userJoinStatus.value = false;
showGameRank.value = false;
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧', 30000)
//这里还要再发
} else {
setDivDescVisible(false)
submitScore(true)
showGameOverRank()
}
return
......@@ -242,7 +243,7 @@ if (wechat) {
rank.value = nextRank
}
}
return { code: 'JBJF', score: score.value }
return { code: 'JBJF', score: score.value, rank_no: rank.value }
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
......
......@@ -134,14 +134,14 @@ function startGameCountdown(seconds = 60) {
if (countdownInterval.value <= 0) {
countdownInterval.value = 0
gameCountdownTimer = undefined
currentView.value === 'loading'
currentView.value = 'loading'
setDivDescVisible(false)
submitScore(true)
if (userTop10RankStatus.value) {
userJoinStatus.value = false;
showGameRank.value = false;
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧', 30000)
} else {
setDivDescVisible(false)
submitScore(true)
showGameOverRank()
}
return
......@@ -251,7 +251,7 @@ if (wechat) {
rank.value = nextRank
}
}
return { code: 'MSYF', score: score.value }
return { code: 'MSYF', score: score.value , rank_no: rank.value}
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
......@@ -383,7 +383,7 @@ const rankCloseHandler = () => {
<LoadingView v-if="currentView === 'loading'" :image-urls="imageUrls" :user-join-status="userJoinStatus"
@touchGameRule="showGameRuleHandler" />
<PlayingView v-else :image-urls="imageUrls" :tick="score" :rank="rank" :countdown-interval="countdownInterval"
:is-div-desc-visible="isDivDescVisible" @touch="touchHandler" @score-change="scoreChangeHandler" />
:is-div-desc-visible="isDivDescVisible" @touch="touchHandler" @score-change="scoreChangeHandler" :userTop10RankStatus="userTop10RankStatus" />
</MobileStage>
<div v-else style="text-align: center; width: 100vw; height: 100vh; line-height: 30; font-size: 20px;">
请使用微信扫码进入游戏
......
......@@ -16,6 +16,7 @@ const props = defineProps<{
isDivDescVisible: boolean;
tick: number;
rank: number;
userTop10RankStatus:boolean
}>();
const emit = defineEmits<{
......
......@@ -112,13 +112,14 @@ function startGameCountdown(seconds = 60) {
if (countdownInterval.value <= 0) {
countdownInterval.value = 0;
gameCountdownTimer = undefined;
setDivDescVisible(false);
submitScore(true);
if (userTop10RankStatus.value) {
userJoinStatus.value = false;
// showGameRank.value = false;
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧', 30000)
} else {
setDivDescVisible(false);
submitScore(true);
showScoreView();
}
return;
......@@ -233,7 +234,7 @@ if (wechat) {
if (Number.isFinite(nextRank) && nextRank > 0) {
rank.value = nextRank;
}
return { code: "CMYF", score: tick.value };
return { code: "CMYF", score: tick.value, rank_no: rank.value };
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
......@@ -287,7 +288,8 @@ onBeforeUnmount(() => {
<!-- <PlayingView v-else :image-urls="imageUrls" :tick="tick" :rank="rank" -->
<PlayingView v-else-if="currentView === 'playing'" :image-urls="imageUrls" :tick="tick" :rank="rank"
:currentHorse="currentHorse" :currentYaoyiyao="currentYaoyiyao" :countdown-interval="countdownInterval"
:is-div-desc-visible="isDivDescVisible" @touch="touchHandler" />
:is-div-desc-visible="isDivDescVisible" @touch="touchHandler"
:userTop10RankStatus="userTop10RankStatus" />
<ScoreView v-else :image-urls="imageUrls" :tick="tick" :level="rank" @replay="replayGame" @back="backToWaiting" />
</MobileStage>
<div v-else style="
......
......@@ -11,7 +11,8 @@ const props = defineProps<{
tick: number
rank: number
currentHorse: string
currentYaoyiyao: string
currentYaoyiyao: string,
userTop10RankStatus: boolean
}>()
const emit = defineEmits<{
......@@ -201,7 +202,7 @@ const onTapHorse = async () => {
<div class="play-content">
<div>当前得分</div>
<div>{{ tick }}</div>
<div>当前排名: &nbsp;&nbsp;<label>{{ rank }}</label>&nbsp;</div>
<div v-if="!userTop10RankStatus">当前排名: &nbsp;&nbsp;<label>{{ rank }}</label>&nbsp;</div>
</div>
<!-- iOS 权限提示蒙层 -->
<Transition name="ios-hint-fade">
......
......@@ -137,7 +137,7 @@ function submitScore(save: boolean = false) {
const data = {
score: tick.value,
wechat: wechat.token,
item_num: 1,
item_num: 5,
nickname: wechat.nickname,
avatar: wechat.avatar,
rank: rank.value,
......@@ -162,13 +162,13 @@ function startGameCountdown(seconds = 60) {
if (countdownInterval.value <= 0) {
countdownInterval.value = 0
gameCountdownTimer = undefined
setDivDescVisible(false)
submitScore(true)
if (userTop10RankStatus.value) {
userJoinStatus.value = false;
// showGameRank.value = false;
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧', 30000)
} else {
setDivDescVisible(false)
submitScore(true)
} else {
showGameOverRank()
}
return
......@@ -301,7 +301,7 @@ if (wechat) {
rank.value = nextRank
}
}
return { code: 'QCNF', score: tick.value }
return { code: 'QCNF', score: tick.value, rank_no: rank.value }
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
......
......@@ -124,13 +124,13 @@ function startGameCountdown(seconds = 60) {
countdownInterval.value = 0
gameCountdownTimer = undefined
currentView.value = 'loading'
setDivDescVisible(false)
submitScore(true)
if (userTop10RankStatus.value) {
userJoinStatus.value = false;
showGameRank.value = false;
$toast('一人只能上榜领奖一次,您的福利已到手,把机会留给其他玩家吧', 30000)
} else {
setDivDescVisible(false)
submitScore(true)
showGameOverRank()
}
return
......@@ -249,7 +249,7 @@ if (wechat) {
rank.value = nextRank
}
}
return { code: 'FYDT', score: score.value }
return { code: 'FYDT', score: score.value, rank_no: rank.value }
},
onRescoreSubmitted: (_recount) => {
submitScore(true);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment