fix: 설문과 장수 선택 기한 및 토너먼트 개최를 게임 시각으로 통일

This commit is contained in:
2026-09-16 01:38:21 +00:00
parent a51574d20c
commit f4aabec1fa
9 changed files with 388 additions and 56 deletions
+16 -22
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { computed, onMounted, ref, watch } from 'vue';
import { RouterLink, useRoute, useRouter } from 'vue-router';
import { useGameFeedback } from '../composables/useGameFeedback';
import PanelCard from '../components/ui/PanelCard.vue';
@@ -11,7 +11,7 @@ import { useSessionStore } from '../stores/session';
import { cityLevelMap, formatOfficerLevelText, regionMap } from '../utils/nationFormat';
import { getNpcColor } from '../utils/npcColor';
import { useClockDisplay } from '../composables/useClockDisplay';
const { formatTime: formatSeoulDateTime } = useClockDisplay();
const { formatTime: formatSeoulDateTime, gameTime } = useClockDisplay();
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../utils/generalIcon';
import { abilityLeadint, abilityLeadpow, abilityPowint, abilityRand, type GeneralStats } from '../utils/generalStats';
import { legacyLuminanceTextColor } from '../utils/legacyNationColor';
@@ -185,8 +185,6 @@ const npcReservation = ref<PossessReservation | null>(null);
const npcLoading = ref(false);
const npcError = ref<string | null>(null);
const keptNpcIds = ref<number[]>([]);
const nowMs = ref(Date.now());
const npcPickMoreAvailableAtMs = ref(0);
const pendingPossessAction = ref<PendingPossessAction | null>(null);
const npcGeneralList = ref<NpcGeneralList | null>(null);
const npcGeneralListLoading = ref(false);
@@ -202,17 +200,22 @@ const publicGeneralsLoaded = ref(false);
const publicGeneralsLoading = ref(false);
const publicGeneralsError = ref('');
const publicGeneralFilter = ref('');
let npcTimer: number | null = null;
const npcCandidates = computed<PossessCandidate[]>(() => npcReservation.value?.candidates ?? []);
const npcValidUntilMs = computed(() => {
const value = npcReservation.value?.validUntil;
return value ? new Date(value).getTime() : 0;
});
const npcExpired = computed(() => npcValidUntilMs.value > 0 && npcValidUntilMs.value < nowMs.value);
const npcPickMoreSeconds = computed(() =>
Math.max(0, Math.ceil((npcPickMoreAvailableAtMs.value - nowMs.value) / 1000))
const npcExpired = computed(
() => npcValidUntilMs.value > 0 && gameTime.value !== null && npcValidUntilMs.value < gameTime.value.getTime()
);
const npcPickMoreSeconds = computed(() => {
const reservation = npcReservation.value;
if (!reservation) return 0;
if (!gameTime.value) return reservation.pickMoreSeconds;
// pickMoreFrom은 GAME 기한이므로 복구 배속과 정지 상태도 같은 시계를 따른다.
return Math.max(0, Math.ceil((new Date(reservation.pickMoreFrom).getTime() - gameTime.value.getTime()) / 1000));
});
const hasPendingPossession = computed(
() => pendingPossessAction.value !== null && pendingPossessAction.value.ownerUserId === joinConfig.value?.user.id
);
@@ -261,7 +264,8 @@ const filteredPublicGenerals = computed(() => {
return sortGeneralsByTypeThenName(filtered);
});
const npcValidColor = computed(() => {
const remaining = npcValidUntilMs.value - nowMs.value;
if (!gameTime.value) return '#ffffff';
const remaining = npcValidUntilMs.value - gameTime.value.getTime();
if (remaining > 30_000) return '#ffffff';
const channel = Math.max(0, Math.min(255, Math.round((remaining / 30_000) * 255)));
return `rgb(255, ${channel}, ${channel})`;
@@ -465,9 +469,6 @@ const loadNpcCandidates = async (refresh = false) => {
});
npcReservation.value = reservation;
keptNpcIds.value = [];
const receivedAt = Date.now();
nowMs.value = receivedAt;
npcPickMoreAvailableAtMs.value = receivedAt + reservation.pickMoreSeconds * 1000;
} catch (err) {
npcError.value = err instanceof Error ? err.message : 'npc_list_failed';
if (refresh) {
@@ -648,17 +649,8 @@ watch(contextTab, (value) => {
});
onMounted(() => {
npcTimer = window.setInterval(() => {
nowMs.value = Date.now();
}, 250);
void loadConfig();
});
onUnmounted(() => {
if (npcTimer !== null) {
window.clearInterval(npcTimer);
}
});
</script>
<template>
@@ -1119,7 +1111,9 @@ onUnmounted(() => {
id="btn-pick-more"
class="legacy-button legacy-button--secondary"
type="button"
:disabled="npcLoading || npcPickMoreSeconds > 0 || submitting || hasPendingPossession"
:disabled="
npcLoading || !gameTime || npcPickMoreSeconds > 0 || submitting || hasPendingPossession
"
@click="loadNpcCandidates(true)"
>
다른 장수 보기<span v-if="npcPickMoreSeconds > 0">({{ npcPickMoreSeconds }})</span>