From 27fbf0541d0a601098dc0f82bc50f866a54481c7 Mon Sep 17 00:00:00 2001 From: Jaybe Date: Tue, 27 May 2025 00:18:59 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B2=B0=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/controllers/clubController.js | 4 ++-- backend/models/Club.js | 3 +++ frontend/src/App.vue | 13 +++++++--- frontend/src/stores/clubStore.js | 12 +++++++++- .../subscription/SubscriptionManagement.vue | 24 ++++++++++++++++--- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/backend/controllers/clubController.js b/backend/controllers/clubController.js index 515ff48..5f207ba 100644 --- a/backend/controllers/clubController.js +++ b/backend/controllers/clubController.js @@ -755,7 +755,7 @@ exports.getRecentMeetings = async (req, res) => { // 사용자 클럽 목록 조회 exports.getUserClubs = async (req, res) => { try { - // 사용자가 속한 클럽 목록 조회 (Member 테이블 조인) + const { userId } = req.body; // admin이면 모든 클럽을, 아니면 자신의 클럽만 조회 const hasAdminAccess = isAdmin(req.user); @@ -768,7 +768,7 @@ exports.getUserClubs = async (req, res) => { queryOptions.include = [{ model: Member, where: { - userId: req.user.id + userId: userId }, attributes: ['memberType'] }]; diff --git a/backend/models/Club.js b/backend/models/Club.js index 0df1cba..35c3a88 100644 --- a/backend/models/Club.js +++ b/backend/models/Club.js @@ -89,6 +89,9 @@ Club.associate = (models) => { through: models.ClubFeature, foreignKey: 'clubId', }); + + // Member와의 관계 추가 + Club.hasMany(models.Member, { foreignKey: 'clubId' }); }; module.exports = Club; diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 5a6e7a7..88fb91c 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -130,7 +130,7 @@ const ownerName = ref(''); const isRouterReady = ref(false); const userRole = computed(() => user.value?.role || ''); const isAdmin = computed(() => userRole.value === 'admin' || userRole.value === 'superadmin'); -const userClubRole = ref(localStorage.getItem('userClubRole') || ''); +const userClubRole = computed(() => localStorage.getItem('userClubRole') || ''); // 화면 크기 변경 감지 const handleResize = () => { @@ -187,14 +187,20 @@ const fetchClubs = async () => { ...club, memberType: club.memberType || '' })); - // 첫 번째 클럽의 memberType을 localStorage에 저장 - if (clubs.value.length > 0 && !selectedClubId.value) { + if ((clubs.value.length > 0 && !selectedClubId.value) || clubs.value.length === 1) { selectedClubId.value = clubs.value[0].id; await setSelectedClub(clubs.value[0]); } } catch (error) { console.error('클럽 목록 로드 실패:', error); + + // 클럽 목록을 가져오지 못했거나 클럽이 없는 경우 + const userRole = localStorage.getItem('userRole'); + // 관리자가 아닌 경우에만 클럽 생성 페이지로 리다이렉트 + if (userRole !== 'admin' && userRole !== 'superadmin') { + router.push('/club/create'); + } } }; @@ -341,6 +347,7 @@ const loadUserData = async () => { try { const response = await authService.getCurrentUser(); user.value = response.data; + localStorage.setItem('userRole', response.data.role); } catch (error) { console.error('사용자 정보 로드 실패:', error); } diff --git a/frontend/src/stores/clubStore.js b/frontend/src/stores/clubStore.js index 9c49e9b..2a195e2 100644 --- a/frontend/src/stores/clubStore.js +++ b/frontend/src/stores/clubStore.js @@ -1,5 +1,6 @@ import { defineStore } from 'pinia'; -import apiClient from '../services/api'; +import apiClient from '@/services/api'; +import router from '@/router'; export const useClubStore = defineStore('club', { state: () => ({ @@ -37,9 +38,18 @@ export const useClubStore = defineStore('club', { return response.data; } catch (error) { + const userClubRole = localStorage.getItem('userClubRole'); console.error('구독 정보를 가져오는 중 오류가 발생했습니다:', error); this.subscription = null; this.subscriptionFeatures = []; + // 사용자 권한 확인 + if (userClubRole === '모임장' || userClubRole === '운영진') { + // 구독 페이지로 이동 + setTimeout(() => { + router.push('/club/subscription'); + }, 100); + } + return null; } }, diff --git a/frontend/src/views/club/subscription/SubscriptionManagement.vue b/frontend/src/views/club/subscription/SubscriptionManagement.vue index 75eeec9..3110bdb 100644 --- a/frontend/src/views/club/subscription/SubscriptionManagement.vue +++ b/frontend/src/views/club/subscription/SubscriptionManagement.vue @@ -905,8 +905,16 @@ const calculateSelectedFeaturesTotal = () => { // 현재 총 결제 금액 계산 const calculateTotalPrice = () => { + console.log('currentSubscription.value', currentSubscription.value); const planPrice = currentSubscription.value?.planPrice || 0; - const activeFeatureTotal = 0; // 활성화된 기능의 월 금액 계산 (추후 구현) + + // 활성화된 기능의 월 금액 계산 + const activeFeatureTotal = activeFeatures.value.reduce((total, feature) => { + // 각 활성화된 기능에 대해 해당 기능의 가격 찾기 + const featureInfo = availableFeatures.value.find(f => f.id === feature.featureId); + // 기능 정보가 있고 가격이 있으면 더하기, 없으면 0 더하기 + return total + (featureInfo?.price || 0); + }, 0); return planPrice + activeFeatureTotal; }; @@ -995,8 +1003,18 @@ const totalFeaturesPrice = computed(() => { // 최종 결제 금액 const finalAmount = computed(() => { + // 현재 구독이 없고 새로운 플랜을 선택한 경우 (신규 구독) + if (!currentSubscription.value && selectedPlan.value) { + // 플랜 총액 계산 (기간 할인 적용) + const planTotal = calculatePlanTotalPrice(selectedPlan.value); + // 추가 기능 총액 + const featuresTotal = totalFeaturesPrice.value; + // 10원 단위로 절삭 + const amount = planTotal + featuresTotal; + return Math.floor(amount / 10) * 10; + } // 플랜 변경이 있는 경우 - if (selectedPlan.value && !isCurrentPlan(selectedPlan.value.id)) { + else if (selectedPlan.value && !isCurrentPlan(selectedPlan.value.id)) { // 업그레이드이고 즉시 적용인 경우 if (isUpgrade.value && changeOption.value === 'immediate') { // 3개월 이상 구독인 경우 총 금액에서 환불액을 빼야 함 @@ -1015,7 +1033,7 @@ const finalAmount = computed(() => { // 10원 단위로 절삭 return Math.floor(totalFeaturesPrice.value / 10) * 10; } - // 새로운 구독인 경우 플랜 총액 계산 + // 기타 플랜 변경 케이스 else { // 10원 단위로 절삭 const amount = calculatePlanTotalPrice(selectedPlan.value) + totalFeaturesPrice.value;