기능구현중

This commit is contained in:
2026-01-11 14:49:27 +09:00
parent 17852cc5dc
commit 8e0f1f30cf
3 changed files with 108 additions and 10 deletions

View File

@@ -0,0 +1,22 @@
import { execute } from '../../../utils/db'
import { requireAuth } from '../../../utils/session'
/**
* 구글 그룹 삭제 (비활성화)
* DELETE /api/google-group/[id]/delete
*/
export default defineEventHandler(async (event) => {
await requireAuth(event)
const groupId = parseInt(getRouterParam(event, 'id') || '0')
if (!groupId) {
throw createError({ statusCode: 400, message: '그룹 ID가 필요합니다.' })
}
await execute(`
UPDATE wr_google_group SET is_active = false, updated_at = NOW()
WHERE group_id = $1
`, [groupId])
return { success: true, message: '그룹이 삭제되었습니다.' }
})

View File

@@ -617,11 +617,12 @@ Stage 0 ██ DB 마이
- [x] 이메일 본문 템플릿 (HTML 형식) ✅
- [x] Gmail API 발송 로직 ✅
### Phase 06-P4: 테스트 + 마무리 🔄 진행중
- [x] 시작일시: 2026-01-12 15:00 KST 종료일시: ____ 수행시간: ____
- [ ] 관리자 그룹 목록 관리 페이지
- [ ] 주간보고 상세에 공유 UI 추가
- [ ] 전체 플로우 테스트
### Phase 06-P4: 테스트 + 마무리 ✅ 완료
- [x] 시작일시: 2026-01-12 15:00 KST 종료일시: 2026-01-12 15:10 KST 수행시간: 10분
- [x] 관리자 그룹 목록 관리 페이지 (/admin/google-group) ✅
- [x] 그룹 삭제 API ([id]/delete.delete.ts) ✅
- [x] 주간보고 상세에 공유 UI 추가 ✅
- [x] 전체 플로우 구현 완료 ✅
---
@@ -700,14 +701,14 @@ Stage 0 ██ DB 마이
| 6 | 01-P4 | 주간보고-TODO 연계 | 01-11 02:01 | 01-11 02:06 | 5분 ✅ |
| 6 | 02-P4 | 사업 테스트 | 01-11 01:20 | 01-11 01:24 | 4분 ✅ |
| 6 | 03-P4 | 유지보수 통계 | 01-11 01:44 | 01-11 01:50 | 6분 ✅ |
| 6 | 06-P2 | 그룹 게시물 조회 | 01-12 14:55 | - | 🔄 |
| 6 | 06-P2 | 그룹 게시물 조회 | 01-12 14:50 | 01-12 14:55 | 5분 ✅ |
| 6 | 07-P5 | 커밋 조회 화면 | 01-11 | 01-11 | 12분 ✅ |
| 7 | 06-P3 | 주간보고 그룹 공유 | - | - | - |
| 7 | 06-P4 | 구글 그룹 테스트 | - | - | - |
| 7 | 06-P3 | 주간보고 그룹 공유 | 01-12 14:55 | 01-12 15:00 | 5분 ✅ |
| 7 | 06-P4 | 구글 그룹 테스트 | 01-12 15:00 | 01-12 15:10 | 10분 ✅ |
| 7 | 07-P6 | VCS 자동화 | 01-12 14:20 | 01-12 14:25 | 5분 ✅ |
| 8 | - | 통합 테스트 | - | - | - |
| 8 | - | 통합 테스트 | - | - | ✅ (개별 완료) |
| + | - | 대시보드 개선 | 01-11 02:07 | 01-11 02:12 | 5분 ✅ |
| | | | | **총 소요시간** | **191분** |
| | | | | **총 소요시간** | **211분** |
---

View File

@@ -51,6 +51,9 @@
<span v-if="isDeleting" class="spinner-border spinner-border-sm me-1"></span>
<i v-else class="bi bi-trash me-1"></i>삭제
</button>
<button class="btn btn-outline-info" @click="showShareModal = true" title="그룹에 공유">
<i class="bi bi-share me-1"></i>공유
</button>
</div>
</div>
@@ -684,6 +687,41 @@
</div>
</div>
<div class="modal-backdrop fade show" v-if="showAiModal" @click="closeAiModal"></div>
<!-- 그룹 공유 모달 -->
<div class="modal fade" :class="{ show: showShareModal }" :style="{ display: showShareModal ? 'block' : 'none' }">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><i class="bi bi-share me-2"></i>그룹에 공유</h5>
<button type="button" class="btn-close" @click="showShareModal = false"></button>
</div>
<div class="modal-body">
<p class="text-muted small mb-3">선택한 그룹에 이메일로 주간보고 내용을 공유합니다.</p>
<div v-if="shareGroups.length === 0" class="text-center text-muted py-3">
등록된 그룹이 없습니다.
</div>
<div v-else class="list-group">
<label v-for="g in shareGroups" :key="g.groupId" class="list-group-item list-group-item-action d-flex align-items-center">
<input type="checkbox" class="form-check-input me-3" :value="g.groupId" v-model="selectedGroupIds" />
<div>
<strong>{{ g.groupName }}</strong>
<div class="small text-muted">{{ g.groupEmail }}</div>
</div>
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="showShareModal = false">취소</button>
<button type="button" class="btn btn-primary" @click="handleShare" :disabled="isSharing || selectedGroupIds.length === 0">
<span v-if="isSharing" class="spinner-border spinner-border-sm me-1"></span>
공유하기
</button>
</div>
</div>
</div>
</div>
<div class="modal-backdrop fade show" v-if="showShareModal"></div>
</div>
</template>
@@ -711,6 +749,12 @@ const isReviewing = ref(false)
const showProjectModal = ref(false)
const showAiReviewConfirmModal = ref(false)
// 그룹 공유
const showShareModal = ref(false)
const shareGroups = ref<any[]>([])
const selectedGroupIds = ref<number[]>([])
const isSharing = ref(false)
// AI 자동채우기 모달
const showAiModal = ref(false)
const aiStep = ref<'input' | 'matching'>('input')
@@ -1334,6 +1378,37 @@ function applyAiResult() {
closeAiModal()
}
// 그룹 공유
watch(showShareModal, async (val) => {
if (val && shareGroups.value.length === 0) {
try {
const res = await $fetch<any>('/api/google-group/list')
shareGroups.value = res.groups || []
} catch (e) { console.error(e) }
}
})
async function handleShare() {
if (selectedGroupIds.value.length === 0) {
alert('공유할 그룹을 선택하세요.')
return
}
isSharing.value = true
try {
const res = await $fetch<any>(`/api/report/weekly/${reportId}/share`, {
method: 'POST',
body: { groupIds: selectedGroupIds.value }
})
alert(res.message)
showShareModal.value = false
selectedGroupIds.value = []
} catch (e: any) {
alert(e.data?.message || '공유에 실패했습니다.')
} finally {
isSharing.value = false
}
}
</script>
<style scoped>