추가
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-3">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
@@ -25,6 +25,13 @@
|
||||
placeholder="프로젝트명 또는 코드 검색"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-select" v-model="filterType">
|
||||
<option value="">전체 유형</option>
|
||||
<option value="SI">SI</option>
|
||||
<option value="SM">SM</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<select class="form-select" v-model="filterStatus">
|
||||
<option value="">전체 상태</option>
|
||||
@@ -48,8 +55,9 @@
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>프로젝트 코드</th>
|
||||
<th style="width: 120px">코드</th>
|
||||
<th>프로젝트명</th>
|
||||
<th style="width: 80px">유형</th>
|
||||
<th>발주처</th>
|
||||
<th style="width: 120px">기간</th>
|
||||
<th style="width: 100px">상태</th>
|
||||
@@ -62,6 +70,11 @@
|
||||
<td>
|
||||
<strong>{{ project.projectName }}</strong>
|
||||
</td>
|
||||
<td>
|
||||
<span :class="getTypeBadgeClass(project.projectType)">
|
||||
{{ project.projectType || 'SI' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ project.clientName || '-' }}</td>
|
||||
<td>
|
||||
<small v-if="project.startDate">
|
||||
@@ -85,7 +98,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="filteredProjects.length === 0">
|
||||
<td colspan="6" class="text-center py-5 text-muted">
|
||||
<td colspan="7" class="text-center py-5 text-muted">
|
||||
<i class="bi bi-inbox display-4"></i>
|
||||
<p class="mt-2 mb-0">프로젝트가 없습니다.</p>
|
||||
</td>
|
||||
@@ -106,14 +119,17 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">프로젝트 코드</label>
|
||||
<input type="text" class="form-control" v-model="newProject.projectCode" placeholder="예: 2026-KDCA-001" />
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label class="form-label">프로젝트명 <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" v-model="newProject.projectName" required />
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">프로젝트 유형 <span class="text-danger">*</span></label>
|
||||
<select class="form-select" v-model="newProject.projectType">
|
||||
<option value="SI">SI (시스템 구축)</option>
|
||||
<option value="SM">SM (시스템 유지보수)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">발주처</label>
|
||||
<input type="text" class="form-control" v-model="newProject.clientName" />
|
||||
@@ -135,11 +151,20 @@
|
||||
<textarea class="form-control" v-model="newProject.projectDescription" rows="3"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info mt-3 mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
프로젝트 코드는 자동 생성됩니다. (예: 2026-001)
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" @click="showCreateModal = false">취소</button>
|
||||
<button type="button" class="btn btn-primary" @click="createProject">
|
||||
<i class="bi bi-check-lg me-1"></i> 등록
|
||||
<button type="button" class="btn btn-primary" @click="createProject" :disabled="isCreating">
|
||||
<span v-if="isCreating">
|
||||
<span class="spinner-border spinner-border-sm me-1"></span>등록 중...
|
||||
</span>
|
||||
<span v-else>
|
||||
<i class="bi bi-check-lg me-1"></i>등록
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -155,14 +180,16 @@ const router = useRouter()
|
||||
|
||||
const projects = ref<any[]>([])
|
||||
const searchKeyword = ref('')
|
||||
const filterType = ref('')
|
||||
const filterStatus = ref('')
|
||||
const showCreateModal = ref(false)
|
||||
const isCreating = ref(false)
|
||||
|
||||
const newProject = ref({
|
||||
projectCode: '',
|
||||
projectName: '',
|
||||
projectType: 'SI',
|
||||
clientName: '',
|
||||
contractAmount: null,
|
||||
contractAmount: null as number | null,
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
projectDescription: ''
|
||||
@@ -179,6 +206,10 @@ const filteredProjects = computed(() => {
|
||||
)
|
||||
}
|
||||
|
||||
if (filterType.value) {
|
||||
list = list.filter(p => p.projectType === filterType.value)
|
||||
}
|
||||
|
||||
if (filterStatus.value) {
|
||||
list = list.filter(p => p.projectStatus === filterStatus.value)
|
||||
}
|
||||
@@ -211,27 +242,38 @@ async function createProject() {
|
||||
return
|
||||
}
|
||||
|
||||
isCreating.value = true
|
||||
try {
|
||||
await $fetch('/api/project/create', {
|
||||
method: 'POST',
|
||||
body: newProject.value
|
||||
})
|
||||
showCreateModal.value = false
|
||||
newProject.value = {
|
||||
projectCode: '',
|
||||
projectName: '',
|
||||
clientName: '',
|
||||
contractAmount: null,
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
projectDescription: ''
|
||||
}
|
||||
resetNewProject()
|
||||
await loadProjects()
|
||||
} catch (e: any) {
|
||||
alert(e.data?.message || e.message || '등록에 실패했습니다.')
|
||||
} finally {
|
||||
isCreating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function resetNewProject() {
|
||||
newProject.value = {
|
||||
projectName: '',
|
||||
projectType: 'SI',
|
||||
clientName: '',
|
||||
contractAmount: null,
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
projectDescription: ''
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeBadgeClass(type: string) {
|
||||
return type === 'SM' ? 'badge bg-info' : 'badge bg-primary'
|
||||
}
|
||||
|
||||
function getStatusBadgeClass(status: string) {
|
||||
const classes: Record<string, string> = {
|
||||
'ACTIVE': 'badge bg-success',
|
||||
|
||||
Reference in New Issue
Block a user