78 lines
2.7 KiB
Vue
78 lines
2.7 KiB
Vue
<template>
|
||
<section>
|
||
<header class="sticky top-0 z-10 border-b border-line bg-white px-4 pb-3 pt-4">
|
||
<div class="flex items-center justify-between">
|
||
<button class="btn-secondary min-h-10 px-3" @click="moveMonth(-1)">‹</button>
|
||
<input v-model="selectedMonth" class="w-36 rounded-md border border-line px-3 py-2 text-center font-semibold" type="month">
|
||
<button class="btn-secondary min-h-10 px-3" @click="moveMonth(1)">›</button>
|
||
</div>
|
||
<div class="mt-4 grid grid-cols-3 gap-2 text-sm">
|
||
<div>
|
||
<p class="text-muted">수입</p>
|
||
<p class="font-bold text-brand-700">{{ formatWon(data?.summary.income || 0) }}</p>
|
||
</div>
|
||
<div>
|
||
<p class="text-muted">지출</p>
|
||
<p class="font-bold text-red-600">{{ formatWon(data?.summary.expense || 0) }}</p>
|
||
</div>
|
||
<div>
|
||
<p class="text-muted">차액</p>
|
||
<p class="font-bold">{{ formatWon(data?.summary.diff || 0) }}</p>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="divide-y divide-line">
|
||
<NuxtLink
|
||
v-for="tx in data?.transactions"
|
||
:key="tx.id"
|
||
:to="`/transactions/${tx.id}`"
|
||
class="grid grid-cols-[1fr_auto] gap-3 px-4 py-3"
|
||
>
|
||
<div class="min-w-0">
|
||
<p class="truncate font-semibold text-ink">{{ tx.title }}</p>
|
||
<p class="mt-1 text-xs text-muted">
|
||
{{ timeLabel(tx.occurredAt) }} · {{ tx.asset.name }}
|
||
</p>
|
||
<p class="mt-1 truncate text-xs text-muted">
|
||
{{ categoryLabel(tx.category) }}
|
||
</p>
|
||
</div>
|
||
<div class="text-right">
|
||
<p class="font-bold" :class="tx.type === 'income' ? 'text-brand-700' : 'text-red-600'">
|
||
{{ tx.type === 'income' ? '+' : '-' }}{{ formatWon(tx.amount) }}
|
||
</p>
|
||
</div>
|
||
</NuxtLink>
|
||
</div>
|
||
|
||
<div v-if="!data?.transactions.length" class="px-4 py-16 text-center text-muted">
|
||
아직 거래가 없습니다.
|
||
</div>
|
||
</section>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { addMonths, format, parse } from 'date-fns'
|
||
import type { Category } from '~/composables/useMoney'
|
||
|
||
const selectedMonth = ref(monthKey())
|
||
const { data } = await useFetch('/api/transactions', {
|
||
query: { month: selectedMonth }
|
||
})
|
||
|
||
function moveMonth(amount: number) {
|
||
const date = parse(selectedMonth.value, 'yyyy-MM', new Date())
|
||
selectedMonth.value = format(addMonths(date, amount), 'yyyy-MM')
|
||
}
|
||
|
||
function timeLabel(value: string) {
|
||
return new Intl.DateTimeFormat('ko-KR', { hour: '2-digit', minute: '2-digit' }).format(new Date(value))
|
||
}
|
||
|
||
function categoryLabel(category: Category & { parent?: Category | null }) {
|
||
return category.parent ? `${category.parent.name} > ${category.name}` : category.name
|
||
}
|
||
|
||
</script>
|