feat: API配置前端持久化保存
This commit is contained in:
@@ -71,13 +71,19 @@
|
|||||||
placeholder="输入您的API Key">
|
placeholder="输入您的API Key">
|
||||||
<p class="mt-1 text-sm text-gray-500">如不填写,将使用系统默认配置</p>
|
<p class="mt-1 text-sm text-gray-500">如不填写,将使用系统默认配置</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end">
|
<div class="flex justify-between">
|
||||||
<button id="resetApiConfig" class="text-gray-600 hover:text-gray-800 text-sm mr-3">
|
<div class="flex items-center">
|
||||||
重置为默认
|
<input type="checkbox" id="saveApiConfig" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
|
||||||
</button>
|
<label for="saveApiConfig" class="ml-2 block text-sm text-gray-700">保存配置到本地</label>
|
||||||
<button id="testApiConfig" class="bg-blue-100 text-blue-700 px-3 py-1 rounded hover:bg-blue-200 text-sm">
|
</div>
|
||||||
测试连接
|
<div>
|
||||||
</button>
|
<button id="resetApiConfig" class="text-gray-600 hover:text-gray-800 text-sm mr-3">
|
||||||
|
重置为默认
|
||||||
|
</button>
|
||||||
|
<button id="testApiConfig" class="bg-blue-100 text-blue-700 px-3 py-1 rounded hover:bg-blue-200 text-sm">
|
||||||
|
测试连接
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -430,7 +436,7 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('请求失败:', error);
|
console.error('请求失败:', error);
|
||||||
resultContent.innerHTML = `
|
resultContent.innerHTML = `
|
||||||
<div class="p-4 bg-red-50 text-red-600 rounded">
|
<div class="p-6 bg-yellow-50 text-yellow-600 rounded-lg text-center">
|
||||||
分析出错:${error.message}
|
分析出错:${error.message}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -705,73 +711,147 @@
|
|||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// API配置面板切换
|
// API配置面板切换
|
||||||
const toggleBtn = document.getElementById('toggleApiConfig');
|
const toggleApiConfig = document.getElementById('toggleApiConfig');
|
||||||
const configPanel = document.getElementById('apiConfigPanel');
|
const apiConfigPanel = document.getElementById('apiConfigPanel');
|
||||||
const toggleText = document.getElementById('toggleApiConfigText');
|
const toggleApiConfigText = document.getElementById('toggleApiConfigText');
|
||||||
const toggleIcon = document.getElementById('toggleApiConfigIcon');
|
const toggleApiConfigIcon = document.getElementById('toggleApiConfigIcon');
|
||||||
|
const apiUrl = document.getElementById('apiUrl');
|
||||||
|
const apiKey = document.getElementById('apiKey');
|
||||||
|
const apiModel = document.getElementById('apiModel');
|
||||||
|
const saveApiConfig = document.getElementById('saveApiConfig');
|
||||||
|
const resetApiConfig = document.getElementById('resetApiConfig');
|
||||||
|
const testApiConfig = document.getElementById('testApiConfig');
|
||||||
|
|
||||||
toggleBtn.addEventListener('click', function() {
|
// 从localStorage加载保存的配置
|
||||||
const isHidden = configPanel.classList.contains('hidden');
|
loadApiConfig();
|
||||||
configPanel.classList.toggle('hidden', !isHidden);
|
|
||||||
toggleText.textContent = isHidden ? '隐藏配置' : '显示配置';
|
// 切换API配置面板显示/隐藏
|
||||||
toggleIcon.style.transform = isHidden ? 'rotate(180deg)' : '';
|
toggleApiConfig.addEventListener('click', function() {
|
||||||
|
apiConfigPanel.classList.toggle('hidden');
|
||||||
|
|
||||||
|
if (apiConfigPanel.classList.contains('hidden')) {
|
||||||
|
toggleApiConfigText.textContent = '显示配置';
|
||||||
|
toggleApiConfigIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>';
|
||||||
|
} else {
|
||||||
|
toggleApiConfigText.textContent = '隐藏配置';
|
||||||
|
toggleApiConfigIcon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7"></path>';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 重置API配置
|
// 重置API配置
|
||||||
document.getElementById('resetApiConfig').addEventListener('click', function() {
|
resetApiConfig.addEventListener('click', function() {
|
||||||
document.getElementById('apiUrl').value = '{{ default_api_url }}';
|
apiUrl.value = '{{ default_api_url }}';
|
||||||
document.getElementById('apiModel').value = '{{ default_api_model }}';
|
apiKey.value = '';
|
||||||
document.getElementById('apiKey').value = '';
|
apiModel.value = '{{ default_api_model }}';
|
||||||
|
saveApiConfig.checked = false;
|
||||||
|
|
||||||
|
// 清除localStorage中的配置
|
||||||
|
localStorage.removeItem('apiConfig');
|
||||||
|
|
||||||
|
alert('已重置为默认配置');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 测试API连接
|
// 测试API连接
|
||||||
document.getElementById('testApiConfig').addEventListener('click', async function() {
|
testApiConfig.addEventListener('click', async function() {
|
||||||
const apiUrl = document.getElementById('apiUrl').value.trim();
|
const url = apiUrl.value.trim();
|
||||||
const apiKey = document.getElementById('apiKey').value.trim();
|
const key = apiKey.value.trim();
|
||||||
const apiModel = document.getElementById('apiModel').value.trim();
|
const model = apiModel.value.trim();
|
||||||
|
|
||||||
if (!apiUrl) {
|
if (!url) {
|
||||||
alert('请输入API URL');
|
alert('请输入API URL');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!key) {
|
||||||
alert('请输入API Key');
|
alert('请输入API Key');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.textContent = '测试中...';
|
|
||||||
this.disabled = true;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 使用后端代理进行API测试
|
testApiConfig.disabled = true;
|
||||||
|
testApiConfig.textContent = '测试中...';
|
||||||
|
|
||||||
const response = await fetch('/test_api_connection', {
|
const response = await fetch('/test_api_connection', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
api_url: apiUrl,
|
api_url: url,
|
||||||
api_key: apiKey,
|
api_key: key,
|
||||||
api_model: apiModel
|
api_model: model
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (response.ok && data.success) {
|
if (result.success) {
|
||||||
alert('API连接成功!');
|
alert(result.message);
|
||||||
|
|
||||||
|
// 如果勾选了保存配置,则保存到localStorage
|
||||||
|
if (saveApiConfig.checked) {
|
||||||
|
saveApiConfigToLocalStorage();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alert(`API连接失败: ${data.message || '未知错误'}`);
|
alert(result.message);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(`API连接测试失败: ${error.message}`);
|
alert(error.message);
|
||||||
} finally {
|
} finally {
|
||||||
this.textContent = '测试连接';
|
testApiConfig.disabled = false;
|
||||||
this.disabled = false;
|
testApiConfig.textContent = '测试连接';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听输入变化,自动保存配置
|
||||||
|
[apiUrl, apiKey, apiModel].forEach(input => {
|
||||||
|
input.addEventListener('change', function() {
|
||||||
|
if (saveApiConfig.checked) {
|
||||||
|
saveApiConfigToLocalStorage();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听保存配置复选框变化
|
||||||
|
saveApiConfig.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
saveApiConfigToLocalStorage();
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem('apiConfig');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 保存API配置到localStorage
|
||||||
|
function saveApiConfigToLocalStorage() {
|
||||||
|
const apiConfig = {
|
||||||
|
url: document.getElementById('apiUrl').value.trim(),
|
||||||
|
model: document.getElementById('apiModel').value.trim(),
|
||||||
|
key: document.getElementById('apiKey').value.trim(),
|
||||||
|
saveEnabled: true
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorage.setItem('apiConfig', JSON.stringify(apiConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从localStorage加载API配置
|
||||||
|
function loadApiConfig() {
|
||||||
|
const savedConfig = localStorage.getItem('apiConfig');
|
||||||
|
|
||||||
|
if (savedConfig) {
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(savedConfig);
|
||||||
|
|
||||||
|
if (config.url) document.getElementById('apiUrl').value = config.url;
|
||||||
|
if (config.model) document.getElementById('apiModel').value = config.model;
|
||||||
|
if (config.key) document.getElementById('apiKey').value = config.key;
|
||||||
|
|
||||||
|
document.getElementById('saveApiConfig').checked = config.saveEnabled || false;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载API配置时出错:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
// 添加 Markdown 样式
|
// 添加 Markdown 样式
|
||||||
|
|||||||
@@ -163,20 +163,20 @@ def test_api_connection():
|
|||||||
|
|
||||||
# 检查响应
|
# 检查响应
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
logger.info(f"API连接测试成功: {response.status_code}")
|
logger.info(f"API 连接测试成功: {response.status_code}")
|
||||||
return jsonify({'success': True, 'message': '连接成功'})
|
return jsonify({'success': True, 'message': 'API 连接测试成功'})
|
||||||
else:
|
else:
|
||||||
error_message = response.json().get('error', {}).get('message', '未知错误')
|
error_message = response.json().get('error', {}).get('message', '未知错误')
|
||||||
logger.warning(f"API连接测试失败: {response.status_code} - {error_message}")
|
logger.warning(f"API连接测试失败: {response.status_code} - {error_message}")
|
||||||
return jsonify({'success': False, 'message': f'连接失败: {error_message}', 'status_code': response.status_code}), 400
|
return jsonify({'success': False, 'message': f'API 连接测试失败: {error_message}', 'status_code': response.status_code}), 400
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
logger.error(f"API连接请求错误: {str(e)}")
|
logger.error(f"API 连接请求错误: {str(e)}")
|
||||||
return jsonify({'success': False, 'message': f'请求错误: {str(e)}'}), 400
|
return jsonify({'success': False, 'message': f'请求错误: {str(e)}'}), 400
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"测试API连接时出错: {str(e)}")
|
logger.error(f"测试 API 连接时出错: {str(e)}")
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
return jsonify({'success': False, 'message': f'测试连接时出错: {str(e)}'}), 500
|
return jsonify({'success': False, 'message': f'API 测试连接时出错: {str(e)}'}), 500
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
logger.info("股票分析系统启动")
|
logger.info("股票分析系统启动")
|
||||||
|
|||||||
Reference in New Issue
Block a user