storeManagement contentmanagement edit
This commit is contained in:
parent
7315bac5a3
commit
e0a23ed6d2
@ -19,53 +19,308 @@ export const useContentStore = defineStore('content', () => {
|
||||
dateRange: 'all',
|
||||
})
|
||||
|
||||
// 임시 데이터 (실제로는 API에서 가져옴)
|
||||
// 풍부한 더미 데이터
|
||||
const sampleContents = [
|
||||
{
|
||||
id: 1,
|
||||
title: '떡볶이 신메뉴 출시 이벤트',
|
||||
title: '🌶️ 떡볶이 신메뉴 출시 이벤트',
|
||||
type: 'sns',
|
||||
platform: 'instagram',
|
||||
content: '🌶️ 떡볶이 신메뉴 출시! 치즈가 듬뿍 들어간 치즈떡볶이가 새로 나왔어요!',
|
||||
hashtags: ['떡볶이', '신메뉴', '치즈떡볶이', '맛집'],
|
||||
platform: 'INSTAGRAM',
|
||||
content: '🌶️ 떡볶이 신메뉴 출시! 치즈가 듬뿍 들어간 치즈떡볶이가 새로 나왔어요! 매콤한 떡볶이와 고소한 치즈의 완벽한 조화✨\n\n#떡볶이 #신메뉴 #치즈떡볶이 #맛집 #분식 #매콤달콤',
|
||||
hashtags: ['떡볶이', '신메뉴', '치즈떡볶이', '맛집', '분식', '매콤달콤'],
|
||||
images: ['/images/menu-placeholder.png'],
|
||||
status: 'published',
|
||||
status: 'PUBLISHED',
|
||||
views: 1240,
|
||||
likes: 85,
|
||||
comments: 12,
|
||||
createdAt: new Date('2024-01-15T10:30:00'),
|
||||
publishedAt: new Date('2024-01-15T14:00:00'),
|
||||
createdAt: '2024-01-15T10:30:00',
|
||||
publishedAt: '2024-01-15T14:00:00',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: '매장 소개 포스터',
|
||||
title: '📸 우리 매장 소개 포스터',
|
||||
type: 'poster',
|
||||
platform: 'blog',
|
||||
content: '우리 매장을 소개하는 포스터입니다.',
|
||||
hashtags: ['매장소개', '분식집', '맛집'],
|
||||
platform: 'POSTER',
|
||||
content: '따뜻한 분위기의 우리 매장을 소개합니다. 정성스럽게 만든 음식으로 여러분을 맞이하겠습니다.',
|
||||
hashtags: ['매장소개', '분식집', '맛집', '정성'],
|
||||
images: ['/images/store-placeholder.png'],
|
||||
status: 'draft',
|
||||
status: 'DRAFT',
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
createdAt: new Date('2024-01-14T16:20:00'),
|
||||
createdAt: '2024-01-14T16:20:00',
|
||||
publishedAt: null,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: '할인 이벤트 안내',
|
||||
title: '🎉 특별 할인 이벤트 안내',
|
||||
type: 'sns',
|
||||
platform: 'instagram',
|
||||
content: '🎉 특별 할인 이벤트! 오늘 하루만 모든 메뉴 20% 할인!',
|
||||
hashtags: ['할인', '이벤트', '특가', '분식'],
|
||||
images: ['/images/ai-character.png'],
|
||||
status: 'scheduled',
|
||||
platform: 'INSTAGRAM',
|
||||
content: '🎉 오늘 하루만 특별 할인! 모든 메뉴 20% 할인 이벤트 진행중🔥\n\n놓치면 후회할 기회! 지금 바로 방문하세요!\n\n⏰ 할인 시간: 오후 6시까지\n📍 위치: 서울 강남구 테헤란로 123',
|
||||
hashtags: ['할인', '이벤트', '특가', '분식', '강남맛집'],
|
||||
images: ['/images/event-poster.png'],
|
||||
status: 'PUBLISHED',
|
||||
views: 892,
|
||||
likes: 45,
|
||||
comments: 8,
|
||||
createdAt: '2024-01-13T09:15:00',
|
||||
publishedAt: '2024-01-13T12:00:00',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: '🍜 김치찌개 맛집 블로그 포스팅',
|
||||
type: 'blog',
|
||||
platform: 'NAVER_BLOG',
|
||||
content: '추운 겨울, 몸을 따뜻하게 해줄 김치찌개 한 그릇은 어떠세요? 우리 매장의 시그니처 메뉴인 김치찌개를 소개합니다.\n\n✅ 3년 묵은 김치 사용\n✅ 국내산 돼지고기\n✅ 진한 국물맛\n✅ 푸짐한 양\n\n한 번 맛보시면 계속 생각나는 그런 맛입니다!',
|
||||
hashtags: ['김치찌개', '맛집', '추천메뉴', '겨울음식', '따뜻한국물'],
|
||||
images: ['/images/kimchi-jjigae.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 2156,
|
||||
likes: 123,
|
||||
comments: 15,
|
||||
createdAt: '2024-01-12T14:45:00',
|
||||
publishedAt: '2024-01-12T16:00:00',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: '🥢 순대국밥 홍보 포스터',
|
||||
type: 'poster',
|
||||
platform: 'POSTER',
|
||||
content: '진짜 맛있는 순대국밥! 24시간 끓인 진한 국물과 신선한 순대로 만든 특별한 한 그릇',
|
||||
hashtags: ['순대국밥', '24시간', '진한국물', '신선한순대'],
|
||||
images: ['/images/sundae-soup.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 567,
|
||||
likes: 34,
|
||||
comments: 3,
|
||||
createdAt: '2024-01-11T11:20:00',
|
||||
publishedAt: '2024-01-11T15:30:00',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
title: '🌈 컬러풀 떡볶이 인스타 스토리',
|
||||
type: 'sns',
|
||||
platform: 'INSTAGRAM',
|
||||
content: '무지개 떡볶이 만들어봤어요! 🌈 천연 색소로 만든 건강한 컬러 떡볶이✨ 맛도 색깔만큼 다양해요!\n\n빨강: 매운맛 🔥\n노랑: 치즈맛 🧀\n초록: 깻잎맛 🌿\n보라: 자색고구마맛 🍠',
|
||||
hashtags: ['컬러떡볶이', '무지개떡볶이', '천연색소', '건강한간식', '예쁜음식'],
|
||||
images: ['/images/colorful-tteokbokki.jpg'],
|
||||
status: 'DRAFT',
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
createdAt: new Date('2024-01-13T09:15:00'),
|
||||
scheduledAt: new Date('2024-01-16T12:00:00'),
|
||||
createdAt: '2024-01-10T13:30:00',
|
||||
publishedAt: null,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
title: '🍖 불고기 김밥 신메뉴 소개',
|
||||
type: 'blog',
|
||||
platform: 'NAVER_BLOG',
|
||||
content: '달콤짭짤한 불고기와 신선한 채소가 들어간 불고기 김밥이 새로 출시되었습니다!\n\n🥩 국내산 소고기 불고기\n🥬 신선한 상추와 당근\n🍚 고슬고슬한 밥\n🥒 아삭한 단무지\n\n한 입 베어물면 입 안 가득 퍼지는 불고기의 달콤함과 채소의 아삭함이 조화롭게 어우러집니다.',
|
||||
hashtags: ['불고기김밥', '신메뉴', '국내산소고기', '신선한채소', '달콤짭짤'],
|
||||
images: ['/images/bulgogi-kimbap.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 1834,
|
||||
likes: 76,
|
||||
comments: 9,
|
||||
createdAt: '2024-01-09T16:15:00',
|
||||
publishedAt: '2024-01-09T18:00:00',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: '🎊 개업 1주년 기념 이벤트',
|
||||
type: 'poster',
|
||||
platform: 'POSTER',
|
||||
content: '감사합니다! 개업 1주년을 맞아 특별 이벤트를 준비했습니다. 고객님들의 사랑에 보답하는 마음으로!',
|
||||
hashtags: ['1주년', '감사이벤트', '특별할인', '기념일'],
|
||||
images: ['/images/anniversary-event.jpg'],
|
||||
status: 'DRAFT',
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
createdAt: '2024-01-08T10:00:00',
|
||||
publishedAt: null,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
title: '🍲 라면 끓이기 꿀팁 공유',
|
||||
type: 'sns',
|
||||
platform: 'NAVER_BLOG',
|
||||
content: '집에서도 맛있는 라면 끓이는 법! 우리 매장 셰프가 알려주는 특별한 비법을 공개합니다.\n\n1️⃣ 물이 끓기 시작할 때 면 투입\n2️⃣ 스프는 면이 익은 후 넣기\n3️⃣ 계란은 마지막 1분에 추가\n4️⃣ 파는 불을 끄기 직전에!\n\n이 방법으로 끓이면 훨씬 더 맛있어요! 한번 시도해보세요 😊',
|
||||
hashtags: ['라면끓이기', '꿀팁', '요리비법', '맛있는라면', '셰프추천'],
|
||||
images: ['/images/ramen-cooking.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 3245,
|
||||
likes: 189,
|
||||
comments: 27,
|
||||
createdAt: '2024-01-07T12:30:00',
|
||||
publishedAt: '2024-01-07T14:00:00',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
title: '🥟 수제 만두 제작 과정',
|
||||
type: 'sns',
|
||||
platform: 'INSTAGRAM',
|
||||
content: '손으로 직접 빚는 우리 매장의 수제 만두! 👐\n\n매일 아침 일찍 와서 정성스럽게 만듭니다 🥟\n신선한 재료만 사용해요!\n\n📹 만두 빚는 과정 영상도 준비했어요\n👀 스토리에서 확인하세요!',
|
||||
hashtags: ['수제만두', '정성', '신선한재료', '매일제작', '장인정신'],
|
||||
images: ['/images/handmade-mandu.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 987,
|
||||
likes: 67,
|
||||
comments: 5,
|
||||
createdAt: '2024-01-06T08:45:00',
|
||||
publishedAt: '2024-01-06T10:00:00',
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
title: '❄️ 겨울 한정 메뉴 출시',
|
||||
type: 'poster',
|
||||
platform: 'POSTER',
|
||||
content: '추운 겨울을 따뜻하게! 겨울 한정 메뉴들이 출시되었습니다. 몸과 마음을 따뜻하게 해드릴게요.',
|
||||
hashtags: ['겨울한정', '따뜻한음식', '한정메뉴', '계절메뉴'],
|
||||
images: ['/images/winter-menu.jpg'],
|
||||
status: 'DRAFT',
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
createdAt: '2024-01-05T15:20:00',
|
||||
publishedAt: null,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
title: '🍜 우동 맛집 후기 모음',
|
||||
type: 'blog',
|
||||
platform: 'NAVER_BLOG',
|
||||
content: '고객님들이 남겨주신 우동 후기를 모아봤습니다! 정말 감사한 마음입니다 💕\n\n"국물이 정말 진해요!"\n"면발이 쫄깃쫄깃해서 좋아요"\n"야채가 신선하고 양도 많아요"\n"사장님이 친절하세요"\n\n앞으로도 더 맛있는 우동으로 보답하겠습니다!',
|
||||
hashtags: ['우동', '고객후기', '진한국물', '쫄깃한면', '신선한야채'],
|
||||
images: ['/images/udon-reviews.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 1456,
|
||||
likes: 89,
|
||||
comments: 12,
|
||||
createdAt: '2024-01-04T14:10:00',
|
||||
publishedAt: '2024-01-04T16:30:00',
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
title: '🎯 주말 특가 이벤트',
|
||||
type: 'sns',
|
||||
platform: 'INSTAGRAM',
|
||||
content: '주말 특가 이벤트! 🎯\n\n토요일, 일요일 이틀간만!\n모든 음료 50% 할인! 🥤\n\n✅ 콜라, 사이다\n✅ 주스류\n✅ 전통차\n✅ 커피\n\n주말에 가족, 친구들과 함께 오세요! 👨👩👧👦',
|
||||
hashtags: ['주말특가', '음료할인', '50%할인', '가족외식', '친구모임'],
|
||||
images: ['/images/weekend-drink-sale.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 1123,
|
||||
likes: 78,
|
||||
comments: 14,
|
||||
createdAt: '2024-01-03T11:00:00',
|
||||
publishedAt: '2024-01-03T13:00:00',
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
title: '🏆 맛집 인증서 획득!',
|
||||
type: 'poster',
|
||||
platform: 'POSTER',
|
||||
content: '드디어! 지역 맛집 인증서를 받았습니다! 고객님들의 사랑 덕분입니다. 감사합니다!',
|
||||
hashtags: ['맛집인증', '지역맛집', '인증서', '고객감사'],
|
||||
images: ['/images/restaurant-certificate.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 756,
|
||||
likes: 124,
|
||||
comments: 18,
|
||||
createdAt: '2024-01-02T09:30:00',
|
||||
publishedAt: '2024-01-02T11:00:00',
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
title: '🌟 2024년 신년 인사',
|
||||
type: 'sns',
|
||||
platform: 'NAVER_BLOG',
|
||||
content: '2024년 새해가 밝았습니다! ✨\n\n지난 한 해 동안 저희 매장을 사랑해주신 모든 고객님들께 진심으로 감사드립니다.\n\n새해에도 더욱 맛있는 음식과 따뜻한 서비스로 보답하겠습니다.\n\n🎊 새해 복 많이 받으세요! 🎊\n\n올해도 많은 관심과 사랑 부탁드립니다!',
|
||||
hashtags: ['신년인사', '새해복', '고객감사', '2024년', '따뜻한서비스'],
|
||||
images: ['/images/new-year-greeting.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 2341,
|
||||
likes: 156,
|
||||
comments: 23,
|
||||
createdAt: '2024-01-01T00:00:00',
|
||||
publishedAt: '2024-01-01T09:00:00',
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
title: '🍕 피자떡볶이 실험중!',
|
||||
type: 'sns',
|
||||
platform: 'INSTAGRAM',
|
||||
content: '새로운 메뉴 개발중! 🍕+🌶️\n\n피자떡볶이가 과연 맛있을까요?\nR&D 중인 신메뉴를 살짝 공개! 👀\n\n토마토 소스 베이스에\n모짜렐라 치즈 토핑\n바질과 오레가노 향신료까지!\n\n출시 전 맛보기 이벤트도 계획중이에요!',
|
||||
hashtags: ['피자떡볶이', '신메뉴개발', 'R&D', '실험적메뉴', '맛보기이벤트'],
|
||||
images: ['/images/pizza-tteokbokki.jpg'],
|
||||
status: 'DRAFT',
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
createdAt: '2023-12-30T16:45:00',
|
||||
publishedAt: null,
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
title: '🎄 크리스마스 특별 메뉴',
|
||||
type: 'poster',
|
||||
platform: 'POSTER',
|
||||
content: '크리스마스를 맛있게! 특별한 날을 위한 특별한 메뉴들을 준비했습니다.',
|
||||
hashtags: ['크리스마스', '특별메뉴', '연말', '특별한날'],
|
||||
images: ['/images/christmas-menu.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 1678,
|
||||
likes: 93,
|
||||
comments: 7,
|
||||
createdAt: '2023-12-20T10:15:00',
|
||||
publishedAt: '2023-12-20T12:00:00',
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
title: '🔥 매운맛 도전 이벤트',
|
||||
type: 'sns',
|
||||
platform: 'INSTAGRAM',
|
||||
content: '매운맛 도전자 모집! 🔥🔥🔥\n\n👹 지옥 떡볶이 도전!\n🌶️ 매운맛 단계별 도전\n🏅 완주시 상품 증정\n📹 도전 영상 촬영 가능\n\n용기있는 분들의 도전을 기다립니다!\n(단, 매운 것 못 드시는 분은 조심하세요 😅)',
|
||||
hashtags: ['매운맛도전', '지옥떡볶이', '도전이벤트', '상품증정', '용기있는자'],
|
||||
images: ['/images/spicy-challenge.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 2567,
|
||||
likes: 234,
|
||||
comments: 45,
|
||||
createdAt: '2023-12-15T14:20:00',
|
||||
publishedAt: '2023-12-15T15:00:00',
|
||||
},
|
||||
{
|
||||
id: 19,
|
||||
title: '☕ 겨울 음료 메뉴 소개',
|
||||
type: 'blog',
|
||||
platform: 'NAVER_BLOG',
|
||||
content: '추운 겨울, 따뜻한 음료 한 잔은 어떠세요? ☕\n\n우리 매장의 겨울 음료 메뉴를 소개합니다:\n\n🍫 진한 핫초콜릿\n🍯 꿀유자차\n🌿 생강차\n☕ 아메리카노\n🥛 따뜻한 우유\n\n모든 음료는 직접 우린 차와 신선한 재료로 만듭니다!\n겨울 추위를 이겨내는 따뜻함을 선사해드릴게요.',
|
||||
hashtags: ['겨울음료', '따뜻한차', '핫초콜릿', '꿀유자차', '생강차'],
|
||||
images: ['/images/winter-drinks.jpg'],
|
||||
status: 'PUBLISHED',
|
||||
views: 1234,
|
||||
likes: 67,
|
||||
comments: 8,
|
||||
createdAt: '2023-12-10T13:30:00',
|
||||
publishedAt: '2023-12-10T15:00:00',
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
title: '🍱 도시락 배달 서비스 시작',
|
||||
type: 'poster',
|
||||
platform: 'POSTER',
|
||||
content: '이제 도시락 배달도 가능합니다! 회사나 집에서 편리하게 주문하세요.',
|
||||
hashtags: ['도시락배달', '배달서비스', '회사도시락', '편리한주문'],
|
||||
images: ['/images/lunchbox-delivery.jpg'],
|
||||
status: 'DRAFT',
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
createdAt: '2023-12-05T11:45:00',
|
||||
publishedAt: null,
|
||||
}
|
||||
]
|
||||
|
||||
// Getters
|
||||
@ -90,15 +345,15 @@ export const useContentStore = defineStore('content', () => {
|
||||
})
|
||||
|
||||
const publishedContents = computed(() =>
|
||||
contents.value.filter((content) => content.status === 'published')
|
||||
contents.value.filter((content) => content.status === 'PUBLISHED')
|
||||
)
|
||||
|
||||
const draftContents = computed(() =>
|
||||
contents.value.filter((content) => content.status === 'draft')
|
||||
contents.value.filter((content) => content.status === 'DRAFT')
|
||||
)
|
||||
|
||||
const scheduledContents = computed(() =>
|
||||
contents.value.filter((content) => content.status === 'scheduled')
|
||||
contents.value.filter((content) => content.status === 'SCHEDULED')
|
||||
)
|
||||
|
||||
const recentContents = computed(() => {
|
||||
@ -114,17 +369,18 @@ export const useContentStore = defineStore('content', () => {
|
||||
)
|
||||
|
||||
// Actions
|
||||
const loadContents = async () => {
|
||||
const fetchContents = async () => {
|
||||
try {
|
||||
isLoading.value = true
|
||||
|
||||
// API 호출 시뮬레이션
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
|
||||
// 임시로 샘플 데이터 사용
|
||||
// 더미 데이터 로드
|
||||
contents.value = [...sampleContents]
|
||||
|
||||
console.log('콘텐츠 목록 로드 완료:', contents.value.length)
|
||||
return contents.value
|
||||
} catch (error) {
|
||||
console.error('콘텐츠 로드 실패:', error)
|
||||
throw error
|
||||
@ -133,6 +389,10 @@ export const useContentStore = defineStore('content', () => {
|
||||
}
|
||||
}
|
||||
|
||||
const loadContents = async () => {
|
||||
return await fetchContents()
|
||||
}
|
||||
|
||||
const getContentById = (id) => {
|
||||
return contents.value.find((content) => content.id === parseInt(id))
|
||||
}
|
||||
@ -141,7 +401,7 @@ export const useContentStore = defineStore('content', () => {
|
||||
const newContent = {
|
||||
...content,
|
||||
id: Date.now(), // 임시 ID
|
||||
createdAt: new Date(),
|
||||
createdAt: new Date().toISOString(),
|
||||
views: 0,
|
||||
likes: 0,
|
||||
comments: 0,
|
||||
@ -150,27 +410,66 @@ export const useContentStore = defineStore('content', () => {
|
||||
return newContent
|
||||
}
|
||||
|
||||
const updateContent = (contentId, updatedData) => {
|
||||
const index = contents.value.findIndex((content) => content.id === contentId)
|
||||
if (index !== -1) {
|
||||
contents.value[index] = {
|
||||
...contents.value[index],
|
||||
...updatedData,
|
||||
updatedAt: new Date(),
|
||||
const updateContent = async (contentId, updatedData) => {
|
||||
try {
|
||||
const index = contents.value.findIndex((content) => content.id === contentId)
|
||||
if (index !== -1) {
|
||||
contents.value[index] = {
|
||||
...contents.value[index],
|
||||
...updatedData,
|
||||
updatedAt: new Date().toISOString(),
|
||||
}
|
||||
|
||||
// API 호출 시뮬레이션
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
return contents.value[index]
|
||||
}
|
||||
return contents.value[index]
|
||||
throw new Error('콘텐츠를 찾을 수 없습니다.')
|
||||
} catch (error) {
|
||||
console.error('콘텐츠 수정 실패:', error)
|
||||
throw error
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const deleteContent = (contentId) => {
|
||||
const index = contents.value.findIndex((content) => content.id === contentId)
|
||||
if (index !== -1) {
|
||||
const deletedContent = contents.value[index]
|
||||
contents.value.splice(index, 1)
|
||||
return deletedContent
|
||||
const deleteContent = async (contentId) => {
|
||||
try {
|
||||
const index = contents.value.findIndex((content) => content.id === contentId)
|
||||
if (index !== -1) {
|
||||
const deletedContent = contents.value[index]
|
||||
contents.value.splice(index, 1)
|
||||
|
||||
// API 호출 시뮬레이션
|
||||
await new Promise((resolve) => setTimeout(resolve, 300))
|
||||
|
||||
return deletedContent
|
||||
}
|
||||
throw new Error('콘텐츠를 찾을 수 없습니다.')
|
||||
} catch (error) {
|
||||
console.error('콘텐츠 삭제 실패:', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMultipleContents = async (contentIds) => {
|
||||
try {
|
||||
// API 호출 시뮬레이션
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
const deletedContents = []
|
||||
contentIds.forEach(id => {
|
||||
const index = contents.value.findIndex((content) => content.id === id)
|
||||
if (index !== -1) {
|
||||
deletedContents.push(contents.value[index])
|
||||
contents.value.splice(index, 1)
|
||||
}
|
||||
})
|
||||
|
||||
return deletedContents
|
||||
} catch (error) {
|
||||
console.error('콘텐츠 일괄 삭제 실패:', error)
|
||||
throw error
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const publishContent = async (contentId) => {
|
||||
@ -181,8 +480,8 @@ export const useContentStore = defineStore('content', () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
|
||||
const content = updateContent(contentId, {
|
||||
status: 'published',
|
||||
publishedAt: new Date(),
|
||||
status: 'PUBLISHED',
|
||||
publishedAt: new Date().toISOString(),
|
||||
})
|
||||
|
||||
console.log('콘텐츠 발행 완료:', content?.title)
|
||||
@ -203,8 +502,8 @@ export const useContentStore = defineStore('content', () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
const content = updateContent(contentId, {
|
||||
status: 'scheduled',
|
||||
scheduledAt: new Date(scheduledTime),
|
||||
status: 'SCHEDULED',
|
||||
scheduledAt: new Date(scheduledTime).toISOString(),
|
||||
})
|
||||
|
||||
console.log('콘텐츠 예약 완료:', content?.title)
|
||||
@ -231,7 +530,7 @@ export const useContentStore = defineStore('content', () => {
|
||||
content: `AI가 생성한 ${options.type} 콘텐츠입니다. ${options.description || ''}`,
|
||||
hashtags: options.hashtags || [],
|
||||
images: options.images || [],
|
||||
status: 'draft',
|
||||
status: 'DRAFT',
|
||||
}
|
||||
|
||||
const newContent = addContent(generatedContent)
|
||||
@ -285,10 +584,12 @@ export const useContentStore = defineStore('content', () => {
|
||||
totalLikes,
|
||||
// Actions
|
||||
loadContents,
|
||||
fetchContents,
|
||||
getContentById,
|
||||
addContent,
|
||||
updateContent,
|
||||
deleteContent,
|
||||
deleteMultipleContents,
|
||||
publishContent,
|
||||
scheduleContent,
|
||||
generateContent,
|
||||
@ -297,4 +598,4 @@ export const useContentStore = defineStore('content', () => {
|
||||
setCurrentContent,
|
||||
clearCurrentContent,
|
||||
}
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
@ -466,10 +466,532 @@
|
||||
>
|
||||
{{ snackbar.message }}
|
||||
</v-snackbar>
|
||||
|
||||
<!-- 매장 등록/수정 다이얼로그 -->
|
||||
<v-dialog
|
||||
v-model="showCreateDialog"
|
||||
max-width="800"
|
||||
persistent
|
||||
scrollable
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="pa-4">
|
||||
<span class="text-h6">{{ editMode ? '매장 정보 수정' : '매장 정보 등록' }}</span>
|
||||
<v-spacer />
|
||||
</v-card-title>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-text class="pa-6" style="max-height: 500px;">
|
||||
<v-form ref="storeForm" v-model="formValid">
|
||||
<v-row>
|
||||
<!-- 매장 이미지 -->
|
||||
<v-col cols="12">
|
||||
<h4 class="text-subtitle-1 font-weight-bold mb-3">매장 이미지</h4>
|
||||
<div class="text-center mb-4">
|
||||
<v-avatar size="120" class="mb-3">
|
||||
<v-img
|
||||
:src="formData.imageUrl || '/images/store-placeholder.png'"
|
||||
alt="매장 이미지"
|
||||
/>
|
||||
</v-avatar>
|
||||
<br>
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
prepend-icon="mdi-camera"
|
||||
@click="selectImage"
|
||||
>
|
||||
이미지 선택
|
||||
</v-btn>
|
||||
<input
|
||||
ref="imageInput"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
style="display: none;"
|
||||
@change="handleImageUpload"
|
||||
>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
<!-- 기본 정보 -->
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="formData.storeName"
|
||||
label="매장명 *"
|
||||
variant="outlined"
|
||||
:rules="[v => !!v || '매장명을 입력해주세요']"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-select
|
||||
v-model="formData.businessType"
|
||||
label="업종 *"
|
||||
variant="outlined"
|
||||
:items="businessTypes"
|
||||
:rules="[v => !!v || '업종을 선택해주세요']"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="formData.ownerName"
|
||||
label="사업자명 *"
|
||||
variant="outlined"
|
||||
:rules="[v => !!v || '사업자명을 입력해주세요']"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="formData.businessNumber"
|
||||
label="사업자등록번호 *"
|
||||
variant="outlined"
|
||||
:rules="businessNumberRules"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-text-field
|
||||
v-model="formData.address"
|
||||
label="주소 *"
|
||||
variant="outlined"
|
||||
:rules="[v => !!v || '주소를 입력해주세요']"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="formData.phoneNumber"
|
||||
label="연락처 *"
|
||||
variant="outlined"
|
||||
:rules="phoneRules"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model.number="formData.seatCount"
|
||||
label="좌석 수"
|
||||
variant="outlined"
|
||||
type="number"
|
||||
min="0"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- SNS 정보 -->
|
||||
<div class="form-section">
|
||||
<h3 class="text-h6 font-weight-bold mb-4">SNS 계정 정보</h3>
|
||||
|
||||
<v-row>
|
||||
<!-- 인스타그램 -->
|
||||
<v-col cols="12" md="6">
|
||||
<div class="d-flex align-center mb-2">
|
||||
<v-icon color="purple" class="mr-2">mdi-instagram</v-icon>
|
||||
<span class="text-subtitle-2 font-weight-medium">인스타그램</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2 align-center">
|
||||
<v-text-field
|
||||
v-model="formData.instagramUrl"
|
||||
placeholder="@계정명 또는 URL 입력"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
prepend-inner-icon="mdi-at"
|
||||
hide-details="auto"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
<v-btn
|
||||
color="purple"
|
||||
size="small"
|
||||
variant="tonal"
|
||||
:loading="snsCheckLoading.instagram"
|
||||
@click="checkSnsConnection('instagram')"
|
||||
>
|
||||
연동 확인
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
<!-- 네이버 블로그 -->
|
||||
<v-col cols="12" md="6">
|
||||
<div class="d-flex align-center mb-2">
|
||||
<v-icon color="green" class="mr-2">mdi-blogger</v-icon>
|
||||
<span class="text-subtitle-2 font-weight-medium">네이버 블로그</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2 align-center">
|
||||
<v-text-field
|
||||
v-model="formData.blogUrl"
|
||||
placeholder="blog.naver.com/계정명"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
prepend-inner-icon="mdi-web"
|
||||
hide-details="auto"
|
||||
class="flex-grow-1"
|
||||
/>
|
||||
<v-btn
|
||||
color="green"
|
||||
size="small"
|
||||
variant="tonal"
|
||||
:loading="snsCheckLoading.naver_blog"
|
||||
@click="checkSnsConnection('naver_blog')"
|
||||
>
|
||||
연동 확인
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<!-- 운영 정보 -->
|
||||
<v-col cols="12">
|
||||
<h4 class="text-subtitle-1 font-weight-bold mb-3">운영 정보</h4>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="formData.openTime"
|
||||
label="오픈 시간"
|
||||
variant="outlined"
|
||||
type="time"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="formData.closeTime"
|
||||
label="마감 시간"
|
||||
variant="outlined"
|
||||
type="time"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-select
|
||||
v-model="formData.holidays"
|
||||
label="휴무일"
|
||||
variant="outlined"
|
||||
:items="daysOfWeek"
|
||||
multiple
|
||||
chips
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-switch
|
||||
v-model="formData.deliveryAvailable"
|
||||
label="배달 서비스"
|
||||
color="primary"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<v-switch
|
||||
v-model="formData.takeoutAvailable"
|
||||
label="포장 서비스"
|
||||
color="primary"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="closeDialog"
|
||||
>
|
||||
취소
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
:loading="saving"
|
||||
:disabled="!formValid"
|
||||
@click="saveStoreInfo"
|
||||
>
|
||||
{{ editMode ? '수정하기' : '등록하기' }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 메뉴 등록/수정 다이얼로그 -->
|
||||
<v-dialog
|
||||
v-model="showMenuDialog"
|
||||
max-width="600"
|
||||
persistent
|
||||
scrollable
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="pa-4">
|
||||
<span class="text-h6">{{ editMenuMode ? '메뉴 수정' : '메뉴 등록' }}</span>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
icon
|
||||
@click="closeMenuDialog"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-text class="pa-6" style="max-height: 500px;">
|
||||
<v-form ref="menuForm" v-model="menuFormValid">
|
||||
<!-- 메뉴 이미지 -->
|
||||
<div class="text-center mb-6">
|
||||
<v-img
|
||||
:src="menuFormData.imageUrl || '/images/menu-placeholder.png'"
|
||||
:alt="menuFormData.menuName"
|
||||
max-width="200"
|
||||
max-height="150"
|
||||
class="mx-auto mb-3 rounded"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
prepend-icon="mdi-camera"
|
||||
@click="selectMenuImage"
|
||||
>
|
||||
이미지 선택
|
||||
</v-btn>
|
||||
<input
|
||||
ref="menuImageInput"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
style="display: none;"
|
||||
@change="handleMenuImageUpload"
|
||||
>
|
||||
</div>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" sm="8">
|
||||
<v-text-field
|
||||
v-model="menuFormData.menuName"
|
||||
label="메뉴명 *"
|
||||
variant="outlined"
|
||||
:rules="[v => !!v || '메뉴명을 입력해주세요']"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="4">
|
||||
<v-text-field
|
||||
v-model.number="menuFormData.price"
|
||||
label="가격 *"
|
||||
variant="outlined"
|
||||
type="number"
|
||||
prefix="₩"
|
||||
:rules="priceRules"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-combobox
|
||||
v-model="menuFormData.category"
|
||||
label="카테고리 *"
|
||||
variant="outlined"
|
||||
:items="menuCategories"
|
||||
:rules="[v => !!v || '카테고리를 선택해주세요']"
|
||||
required
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-textarea
|
||||
v-model="menuFormData.description"
|
||||
label="메뉴 설명"
|
||||
variant="outlined"
|
||||
rows="3"
|
||||
placeholder="메뉴에 대한 자세한 설명을 입력해주세요"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" sm="6">
|
||||
<div class="d-flex flex-column gap-2 mt-4">
|
||||
<v-switch
|
||||
v-model="menuFormData.available"
|
||||
label="판매 중"
|
||||
color="success"
|
||||
/>
|
||||
<v-switch
|
||||
v-model="menuFormData.recommended"
|
||||
label="추천 메뉴"
|
||||
color="warning"
|
||||
/>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="closeMenuDialog"
|
||||
>
|
||||
취소
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
:loading="savingMenu"
|
||||
:disabled="!menuFormValid"
|
||||
@click="saveMenu"
|
||||
>
|
||||
{{ editMenuMode ? '수정하기' : '등록하기' }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 메뉴 삭제 확인 다이얼로그 -->
|
||||
<v-dialog v-model="showDeleteMenuDialog" max-width="400">
|
||||
<v-card>
|
||||
<v-card-title class="text-h6">메뉴 삭제</v-card-title>
|
||||
<v-card-text>
|
||||
<p>정말로 <strong>{{ deleteMenuTarget?.menuName }}</strong> 메뉴를 삭제하시겠습니까?</p>
|
||||
<v-alert type="warning" variant="tonal" class="mt-3">
|
||||
삭제된 메뉴는 복구할 수 없습니다.
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@click="showDeleteMenuDialog = false"
|
||||
>
|
||||
취소
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
:loading="deletingMenu"
|
||||
@click="deleteMenu"
|
||||
>
|
||||
삭제
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 메뉴 상세 다이얼로그 -->
|
||||
<v-dialog v-model="showMenuDetailDialog" max-width="500">
|
||||
<v-card class="menu-detail-card">
|
||||
<v-card-title class="pa-4">
|
||||
<span class="text-h6">메뉴 상세 정보</span>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
icon
|
||||
@click="showMenuDetailDialog = false"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-text class="pa-4" v-if="selectedMenuDetail">
|
||||
<!-- 메뉴 이미지 -->
|
||||
<div class="text-center mb-4">
|
||||
<v-img
|
||||
:src="selectedMenuDetail.imageUrl || '/images/menu-placeholder.png'"
|
||||
:alt="selectedMenuDetail.menuName"
|
||||
max-width="300"
|
||||
max-height="200"
|
||||
class="mx-auto rounded"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 메뉴 기본 정보 -->
|
||||
<div class="menu-detail-info mb-4">
|
||||
<h3 class="text-h6 font-weight-bold mb-2">{{ selectedMenuDetail.menuName }}</h3>
|
||||
<p class="text-body-1 mb-2">
|
||||
{{ selectedMenuDetail.description || '설명이 없습니다.' }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 메뉴 정보 카드들 -->
|
||||
<v-row>
|
||||
<v-col cols="6">
|
||||
<v-card variant="tonal" color="primary" class="text-center pa-4">
|
||||
<v-icon size="32" class="mb-2">mdi-food</v-icon>
|
||||
<h4 class="text-subtitle-1 font-weight-bold">카테고리</h4>
|
||||
<p class="text-body-2">{{ selectedMenuDetail.category }}</p>
|
||||
</v-card>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<v-card variant="tonal" color="success" class="text-center pa-4">
|
||||
<v-icon size="32" class="mb-2">mdi-currency-krw</v-icon>
|
||||
<h4 class="text-subtitle-1 font-weight-bold">가격</h4>
|
||||
<p class="text-body-2">{{ formatCurrency(selectedMenuDetail.price) }}</p>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-actions class="pa-4 justify-end">
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="showMenuDetailDialog = false"
|
||||
>
|
||||
닫기
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="editFromDetail"
|
||||
>
|
||||
수정하기
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- SNS 연동 확인 결과 다이얼로그 -->
|
||||
<v-dialog v-model="showSnsResultDialog" max-width="400">
|
||||
<v-card>
|
||||
<v-card-title class="pa-4">
|
||||
<v-icon :color="snsConnectionResult.success ? 'success' : 'error'" class="mr-2">
|
||||
{{ snsConnectionResult.success ? 'mdi-check-circle' : 'mdi-alert-circle' }}
|
||||
</v-icon>
|
||||
SNS 연동 확인
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-4">
|
||||
<p>{{ snsConnectionResult.message }}</p>
|
||||
</v-card-text>
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="showSnsResultDialog = false"
|
||||
>
|
||||
확인
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useStoreStore } from '@/stores/store'
|
||||
import { useStoreStore } from '@/store/index'
|
||||
|
||||
/**
|
||||
* AI 마케팅 서비스 - 매장 관리 페이지
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user