121 lines
4.4 KiB
Vue
121 lines
4.4 KiB
Vue
<template>
|
|
<div>
|
|
<AppHeader />
|
|
<div class="container py-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h4 class="mb-0"><i class="bi bi-google me-2"></i>구글 그룹 관리</h4>
|
|
<button class="btn btn-primary" @click="openModal()">
|
|
<i class="bi bi-plus me-1"></i>그룹 추가
|
|
</button>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-body p-0">
|
|
<div v-if="isLoading" class="text-center py-5">
|
|
<div class="spinner-border text-primary"></div>
|
|
</div>
|
|
<div v-else-if="groups.length === 0" class="text-center py-5 text-muted">
|
|
<i class="bi bi-inbox display-4 d-block mb-2"></i>
|
|
등록된 그룹이 없습니다.
|
|
</div>
|
|
<table v-else class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>그룹명</th>
|
|
<th>이메일</th>
|
|
<th>설명</th>
|
|
<th style="width:100px" class="text-center">관리</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="g in groups" :key="g.groupId">
|
|
<td><strong>{{ g.groupName }}</strong></td>
|
|
<td><code>{{ g.groupEmail }}</code></td>
|
|
<td class="text-muted small">{{ g.description || '-' }}</td>
|
|
<td class="text-center">
|
|
<button class="btn btn-sm btn-outline-danger" @click="deleteGroup(g)">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 추가 모달 -->
|
|
<div class="modal fade" :class="{ show: showModal }" :style="{ display: showModal ? 'block' : 'none' }">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">그룹 추가</h5>
|
|
<button type="button" class="btn-close" @click="showModal = false"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label">그룹 이메일 <span class="text-danger">*</span></label>
|
|
<input type="email" class="form-control" v-model="form.groupEmail" placeholder="group@company.com" />
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">그룹명 <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" v-model="form.groupName" placeholder="개발팀" />
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">설명</label>
|
|
<input type="text" class="form-control" v-model="form.description" />
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" @click="showModal = false">취소</button>
|
|
<button type="button" class="btn btn-primary" @click="saveGroup">저장</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-backdrop fade show" v-if="showModal"></div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const groups = ref<any[]>([])
|
|
const isLoading = ref(true)
|
|
const showModal = ref(false)
|
|
const form = ref({ groupEmail: '', groupName: '', description: '' })
|
|
|
|
onMounted(() => loadGroups())
|
|
|
|
async function loadGroups() {
|
|
isLoading.value = true
|
|
try {
|
|
const res = await $fetch<any>('/api/google-group/list')
|
|
groups.value = res.groups || []
|
|
} catch (e) { console.error(e) }
|
|
finally { isLoading.value = false }
|
|
}
|
|
|
|
function openModal() {
|
|
form.value = { groupEmail: '', groupName: '', description: '' }
|
|
showModal.value = true
|
|
}
|
|
|
|
async function saveGroup() {
|
|
if (!form.value.groupEmail || !form.value.groupName) {
|
|
alert('이메일과 이름은 필수입니다.'); return
|
|
}
|
|
try {
|
|
await $fetch('/api/google-group/create', { method: 'POST', body: form.value })
|
|
showModal.value = false
|
|
loadGroups()
|
|
} catch (e: any) { alert(e.data?.message || '저장 실패') }
|
|
}
|
|
|
|
async function deleteGroup(g: any) {
|
|
if (!confirm(`"${g.groupName}" 그룹을 삭제하시겠습니까?`)) return
|
|
try {
|
|
await $fetch(`/api/google-group/${g.groupId}/delete`, { method: 'DELETE' })
|
|
loadGroups()
|
|
} catch (e: any) { alert(e.data?.message || '삭제 실패') }
|
|
}
|
|
</script>
|