기능구현중
This commit is contained in:
@@ -130,7 +130,7 @@
|
||||
</div>
|
||||
|
||||
<!-- PM/PL 이력 -->
|
||||
<div class="card">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-person-badge me-2"></i>PM/PL 담당 이력</span>
|
||||
<button class="btn btn-sm btn-primary" @click="showAssignModal = true">
|
||||
@@ -161,6 +161,44 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 저장소 관리 -->
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-git me-2"></i>저장소 관리</span>
|
||||
<button class="btn btn-sm btn-primary" @click="openRepoModal()">
|
||||
<i class="bi bi-plus"></i> 저장소 추가
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-bordered mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 70px">타입</th>
|
||||
<th>저장소명</th>
|
||||
<th>경로</th>
|
||||
<th style="width: 100px">브랜치</th>
|
||||
<th style="width: 100px">작업</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="r in repositories" :key="r.repoId">
|
||||
<td><span :class="r.serverType === 'GIT' ? 'badge bg-dark' : 'badge bg-warning text-dark'">{{ r.serverType }}</span></td>
|
||||
<td>{{ r.repoName }}</td>
|
||||
<td><small class="text-muted">{{ r.serverName }} ></small> {{ r.repoPath }}</td>
|
||||
<td>{{ r.defaultBranch || '-' }}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-secondary me-1" @click="openRepoModal(r)" title="수정"><i class="bi bi-pencil"></i></button>
|
||||
<button class="btn btn-sm btn-outline-danger" @click="deleteRepo(r.repoId)" title="삭제"><i class="bi bi-trash"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="repositories.length === 0">
|
||||
<td colspan="5" class="text-center text-muted py-3">등록된 저장소가 없습니다.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
@@ -237,6 +275,55 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-backdrop fade show" v-if="showAssignModal"></div>
|
||||
|
||||
<!-- 저장소 추가/수정 모달 -->
|
||||
<div class="modal fade" :class="{ show: showRepoModal }" :style="{ display: showRepoModal ? 'block' : 'none' }">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ repoForm.repoId ? '저장소 수정' : '저장소 추가' }}</h5>
|
||||
<button type="button" class="btn-close" @click="showRepoModal = false"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">VCS 서버 <span class="text-danger">*</span></label>
|
||||
<select class="form-select" v-model="repoForm.serverId">
|
||||
<option value="">선택하세요</option>
|
||||
<option v-for="s in vcsServers" :key="s.serverId" :value="s.serverId">[{{ s.serverType }}] {{ s.serverName }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">저장소명</label>
|
||||
<input type="text" class="form-control" v-model="repoForm.repoName" placeholder="표시용 이름" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">저장소 경로 <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" v-model="repoForm.repoPath" placeholder="/owner/repo.git 또는 /svn/project/trunk" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">전체 URL</label>
|
||||
<input type="text" class="form-control" v-model="repoForm.repoUrl" placeholder="https://github.com/owner/repo.git" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">기본 브랜치 (Git)</label>
|
||||
<input type="text" class="form-control" v-model="repoForm.defaultBranch" placeholder="main" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">설명</label>
|
||||
<textarea class="form-control" v-model="repoForm.description" rows="2"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" @click="showRepoModal = false">취소</button>
|
||||
<button type="button" class="btn btn-primary" @click="saveRepo" :disabled="isSavingRepo">
|
||||
<span v-if="isSavingRepo"><span class="spinner-border spinner-border-sm me-1"></span></span>
|
||||
<i class="bi bi-check-lg me-1" v-else></i>저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-backdrop fade show" v-if="showRepoModal"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -275,10 +362,25 @@ const assignForm = ref({
|
||||
changeReason: ''
|
||||
})
|
||||
|
||||
// 저장소 관련
|
||||
const repositories = ref<any[]>([])
|
||||
const vcsServers = ref<any[]>([])
|
||||
const showRepoModal = ref(false)
|
||||
const isSavingRepo = ref(false)
|
||||
const repoForm = ref({
|
||||
repoId: null as number | null,
|
||||
serverId: '',
|
||||
repoName: '',
|
||||
repoPath: '',
|
||||
repoUrl: '',
|
||||
defaultBranch: 'main',
|
||||
description: ''
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
const user = await fetchCurrentUser()
|
||||
if (!user) { router.push('/login'); return }
|
||||
await Promise.all([loadProject(), loadBusinesses(), loadEmployees()])
|
||||
await Promise.all([loadProject(), loadBusinesses(), loadEmployees(), loadVcsServers(), loadRepositories()])
|
||||
})
|
||||
|
||||
async function loadProject() {
|
||||
@@ -310,6 +412,68 @@ async function loadEmployees() {
|
||||
} catch (e) { console.error(e) }
|
||||
}
|
||||
|
||||
async function loadVcsServers() {
|
||||
try {
|
||||
const res = await $fetch<{ servers: any[] }>('/api/vcs-server/list')
|
||||
vcsServers.value = res.servers || []
|
||||
} catch (e) { console.error(e) }
|
||||
}
|
||||
|
||||
async function loadRepositories() {
|
||||
try {
|
||||
const res = await $fetch<{ repositories: any[] }>(`/api/repository/list?projectId=${route.params.id}`)
|
||||
repositories.value = res.repositories || []
|
||||
} catch (e) { console.error(e) }
|
||||
}
|
||||
|
||||
function openRepoModal(repo?: any) {
|
||||
if (repo) {
|
||||
repoForm.value = {
|
||||
repoId: repo.repoId,
|
||||
serverId: repo.serverId?.toString() || '',
|
||||
repoName: repo.repoName || '',
|
||||
repoPath: repo.repoPath || '',
|
||||
repoUrl: repo.repoUrl || '',
|
||||
defaultBranch: repo.defaultBranch || 'main',
|
||||
description: repo.description || ''
|
||||
}
|
||||
} else {
|
||||
repoForm.value = { repoId: null, serverId: '', repoName: '', repoPath: '', repoUrl: '', defaultBranch: 'main', description: '' }
|
||||
}
|
||||
showRepoModal.value = true
|
||||
}
|
||||
|
||||
async function saveRepo() {
|
||||
if (!repoForm.value.serverId || !repoForm.value.repoPath) {
|
||||
alert('VCS 서버와 저장소 경로는 필수입니다.')
|
||||
return
|
||||
}
|
||||
isSavingRepo.value = true
|
||||
try {
|
||||
if (repoForm.value.repoId) {
|
||||
await $fetch(`/api/repository/${repoForm.value.repoId}`, { method: 'PUT', body: repoForm.value })
|
||||
} else {
|
||||
await $fetch('/api/repository/create', { method: 'POST', body: { ...repoForm.value, projectId: Number(route.params.id) } })
|
||||
}
|
||||
showRepoModal.value = false
|
||||
await loadRepositories()
|
||||
} catch (e: any) {
|
||||
alert(e.data?.message || '저장에 실패했습니다.')
|
||||
} finally {
|
||||
isSavingRepo.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteRepo(repoId: number) {
|
||||
if (!confirm('이 저장소를 삭제하시겠습니까?')) return
|
||||
try {
|
||||
await $fetch(`/api/repository/${repoId}`, { method: 'DELETE' })
|
||||
await loadRepositories()
|
||||
} catch (e: any) {
|
||||
alert(e.data?.message || '삭제에 실패했습니다.')
|
||||
}
|
||||
}
|
||||
|
||||
function toggleEdit() {
|
||||
if (!isEditing.value) {
|
||||
form.value = {
|
||||
|
||||
Reference in New Issue
Block a user