feat: 프로필 감사 화면에서 정책 버전과 전후 값을 조회

This commit is contained in:
2026-09-16 05:02:32 +00:00
parent d549cbf887
commit 3d60e6122d
8 changed files with 845 additions and 11 deletions
+61 -8
View File
@@ -5,6 +5,7 @@ import PanelCard from '../components/ui/PanelCard.vue';
import AuditNationSeries from '../components/playAudit/AuditNationSeries.vue';
import AuditNationSnapshot from '../components/playAudit/AuditNationSnapshot.vue';
import AuditGeneralDetail from '../components/playAudit/AuditGeneralDetail.vue';
import AuditPolicyHistory from '../components/playAudit/AuditPolicyHistory.vue';
import AuditCityDetail from '../components/playAudit/AuditCityDetail.vue';
import { usePageExit } from '../composables/usePageExit';
import { trpc } from '../utils/trpc';
@@ -29,6 +30,28 @@ const profileName = ref('');
const loading = ref(false);
const error = ref('');
const tab = ref('nations');
const policyArea = ref<'NPC_VALUES' | 'NPC_NATION_PRIORITY' | 'NPC_GENERAL_PRIORITY' | 'DEFENCE'>('NPC_VALUES');
const appliedPolicy = computed(() => {
const to = {
year: numeric(route.query.year, coverage.value?.year ?? 0),
month: numeric(route.query.month, coverage.value?.month ?? 1),
};
const start = Math.max(
(coverage.value?.startYear ?? to.year) * 12 + (coverage.value?.startMonth ?? 1) - 1,
to.year * 12 + to.month - 6
);
return {
nationId: numeric(route.query.nation, 0),
area: (['NPC_NATION_PRIORITY', 'NPC_GENERAL_PRIORITY', 'DEFENCE'].includes(String(route.query.policyArea))
? route.query.policyArea
: 'NPC_VALUES') as typeof policyArea.value,
from: {
year: numeric(route.query.fromYear, Math.floor(start / 12)),
month: numeric(route.query.fromMonth, (start % 12) + 1),
},
to,
};
});
const nationId = ref('');
const cityId = ref('');
const population = ref('');
@@ -91,9 +114,10 @@ const result = computed(() =>
: series.value
);
const readQuery = () => {
tab.value = ['nations', 'generals', 'cities'].includes(String(route.query.tab))
tab.value = ['nations', 'generals', 'cities', 'policies'].includes(String(route.query.tab))
? String(route.query.tab)
: 'nations';
policyArea.value = appliedPolicy.value.area;
nationId.value = route.query.nation ? String(numeric(route.query.nation, 0)) : '';
cityId.value = route.query.city ? String(numeric(route.query.city, 0)) : '';
population.value = ['human', 'npc', 'troopNpc'].includes(String(route.query.population))
@@ -149,6 +173,8 @@ const load = async (append = false) => {
...response,
items: append ? [...(cities.value?.items ?? []), ...response.items] : response.items,
};
} else if (tab.value === 'policies') {
// 정책 목록/상세는 해당 component가 필요한 요청만 실행한다.
} else if (nationId.value !== '' && moment.value === 'final') {
const response = await trpc.playAudit.nationSnapshot.query({
nationId: Number(nationId.value),
@@ -201,6 +227,7 @@ const apply = async () => {
fromYear: String(fromYear.value),
fromMonth: String(fromMonth.value),
resolution: resolution.value,
policyArea: tab.value === 'policies' ? policyArea.value : undefined,
};
if (JSON.stringify(route.query) === JSON.stringify(query)) await refresh();
else {
@@ -236,7 +263,10 @@ const moreNations = async () => {
}
};
watch(
() => JSON.stringify(Object.entries(route.query).filter(([key]) => key !== 'general' && key !== 'cityRecord')),
() =>
JSON.stringify(
Object.entries(route.query).filter(([key]) => key !== 'general' && key !== 'cityRecord' && key !== 'policy')
),
() => {
if (authorized.value) {
readQuery();
@@ -286,11 +316,14 @@ onMounted(async () => {
<option value="nations">국가 시계열</option>
<option value="generals">전체 장수</option>
<option value="cities">도시 상태</option>
<option value="policies">정책 변경 이력</option>
</select></label
>
<label
>국가<select class="legacy-sort-select" v-model="nationId">
<option value="">{{ tab === 'nations' ? '국가 선택' : '모든 국가' }}</option>
<option value="">
{{ tab === 'nations' || tab === 'policies' ? '국가 선택' : '모든 국가' }}
</option>
<option value="0">무소속</option>
<option
v-for="nation in nations?.items.filter((item) => item.id !== 0)"
@@ -328,7 +361,7 @@ onMounted(async () => {
</select></label
>
<label
>{{ tab === 'nations' ? '종료 연도' : '표본 연도'
>{{ tab === 'nations' || tab === 'policies' ? '종료 연도' : '표본 연도'
}}<input
v-model.number="year"
type="number"
@@ -344,7 +377,7 @@ onMounted(async () => {
:max="year === coverage.year ? coverage.month : 12"
required
/></label>
<template v-if="tab === 'nations' && moment !== 'final'">
<template v-if="(tab === 'nations' && moment !== 'final') || tab === 'policies'">
<label
>시작 연도<input
v-model.number="fromYear"
@@ -361,13 +394,21 @@ onMounted(async () => {
:max="fromYear === coverage.year ? coverage.month : 12"
required
/></label>
<label
<label v-if="tab === 'nations'"
>간격<select class="legacy-sort-select" v-model="resolution">
<option value="halfYear">반기 (1~6월 / 7~12월)</option>
<option value="month">매월</option>
</select></label
>
</template>
<label v-if="tab === 'policies'"
>정책 영역<select class="legacy-sort-select" v-model="policyArea">
<option value="NPC_VALUES">NPC 국가 정책</option>
<option value="NPC_NATION_PRIORITY">국가 행동 우선순위</option>
<option value="NPC_GENERAL_PRIORITY">장수 행동 우선순위</option>
<option value="DEFENCE">국방 설정</option>
</select></label
>
<template v-if="tab === 'generals'">
<label>도시 번호<input v-model="cityId" type="number" min="0" placeholder="모든 도시" /></label>
<label
@@ -385,12 +426,24 @@ onMounted(async () => {
</PanelCard>
<PanelCard
v-if="authorized && coverage"
:title="tab === 'nations' ? '국가 시계열' : tab === 'generals' ? '전체 장수' : '도시 상태'"
:title="
tab === 'nations'
? '국가 시계열'
: tab === 'generals'
? '전체 장수'
: tab === 'policies'
? '정책 변경 이력'
: '도시 상태'
"
>
<p v-if="result">조회 시각 {{ result.asOf }} · tick {{ result.tick ?? '없음' }}</p>
<p v-if="tab === 'nations' && !nationId">
<p v-if="(tab === 'nations' || tab === 'policies') && !nationId">
국가를 선택하고 조회해 주세요. 멸망한 국가는 해당 월말 기준의 국가 목록에서 선택할 수 있습니다.
</p>
<AuditPolicyHistory
v-if="tab === 'policies' && route.query.tab === 'policies' && route.query.nation"
v-bind="appliedPolicy"
/>
<AuditNationSeries v-if="series && tab === 'nations'" :data="series" />
<AuditNationSnapshot v-if="nationSnapshot && tab === 'nations'" :data="nationSnapshot" />
<template v-if="generals && tab === 'generals'">