diff --git a/src/api/character.js b/src/api/character.js index 8a824f4..20cec09 100644 --- a/src/api/character.js +++ b/src/api/character.js @@ -57,36 +57,15 @@ async function createCharacter(characterData) { } // 캐릭터 수정 -async function updateCharacter(characterData) { +async function updateCharacter(characterData, image = null) { const formData = new FormData() - // 이미지만 FormData에 추가 - if (characterData.image) formData.append('image', characterData.image) + // 이미지가 있는 경우에만 FormData에 추가 + if (image) formData.append('image', image) - // 나머지 데이터는 JSON 문자열로 변환하여 request 필드에 추가 - const requestData = { - id: characterData.id, - name: characterData.name, - systemPrompt: characterData.systemPrompt, - description: characterData.description, - age: characterData.age, - gender: characterData.gender, - mbti: characterData.mbti, - speechPattern: characterData.speechPattern, - speechStyle: characterData.conversationStyle, - appearance: characterData.appearance, - tags: characterData.tags || [], - hobbies: characterData.hobbies || [], - values: characterData.values || [], - goals: characterData.goals || [], - relationships: characterData.relationships || [], - personalities: characterData.personalities || [], - backgrounds: characterData.backgrounds || [], - memories: characterData.memories || [], - isActive: characterData.isActive - } - - formData.append('request', JSON.stringify(requestData)) + // 변경된 데이터만 JSON 문자열로 변환하여 request 필드에 추가 + // characterData는 이미 변경된 필드만 포함하고 있음 + formData.append('request', JSON.stringify(characterData)) return Vue.axios.put(`/admin/chat/character/update`, formData, { headers: { diff --git a/src/views/Chat/CharacterForm.vue b/src/views/Chat/CharacterForm.vue index 3c4e397..504cab5 100644 --- a/src/views/Chat/CharacterForm.vue +++ b/src/views/Chat/CharacterForm.vue @@ -914,6 +914,7 @@ export default { goals: [], personalities: [], backgrounds: [], + originalCharacter: null, // 원본 캐릭터 데이터 저장용 character: { id: null, name: '', @@ -1233,6 +1234,97 @@ export default { this.backgrounds.splice(index, 1); }, + // 변경된 필드만 추출하는 함수 + getChangedFields() { + if (!this.originalCharacter || !this.isEdit) { + // 신규 등록인 경우 또는 원본 데이터가 없는 경우 전체 데이터 반환 + return { + name: this.character.name, + systemPrompt: this.character.systemPrompt, + description: this.character.description, + age: this.character.age, + gender: this.character.gender, + mbti: this.character.mbti, + speechPattern: this.character.speechPattern, + speechStyle: this.character.conversationStyle, + appearance: this.character.appearance, + tags: this.character.tags || [], + hobbies: this.character.hobbies || [], + values: this.character.values || [], + goals: this.character.goals || [], + relationships: this.character.relationships || [], + personalities: this.character.personalities || [], + backgrounds: this.character.backgrounds || [], + memories: this.character.memories || [], + isActive: this.character.isActive + }; + } + + // 변경된 필드만 포함하는 객체 + const changedFields = { + id: this.character.id // ID는 항상 포함 + }; + + // 기본 필드 비교 + const simpleFields = [ + 'name', 'description', 'age', 'gender', 'mbti', + 'speechPattern', 'isActive' + ]; + + simpleFields.forEach(field => { + if (this.character[field] !== this.originalCharacter[field]) { + changedFields[field] = this.character[field]; + } + }); + + // 특수 필드 매핑 처리 (conversationStyle은 API에서 speechStyle로 사용됨) + if (this.character.conversationStyle !== this.originalCharacter.conversationStyle) { + changedFields.speechStyle = this.character.conversationStyle; + } + + if (this.character.systemPrompt !== this.originalCharacter.systemPrompt) { + changedFields.systemPrompt = this.character.systemPrompt; + } + + if (this.character.appearance !== this.originalCharacter.appearance) { + changedFields.appearance = this.character.appearance; + } + + // 배열 필드 비교 (깊은 비교) + const arrayFields = [ + 'tags', 'hobbies', 'values', 'goals', 'relationships' + ]; + + arrayFields.forEach(field => { + const original = this.originalCharacter[field] || []; + const current = this.character[field] || []; + + // 길이가 다르거나 내용이 다른 경우 + if (original.length !== current.length || + JSON.stringify(original) !== JSON.stringify(current)) { + changedFields[field] = current; + } + }); + + // 복잡한 객체 배열 비교 + const objectArrayFields = [ + 'personalities', 'backgrounds', 'memories' + ]; + + objectArrayFields.forEach(field => { + const original = this.originalCharacter[field] || []; + const current = this.character[field] || []; + + // 길이가 다르거나 내용이 다른 경우 + if (original.length !== current.length || + JSON.stringify(original) !== JSON.stringify(current)) { + changedFields[field] = current; + } + }); + + return changedFields; + }, + async loadCharacter(id) { this.isLoading = true; try { @@ -1242,6 +1334,9 @@ export default { if (response && response.data) { const data = response.data; + // 원본 데이터 저장 (깊은 복사) + this.originalCharacter = JSON.parse(JSON.stringify(data)); + // 기본 데이터 설정 this.character = { ...this.character, // 기본 구조 유지 @@ -1293,9 +1388,15 @@ export default { let response; if (this.isEdit) { - response = await updateCharacter(this.character); + // 수정 시 변경된 필드만 전송 + const changedData = this.getChangedFields(); + console.log('변경된 필드만 전송:', changedData); + response = await updateCharacter(changedData, this.character.image); } else { - response = await createCharacter(this.character); + // 신규 등록 시 ID 필드를 제외한 데이터 전송 + const characterWithoutId = { ...this.character }; + delete characterWithoutId.id; + response = await createCharacter(characterWithoutId); } if (response && response.data) {