버그 수정
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
.history
|
.history
|
||||||
.env
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
.vite
|
||||||
.windsurfrules
|
.windsurfrules
|
||||||
config.js
|
config.js
|
||||||
backend/node_modules/*
|
backend/node_modules/*
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ app.get('/', (req, res) => {
|
|||||||
// 서버 시작
|
// 서버 시작
|
||||||
const PORT = process.env.PORT || 3030;
|
const PORT = process.env.PORT || 3030;
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`서버가 포트 ${PORT}에서 실행 중입니다.`);
|
console.log(`서버가 ${process.env.NODE_ENV} 환경으로 포트 ${PORT}에서 실행 중입니다.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
const { Sequelize } = require('sequelize');
|
const { Sequelize } = require('sequelize');
|
||||||
require('dotenv').config();
|
const path = require('path');
|
||||||
|
|
||||||
|
// 환경 변수 설정
|
||||||
|
const env = process.env.NODE_ENV || 'development';
|
||||||
|
const envPath = path.resolve(process.cwd(), `.env.${env}`);
|
||||||
|
|
||||||
|
// 환경별 .env 파일 로드
|
||||||
|
require('dotenv').config({
|
||||||
|
path: envPath
|
||||||
|
});
|
||||||
|
|
||||||
const sequelize = new Sequelize(
|
const sequelize = new Sequelize(
|
||||||
process.env.DB_NAME,
|
process.env.DB_NAME,
|
||||||
@@ -9,7 +18,7 @@ const sequelize = new Sequelize(
|
|||||||
host: process.env.DB_HOST,
|
host: process.env.DB_HOST,
|
||||||
port: process.env.DB_PORT,
|
port: process.env.DB_PORT,
|
||||||
dialect: 'mysql',
|
dialect: 'mysql',
|
||||||
logging: true, // 개발 중에는 true로 설정하여 SQL 쿼리 로그 확인 가능
|
logging: process.env.NODE_ENV === 'development' ? console.log : false, // 개발 환경에서만 로깅 활성화
|
||||||
pool: {
|
pool: {
|
||||||
max: 5,
|
max: 5,
|
||||||
min: 0,
|
min: 0,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ exports.getAllEvents = async (req, res) => {
|
|||||||
where: {
|
where: {
|
||||||
status: { [Op.ne]: '취소' }
|
status: { [Op.ne]: '취소' }
|
||||||
},
|
},
|
||||||
|
required: false,
|
||||||
include: [{
|
include: [{
|
||||||
model: Member,
|
model: Member,
|
||||||
attributes: ['id', 'name', 'memberType', 'gender']
|
attributes: ['id', 'name', 'memberType', 'gender']
|
||||||
@@ -83,6 +84,7 @@ exports.getEventById = async (req, res) => {
|
|||||||
where: {
|
where: {
|
||||||
status: { [Op.ne]: '취소' }
|
status: { [Op.ne]: '취소' }
|
||||||
},
|
},
|
||||||
|
required: false,
|
||||||
include: [{
|
include: [{
|
||||||
model: Member,
|
model: Member,
|
||||||
attributes: ['id', 'name']
|
attributes: ['id', 'name']
|
||||||
@@ -145,7 +147,7 @@ exports.createEvent = async (req, res) => {
|
|||||||
clubId,
|
clubId,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
startDate: new Date(startDate),
|
startDate: startDate ? startDate : null,
|
||||||
endDate: endDateVal,
|
endDate: endDateVal,
|
||||||
location,
|
location,
|
||||||
maxParticipants: maxParticipants || 0,
|
maxParticipants: maxParticipants || 0,
|
||||||
@@ -220,8 +222,8 @@ exports.updateEvent = async (req, res) => {
|
|||||||
const updateData = {
|
const updateData = {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
startDate: startDate ? new Date(startDate) : event.startDate,
|
startDate: startDate ? startDate : event.startDate,
|
||||||
endDate: endDate ? new Date(endDate) : null,
|
endDate: endDate || null,
|
||||||
location,
|
location,
|
||||||
maxParticipants: maxParticipants || event.maxParticipants,
|
maxParticipants: maxParticipants || event.maxParticipants,
|
||||||
eventType: eventType || event.eventType,
|
eventType: eventType || event.eventType,
|
||||||
@@ -246,11 +248,16 @@ exports.updateEvent = async (req, res) => {
|
|||||||
attributes: ['id', 'status'],
|
attributes: ['id', 'status'],
|
||||||
where: {
|
where: {
|
||||||
status: { [Op.ne]: '취소' }
|
status: { [Op.ne]: '취소' }
|
||||||
}
|
},
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!updatedEvent) {
|
||||||
|
return res.status(404).json({ message: '이벤트를 찾을 수 없습니다.' });
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
message: '이벤트가 수정되었습니다.',
|
message: '이벤트가 수정되었습니다.',
|
||||||
event: {
|
event: {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const { sequelize } = require('../config/database');
|
const { sequelize } = require('../config/database');
|
||||||
|
const { Op } = require('sequelize');
|
||||||
const User = require('./User');
|
const User = require('./User');
|
||||||
const Club = require('./Club');
|
const Club = require('./Club');
|
||||||
const Event = require('./Event');
|
const Event = require('./Event');
|
||||||
@@ -160,7 +161,7 @@ const createSampleData = async () => {
|
|||||||
await Club.destroy({ where: {} });
|
await Club.destroy({ where: {} });
|
||||||
await Feature.destroy({ where: {} });
|
await Feature.destroy({ where: {} });
|
||||||
await SubscriptionPlan.destroy({ where: {} });
|
await SubscriptionPlan.destroy({ where: {} });
|
||||||
await User.destroy({ where: {} });
|
await User.destroy({ where: { email: { [Op.ne]: process.env.ADMIN_EMAIL } } });
|
||||||
console.log('기존 데이터가 모두 삭제되었습니다.');
|
console.log('기존 데이터가 모두 삭제되었습니다.');
|
||||||
|
|
||||||
// 2. 샘플 사용자 데이터 생성
|
// 2. 샘플 사용자 데이터 생성
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"start": "NODE_ENV=production node app.js",
|
||||||
|
"cleanup": "lsof -ti:3030 | xargs kill -9 || true",
|
||||||
|
"dev": "npm run cleanup && NODE_ENV=development nodemon app.js",
|
||||||
|
"test": "NODE_ENV=test jest"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const { Club, Member, User, Feature, ClubFeature, ActivityLog, SubscriptionPlan, Meeting, MeetingParticipant, ClubSubscription } = require('../models');
|
const { Club, Member, User, Feature, ClubFeature, ActivityLog, SubscriptionPlan, Meeting, MeetingParticipant, ClubSubscription } = require('../models');
|
||||||
|
const clubController = require('../controllers/clubController');
|
||||||
const { sequelize } = require('../models/index');
|
const { sequelize } = require('../models/index');
|
||||||
const { Op } = require('sequelize');
|
const { Op } = require('sequelize');
|
||||||
const { authenticateJWT, authorizeRoles } = require('../middleware/authMiddleware');
|
const { authenticateJWT, authorizeRoles } = require('../middleware/authMiddleware');
|
||||||
@@ -1294,6 +1295,9 @@ router.get('/clubs/:id', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 새 클럽 생성
|
||||||
|
router.post('/clubs', authenticateJWT, clubController.createClub);
|
||||||
|
|
||||||
// 클럽 수정
|
// 클럽 수정
|
||||||
router.put('/clubs/:id', async (req, res) => {
|
router.put('/clubs/:id', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0 --port 5173",
|
"cleanup": "pkill -f esbuild || true",
|
||||||
|
"dev": "npm run cleanup && vite --host 0.0.0.0 --port 5173",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -99,6 +99,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, toRefs, computed } from 'vue';
|
import { ref, watch, toRefs, computed } from 'vue';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
const statusOptions = [
|
const statusOptions = [
|
||||||
{ name: '준비', value: '준비' },
|
{ name: '준비', value: '준비' },
|
||||||
@@ -145,9 +146,7 @@ const eventModel = ref({ ...props.event });
|
|||||||
// 날짜 형식 변환
|
// 날짜 형식 변환
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
if (!date) return null;
|
if (!date) return null;
|
||||||
const d = new Date(date);
|
return dayjs(date).toDate();
|
||||||
d.setHours(d.getHours() + 9); // UTC to KST
|
|
||||||
return d;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// props 변경 시 이벤트 모델 업데이트
|
// props 변경 시 이벤트 모델 업데이트
|
||||||
@@ -161,23 +160,17 @@ watch(() => props.event, (newValue) => {
|
|||||||
eventModel.value = formattedEvent;
|
eventModel.value = formattedEvent;
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
|
|
||||||
// 이벤트 저장 시 UTC로 변환
|
// 이벤트 저장
|
||||||
const saveEvent = () => {
|
const saveEvent = () => {
|
||||||
const eventData = { ...eventModel.value };
|
const eventData = { ...eventModel.value };
|
||||||
if (eventData.startDate) {
|
if (eventData.startDate) {
|
||||||
const d = new Date(eventData.startDate);
|
eventData.startDate = dayjs(eventData.startDate).toDate();
|
||||||
d.setHours(d.getHours() - 9); // KST to UTC
|
|
||||||
eventData.startDate = d;
|
|
||||||
}
|
}
|
||||||
if (eventData.endDate) {
|
if (eventData.endDate) {
|
||||||
const d = new Date(eventData.endDate);
|
eventData.endDate = dayjs(eventData.endDate).toDate();
|
||||||
d.setHours(d.getHours() - 9); // KST to UTC
|
|
||||||
eventData.endDate = d;
|
|
||||||
}
|
}
|
||||||
if (eventData.registrationDeadline) {
|
if (eventData.registrationDeadline) {
|
||||||
const d = new Date(eventData.registrationDeadline);
|
eventData.registrationDeadline = dayjs(eventData.registrationDeadline).toDate();
|
||||||
d.setHours(d.getHours() - 9); // KST to UTC
|
|
||||||
eventData.registrationDeadline = d;
|
|
||||||
}
|
}
|
||||||
emit('save', eventData);
|
emit('save', eventData);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -114,7 +114,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted, defineEmits } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
import { useToast } from 'primevue/usetoast';
|
import { useToast } from 'primevue/usetoast';
|
||||||
import eventService from '@/services/eventService';
|
import eventService from '@/services/eventService';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ import { createPinia } from 'pinia'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
|
||||||
|
// dayjs configuration
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import timezone from 'dayjs/plugin/timezone'
|
||||||
|
import utc from 'dayjs/plugin/utc'
|
||||||
|
|
||||||
|
dayjs.extend(utc)
|
||||||
|
dayjs.extend(timezone)
|
||||||
|
dayjs.tz.setDefault('Asia/Seoul')
|
||||||
|
|
||||||
// PrimeVue
|
// PrimeVue
|
||||||
import PrimeVue from 'primevue/config'
|
import PrimeVue from 'primevue/config'
|
||||||
import 'primevue/resources/themes/lara-light-blue/theme.css'
|
import 'primevue/resources/themes/lara-light-blue/theme.css'
|
||||||
|
|||||||
@@ -29,6 +29,15 @@ const adminService = {
|
|||||||
return apiClient.get(`/api/admin/clubs/${id}`);
|
return apiClient.get(`/api/admin/clubs/${id}`);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 새 클럽 생성
|
||||||
|
* @param {Object} clubData - 클럽 정보
|
||||||
|
* @returns {Promise} - 생성된 클럽 정보
|
||||||
|
*/
|
||||||
|
createClub(clubData) {
|
||||||
|
return apiClient.post('/api/admin/clubs', clubData);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 클럽 정보 업데이트
|
* 클럽 정보 업데이트
|
||||||
* @param {Number} id - 클럽 ID
|
* @param {Number} id - 클럽 ID
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const formattedEvent = {
|
const formattedEvent = {
|
||||||
...event,
|
...event,
|
||||||
startDate: dayjs(event.startDate).format('YYYY-MM-DD'),
|
startDate: dayjs(event.startDate).format('YYYY-MM-DDTHH:mm:ssZ'),
|
||||||
endDate: event.endDate ? dayjs(event.endDate).format('YYYY-MM-DD') : null
|
endDate: event.endDate ? dayjs(event.endDate).format('YYYY-MM-DDTHH:mm:ssZ') : null
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await apiClient.post('/api/club/events/create', formattedEvent);
|
const response = await apiClient.post('/api/club/events/create', formattedEvent);
|
||||||
@@ -87,8 +87,8 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const formattedEvent = {
|
const formattedEvent = {
|
||||||
...event,
|
...event,
|
||||||
startDate: dayjs(event.startDate).format('YYYY-MM-DD'),
|
startDate: dayjs(event.startDate).format('YYYY-MM-DDTHH:mm:ssZ'),
|
||||||
endDate: dayjs(event.endDate).format('YYYY-MM-DD')
|
endDate: event.endDate ? dayjs(event.endDate).format('YYYY-MM-DDTHH:mm:ssZ') : null
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await apiClient.put(`/api/club/events/${event.id}`, formattedEvent);
|
const response = await apiClient.put(`/api/club/events/${event.id}`, formattedEvent);
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ import { useToast } from 'primevue/usetoast';
|
|||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useClubStore } from '@/stores/clubStore';
|
import { useClubStore } from '@/stores/clubStore';
|
||||||
import eventService from '@/services/eventService';
|
import eventService from '@/services/eventService';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
import clubService from '@/services/clubService';
|
import clubService from '@/services/clubService';
|
||||||
import ScoreManagement from '@/components/event/ScoreManagement.vue';
|
import ScoreManagement from '@/components/event/ScoreManagement.vue';
|
||||||
import ParticipantManagement from '@/components/event/ParticipantManagement.vue';
|
import ParticipantManagement from '@/components/event/ParticipantManagement.vue';
|
||||||
@@ -214,14 +215,7 @@ onMounted(async () => {
|
|||||||
// 날짜 포맷 함수
|
// 날짜 포맷 함수
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
if (!date) return '';
|
if (!date) return '';
|
||||||
const d = new Date(date);
|
return dayjs(date).format('YYYY. MM. DD. HH:mm');
|
||||||
return d.toLocaleString('ko-KR', {
|
|
||||||
year: 'numeric',
|
|
||||||
month: '2-digit',
|
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 이벤트 유형에 따른 Badge 스타일
|
// 이벤트 유형에 따른 Badge 스타일
|
||||||
@@ -336,18 +330,14 @@ const saveEvent = async (eventData) => {
|
|||||||
...eventData,
|
...eventData,
|
||||||
clubId: clubId.value
|
clubId: clubId.value
|
||||||
});
|
});
|
||||||
const updatedEvent = response;
|
await fetchEvents(); // 목록 갱신
|
||||||
const index = events.value.findIndex(e => e.id === updatedEvent.id);
|
|
||||||
if (index !== -1) {
|
|
||||||
events.value[index] = updatedEvent;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 이벤트 생성
|
// 이벤트 생성
|
||||||
const response = await eventService.createEvent({
|
const response = await eventService.createEvent({
|
||||||
...eventData,
|
...eventData,
|
||||||
clubId: clubId.value
|
clubId: clubId.value
|
||||||
});
|
});
|
||||||
events.value.push(response);
|
await fetchEvents(); // 목록 갱신
|
||||||
}
|
}
|
||||||
toast.add({
|
toast.add({
|
||||||
severity: 'success',
|
severity: 'success',
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default defineConfig({
|
|||||||
server: {
|
server: {
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
port: 5173,
|
port: 5173,
|
||||||
//strictPort: true,
|
strictPort: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://localhost:3030',
|
target: 'http://localhost:3030',
|
||||||
|
|||||||
Reference in New Issue
Block a user