edit views

This commit is contained in:
unknown 2025-06-11 15:28:34 +09:00
parent 9d1d11108f
commit 1d06854f94
2 changed files with 245 additions and 496 deletions

View File

@ -16,12 +16,12 @@
:items="stepperItems" :items="stepperItems"
alt-labels alt-labels
> >
<!-- Stepper Window로 단계 구현 -->
<v-stepper-window>
<!-- Step 1: 콘텐츠 타입 선택 --> <!-- Step 1: 콘텐츠 타입 선택 -->
<template v-slot:item.1> <v-stepper-window-item value="1">
<v-card <v-card class="pa-4" flat>
class="pa-4"
flat
>
<h3 class="text-h6 mb-4">어떤 콘텐츠를 만들까요?</h3> <h3 class="text-h6 mb-4">어떤 콘텐츠를 만들까요?</h3>
<v-row> <v-row>
@ -54,26 +54,17 @@
</v-col> </v-col>
</v-row> </v-row>
</v-card> </v-card>
</template> </v-stepper-window-item>
<!-- Step 2: 홍보 대상 선택 --> <!-- Step 2: 홍보 대상 선택 -->
<template v-slot:item.2> <v-stepper-window-item value="2">
<v-card class="pa-4" flat> <v-card class="pa-4" flat>
<h3 class="text-h6 mb-4">무엇을 홍보할까요?</h3> <h3 class="text-h6 mb-4">무엇을 홍보할까요?</h3>
<v-radio-group v-model="contentData.target"> <v-radio-group v-model="contentData.target">
<v-radio <v-radio label="🍜 메뉴 홍보" value="menu" />
label="🍜 메뉴 홍보" <v-radio label="🏪 매장 소개" value="store" />
value="menu" <v-radio label="🎉 이벤트 홍보" value="event" />
/>
<v-radio
label="🏪 매장 소개"
value="store"
/>
<v-radio
label="🎉 이벤트 홍보"
value="event"
/>
</v-radio-group> </v-radio-group>
<!-- 메뉴 선택 --> <!-- 메뉴 선택 -->
@ -98,10 +89,10 @@
class="mt-4" class="mt-4"
/> />
</v-card> </v-card>
</template> </v-stepper-window-item>
<!-- Step 3: 이미지 업로드 --> <!-- Step 3: 이미지 업로드 -->
<template v-slot:item.3> <v-stepper-window-item value="3">
<v-card class="pa-4" flat> <v-card class="pa-4" flat>
<h3 class="text-h6 mb-4">이미지를 업로드하세요</h3> <h3 class="text-h6 mb-4">이미지를 업로드하세요</h3>
@ -126,19 +117,15 @@
md="3" md="3"
> >
<v-card class="pa-2"> <v-card class="pa-2">
<v-img <v-img :src="url" height="100" cover />
:src="url"
height="100"
cover
/>
</v-card> </v-card>
</v-col> </v-col>
</v-row> </v-row>
</v-card> </v-card>
</template> </v-stepper-window-item>
<!-- Step 4: 세부 옵션 --> <!-- Step 4: 세부 옵션 -->
<template v-slot:item.4> <v-stepper-window-item value="4">
<v-card class="pa-4" flat> <v-card class="pa-4" flat>
<h3 class="text-h6 mb-4">세부 옵션을 설정하세요</h3> <h3 class="text-h6 mb-4">세부 옵션을 설정하세요</h3>
@ -212,10 +199,10 @@
</v-col> </v-col>
</v-row> </v-row>
</v-card> </v-card>
</template> </v-stepper-window-item>
<!-- Step 5: 생성 결과 --> <!-- Step 5: 생성 결과 -->
<template v-slot:item.5> <v-stepper-window-item value="5">
<v-card class="pa-4" flat> <v-card class="pa-4" flat>
<h3 class="text-h6 mb-4">생성된 콘텐츠</h3> <h3 class="text-h6 mb-4">생성된 콘텐츠</h3>
@ -274,7 +261,9 @@
<p class="text-body-2">{{ generationError }}</p> <p class="text-body-2">{{ generationError }}</p>
</v-card> </v-card>
</v-card> </v-card>
</template> </v-stepper-window-item>
</v-stepper-window>
</v-stepper> </v-stepper>
</v-card-text> </v-card-text>
@ -347,244 +336,3 @@
</v-snackbar> </v-snackbar>
</v-container> </v-container>
</template> </template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useContentStore } from '@/store/content'
import { useStoreStore } from '@/store/store'
import { TONE_OPTIONS, EMOTION_INTENSITY, PROMOTION_OPTIONS, PLATFORMS } from '@/utils/constants'
const router = useRouter()
const contentStore = useContentStore()
const storeStore = useStoreStore()
//
const currentStep = ref(1)
const stepperItems = [
{ title: '타입 선택', value: 1 },
{ title: '홍보 대상', value: 2 },
{ title: '이미지 업로드', value: 3 },
{ title: '세부 옵션', value: 4 },
{ title: '생성 완료', value: 5 }
]
//
const contentData = ref({
type: '',
target: '',
selectedMenu: null,
eventName: '',
images: [],
toneAndManner: '친근함',
emotionIntensity: '보통',
promotion: '없음',
platform: 'INSTAGRAM',
startDate: '',
endDate: ''
})
//
const generating = ref(false)
const saving = ref(false)
const generatedContent = ref(null)
const generationError = ref('')
const showSuccess = ref(false)
const showError = ref(false)
const errorMessage = ref('')
//
const imagePreviewUrls = ref([])
//
const canProceed = computed(() => {
switch (currentStep.value) {
case 1:
return !!contentData.value.type
case 2:
if (contentData.value.target === 'menu') {
return !!contentData.value.selectedMenu
} else if (contentData.value.target === 'event') {
return !!contentData.value.eventName
}
return !!contentData.value.target
case 3:
return contentData.value.images.length > 0
case 4:
return true
default:
return false
}
})
const menuOptions = computed(() => {
return storeStore.menus.map(menu => ({
text: menu.menuName,
value: menu.id
}))
})
const platformOptions = [
{ text: '인스타그램', value: 'INSTAGRAM' },
{ text: '네이버 블로그', value: 'NAVER_BLOG' }
]
/**
* 다음 단계로 이동
*/
const nextStep = async () => {
if (currentStep.value === 4) {
await generateContent()
} else {
currentStep.value++
}
}
/**
* 콘텐츠 생성
*/
const generateContent = async () => {
generating.value = true
generationError.value = ''
currentStep.value = 5
try {
let response
if (contentData.value.type === 'SNS_POST') {
response = await contentStore.generateSNSContent({
target: contentData.value.target,
selectedMenu: contentData.value.selectedMenu,
eventName: contentData.value.eventName,
images: contentData.value.images,
toneAndManner: contentData.value.toneAndManner,
emotionIntensity: contentData.value.emotionIntensity,
promotion: contentData.value.promotion,
platform: contentData.value.platform,
startDate: contentData.value.startDate,
endDate: contentData.value.endDate
})
} else {
response = await contentStore.generatePosterContent({
target: contentData.value.target,
selectedMenu: contentData.value.selectedMenu,
eventName: contentData.value.eventName,
images: contentData.value.images,
toneAndManner: contentData.value.toneAndManner,
promotion: contentData.value.promotion,
startDate: contentData.value.startDate,
endDate: contentData.value.endDate
})
}
generatedContent.value = response
} catch (error) {
console.error('콘텐츠 생성 실패:', error)
generationError.value = '콘텐츠 생성 중 오류가 발생했습니다.'
//
generatedContent.value = {
title: '신메뉴 떡볶이 출시!',
content: `🔥 새로운 맛의 떡볶이가 출시되었어요! 🔥
매콤달콤한 특제 소스로 만든 우리 매장만의 시그니처 떡볶이를 맛보세요!
신선한 떡과 정성스럽게 끓인 국물의 조화가 일품입니다.
지금 방문하시면 특별 할인가로 만나보실 있어요! `,
hashtags: ['#떡볶이', '#신메뉴', '#분식맛집', '#김사장님분식점', '#매운맛', '#달콤한맛']
}
} finally {
generating.value = false
}
}
/**
* 콘텐츠 재생성
*/
const regenerateContent = async () => {
generatedContent.value = null
await generateContent()
}
/**
* 콘텐츠 저장
*/
const saveContent = async () => {
saving.value = true
try {
const saveData = {
...contentData.value,
...generatedContent.value
}
if (contentData.value.type === 'SNS_POST') {
await contentStore.saveSNSContent(saveData)
} else {
await contentStore.savePosterContent(saveData)
}
showSuccess.value = true
//
setTimeout(() => {
router.push({ name: 'ContentManagement' })
}, 2000)
} catch (error) {
console.error('콘텐츠 저장 실패:', error)
errorMessage.value = '콘텐츠 저장 중 오류가 발생했습니다.'
showError.value = true
} finally {
saving.value = false
}
}
//
watch(() => contentData.value.images, (newImages) => {
imagePreviewUrls.value = []
if (newImages && newImages.length > 0) {
newImages.forEach(file => {
const reader = new FileReader()
reader.onload = (e) => {
imagePreviewUrls.value.push(e.target.result)
}
reader.readAsDataURL(file)
})
}
})
//
onMounted(async () => {
try {
await storeStore.fetchMenus()
} catch (error) {
console.error('메뉴 데이터 로드 실패:', error)
}
//
const today = new Date().toISOString().split('T')[0]
const nextWeek = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
contentData.value.startDate = today
contentData.value.endDate = nextWeek
})
</script>
<style scoped>
.content-type-card {
transition: all 0.3s;
cursor: pointer;
border: 2px solid transparent;
}
.content-type-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 25px rgba(0,0,0,0.15);
}
.content-type-card.selected {
border-color: #1976D2;
background-color: #E3F2FD;
}
</style>

View File

@ -979,7 +979,8 @@ onMounted(async () => {
.content-preview { .content-preview {
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 3; line-clamp: 3; /* 표준 속성 추가 */
-webkit-line-clamp: 3; /* 웹킷 fallback */
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
line-height: 1.4; line-height: 1.4;