Files
hr-position-system/fix_cors.js
DonaldFang 方士碩 b2584772c4 feat: 新增崗位描述與清單整合功能 v2.1
主要功能更新:
- 崗位描述保存功能:保存後資料寫入資料庫
- 崗位清單自動刷新:切換模組時自動載入最新資料
- 崗位清單檢視功能:點擊「檢視」按鈕載入對應描述
- 管理者頁面擴充:新增崗位資料管理與匯出功能
- CSV 批次匯入:支援崗位與職務資料批次匯入

後端 API 新增:
- Position Description CRUD APIs
- Position List Query & Export APIs
- CSV Template Download & Import APIs

文件更新:
- SDD.md 更新至版本 2.1
- README.md 更新功能說明與版本歷史

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:46:36 +08:00

156 lines
4.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* CORS 錯誤修正
* 將直接調用 Claude API 改為通過後端 Flask API 調用
*
* 使用方法:
* 1. 在 index.html 中找到 callClaudeAPI 函數
* 2. 將其替換為下面的新版本
*/
// ==================== 修正後的 AI Generation Functions ====================
/**
* 調用後端 LLM API 生成文字
* @param {string} prompt - 提示詞
* @param {string} api - API 名稱 (gemini, deepseek, openai)
* @returns {Promise<Object>} - 生成的 JSON 數據
*/
async function callClaudeAPI(prompt, api = 'gemini') {
try {
// 調用後端 Flask API而不是直接調用 Claude API
const response = await fetch("/api/llm/generate", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
api: api, // 使用 Gemini 作為默認
prompt: prompt,
max_tokens: 2000
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || `API 請求失敗: ${response.status}`);
}
const data = await response.json();
if (!data.success) {
throw new Error(data.error || 'API 調用失敗');
}
// 解析返回的文字為 JSON
let responseText = data.text;
// 移除可能的 markdown 代碼塊標記
responseText = responseText.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
// 解析 JSON
return JSON.parse(responseText);
} catch (error) {
console.error("Error calling LLM API:", error);
// 使用全局錯誤處理器顯示錯誤
if (window.errorHandler) {
window.errorHandler.showError({
title: 'AI 生成錯誤',
message: error.message || '調用 AI API 時發生錯誤',
type: 'error',
details: error.stack
});
} else {
alert(`AI 生成錯誤: ${error.message}`);
}
throw error;
}
}
/**
* 設置按鈕載入狀態
* @param {HTMLElement} btn - 按鈕元素
* @param {boolean} loading - 是否載入中
*/
function setButtonLoading(btn, loading) {
if (loading) {
btn.disabled = true;
btn.innerHTML = '<div class="spinner"></div><span>AI 生成中...</span>';
} else {
btn.disabled = false;
btn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg><span>✨ I\'m feeling lucky</span>';
}
}
// ==================== 選擇 LLM API 提供者 ====================
/**
* 讓用戶選擇使用哪個 LLM API
* @returns {Promise<string>} - 選擇的 API 名稱
*/
async function selectLLMProvider() {
// 獲取可用的 API 列表
try {
const response = await fetch('/api/llm/config');
const config = await response.json();
const enabledAPIs = [];
for (const [key, value] of Object.entries(config)) {
if (value.enabled) {
enabledAPIs.push({
key: key,
name: value.name
});
}
}
if (enabledAPIs.length === 0) {
throw new Error('沒有可用的 LLM API請先配置 API Key');
}
// 如果只有一個 API直接使用
if (enabledAPIs.length === 1) {
return enabledAPIs[0].key;
}
// 多個 API 時,使用第一個(默認 Gemini
return enabledAPIs[0].key;
} catch (error) {
console.error('無法獲取 LLM 配置:', error);
// 默認使用 Gemini
return 'gemini';
}
}
/**
* 增強版的 callClaudeAPI - 自動選擇最佳 API
* @param {string} prompt - 提示詞
* @returns {Promise<Object>} - 生成的 JSON 數據
*/
async function callAIAPI(prompt) {
const api = await selectLLMProvider();
return callClaudeAPI(prompt, api);
}
// ==================== 使用示例 ====================
/*
// 原來的調用方式(會導致 CORS 錯誤):
const result = await callClaudeAPI(prompt);
// 修正後的調用方式 1使用默認 Gemini
const result = await callClaudeAPI(prompt, 'gemini');
// 修正後的調用方式 2使用 DeepSeek
const result = await callClaudeAPI(prompt, 'deepseek');
// 修正後的調用方式 3使用 OpenAI
const result = await callClaudeAPI(prompt, 'openai');
// 修正後的調用方式 4自動選擇最佳 API
const result = await callAIAPI(prompt);
*/