store backend connect

This commit is contained in:
unknown 2025-06-16 15:24:11 +09:00
parent edaf5da6ed
commit 76a69a6453
5 changed files with 967 additions and 2239 deletions

View File

@ -8,10 +8,10 @@ const getApiUrls = () => {
GATEWAY_URL: config.GATEWAY_URL || 'http://20.1.2.3',
AUTH_URL: 'http://localhost:8081/api/auth',
MEMBER_URL: 'http://localhost:8081/api/member',
STORE_URL: config.STORE_URL || 'http://20.1.2.3/api/store',
STORE_URL: config.STORE_URL || 'http://localhost:8082/api/store',
CONTENT_URL: config.CONTENT_URL || 'http://20.1.2.3/api/content',
MENU_URL: config.MENU_URL || 'http://20.1.2.3/api/menu',
SALES_URL: config.SALES_URL || 'http://20.1.2.3/api/sales',
MENU_URL: config.MENU_URL || 'http://localhost:8082/api/menu',
SALES_URL: config.SALES_URL || 'http://localhost:8082/api/sales',
RECOMMEND_URL: config.RECOMMEND_URL || 'http://20.1.2.3/api/recommendation',
}
}

View File

@ -1,9 +1,9 @@
//* src/services/store.js - 기존 파일 수정 (API 설계서 기준)
import { storeApi, menuApi, salesApi, handleApiError, formatSuccessResponse } from './api.js'
//* src/services/store.js - 매장 서비스 완전 수정
import { storeApi, handleApiError, formatSuccessResponse } from './api.js'
/**
* 매장 관련 API 서비스
* API 설계서 기준으로 수정됨
* 백엔드 Store Controller와 연동 (포트 8082)
*/
class StoreService {
/**
@ -13,171 +13,225 @@ class StoreService {
*/
async registerStore(storeData) {
try {
const response = await storeApi.post('/register', {
console.log('=== 매장 등록 API 호출 ===')
console.log('요청 데이터:', storeData)
// 백엔드 StoreCreateRequest에 맞는 형태로 변환
const requestData = {
storeName: storeData.storeName,
businessType: storeData.businessType,
address: storeData.address,
phoneNumber: storeData.phoneNumber,
businessHours: storeData.businessHours || storeData.operatingHours,
businessHours: storeData.businessHours,
closedDays: storeData.closedDays,
seatCount: storeData.seatCount,
snsAccounts: storeData.snsAccounts || `인스타그램: ${storeData.instaAccount || ''}, 네이버블로그: ${storeData.naverBlogAccount || ''}`,
seatCount: parseInt(storeData.seatCount) || 0,
instaAccounts: storeData.instaAccounts || '',
blogAccounts: storeData.blogAccounts || '',
description: storeData.description || ''
})
return formatSuccessResponse(response.data.data, '매장이 등록되었습니다.')
}
console.log('=== 각 필드 상세 검증 ===')
console.log('storeName:', requestData.storeName, '(타입:', typeof requestData.storeName, ')')
console.log('businessType:', requestData.businessType, '(타입:', typeof requestData.businessType, ')')
console.log('address:', requestData.address, '(타입:', typeof requestData.address, ')')
console.log('seatCount:', requestData.seatCount, '(타입:', typeof requestData.seatCount, ')')
console.log('백엔드 전송 데이터:', requestData)
const response = await storeApi.post('/register', requestData)
console.log('매장 등록 API 응답:', response.data)
// 백엔드 응답 구조에 맞게 처리
if (response.data && (response.data.status === 200 || response.data.success !== false)) {
return {
success: true,
message: response.data.message || '매장이 등록되었습니다.',
data: response.data.data
}
} else {
throw new Error(response.data.message || '매장 등록에 실패했습니다.')
}
} catch (error) {
console.error('매장 등록 실패:', error)
if (error.response) {
console.error('응답 상태:', error.response.status)
console.error('응답 데이터:', error.response.data)
}
return handleApiError(error)
}
}
/**
* 매장 정보 조회 (STR-005: 매장 조회)
* 매장 정보 조회 (STR-005: 매장 정보 관리)
* @returns {Promise<Object>} 매장 정보
*/
async getStore() {
try {
const response = await storeApi.get('/')
return formatSuccessResponse(response.data.data, '매장 정보를 조회했습니다.')
console.log('=== 매장 정보 조회 API 호출 ===')
// URL 슬래시 문제 해결: 빈 문자열로 호출하여 '/api/store'가 되도록 함
const response = await storeApi.get('')
console.log('매장 정보 조회 API 응답:', response.data)
// 백엔드 응답 구조 수정: 디버깅 결과에 맞게 처리
if (response.data && response.data.status === 200 && response.data.data) {
console.log('✅ 매장 정보 조회 성공:', response.data.data)
return {
success: true,
message: response.data.message || '매장 정보를 조회했습니다.',
data: response.data.data
}
} else if (response.data && response.data.status === 404) {
// 매장이 없는 경우
console.log('⚠️ 등록된 매장이 없음')
return {
success: false,
message: '등록된 매장이 없습니다',
data: null
}
} else {
console.warn('예상치 못한 응답 구조:', response.data)
throw new Error(response.data.message || '매장 정보를 찾을 수 없습니다.')
}
} catch (error) {
console.error('매장 정보 조회 실패:', error)
// 404 오류 처리 (매장이 없음)
if (error.response?.status === 404) {
return {
success: false,
message: '등록된 매장이 없습니다',
data: null
}
}
// 500 오류 처리 (서버 내부 오류)
if (error.response?.status === 500) {
console.error('서버 내부 오류 - 백엔드 로그 확인 필요:', error.response?.data)
return {
success: false,
message: '서버 오류가 발생했습니다. 관리자에게 문의하세요.',
data: null
}
}
return handleApiError(error)
}
}
/**
* 매장 정보 수정 (STR-010: 매장 수정)
* @param {number} storeId - 매장 ID (현재는 사용하지 않음 - JWT에서 사용자 확인)
* @param {Object} storeData - 수정할 매장 정보
* @returns {Promise<Object>} 매장 수정 결과
*/
async updateStore(storeData) {
async updateStore(storeId, storeData) {
try {
const response = await storeApi.put('/', {
console.log('=== 매장 정보 수정 API 호출 ===')
console.log('요청 데이터:', storeData)
// 백엔드 StoreUpdateRequest에 맞는 형태로 변환
const requestData = {
storeName: storeData.storeName,
businessType: storeData.businessType,
address: storeData.address,
phoneNumber: storeData.phoneNumber,
businessHours: storeData.businessHours || storeData.operatingHours,
businessHours: storeData.businessHours,
closedDays: storeData.closedDays,
seatCount: storeData.seatCount,
snsAccounts: storeData.snsAccounts || `인스타그램: ${storeData.instaAccount || ''}, 네이버블로그: ${storeData.naverBlogAccount || ''}`,
seatCount: parseInt(storeData.seatCount) || 0,
instaAccounts: storeData.instaAccounts || '',
blogAccounts: storeData.blogAccounts || '',
description: storeData.description || ''
})
return formatSuccessResponse(response.data.data, '매장 정보가 수정되었습니다.')
}
console.log('백엔드 전송 데이터:', requestData)
// PUT 요청 (storeId는 JWT에서 추출하므로 URL에 포함하지 않음)
const response = await storeApi.put('/', requestData)
console.log('매장 정보 수정 API 응답:', response.data)
if (response.data && (response.data.status === 200 || response.data.success !== false)) {
return {
success: true,
message: response.data.message || '매장 정보가 수정되었습니다.',
data: response.data.data
}
} else {
throw new Error(response.data.message || '매장 정보 수정에 실패했습니다.')
}
} catch (error) {
console.error('매장 정보 수정 실패:', error)
return handleApiError(error)
}
}
/**
* 매출 정보 조회 (SAL-005: 매출 조회)
* @param {number} storeId - 매장 ID
* 매출 정보 조회 (STR-020: 대시보드)
* @param {string} period - 조회 기간 (today, week, month, year)
* @returns {Promise<Object>} 매출 정보
*/
async getSales(storeId) {
async getSales(period = 'today') {
try {
const response = await salesApi.get(`/${storeId}`)
return formatSuccessResponse(response.data.data, '매출 정보를 조회했습니다.')
// 현재는 목업 데이터 반환 (추후 실제 API 연동 시 수정)
const mockSalesData = {
todaySales: 150000,
yesterdaySales: 120000,
changeRate: 25.0,
monthlyTarget: 3000000,
achievementRate: 45.2
}
return formatSuccessResponse(mockSalesData, '매출 정보를 조회했습니다.')
} catch (error) {
return handleApiError(error)
}
}
/**
* 메뉴 등록 (MNU-010: 메뉴 등록)
* @param {Object} menuData - 메뉴 정보
* @returns {Promise<Object>} 메뉴 등록 결과
*/
async registerMenu(menuData) {
try {
const response = await menuApi.post('/register', {
menuName: menuData.menuName,
menuCategory: menuData.menuCategory || menuData.category,
menuImage: menuData.menuImage || menuData.image,
price: menuData.price,
description: menuData.description,
isPopular: menuData.isPopular || false,
isRecommended: menuData.isRecommended || false,
})
return formatSuccessResponse(response.data.data, '메뉴가 등록되었습니다.')
} catch (error) {
return handleApiError(error)
}
}
/**
* 메뉴 목록 조회 (MNU-005: 메뉴 조회)
* @param {number} storeId - 매장 ID
* 메뉴 목록 조회 (개발 예정)
* @returns {Promise<Object>} 메뉴 목록
*/
async getMenus(storeId) {
async getMenus() {
try {
const response = await menuApi.get(`/${storeId}`)
return formatSuccessResponse(response.data.data, '메뉴 목록을 조회했습니다.')
} catch (error) {
return handleApiError(error)
}
}
/**
* 메뉴 수정 (MNU-015: 메뉴 수정)
* @param {number} menuId - 메뉴 ID
* @param {Object} menuData - 수정할 메뉴 정보
* @returns {Promise<Object>} 메뉴 수정 결과
*/
async updateMenu(menuId, menuData) {
try {
const response = await menuApi.put(`/${menuId}`, {
menuName: menuData.menuName,
menuCategory: menuData.menuCategory || menuData.category,
menuImage: menuData.menuImage || menuData.image,
price: menuData.price,
description: menuData.description,
isPopular: menuData.isPopular || false,
isRecommended: menuData.isRecommended || false,
})
return formatSuccessResponse(response.data.data, '메뉴가 수정되었습니다.')
} catch (error) {
return handleApiError(error)
}
}
/**
* 메뉴 삭제 (MNU-020: 메뉴 삭제)
* @param {number} menuId - 메뉴 ID
* @returns {Promise<Object>} 메뉴 삭제 결과
*/
async deleteMenu(menuId) {
try {
await menuApi.delete(`/${menuId}`)
return formatSuccessResponse(null, '메뉴가 삭제되었습니다.')
} catch (error) {
return handleApiError(error)
}
}
/**
* 다중 메뉴 삭제
* @param {number[]} menuIds - 삭제할 메뉴 ID 배열
* @returns {Promise<Object>} 삭제 결과
*/
async deleteMenus(menuIds) {
try {
const deletePromises = menuIds.map((menuId) => this.deleteMenu(menuId))
await Promise.all(deletePromises)
return formatSuccessResponse(null, `${menuIds.length}개의 메뉴가 삭제되었습니다.`)
// 현재는 목업 데이터 반환 (추후 실제 API 연동 시 수정)
const mockMenus = [
{
id: 1,
name: '아메리카노',
price: 4000,
category: '커피',
description: '진한 풍미의 아메리카노',
imageUrl: '/images/americano.jpg',
isAvailable: true
},
{
id: 2,
name: '카페라떼',
price: 4500,
category: '커피',
description: '부드러운 우유가 들어간 라떼',
imageUrl: '/images/latte.jpg',
isAvailable: true
}
]
return formatSuccessResponse(mockMenus, '메뉴 목록을 조회했습니다.')
} catch (error) {
return handleApiError(error)
}
}
}
// 싱글톤 인스턴스 생성 및 export
export const storeService = new StoreService()
export default storeService
export default storeService
// 디버깅을 위한 전역 노출 (개발 환경에서만)
if (process.env.NODE_ENV === 'development') {
window.storeService = storeService
}

View File

@ -1,285 +1,205 @@
//* src/store/index.js
/**
* Pinia 스토어 설정
* 전역 상태 관리
*/
//* src/store/index.js - Store 스토어 수정 (fetchMenus 메서드 추가)
import { defineStore } from 'pinia'
import authService from '@/services/auth'
import storeService from '@/services/store'
// 인증 스토어
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null,
token: localStorage.getItem('token'),
refreshToken: localStorage.getItem('refreshToken'),
isAuthenticated: false
}),
getters: {
getUserInfo: (state) => state.user,
isLoggedIn: (state) => state.isAuthenticated && !!state.token
},
actions: {
async login(credentials) {
try {
const response = await authService.login(credentials)
this.setAuth(response.data)
return response
} catch (error) {
this.clearAuth()
throw error
}
},
async register(userData) {
try {
const response = await authService.register(userData)
return response
} catch (error) {
throw error
}
},
async logout() {
try {
if (this.token) {
await authService.logout()
}
} catch (error) {
console.error('로그아웃 오류:', error)
} finally {
this.clearAuth()
}
},
async refreshUserInfo() {
try {
const response = await authService.getUserInfo()
this.user = response.data
this.isAuthenticated = true
return response
} catch (error) {
this.clearAuth()
throw error
}
},
setAuth(authData) {
this.user = authData.user
this.token = authData.accessToken
this.refreshToken = authData.refreshToken
this.isAuthenticated = true
localStorage.setItem('token', authData.accessToken)
localStorage.setItem('refreshToken', authData.refreshToken)
},
clearAuth() {
this.user = null
this.token = null
this.refreshToken = null
this.isAuthenticated = false
localStorage.removeItem('token')
localStorage.removeItem('refreshToken')
}
}
})
// 앱 전역 스토어
export const useAppStore = defineStore('app', {
state: () => ({
loading: false,
snackbar: {
show: false,
message: '',
color: 'success',
timeout: 3000
},
notifications: [],
notificationCount: 0
}),
actions: {
setLoading(status) {
this.loading = status
},
showSnackbar(message, color = 'success', timeout = 3000) {
this.snackbar = {
show: true,
message,
color,
timeout
}
},
hideSnackbar() {
this.snackbar.show = false
},
addNotification(notification) {
this.notifications.unshift({
id: Date.now(),
timestamp: new Date(),
...notification
})
this.notificationCount = this.notifications.length
},
clearNotifications() {
this.notifications = []
this.notificationCount = 0
}
}
})
// 매장 스토어
export const useStoreStore = defineStore('store', {
state: () => ({
storeInfo: null,
loading: false
}),
getters: {
hasStoreInfo: (state) => !!state.storeInfo
},
actions: {
setStoreInfo(storeInfo) {
this.storeInfo = storeInfo
},
async fetchStoreInfo() {
try {
this.loading = true
const response = await storeService.getStore() // getStoreInfo가 아닌 getStore
this.storeInfo = response.data
return response
} catch (error) {
throw error
} finally {
this.loading = false
}
},
async registerStore(storeData) {
try {
this.loading = true
const response = await storeService.registerStore(storeData)
this.storeInfo = response.data
return response
} catch (error) {
throw error
} finally {
this.loading = false
}
},
async updateStore(storeId, storeData) {
try {
this.loading = true
const response = await storeService.updateStore(storeId, storeData)
this.storeInfo = response.data
return response
} catch (error) {
throw error
} finally {
this.loading = false
}
},
async createStoreInfo(storeData) {
try {
this.loading = true
const response = await storeService.createStoreInfo(storeData)
this.storeInfo = response.data
return response
} catch (error) {
throw error
} finally {
this.loading = false
}
}
}
})
// 메뉴 스토어
export const useMenuStore = defineStore('menu', {
state: () => ({
menus: [],
menus: [], // 메뉴 목록 추가
loading: false,
totalCount: 0
error: null
}),
getters: {
getMenuById: (state) => (id) => {
return state.menus.find(menu => menu.id === id)
},
getMenusByCategory: (state) => (category) => {
return state.menus.filter(menu => menu.category === category)
}
hasStoreInfo: (state) => !!state.storeInfo,
isLoading: (state) => state.loading,
hasMenus: (state) => state.menus && state.menus.length > 0
},
actions: {
async fetchMenus() {
/**
* 매장 정보 조회
*/
async fetchStoreInfo() {
console.log('=== Store 스토어: 매장 정보 조회 시작 ===')
this.loading = true
this.error = null
try {
this.loading = true
const response = await storeService.getMenus()
this.menus = response.data
this.totalCount = response.data.length
return response
} catch (error) {
throw error
} finally {
this.loading = false
}
},
async createMenu(menuData) {
try {
this.loading = true
const response = await storeService.createMenu(menuData)
this.menus.push(response.data)
this.totalCount++
return response
} catch (error) {
throw error
} finally {
this.loading = false
}
},
async updateMenu(menuId, menuData) {
try {
this.loading = true
const response = await storeService.updateMenu(menuId, menuData)
const index = this.menus.findIndex(menu => menu.id === menuId)
if (index !== -1) {
this.menus[index] = response.data
// 스토어 서비스 임포트
const { storeService } = await import('@/services/store')
console.log('매장 정보 API 호출')
const result = await storeService.getStore()
console.log('=== Store 스토어: API 응답 분석 ===')
console.log('Result:', result)
console.log('Result.success:', result.success)
console.log('Result.data:', result.data)
console.log('Result.message:', result.message)
if (result.success && result.data) {
// 매장 정보가 있는 경우
console.log('✅ 매장 정보 설정:', result.data)
this.storeInfo = result.data
return { success: true, data: result.data }
} else {
// 매장이 없거나 조회 실패한 경우
console.log('⚠️ 매장 정보 없음 또는 조회 실패')
this.storeInfo = null
if (result.message === '등록된 매장이 없습니다') {
return { success: false, message: '등록된 매장이 없습니다' }
} else {
return { success: false, message: result.message || '매장 정보 조회에 실패했습니다' }
}
}
return response
} catch (error) {
throw error
console.error('=== Store 스토어: 매장 정보 조회 실패 ===')
console.error('Error:', error)
this.error = error.message
this.storeInfo = null
// HTTP 상태 코드별 처리
if (error.response?.status === 404) {
return { success: false, message: '등록된 매장이 없습니다' }
}
if (error.response?.status >= 500) {
return { success: false, message: '서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.' }
}
if (error.response?.status === 401) {
return { success: false, message: '로그인이 필요합니다' }
}
return { success: false, message: error.message || '매장 정보 조회에 실패했습니다' }
} finally {
this.loading = false
}
},
async deleteMenu(menuId) {
/**
* 메뉴 목록 조회 - 추가된 메서드
*/
async fetchMenus() {
console.log('=== Store 스토어: 메뉴 목록 조회 시작 ===')
try {
this.loading = true
await storeService.deleteMenu(menuId)
this.menus = this.menus.filter(menu => menu.id !== menuId)
this.totalCount--
// 현재는 목업 데이터 반환 (추후 실제 API 연동 시 수정)
const mockMenus = [
{
id: 1,
name: '아메리카노',
price: 4000,
category: '커피',
description: '진한 풍미의 아메리카노',
imageUrl: '/images/americano.jpg',
isAvailable: true
},
{
id: 2,
name: '카페라떼',
price: 4500,
category: '커피',
description: '부드러운 우유가 들어간 라떼',
imageUrl: '/images/latte.jpg',
isAvailable: true
},
{
id: 3,
name: '치즈케이크',
price: 6000,
category: '디저트',
description: '진한 크림치즈로 만든 케이크',
imageUrl: '/images/cheesecake.jpg',
isAvailable: false
}
]
this.menus = mockMenus
console.log('✅ 메뉴 목록 설정 완료:', mockMenus)
return { success: true, data: mockMenus }
} catch (error) {
throw error
console.error('메뉴 목록 조회 실패:', error)
this.menus = []
return { success: false, message: '메뉴 목록을 불러오는데 실패했습니다' }
}
},
/**
* 매장 등록
*/
async registerStore(storeData) {
console.log('매장 등록 시작:', storeData)
this.loading = true
this.error = null
try {
const { storeService } = await import('@/services/store')
const result = await storeService.registerStore(storeData)
console.log('매장 등록 결과:', result)
if (result.success) {
// 등록 성공 후 매장 정보 다시 조회
await this.fetchStoreInfo()
return result
} else {
this.error = result.message
return result
}
} catch (error) {
console.error('매장 등록 실패:', error)
this.error = error.message
return { success: false, message: error.message || '매장 등록에 실패했습니다' }
} finally {
this.loading = false
}
},
/**
* 매장 정보 수정
*/
async updateStore(storeId, storeData) {
console.log('매장 정보 수정 시작:', { storeId, storeData })
this.loading = true
this.error = null
try {
const { storeService } = await import('@/services/store')
const result = await storeService.updateStore(storeId, storeData)
console.log('매장 수정 결과:', result)
if (result.success) {
// 수정 성공 후 매장 정보 다시 조회
await this.fetchStoreInfo()
return result
} else {
this.error = result.message
return result
}
} catch (error) {
console.error('매장 수정 실패:', error)
this.error = error.message
return { success: false, message: error.message || '매장 수정에 실패했습니다' }
} finally {
this.loading = false
}
},
/**
* 매장 정보 초기화
*/
clearStoreInfo() {
this.storeInfo = null
this.menus = []
this.error = null
this.loading = false
}
}
})

View File

@ -1,202 +1,233 @@
//* src/store/store.js 수정 - 기존 구조 유지하고 API 연동만 추가
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import storeService from '@/services/store'
//* src/services/store.js - 매장 서비스 완전 수정
import { storeApi, handleApiError, formatSuccessResponse } from './api.js'
export const useStoreStore = defineStore('store', () => {
// 기존 상태들 유지
const storeInfo = ref(null)
const menus = ref([])
const salesData = ref(null)
const isLoading = ref(false)
// 기존 computed 속성들 유지
const hasStoreInfo = computed(() => !!storeInfo.value)
const menuCount = computed(() => menus.value?.length || 0)
// fetchStoreInfo를 실제 API 호출로 수정
const fetchStoreInfo = async () => {
if (import.meta.env.DEV) {
console.log('개발 모드: 매장 정보 API 호출 건너뛰기')
return { success: true }
}
isLoading.value = true
/**
* 매장 관련 API 서비스
* 백엔드 Store Controller와 연동 (포트 8082)
*/
class StoreService {
/**
* 매장 등록 (STR-015: 매장 등록)
* @param {Object} storeData - 매장 정보
* @returns {Promise<Object>} 매장 등록 결과
*/
async registerStore(storeData) {
try {
const result = await storeService.getStore()
console.log('=== 매장 등록 API 호출 ===')
console.log('요청 데이터:', storeData)
if (result.success) {
storeInfo.value = result.data
return { success: true }
} else {
console.warn('매장 정보 조회 실패:', result.message)
return { success: false, error: result.message }
}
} catch (error) {
console.warn('매장 정보 조회 실패:', error)
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
}
}
// saveStoreInfo를 실제 API 호출로 수정
const saveStoreInfo = async (storeData) => {
isLoading.value = true
try {
let result
if (storeInfo.value) {
// 기존 매장 정보 수정
result = await storeService.updateStore(storeData)
} else {
// 새 매장 등록
result = await storeService.registerStore(storeData)
// 백엔드 StoreCreateRequest에 맞는 형태로 변환
const requestData = {
storeName: storeData.storeName,
businessType: storeData.businessType,
address: storeData.address,
phoneNumber: storeData.phoneNumber,
businessHours: storeData.businessHours,
closedDays: storeData.closedDays,
seatCount: parseInt(storeData.seatCount) || 0,
instaAccounts: storeData.instaAccounts || '',
blogAccounts: storeData.blogAccounts || '',
description: storeData.description || ''
}
if (result.success) {
storeInfo.value = result.data
return { success: true, message: '매장 정보가 저장되었습니다.' }
} else {
return { success: false, error: result.message }
}
} catch (error) {
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
}
}
// fetchMenus를 실제 API 호출로 수정
const fetchMenus = async () => {
if (!storeInfo.value?.storeId) {
console.warn('매장 ID가 없어 메뉴를 조회할 수 없습니다.')
return { success: false, error: '매장 정보가 필요합니다.' }
}
isLoading.value = true
try {
const result = await storeService.getMenus(storeInfo.value.storeId)
console.log('=== 각 필드 상세 검증 ===')
console.log('storeName:', requestData.storeName, '(타입:', typeof requestData.storeName, ')')
console.log('businessType:', requestData.businessType, '(타입:', typeof requestData.businessType, ')')
console.log('address:', requestData.address, '(타입:', typeof requestData.address, ')')
console.log('seatCount:', requestData.seatCount, '(타입:', typeof requestData.seatCount, ')')
if (result.success) {
menus.value = result.data
return { success: true }
} else {
return { success: false, error: result.message }
}
} catch (error) {
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
}
}
// 메뉴 관련 메서드들 API 연동 추가
const saveMenu = async (menuData) => {
isLoading.value = true
try {
const result = await storeService.registerMenu(menuData)
console.log('백엔드 전송 데이터:', requestData)
if (result.success) {
// 메뉴 목록 새로고침
await fetchMenus()
return { success: true, message: '메뉴가 등록되었습니다.' }
} else {
return { success: false, error: result.message }
}
} catch (error) {
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
}
}
const updateMenu = async (menuId, menuData) => {
isLoading.value = true
try {
const result = await storeService.updateMenu(menuId, menuData)
const response = await storeApi.post('/register', requestData)
if (result.success) {
// 메뉴 목록 새로고침
await fetchMenus()
return { success: true, message: '메뉴가 수정되었습니다.' }
} else {
return { success: false, error: result.message }
}
} catch (error) {
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
}
}
const deleteMenu = async (menuId) => {
isLoading.value = true
try {
const result = await storeService.deleteMenu(menuId)
console.log('매장 등록 API 응답:', response.data)
if (result.success) {
// 메뉴 목록 새로고침
await fetchMenus()
return { success: true, message: '메뉴가 삭제되었습니다.' }
// 백엔드 응답 구조에 맞게 처리
if (response.data && (response.data.status === 200 || response.data.success !== false)) {
return {
success: true,
message: response.data.message || '매장이 등록되었습니다.',
data: response.data.data
}
} else {
return { success: false, error: result.message }
throw new Error(response.data.message || '매장 등록에 실패했습니다.')
}
} catch (error) {
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
}
}
// 매출 정보 조회 추가
const fetchSalesData = async () => {
if (!storeInfo.value?.storeId) {
return { success: false, error: '매장 정보가 필요합니다.' }
}
isLoading.value = true
try {
const result = await storeService.getSales(storeInfo.value.storeId)
console.error('매장 등록 실패:', error)
if (result.success) {
salesData.value = result.data
return { success: true }
} else {
return { success: false, error: result.message }
if (error.response) {
console.error('응답 상태:', error.response.status)
console.error('응답 데이터:', error.response.data)
}
} catch (error) {
return { success: false, error: '네트워크 오류가 발생했습니다.' }
} finally {
isLoading.value = false
return handleApiError(error)
}
}
return {
// 상태
storeInfo,
menus,
salesData,
isLoading,
// 컴퓨티드
hasStoreInfo,
menuCount,
// 메서드
fetchStoreInfo,
saveStoreInfo,
fetchMenus,
saveMenu,
updateMenu,
deleteMenu,
fetchSalesData
/**
* 매장 정보 조회 (STR-005: 매장 정보 관리)
* @returns {Promise<Object>} 매장 정보
*/
async getStore() {
try {
console.log('=== 매장 정보 조회 API 호출 ===')
const response = await storeApi.get('/')
console.log('매장 정보 조회 API 응답:', response.data)
// 백엔드 응답 구조에 맞게 처리
if (response.data && response.data.data) {
return {
success: true,
message: '매장 정보를 조회했습니다.',
data: response.data.data
}
} else if (response.data && response.data.data === null) {
// 매장이 없는 경우
return {
success: false,
message: '등록된 매장이 없습니다',
data: null
}
} else {
throw new Error(response.data.message || '매장 정보를 찾을 수 없습니다.')
}
} catch (error) {
console.error('매장 정보 조회 실패:', error)
// 404 오류 처리 (매장이 없음)
if (error.response?.status === 404) {
return {
success: false,
message: '등록된 매장이 없습니다',
data: null
}
}
// 500 오류 처리 (서버 내부 오류)
if (error.response?.status === 500) {
console.error('서버 내부 오류 - 백엔드 로그 확인 필요:', error.response?.data)
return {
success: false,
message: '서버 오류가 발생했습니다. 관리자에게 문의하세요.',
data: null
}
}
return handleApiError(error)
}
}
})
/**
* 매장 정보 수정 (STR-010: 매장 수정)
* @param {number} storeId - 매장 ID (현재는 사용하지 않음 - JWT에서 사용자 확인)
* @param {Object} storeData - 수정할 매장 정보
* @returns {Promise<Object>} 매장 수정 결과
*/
async updateStore(storeId, storeData) {
try {
console.log('=== 매장 정보 수정 API 호출 ===')
console.log('요청 데이터:', storeData)
// 백엔드 StoreUpdateRequest에 맞는 형태로 변환
const requestData = {
storeName: storeData.storeName,
businessType: storeData.businessType,
address: storeData.address,
phoneNumber: storeData.phoneNumber,
businessHours: storeData.businessHours,
closedDays: storeData.closedDays,
seatCount: parseInt(storeData.seatCount) || 0,
instaAccounts: storeData.instaAccounts || '',
blogAccounts: storeData.blogAccounts || '',
description: storeData.description || ''
}
console.log('백엔드 전송 데이터:', requestData)
// PUT 요청 (storeId는 JWT에서 추출하므로 URL에 포함하지 않음)
const response = await storeApi.put('/', requestData)
console.log('매장 정보 수정 API 응답:', response.data)
if (response.data && (response.data.status === 200 || response.data.success !== false)) {
return {
success: true,
message: response.data.message || '매장 정보가 수정되었습니다.',
data: response.data.data
}
} else {
throw new Error(response.data.message || '매장 정보 수정에 실패했습니다.')
}
} catch (error) {
console.error('매장 정보 수정 실패:', error)
return handleApiError(error)
}
}
/**
* 매출 정보 조회 (STR-020: 대시보드)
* @param {string} period - 조회 기간 (today, week, month, year)
* @returns {Promise<Object>} 매출 정보
*/
async getSales(period = 'today') {
try {
// 현재는 목업 데이터 반환 (추후 실제 API 연동 시 수정)
const mockSalesData = {
todaySales: 150000,
yesterdaySales: 120000,
changeRate: 25.0,
monthlyTarget: 3000000,
achievementRate: 45.2
}
return formatSuccessResponse(mockSalesData, '매출 정보를 조회했습니다.')
} catch (error) {
return handleApiError(error)
}
}
/**
* 메뉴 목록 조회 (개발 예정)
* @returns {Promise<Object>} 메뉴 목록
*/
async getMenus() {
try {
// 현재는 목업 데이터 반환 (추후 실제 API 연동 시 수정)
const mockMenus = [
{
id: 1,
name: '아메리카노',
price: 4000,
category: '커피',
description: '진한 풍미의 아메리카노',
imageUrl: '/images/americano.jpg',
isAvailable: true
},
{
id: 2,
name: '카페라떼',
price: 4500,
category: '커피',
description: '부드러운 우유가 들어간 라떼',
imageUrl: '/images/latte.jpg',
isAvailable: true
}
]
return formatSuccessResponse(mockMenus, '메뉴 목록을 조회했습니다.')
} catch (error) {
return handleApiError(error)
}
}
}
// 싱글톤 인스턴스 생성 및 export
export const storeService = new StoreService()
export default storeService
// 디버깅을 위한 전역 노출 (개발 환경에서만)
if (process.env.NODE_ENV === 'development') {
window.storeService = storeService
}

File diff suppressed because it is too large Load Diff