fix:AI 설정 모달 JavaScript 수정

- 함수들을 window 객체에 명시적으로 할당
- 이벤트 리스너를 DOMContentLoaded 안에서 등록
- IIFE 패턴으로 스코프 분리
This commit is contained in:
pro
2026-01-27 23:11:14 +09:00
parent 79709d6a11
commit b819bc02a5

View File

@@ -209,206 +209,217 @@
@push('scripts')
<script>
const csrfToken = '{{ csrf_token() }}';
(function() {
const csrfToken = '{{ csrf_token() }}';
const defaultModels = {
gemini: 'gemini-2.0-flash',
claude: 'claude-sonnet-4-20250514',
openai: 'gpt-4o'
};
// Provider 변경 시 기본 모델 업데이트
document.getElementById('config-provider').addEventListener('change', function() {
const provider = this.value;
document.getElementById('default-model').textContent = defaultModels[provider];
document.getElementById('config-model').placeholder = '예: ' + defaultModels[provider];
});
// 모달 열기
function openModal(config = null) {
const modal = document.getElementById('config-modal');
const title = document.getElementById('modal-title');
const form = document.getElementById('config-form');
if (config) {
title.textContent = '설정 수정';
document.getElementById('config-id').value = config.id;
document.getElementById('config-provider').value = config.provider;
document.getElementById('config-name').value = config.name;
document.getElementById('config-api-key').value = config.api_key;
document.getElementById('config-model').value = config.model;
document.getElementById('config-base-url').value = config.base_url || '';
document.getElementById('config-description').value = config.description || '';
document.getElementById('config-is-active').checked = config.is_active;
} else {
title.textContent = '새 설정 추가';
form.reset();
document.getElementById('config-id').value = '';
}
modal.classList.remove('hidden');
}
// 모달 닫기
function closeModal() {
document.getElementById('config-modal').classList.add('hidden');
}
// 수정
function editConfig(id, config) {
openModal(config);
}
// 폼 제출
document.getElementById('config-form').addEventListener('submit', async function(e) {
e.preventDefault();
const id = document.getElementById('config-id').value;
const data = {
provider: document.getElementById('config-provider').value,
name: document.getElementById('config-name').value,
api_key: document.getElementById('config-api-key').value,
model: document.getElementById('config-model').value,
base_url: document.getElementById('config-base-url').value || null,
description: document.getElementById('config-description').value || null,
is_active: document.getElementById('config-is-active').checked
const defaultModels = {
gemini: 'gemini-2.0-flash',
claude: 'claude-sonnet-4-20250514',
openai: 'gpt-4o'
};
try {
const url = id
? `{{ url('system/ai-config') }}/${id}`
: '{{ route("system.ai-config.store") }}';
const method = id ? 'PUT' : 'POST';
// 모달 열기
window.openModal = function(config) {
const modal = document.getElementById('config-modal');
const title = document.getElementById('modal-title');
const form = document.getElementById('config-form');
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.ok) {
showToast(result.message, 'success');
closeModal();
location.reload();
if (config) {
title.textContent = '설정 수정';
document.getElementById('config-id').value = config.id;
document.getElementById('config-provider').value = config.provider;
document.getElementById('config-name').value = config.name;
document.getElementById('config-api-key').value = config.api_key;
document.getElementById('config-model').value = config.model;
document.getElementById('config-base-url').value = config.base_url || '';
document.getElementById('config-description').value = config.description || '';
document.getElementById('config-is-active').checked = config.is_active;
} else {
showToast(result.message || '저장 실패', 'error');
title.textContent = '새 설정 추가';
form.reset();
document.getElementById('config-id').value = '';
}
} catch (error) {
showToast('저장 중 오류가 발생했습니다.', 'error');
}
});
// 토글
async function toggleConfig(id) {
try {
const response = await fetch(`{{ url('system/ai-config') }}/${id}/toggle`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
}
});
const result = await response.json();
if (result.ok) {
showToast(result.message, 'success');
location.reload();
} else {
showToast(result.message || '변경 실패', 'error');
}
} catch (error) {
showToast('처리 중 오류가 발생했습니다.', 'error');
}
}
// 삭제
async function deleteConfig(id, name) {
if (!confirm(`'${name}' 설정을 삭제하시겠습니까?`)) {
return;
}
try {
const response = await fetch(`{{ url('system/ai-config') }}/${id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
}
});
const result = await response.json();
if (result.ok) {
showToast(result.message, 'success');
location.reload();
} else {
showToast(result.message || '삭제 실패', 'error');
}
} catch (error) {
showToast('삭제 중 오류가 발생했습니다.', 'error');
}
}
// 연결 테스트 (목록에서)
async function testConnection(id) {
showToast('연결 테스트 중...', 'info');
// 해당 설정의 정보를 가져와서 테스트
const card = document.querySelector(`.config-card[data-id="${id}"]`);
// 실제로는 서버에서 설정을 가져와서 테스트해야 함
// 여기서는 간단히 처리
showToast('설정 수정 화면에서 테스트해주세요.', 'warning');
}
// 연결 테스트 (모달에서)
async function testConnectionFromModal() {
const data = {
provider: document.getElementById('config-provider').value,
api_key: document.getElementById('config-api-key').value,
model: document.getElementById('config-model').value,
base_url: document.getElementById('config-base-url').value || null
modal.classList.remove('hidden');
};
if (!data.api_key) {
showToast('API 키를 입력해주세요.', 'error');
return;
}
// 모달 닫기
window.closeModal = function() {
document.getElementById('config-modal').classList.add('hidden');
};
showToast('연결 테스트 중...', 'info');
// 수정
window.editConfig = function(id, config) {
window.openModal(config);
};
try {
const response = await fetch('{{ route("system.ai-config.test") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify(data)
});
// 토글
window.toggleConfig = async function(id) {
try {
const response = await fetch(`{{ url('system/ai-config') }}/${id}/toggle`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
}
});
const result = await response.json();
const result = await response.json();
if (result.ok) {
showToast('연결 테스트 성공!', 'success');
} else {
showToast(result.error || '연결 테스트 실패', 'error');
if (result.ok) {
showToast(result.message, 'success');
location.reload();
} else {
showToast(result.message || '변경 실패', 'error');
}
} catch (error) {
showToast('처리 중 오류가 발생했습니다.', 'error');
}
} catch (error) {
showToast('테스트 중 오류가 발생했습니다.', 'error');
}
}
};
// 모달 외부 클릭 시 닫기
document.getElementById('config-modal').addEventListener('click', function(e) {
if (e.target === this) {
closeModal();
// 삭제
window.deleteConfig = async function(id, name) {
if (!confirm(`'${name}' 설정을 삭제하시겠습니까?`)) {
return;
}
try {
const response = await fetch(`{{ url('system/ai-config') }}/${id}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
}
});
const result = await response.json();
if (result.ok) {
showToast(result.message, 'success');
location.reload();
} else {
showToast(result.message || '삭제 실패', 'error');
}
} catch (error) {
showToast('삭제 중 오류가 발생했습니다.', 'error');
}
};
// 연결 테스트 (목록에서)
window.testConnection = async function(id) {
showToast('설정 수정 화면에서 테스트해주세요.', 'warning');
};
// 연결 테스트 (모달에서)
window.testConnectionFromModal = async function() {
const data = {
provider: document.getElementById('config-provider').value,
api_key: document.getElementById('config-api-key').value,
model: document.getElementById('config-model').value,
base_url: document.getElementById('config-base-url').value || null
};
if (!data.api_key) {
showToast('API 키를 입력해주세요.', 'error');
return;
}
showToast('연결 테스트 중...', 'info');
try {
const response = await fetch('{{ route("system.ai-config.test") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.ok) {
showToast('연결 테스트 성공!', 'success');
} else {
showToast(result.error || '연결 테스트 실패', 'error');
}
} catch (error) {
showToast('테스트 중 오류가 발생했습니다.', 'error');
}
};
// 폼 제출
async function handleFormSubmit(e) {
e.preventDefault();
const id = document.getElementById('config-id').value;
const data = {
provider: document.getElementById('config-provider').value,
name: document.getElementById('config-name').value,
api_key: document.getElementById('config-api-key').value,
model: document.getElementById('config-model').value,
base_url: document.getElementById('config-base-url').value || null,
description: document.getElementById('config-description').value || null,
is_active: document.getElementById('config-is-active').checked
};
try {
const url = id
? `{{ url('system/ai-config') }}/${id}`
: '{{ route("system.ai-config.store") }}';
const method = id ? 'PUT' : 'POST';
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify(data)
});
const result = await response.json();
if (result.ok) {
showToast(result.message, 'success');
window.closeModal();
location.reload();
} else {
showToast(result.message || '저장 실패', 'error');
}
} catch (error) {
showToast('저장 중 오류가 발생했습니다.', 'error');
}
}
});
// DOM 로드 후 이벤트 리스너 등록
document.addEventListener('DOMContentLoaded', function() {
// Provider 변경 시 기본 모델 업데이트
const providerEl = document.getElementById('config-provider');
if (providerEl) {
providerEl.addEventListener('change', function() {
const provider = this.value;
document.getElementById('default-model').textContent = defaultModels[provider];
document.getElementById('config-model').placeholder = '예: ' + defaultModels[provider];
});
}
// 폼 제출
const formEl = document.getElementById('config-form');
if (formEl) {
formEl.addEventListener('submit', handleFormSubmit);
}
// 모달 외부 클릭 시 닫기
const modalEl = document.getElementById('config-modal');
if (modalEl) {
modalEl.addEventListener('click', function(e) {
if (e.target === this) {
window.closeModal();
}
});
}
});
})();
</script>
@endpush