fix:AI 설정 모달 JavaScript 수정
- 함수들을 window 객체에 명시적으로 할당 - 이벤트 리스너를 DOMContentLoaded 안에서 등록 - IIFE 패턴으로 스코프 분리
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user