feat(character): 캐릭터 폼에 성격 특성, 세계관, 기억 기능 개선
- 성격 특성(personalities): 제목(trait)과 설명(description) 입력 UI 구현, 최대 10개 - 세계관(배경)(backgrounds): 제목(topic)과 설명(description) 입력 UI 구현, 최대 10개 - 기억(memories): 제목(title), 기억(content), 감정(emotion) 입력 UI 구현, 최대 20개
This commit is contained in:
parent
72b1627f3f
commit
7f56d0b423
|
@ -163,7 +163,7 @@
|
|||
<div
|
||||
class="caption grey--text text--darken-1 custom-caption"
|
||||
>
|
||||
태그를 입력하고 엔터 또는 스페이스바를 누르면 추가됩니다. (50자 이내, 최대 20개, 띄어쓰기 불가)
|
||||
태그를 입력하고 엔터를 누르면 추가됩니다. (50자 이내, 최대 20개)
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
@ -178,31 +178,6 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- 세계관 (배경이야기) -->
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-textarea
|
||||
v-model="character.worldView"
|
||||
label="세계관 (배경이야기)"
|
||||
outlined
|
||||
auto-grow
|
||||
rows="4"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- 성격 특성 -->
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-textarea
|
||||
v-model="character.personality"
|
||||
label="성격 특성"
|
||||
outlined
|
||||
auto-grow
|
||||
rows="4"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- 말투/특징적 표현 -->
|
||||
<v-row>
|
||||
|
@ -575,6 +550,191 @@
|
|||
</v-col>
|
||||
</v-row>
|
||||
|
||||
|
||||
<!-- 세계관 (배경이야기) -->
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-divider class="my-4" />
|
||||
<h3 class="mb-2">
|
||||
세계관 (배경이야기)
|
||||
</h3>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-row>
|
||||
<v-col cols="5">
|
||||
<v-text-field
|
||||
v-model="newBackgroundTopic"
|
||||
label="주제 (최대 100자)"
|
||||
outlined
|
||||
dense
|
||||
counter="100"
|
||||
:rules="[v => v.length <= 100 || '최대 100자까지 입력 가능합니다']"
|
||||
@keyup.enter="addBackground"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<v-textarea
|
||||
v-model="newBackgroundDescription"
|
||||
label="배경 설명 (최대 1000자)"
|
||||
outlined
|
||||
dense
|
||||
auto-grow
|
||||
rows="2"
|
||||
counter="1000"
|
||||
:rules="[v => v.length <= 1000 || '최대 1000자까지 입력 가능합니다']"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="1">
|
||||
<v-btn
|
||||
color="primary"
|
||||
class="mt-1"
|
||||
block
|
||||
:disabled="!newBackgroundTopic.trim() || !newBackgroundDescription.trim() || backgrounds.length >= 10"
|
||||
@click="addBackground"
|
||||
>
|
||||
추가
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-card
|
||||
outlined
|
||||
class="memory-container"
|
||||
>
|
||||
<v-list
|
||||
v-if="backgrounds.length > 0"
|
||||
class="memory-list"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(background, index) in backgrounds"
|
||||
:key="index"
|
||||
class="memory-item"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="memory-text font-weight-bold">
|
||||
{{ background.topic }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="memory-text mt-1">
|
||||
{{ background.description }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-btn
|
||||
small
|
||||
color="error"
|
||||
class="delete-btn"
|
||||
@click="removeBackground(index)"
|
||||
>
|
||||
삭제
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-text
|
||||
v-else
|
||||
class="text-center grey--text"
|
||||
>
|
||||
세계관 정보가 없습니다. 위 입력창에서 세계관 정보를 추가해주세요. (최대 10개)
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- 성격 특성 -->
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-divider class="my-4" />
|
||||
<h3 class="mb-2">
|
||||
성격 특성
|
||||
</h3>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-row>
|
||||
<v-col cols="5">
|
||||
<v-text-field
|
||||
v-model="newPersonalityTrait"
|
||||
label="특성 제목 (최대 100자)"
|
||||
outlined
|
||||
dense
|
||||
counter="100"
|
||||
:rules="[v => v.length <= 100 || '최대 100자까지 입력 가능합니다']"
|
||||
@keyup.enter="addPersonality"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<v-textarea
|
||||
v-model="newPersonalityDescription"
|
||||
label="특성 설명 (최대 500자)"
|
||||
outlined
|
||||
dense
|
||||
auto-grow
|
||||
rows="2"
|
||||
counter="500"
|
||||
:rules="[v => v.length <= 500 || '최대 500자까지 입력 가능합니다']"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="1">
|
||||
<v-btn
|
||||
color="primary"
|
||||
class="mt-1"
|
||||
block
|
||||
:disabled="!newPersonalityTrait.trim() || !newPersonalityDescription.trim() || personalities.length >= 10"
|
||||
@click="addPersonality"
|
||||
>
|
||||
추가
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-card
|
||||
outlined
|
||||
class="memory-container"
|
||||
>
|
||||
<v-list
|
||||
v-if="personalities.length > 0"
|
||||
class="memory-list"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(personality, index) in personalities"
|
||||
:key="index"
|
||||
class="memory-item"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="memory-text font-weight-bold">
|
||||
{{ personality.trait }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="memory-text mt-1">
|
||||
{{ personality.description }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-btn
|
||||
small
|
||||
color="error"
|
||||
class="delete-btn"
|
||||
@click="removePersonality(index)"
|
||||
>
|
||||
삭제
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-text
|
||||
v-else
|
||||
class="text-center grey--text"
|
||||
>
|
||||
성격 특성이 없습니다. 위 입력창에서 성격 특성을 추가해주세요. (최대 10개)
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- 기억/메모리 -->
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
|
@ -586,12 +746,36 @@
|
|||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-row>
|
||||
<v-col cols="11">
|
||||
<v-col cols="4">
|
||||
<v-text-field
|
||||
v-model="newMemory"
|
||||
label="새 기억 추가"
|
||||
v-model="newMemoryTitle"
|
||||
label="제목 (최대 100자)"
|
||||
outlined
|
||||
dense
|
||||
counter="100"
|
||||
:rules="[v => v.length <= 100 || '최대 100자까지 입력 가능합니다']"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="4">
|
||||
<v-textarea
|
||||
v-model="newMemoryContent"
|
||||
label="기억 내용 (최대 1000자)"
|
||||
outlined
|
||||
dense
|
||||
auto-grow
|
||||
rows="2"
|
||||
counter="1000"
|
||||
:rules="[v => v.length <= 1000 || '최대 1000자까지 입력 가능합니다']"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="3">
|
||||
<v-text-field
|
||||
v-model="newMemoryEmotion"
|
||||
label="감정 (최대 50자)"
|
||||
outlined
|
||||
dense
|
||||
counter="50"
|
||||
:rules="[v => v.length <= 50 || '최대 50자까지 입력 가능합니다']"
|
||||
@keyup.enter="addMemory"
|
||||
/>
|
||||
</v-col>
|
||||
|
@ -600,7 +784,7 @@
|
|||
color="primary"
|
||||
class="mt-1"
|
||||
block
|
||||
:disabled="!newMemory.trim()"
|
||||
:disabled="!newMemoryTitle.trim() || !newMemoryContent.trim() || memories.length >= 20"
|
||||
@click="addMemory"
|
||||
>
|
||||
추가
|
||||
|
@ -624,9 +808,18 @@
|
|||
class="memory-item"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="memory-text">
|
||||
{{ memory }}
|
||||
<v-list-item-title class="memory-text font-weight-bold">
|
||||
{{ memory.title }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="memory-text mt-1">
|
||||
{{ memory.content }}
|
||||
</v-list-item-subtitle>
|
||||
<v-list-item-subtitle
|
||||
v-if="memory.emotion"
|
||||
class="memory-text mt-1 font-italic"
|
||||
>
|
||||
감정: {{ memory.emotion }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-btn
|
||||
|
@ -644,7 +837,7 @@
|
|||
v-else
|
||||
class="text-center grey--text"
|
||||
>
|
||||
기억이 없습니다. 위 입력창에서 기억을 추가해주세요.
|
||||
기억이 없습니다. 위 입력창에서 기억을 추가해주세요. (최대 20개)
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
@ -702,17 +895,25 @@ export default {
|
|||
isFormValid: false,
|
||||
isEdit: false,
|
||||
previewImage: null,
|
||||
newMemory: '',
|
||||
newMemoryTitle: '',
|
||||
newMemoryContent: '',
|
||||
newMemoryEmotion: '',
|
||||
newRelationship: '',
|
||||
newHobby: '',
|
||||
newValue: '',
|
||||
newGoal: '',
|
||||
newPersonalityTrait: '',
|
||||
newPersonalityDescription: '',
|
||||
newBackgroundTopic: '',
|
||||
newBackgroundDescription: '',
|
||||
tags: [],
|
||||
memories: [],
|
||||
relationships: [],
|
||||
hobbies: [],
|
||||
values: [],
|
||||
goals: [],
|
||||
personalities: [],
|
||||
backgrounds: [],
|
||||
character: {
|
||||
id: null,
|
||||
name: '',
|
||||
|
@ -841,9 +1042,40 @@ export default {
|
|||
},
|
||||
|
||||
addMemory() {
|
||||
if (this.newMemory.trim()) {
|
||||
this.memories.unshift(this.newMemory.trim());
|
||||
this.newMemory = '';
|
||||
if (this.newMemoryTitle.trim() && this.newMemoryContent.trim()) {
|
||||
if (this.memories.length >= 20) {
|
||||
this.notifyError('기억은 최대 20개까지 등록 가능합니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 글자수 제한 적용
|
||||
let title = this.newMemoryTitle.trim();
|
||||
let content = this.newMemoryContent.trim();
|
||||
let emotion = this.newMemoryEmotion.trim();
|
||||
|
||||
if (title.length > 100) {
|
||||
title = title.substring(0, 100);
|
||||
}
|
||||
|
||||
if (content.length > 1000) {
|
||||
content = content.substring(0, 1000);
|
||||
}
|
||||
|
||||
if (emotion.length > 50) {
|
||||
emotion = emotion.substring(0, 50);
|
||||
}
|
||||
|
||||
// 새 기억 객체 생성 및 추가
|
||||
this.memories.unshift({
|
||||
title,
|
||||
content,
|
||||
emotion
|
||||
});
|
||||
|
||||
// 입력 필드 초기화
|
||||
this.newMemoryTitle = '';
|
||||
this.newMemoryContent = '';
|
||||
this.newMemoryEmotion = '';
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -931,6 +1163,76 @@ export default {
|
|||
this.goals.splice(index, 1);
|
||||
},
|
||||
|
||||
addPersonality() {
|
||||
if (this.newPersonalityTrait.trim() && this.newPersonalityDescription.trim()) {
|
||||
if (this.personalities.length >= 10) {
|
||||
this.notifyError('성격 특성은 최대 10개까지 등록 가능합니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 글자수 제한 적용
|
||||
let trait = this.newPersonalityTrait.trim();
|
||||
let description = this.newPersonalityDescription.trim();
|
||||
|
||||
if (trait.length > 100) {
|
||||
trait = trait.substring(0, 100);
|
||||
}
|
||||
|
||||
if (description.length > 500) {
|
||||
description = description.substring(0, 500);
|
||||
}
|
||||
|
||||
// 새 성격 특성 객체 생성 및 추가
|
||||
this.personalities.unshift({
|
||||
trait,
|
||||
description
|
||||
});
|
||||
|
||||
// 입력 필드 초기화
|
||||
this.newPersonalityTrait = '';
|
||||
this.newPersonalityDescription = '';
|
||||
}
|
||||
},
|
||||
|
||||
removePersonality(index) {
|
||||
this.personalities.splice(index, 1);
|
||||
},
|
||||
|
||||
addBackground() {
|
||||
if (this.newBackgroundTopic.trim() && this.newBackgroundDescription.trim()) {
|
||||
if (this.backgrounds.length >= 10) {
|
||||
this.notifyError('세계관 정보는 최대 10개까지 등록 가능합니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 글자수 제한 적용
|
||||
let topic = this.newBackgroundTopic.trim();
|
||||
let description = this.newBackgroundDescription.trim();
|
||||
|
||||
if (topic.length > 100) {
|
||||
topic = topic.substring(0, 100);
|
||||
}
|
||||
|
||||
if (description.length > 1000) {
|
||||
description = description.substring(0, 1000);
|
||||
}
|
||||
|
||||
// 새 세계관 객체 생성 및 추가
|
||||
this.backgrounds.unshift({
|
||||
topic,
|
||||
description
|
||||
});
|
||||
|
||||
// 입력 필드 초기화
|
||||
this.newBackgroundTopic = '';
|
||||
this.newBackgroundDescription = '';
|
||||
}
|
||||
},
|
||||
|
||||
removeBackground(index) {
|
||||
this.backgrounds.splice(index, 1);
|
||||
},
|
||||
|
||||
async loadCharacter(id) {
|
||||
this.isLoading = true;
|
||||
try {
|
||||
|
@ -947,13 +1249,15 @@ export default {
|
|||
image: null // 파일 입력은 초기화
|
||||
};
|
||||
|
||||
// 태그, 메모리, 인물관계, 취미, 가치관, 목표 설정
|
||||
// 태그, 메모리, 인물관계, 취미, 가치관, 목표, 성격 특성, 세계관 설정
|
||||
this.tags = data.tags || [];
|
||||
this.memories = data.memories || [];
|
||||
this.relationships = data.relationships || [];
|
||||
this.hobbies = data.hobbies || [];
|
||||
this.values = data.values || [];
|
||||
this.goals = data.goals || [];
|
||||
this.personalities = data.personalities || [];
|
||||
this.backgrounds = data.backgrounds || [];
|
||||
} else {
|
||||
this.notifyError('캐릭터 정보를 불러올 수 없습니다.');
|
||||
}
|
||||
|
@ -976,13 +1280,15 @@ export default {
|
|||
this.isLoading = true;
|
||||
|
||||
try {
|
||||
// 태그, 메모리, 인물관계, 취미, 가치관, 목표 데이터 설정
|
||||
// 태그, 메모리, 인물관계, 취미, 가치관, 목표, 성격 특성, 세계관 데이터 설정
|
||||
this.character.tags = this.tags.filter(tag => tag && typeof tag === 'string' && tag.trim());
|
||||
this.character.memories = [...this.memories];
|
||||
this.character.relationships = [...this.relationships];
|
||||
this.character.hobbies = [...this.hobbies];
|
||||
this.character.values = [...this.values];
|
||||
this.character.goals = [...this.goals];
|
||||
this.character.personalities = [...this.personalities];
|
||||
this.character.backgrounds = [...this.backgrounds];
|
||||
|
||||
let response;
|
||||
|
||||
|
|
Loading…
Reference in New Issue