feat: 添加五子棋退出拦截器

This commit is contained in:
Litrix2 2024-12-21 12:06:42 +08:00
parent c0df620cea
commit 0d1a86661a
4 changed files with 78 additions and 41 deletions

View File

@ -160,8 +160,7 @@ provide(registerImplKey, async (params) => {
});
async function logout() {
showVerticalHeaderMenu.value = false;
if (!(await userStore.logout())) return;
await userStore.updateSelfUserInfo(true);
await userStore.logout();
}
const showVerticalHeaderMenu = ref(false);
watch(mdLess, (v) => {

View File

@ -507,7 +507,7 @@ function mergeLine(line: SingleTileLine): [lineMergeREsult: LineMergeResult, cha
/**
* 合并所有块.
* @param direction 合并方向
* @return {} 是否有活动空间
* @return 是否有活动空间
*/
async function mergeTiles(direction: Directions) {
function getMergedGrid(

View File

@ -24,8 +24,11 @@ export const useUserStore = defineStore('user', () => {
const logined = computed(() => (userInfo.value && userInfo.value.id !== -1) ?? false);
watch(
userInfo,
() => {
router.push({ path: router.currentRoute.value.fullPath, force: true });
(info) => {
router.push({
path: info && info.id !== -1 ? router.currentRoute.value.fullPath : '/',
force: true,
});
},
{ flush: 'sync' },
);
@ -66,6 +69,7 @@ export const useUserStore = defineStore('user', () => {
const res = await Promise.all(Array.from(logoutInterceptors).map((fn) => fn()));
if (!res.every((r) => r === undefined || r)) return false;
token.value = null;
await updateSelfUserInfo(true);
return true;
}
return {
@ -82,7 +86,7 @@ export const useUserStore = defineStore('user', () => {
logout,
};
});
export type LogoutInterceptor = () => MaybePromise<boolean | undefined>;
export type LogoutInterceptor = () => MaybePromise<boolean | void>;
export function useLogoutInterceptor(fn: LogoutInterceptor) {
const userStore = useUserStore();
userStore.addLogoutInterceptor(fn);

View File

@ -80,9 +80,11 @@
class="gobang-play-page-aside !flex flex-col items-center justify-between"
>
<div class="flex flex-col items-center gap-5px">
<gobang-user v-if="otherUser" :user="otherUser" />
<gobang-side :white="!white" />
<div class="font-bold">{{ otherPrompt }}</div>
<template v-if="otherUser">
<gobang-user :user="otherUser" />
<gobang-side :white="!white" />
<div class="font-bold">{{ otherPrompt }}</div>
</template>
</div>
<div>
<div
@ -171,42 +173,39 @@
}
}
}
::v-deep .gobang-chessboard__cell {
:deep(.gobang-chessboard__cell) {
@apply border border-black rounded-full;
--size: 24px;
width: var(--size);
height: var(--size);
user-select: none;
&--white {
@apply bg-white border-inset;
}
&--black {
@apply bg-black;
}
&--last {
&::after {
@apply absolute inset--1;
content: '';
border: 2px solid red;
animation: blink 1s ease-in-out infinite;
@keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
}
:deep(.gobang-chessboard__cell--white) {
@apply bg-white border-inset;
}
:deep(.gobang-chessboard__cell--black) {
@apply bg-black;
}
:deep(.gobang-chessboard__cell--last::after) {
@apply absolute inset--1;
content: '';
border: 2px solid red;
animation: blink 1s ease-in-out infinite;
@keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
&--win-blink {
// box-shadow: 0 0 10px red;
//
z-index: 2001;
}
}
:deep(.gobang-chessboard__cell--win-blink) {
//
z-index: 2001;
}
</style>
<script lang="ts">
@ -236,15 +235,49 @@ import GobangSide from '@/components/gobang/GobangSide.vue';
import GobangUser from '@/components/gobang/GobangUser.vue';
import router from '@/router';
import { useMediaStore } from '@/stores/media';
import { useUserStore } from '@/stores/user';
import { useLogoutInterceptor, useUserStore } from '@/stores/user';
import { create2DArray, iter2DArray, zip } from '@/utils/array';
import { useGobangSocket, WinFace, type RoomDetail, type RoomId } from '@/views/GobangListPage.vue';
import { ElMessage, ElNotification } from 'element-plus';
import { ElMessage, ElMessageBox, ElNotification, type Action } from 'element-plus';
import { storeToRefs } from 'pinia';
import { computed, onMounted, ref, watch, watchEffect, type CSSProperties } from 'vue';
import { useRoute } from 'vue-router';
import { onBeforeRouteLeave, useRoute } from 'vue-router';
const userStore = useUserStore();
const { smLess, mdLess } = storeToRefs(useMediaStore());
let canExit = false;
useLogoutInterceptor(() => {
if (canExit || matchState.value !== MatchState.GAMING) return true;
ElMessageBox.confirm('你正在游戏中, 是否退出登录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then((action: Action) => {
if (action !== 'confirm') return;
canExit = true;
return userStore.logout();
})
.catch(() => {});
return false;
});
onBeforeRouteLeave((to, _, next) => {
if (canExit || matchState.value !== MatchState.GAMING) {
next(true);
return;
}
ElMessageBox.confirm('你正在游戏中, 是否退出房间?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then((action: Action) => {
if (action !== 'confirm') return;
canExit = true;
router.push(to);
})
.catch(() => {});
next(false);
});
const roomId = useRoute().params.id as RoomId | undefined;
const canvas = ref<HTMLCanvasElement>();
const mainMarginTopCSS = computed(() =>
@ -365,6 +398,7 @@ const enabled = computed(
const room = ref<RoomDetail>();
const otherUser = computed(() => {
if (!room.value) return;
if (!userStore.userInfo || userStore.userInfo.id === -1) return;
const { whiteUser, blackUser } = room.value;
return [whiteUser, blackUser].find((v) => v && v.id !== userStore.userInfo!.id);
});