캐릭터 챗봇 #74
|
@ -280,82 +280,6 @@
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</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="11">
|
|
||||||
<v-text-field
|
|
||||||
v-model="newRelationship"
|
|
||||||
label="새 인물 관계 추가 (최대 200자)"
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
counter="200"
|
|
||||||
:rules="[v => v.length <= 200 || '최대 200자까지 입력 가능합니다']"
|
|
||||||
@keyup.enter="addRelationship"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="1">
|
|
||||||
<v-btn
|
|
||||||
color="primary"
|
|
||||||
class="mt-1"
|
|
||||||
block
|
|
||||||
:disabled="!newRelationship.trim() || relationships.length >= 10"
|
|
||||||
@click="addRelationship"
|
|
||||||
>
|
|
||||||
추가
|
|
||||||
</v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-card
|
|
||||||
outlined
|
|
||||||
class="memory-container"
|
|
||||||
>
|
|
||||||
<v-list
|
|
||||||
v-if="relationships.length > 0"
|
|
||||||
class="memory-list"
|
|
||||||
>
|
|
||||||
<v-list-item
|
|
||||||
v-for="(relationship, index) in relationships"
|
|
||||||
:key="index"
|
|
||||||
class="memory-item"
|
|
||||||
>
|
|
||||||
<v-list-item-content>
|
|
||||||
<v-list-item-title class="memory-text">
|
|
||||||
{{ relationship }}
|
|
||||||
</v-list-item-title>
|
|
||||||
</v-list-item-content>
|
|
||||||
<v-list-item-action>
|
|
||||||
<v-btn
|
|
||||||
small
|
|
||||||
color="error"
|
|
||||||
class="delete-btn"
|
|
||||||
@click="removeRelationship(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-row>
|
||||||
|
@ -881,6 +805,154 @@
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
<!-- 인물 관계 -->
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-divider class="my-4" />
|
||||||
|
<h3 class="mb-2">
|
||||||
|
인물 관계
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12">
|
||||||
|
<!-- 1행: 상대방 이름, 관계명 -->
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="4">
|
||||||
|
<v-text-field
|
||||||
|
v-model="newRelationship.personName"
|
||||||
|
label="상대방 이름 (최대 10자)"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
counter="10"
|
||||||
|
:rules="personNameRules"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="8">
|
||||||
|
<v-text-field
|
||||||
|
v-model="newRelationship.relationshipName"
|
||||||
|
label="관계명 (어머니, 아버지, 친구 등) (최대 20자)"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
counter="20"
|
||||||
|
:rules="relationshipNameRules"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<!-- 2행: 관계 타입, 현재 상태, 중요도 -->
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="5">
|
||||||
|
<v-text-field
|
||||||
|
v-model="newRelationship.relationshipType"
|
||||||
|
label="관계 타입 (최대 10자)"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
counter="10"
|
||||||
|
:rules="relationshipTypeRules"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="5">
|
||||||
|
<v-text-field
|
||||||
|
v-model="newRelationship.currentStatus"
|
||||||
|
label="현재 상태 (최대 10자)"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
counter="10"
|
||||||
|
:rules="relationshipStatusRules"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="2">
|
||||||
|
<v-text-field
|
||||||
|
v-model.number="newRelationship.importance"
|
||||||
|
label="중요도 (1~10)"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="10"
|
||||||
|
:rules="relationshipImportanceRules"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="11">
|
||||||
|
<v-textarea
|
||||||
|
v-model="newRelationship.description"
|
||||||
|
label="관계 설명 (최대 500자)"
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
auto-grow
|
||||||
|
rows="2"
|
||||||
|
counter="500"
|
||||||
|
:rules="relationshipDescriptionRules"
|
||||||
|
@keyup.enter="addRelationship"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="1">
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
class="mt-1"
|
||||||
|
block
|
||||||
|
:disabled="!newRelationship.personName || !newRelationship.relationshipName || !newRelationship.relationshipType || !newRelationship.currentStatus || !newRelationship.importance || relationships.length >= 10"
|
||||||
|
@click="addRelationship"
|
||||||
|
>
|
||||||
|
추가
|
||||||
|
</v-btn>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-card
|
||||||
|
outlined
|
||||||
|
class="memory-container"
|
||||||
|
>
|
||||||
|
<v-list
|
||||||
|
v-if="relationships.length > 0"
|
||||||
|
class="memory-list"
|
||||||
|
>
|
||||||
|
<v-list-item
|
||||||
|
v-for="(relationship, index) in relationships"
|
||||||
|
:key="index"
|
||||||
|
class="memory-item"
|
||||||
|
>
|
||||||
|
<v-list-item-content>
|
||||||
|
<v-list-item-title class="memory-text font-weight-bold">
|
||||||
|
{{ relationship.personName }} - {{ relationship.relationshipName }}
|
||||||
|
</v-list-item-title>
|
||||||
|
<v-list-item-subtitle class="memory-text mt-1">
|
||||||
|
타입: {{ relationship.relationshipType }} | 상태: {{ relationship.currentStatus }} | 중요도: {{ relationship.importance }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
<v-list-item-subtitle
|
||||||
|
v-if="relationship.description"
|
||||||
|
class="memory-text mt-1"
|
||||||
|
>
|
||||||
|
{{ relationship.description }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
</v-list-item-content>
|
||||||
|
<v-list-item-action>
|
||||||
|
<v-btn
|
||||||
|
small
|
||||||
|
color="error"
|
||||||
|
class="delete-btn"
|
||||||
|
@click="removeRelationship(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-show="isEdit">
|
<v-row v-show="isEdit">
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
|
@ -936,7 +1008,14 @@ export default {
|
||||||
newMemoryTitle: '',
|
newMemoryTitle: '',
|
||||||
newMemoryContent: '',
|
newMemoryContent: '',
|
||||||
newMemoryEmotion: '',
|
newMemoryEmotion: '',
|
||||||
newRelationship: '',
|
newRelationship: {
|
||||||
|
personName: '',
|
||||||
|
relationshipName: '',
|
||||||
|
description: '',
|
||||||
|
importance: null,
|
||||||
|
relationshipType: '',
|
||||||
|
currentStatus: ''
|
||||||
|
},
|
||||||
newHobby: '',
|
newHobby: '',
|
||||||
newValue: '',
|
newValue: '',
|
||||||
newGoal: '',
|
newGoal: '',
|
||||||
|
@ -1007,6 +1086,33 @@ export default {
|
||||||
typeOptions: ['Clone', 'Character'],
|
typeOptions: ['Clone', 'Character'],
|
||||||
systemPromptRules: [
|
systemPromptRules: [
|
||||||
v => (this.isEdit ? true : (!!v && v.trim().length > 0) || '시스템 프롬프트를 입력하세요')
|
v => (this.isEdit ? true : (!!v && v.trim().length > 0) || '시스템 프롬프트를 입력하세요')
|
||||||
|
],
|
||||||
|
// 인물 관계 옵션 및 검증 규칙
|
||||||
|
relationshipTypeOptions: ['가족', '친구', '동료', '연인', '기타'],
|
||||||
|
relationshipStatusOptions: ['생존', '사망', '불명'],
|
||||||
|
personNameRules: [
|
||||||
|
v => (v === '' || v != null) || '상대방 이름을 입력하세요',
|
||||||
|
v => (!v || (typeof v === 'string' && v.length <= 10)) || '최대 10자까지 입력 가능합니다',
|
||||||
|
v => (!!v && v.trim().length > 0) || '상대방 이름을 입력하세요'
|
||||||
|
],
|
||||||
|
relationshipNameRules: [
|
||||||
|
v => (!!v && v.trim().length > 0) || '관계명을 입력하세요',
|
||||||
|
v => (typeof v === 'string' && v.length <= 20) || '최대 20자까지 입력 가능합니다'
|
||||||
|
],
|
||||||
|
relationshipDescriptionRules: [
|
||||||
|
v => (!v || (typeof v === 'string' && v.length <= 500)) || '최대 500자까지 입력 가능합니다'
|
||||||
|
],
|
||||||
|
relationshipImportanceRules: [
|
||||||
|
v => (v !== null && v !== '' && !isNaN(v)) || '중요도를 입력하세요',
|
||||||
|
v => (parseInt(v) >= 1 && parseInt(v) <= 10) || '1~10 사이 숫자만 입력 가능합니다'
|
||||||
|
],
|
||||||
|
relationshipTypeRules: [
|
||||||
|
v => (!!v && v.trim().length > 0) || '관계 타입을 입력하세요',
|
||||||
|
v => (typeof v === 'string' && v.length <= 10) || '최대 10자까지 입력 가능합니다'
|
||||||
|
],
|
||||||
|
relationshipStatusRules: [
|
||||||
|
v => (!!v && v.trim().length > 0) || '현재 상태를 입력하세요',
|
||||||
|
v => (typeof v === 'string' && v.length <= 10) || '최대 10자까지 입력 가능합니다'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1145,19 +1251,52 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
addRelationship() {
|
addRelationship() {
|
||||||
if (this.newRelationship.trim()) {
|
const r = this.newRelationship;
|
||||||
if (this.relationships.length >= 10) {
|
// 필수값 검사
|
||||||
this.notifyError('인물 관계는 최대 10개까지 등록 가능합니다.');
|
if (!r.personName || !r.relationshipName || !r.relationshipType || !r.currentStatus || r.importance === null || r.importance === '') {
|
||||||
return;
|
this.notifyError('상대방 이름, 관계명, 관계 타입, 현재 상태, 중요도를 모두 입력하세요.');
|
||||||
}
|
return;
|
||||||
|
|
||||||
if (this.newRelationship.length > 200) {
|
|
||||||
this.newRelationship = this.newRelationship.substring(0, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.relationships.unshift(this.newRelationship.trim());
|
|
||||||
this.newRelationship = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.relationships.length >= 10) {
|
||||||
|
this.notifyError('인물 관계는 최대 10개까지 등록 가능합니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 길이 제한 적용
|
||||||
|
let personName = r.personName.trim().substring(0, 10);
|
||||||
|
let relationshipName = r.relationshipName.trim().substring(0, 20);
|
||||||
|
let description = (r.description || '').trim().substring(0, 500);
|
||||||
|
|
||||||
|
// 중요도 범위 보정
|
||||||
|
let importance = parseInt(r.importance);
|
||||||
|
if (isNaN(importance)) importance = 1;
|
||||||
|
importance = Math.max(1, Math.min(10, importance));
|
||||||
|
|
||||||
|
// 타입/상태 길이 제한 적용
|
||||||
|
let relationshipType = (r.relationshipType || '').trim().substring(0, 10);
|
||||||
|
let currentStatus = (r.currentStatus || '').trim().substring(0, 10);
|
||||||
|
|
||||||
|
const relationshipObj = {
|
||||||
|
personName,
|
||||||
|
relationshipName,
|
||||||
|
description,
|
||||||
|
importance,
|
||||||
|
relationshipType,
|
||||||
|
currentStatus
|
||||||
|
};
|
||||||
|
|
||||||
|
this.relationships.unshift(relationshipObj);
|
||||||
|
|
||||||
|
// 입력 필드 초기화
|
||||||
|
this.newRelationship = {
|
||||||
|
personName: '',
|
||||||
|
relationshipName: '',
|
||||||
|
description: '',
|
||||||
|
importance: null,
|
||||||
|
relationshipType: '',
|
||||||
|
currentStatus: ''
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
removeRelationship(index) {
|
removeRelationship(index) {
|
||||||
|
@ -1371,7 +1510,7 @@ export default {
|
||||||
|
|
||||||
// 배열 필드 비교 (깊은 비교)
|
// 배열 필드 비교 (깊은 비교)
|
||||||
const arrayFields = [
|
const arrayFields = [
|
||||||
'tags', 'hobbies', 'values', 'goals', 'relationships'
|
'tags', 'hobbies', 'values', 'goals'
|
||||||
];
|
];
|
||||||
|
|
||||||
arrayFields.forEach(field => {
|
arrayFields.forEach(field => {
|
||||||
|
@ -1387,7 +1526,7 @@ export default {
|
||||||
|
|
||||||
// 복잡한 객체 배열 비교
|
// 복잡한 객체 배열 비교
|
||||||
const objectArrayFields = [
|
const objectArrayFields = [
|
||||||
'personalities', 'backgrounds', 'memories'
|
'personalities', 'backgrounds', 'memories', 'relationships'
|
||||||
];
|
];
|
||||||
|
|
||||||
objectArrayFields.forEach(field => {
|
objectArrayFields.forEach(field => {
|
||||||
|
|
Loading…
Reference in New Issue