Files
weeklyreport/frontend/report/weekly/[id].vue
2026-01-04 17:24:47 +09:00

191 lines
6.1 KiB
Vue

<template>
<div>
<AppHeader />
<div class="container-fluid py-4">
<div class="mb-4">
<NuxtLink to="/report/weekly" class="text-decoration-none">
<i class="bi bi-arrow-left me-1"></i> 목록으로
</NuxtLink>
</div>
<div class="card" v-if="report">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="bi bi-journal-text me-2"></i>
{{ report.projectName }} - {{ report.reportYear }}-W{{ String(report.reportWeek).padStart(2, '0') }}
</h5>
<span :class="getStatusBadgeClass(report.reportStatus)">
{{ getStatusText(report.reportStatus) }}
</span>
</div>
<div class="card-body">
<!-- 기본 정보 -->
<div class="row mb-4">
<div class="col-md-4">
<label class="form-label text-muted">작성자</label>
<p class="mb-0">{{ report.authorName }}</p>
</div>
<div class="col-md-4">
<label class="form-label text-muted">기간</label>
<p class="mb-0">{{ formatDate(report.weekStartDate) }} ~ {{ formatDate(report.weekEndDate) }}</p>
</div>
<div class="col-md-4">
<label class="form-label text-muted">투입시간</label>
<p class="mb-0">{{ report.workHours ? report.workHours + '시간' : '-' }}</p>
</div>
</div>
<!-- 금주 실적 -->
<div class="mb-4">
<label class="form-label text-muted">
<i class="bi bi-check-circle me-1"></i>금주 실적
</label>
<div class="p-3 bg-light rounded">
<pre class="mb-0" style="white-space: pre-wrap;">{{ report.workDescription || '-' }}</pre>
</div>
</div>
<!-- 차주 계획 -->
<div class="mb-4">
<label class="form-label text-muted">
<i class="bi bi-calendar-event me-1"></i>차주 계획
</label>
<div class="p-3 bg-light rounded">
<pre class="mb-0" style="white-space: pre-wrap;">{{ report.planDescription || '-' }}</pre>
</div>
</div>
<!-- 이슈사항 -->
<div class="mb-4" v-if="report.issueDescription">
<label class="form-label text-muted">
<i class="bi bi-exclamation-triangle me-1"></i>이슈/리스크
</label>
<div class="p-3 bg-warning bg-opacity-10 rounded">
<pre class="mb-0" style="white-space: pre-wrap;">{{ report.issueDescription }}</pre>
</div>
</div>
<!-- 비고 -->
<div class="mb-4" v-if="report.remarkDescription">
<label class="form-label text-muted">
<i class="bi bi-chat-text me-1"></i>비고
</label>
<div class="p-3 bg-light rounded">
<pre class="mb-0" style="white-space: pre-wrap;">{{ report.remarkDescription }}</pre>
</div>
</div>
<!-- 작업 버튼 -->
<div class="d-flex gap-2 mt-4 pt-3 border-top">
<NuxtLink
v-if="report.reportStatus === 'DRAFT'"
:to="`/report/weekly/write?id=${report.reportId}`"
class="btn btn-primary"
>
<i class="bi bi-pencil me-1"></i> 수정
</NuxtLink>
<button
v-if="report.reportStatus === 'DRAFT'"
class="btn btn-success"
@click="submitReport"
>
<i class="bi bi-send me-1"></i> 제출
</button>
<button
v-if="report.reportStatus === 'DRAFT'"
class="btn btn-outline-danger"
@click="deleteReport"
>
<i class="bi bi-trash me-1"></i> 삭제
</button>
</div>
</div>
</div>
<div class="text-center py-5" v-else-if="isLoading">
<div class="spinner-border text-primary"></div>
<p class="mt-2 text-muted">로딩중...</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
const { fetchCurrentUser } = useAuth()
const router = useRouter()
const route = useRoute()
const report = ref<any>(null)
const isLoading = ref(true)
onMounted(async () => {
const user = await fetchCurrentUser()
if (!user) {
router.push('/login')
return
}
await loadReport()
})
async function loadReport() {
isLoading.value = true
try {
const res = await $fetch<{ report: any }>(`/api/report/weekly/${route.params.id}/detail`)
report.value = res.report
} catch (e: any) {
alert('보고서를 불러오는데 실패했습니다.')
router.push('/report/weekly')
} finally {
isLoading.value = false
}
}
async function submitReport() {
if (!confirm('보고서를 제출하시겠습니까?\n제출 후에는 수정이 제한됩니다.')) return
try {
await $fetch(`/api/report/weekly/${route.params.id}/submit`, { method: 'POST' })
await loadReport()
} catch (e: any) {
alert(e.data?.message || e.message || '제출에 실패했습니다.')
}
}
async function deleteReport() {
if (!confirm('보고서를 삭제하시겠습니까?')) return
try {
await $fetch(`/api/report/weekly/${route.params.id}/detail`, { method: 'DELETE' })
router.push('/report/weekly')
} catch (e: any) {
alert(e.data?.message || e.message || '삭제에 실패했습니다.')
}
}
function getStatusBadgeClass(status: string) {
const classes: Record<string, string> = {
'DRAFT': 'badge bg-secondary',
'SUBMITTED': 'badge bg-success',
'AGGREGATED': 'badge bg-info'
}
return classes[status] || 'badge bg-secondary'
}
function getStatusText(status: string) {
const texts: Record<string, string> = {
'DRAFT': '작성중',
'SUBMITTED': '제출완료',
'AGGREGATED': '취합완료'
}
return texts[status] || status
}
function formatDate(dateStr: string) {
const d = new Date(dateStr)
return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`
}
</script>