主要功能更新: - 崗位描述保存功能:保存後資料寫入資料庫 - 崗位清單自動刷新:切換模組時自動載入最新資料 - 崗位清單檢視功能:點擊「檢視」按鈕載入對應描述 - 管理者頁面擴充:新增崗位資料管理與匯出功能 - 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>
253 lines
10 KiB
Python
253 lines
10 KiB
Python
"""
|
||
改進錯誤訊息顯示 - 使錯誤訊息可完整顯示和複製
|
||
"""
|
||
|
||
with open('index.html', 'r', encoding='utf-8') as f:
|
||
content = f.read()
|
||
|
||
# 備份
|
||
with open('index.html.backup2', 'w', encoding='utf-8') as f:
|
||
f.write(content)
|
||
|
||
# 找到錯誤處理的 alert 並替換為更好的顯示方式
|
||
old_error_handling = ''' } catch (error) {
|
||
console.error("Error calling LLM API:", error);
|
||
alert(`AI 生成錯誤: ${error.message}\\n\\n請確保:\\n1. Flask 後端已啟動 (python app_updated.py)\\n2. 已在 .env 文件中配置 LLM API Key\\n3. 網路連線正常`);
|
||
throw error;
|
||
}'''
|
||
|
||
new_error_handling = ''' } catch (error) {
|
||
console.error("Error calling LLM API:", error);
|
||
|
||
// 嘗試解析更詳細的錯誤訊息
|
||
let errorDetails = error.message;
|
||
try {
|
||
// 如果錯誤訊息是 JSON 格式,嘗試美化顯示
|
||
const errorJson = JSON.parse(error.message);
|
||
errorDetails = JSON.stringify(errorJson, null, 2);
|
||
} catch (e) {
|
||
// 不是 JSON,使用原始訊息
|
||
}
|
||
|
||
// 創建可複製的錯誤對話框
|
||
showCopyableError({
|
||
title: 'AI 生成錯誤',
|
||
message: error.message,
|
||
details: errorDetails,
|
||
suggestions: [
|
||
'Flask 後端已啟動 (python start_server.py)',
|
||
'已在 .env 文件中配置有效的 LLM API Key',
|
||
'網路連線正常',
|
||
'嘗試使用不同的 LLM API (DeepSeek 或 OpenAI)'
|
||
]
|
||
});
|
||
|
||
throw error;
|
||
}'''
|
||
|
||
# 替換
|
||
new_content = content.replace(old_error_handling, new_error_handling)
|
||
|
||
if new_content == content:
|
||
print("WARNING: Pattern not found, content not changed")
|
||
else:
|
||
print("SUCCESS: Error handling improved")
|
||
|
||
# 添加 showCopyableError 函數(如果還沒有)
|
||
if 'function showCopyableError' not in new_content:
|
||
# 在 </script> 前添加新函數
|
||
error_display_function = '''
|
||
// 顯示可複製的錯誤訊息
|
||
function showCopyableError(options) {
|
||
const { title, message, details, suggestions } = options;
|
||
|
||
// 創建對話框
|
||
const modal = document.createElement('div');
|
||
modal.style.cssText = `
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0,0,0,0.7);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 10000;
|
||
animation: fadeIn 0.3s;
|
||
`;
|
||
|
||
modal.innerHTML = `
|
||
<div style="
|
||
background: white;
|
||
border-radius: 12px;
|
||
max-width: 600px;
|
||
width: 90%;
|
||
max-height: 80vh;
|
||
overflow: hidden;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
|
||
display: flex;
|
||
flex-direction: column;
|
||
">
|
||
<!-- Header -->
|
||
<div style="
|
||
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
|
||
color: white;
|
||
padding: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
">
|
||
<span style="font-size: 2rem;">❌</span>
|
||
<h3 style="margin: 0; font-size: 1.3rem; flex: 1;">${title}</h3>
|
||
<button onclick="this.closest('[style*=\\'position: fixed\\']').remove()" style="
|
||
background: rgba(255,255,255,0.2);
|
||
border: none;
|
||
color: white;
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
font-size: 1.2rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
">×</button>
|
||
</div>
|
||
|
||
<!-- Body -->
|
||
<div style="
|
||
padding: 25px;
|
||
overflow-y: auto;
|
||
flex: 1;
|
||
">
|
||
<div style="
|
||
color: #333;
|
||
line-height: 1.6;
|
||
margin-bottom: 20px;
|
||
font-size: 1rem;
|
||
">${message}</div>
|
||
|
||
${suggestions && suggestions.length > 0 ? `
|
||
<div style="
|
||
background: #fff3cd;
|
||
border: 1px solid #ffc107;
|
||
border-radius: 6px;
|
||
padding: 15px;
|
||
margin-bottom: 20px;
|
||
">
|
||
<strong style="color: #856404; display: block; margin-bottom: 10px;">💡 請確保:</strong>
|
||
<ul style="margin: 0; padding-left: 20px; color: #856404;">
|
||
${suggestions.map(s => `<li style="margin: 5px 0;">${s}</li>`).join('')}
|
||
</ul>
|
||
</div>
|
||
` : ''}
|
||
|
||
${details ? `
|
||
<details style="
|
||
background: #f8f9fa;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 6px;
|
||
padding: 15px;
|
||
">
|
||
<summary style="
|
||
cursor: pointer;
|
||
font-weight: 600;
|
||
color: #495057;
|
||
user-select: none;
|
||
margin-bottom: 10px;
|
||
">🔍 詳細錯誤訊息(點擊展開)</summary>
|
||
<pre id="errorDetailsText" style="
|
||
background: white;
|
||
padding: 15px;
|
||
border-radius: 4px;
|
||
overflow-x: auto;
|
||
font-size: 0.85rem;
|
||
color: #666;
|
||
margin: 10px 0 0 0;
|
||
white-space: pre-wrap;
|
||
word-break: break-word;
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
">${details}</pre>
|
||
<button onclick="copyErrorDetails()" style="
|
||
background: #007bff;
|
||
color: white;
|
||
border: none;
|
||
padding: 8px 16px;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
margin-top: 10px;
|
||
font-size: 0.9rem;
|
||
">📋 複製錯誤訊息</button>
|
||
</details>
|
||
` : ''}
|
||
</div>
|
||
|
||
<!-- Footer -->
|
||
<div style="
|
||
padding: 15px 25px;
|
||
border-top: 1px solid #f0f0f0;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
">
|
||
<button onclick="this.closest('[style*=\\'position: fixed\\']').remove()" style="
|
||
background: #007bff;
|
||
color: white;
|
||
border: none;
|
||
padding: 10px 25px;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 0.95rem;
|
||
font-weight: 500;
|
||
">確定</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
document.body.appendChild(modal);
|
||
|
||
// 點擊背景關閉
|
||
modal.addEventListener('click', (e) => {
|
||
if (e.target === modal) {
|
||
modal.remove();
|
||
}
|
||
});
|
||
}
|
||
|
||
// 複製錯誤訊息到剪貼板
|
||
function copyErrorDetails() {
|
||
const text = document.getElementById('errorDetailsText').textContent;
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
alert('錯誤訊息已複製到剪貼板!');
|
||
}).catch(err => {
|
||
// Fallback: 選取文字
|
||
const range = document.createRange();
|
||
range.selectNode(document.getElementById('errorDetailsText'));
|
||
window.getSelection().removeAllRanges();
|
||
window.getSelection().addRange(range);
|
||
try {
|
||
document.execCommand('copy');
|
||
alert('錯誤訊息已複製到剪貼板!');
|
||
} catch (e) {
|
||
alert('複製失敗,請手動選取並複製');
|
||
}
|
||
});
|
||
}
|
||
'''
|
||
|
||
new_content = new_content.replace(' </script>', error_display_function + '\n </script>')
|
||
print("Added showCopyableError function")
|
||
|
||
# 寫回
|
||
with open('index.html', 'w', encoding='utf-8') as f:
|
||
f.write(new_content)
|
||
|
||
print("\nDone! Improvements:")
|
||
print("1. Error messages now show in a modal dialog")
|
||
print("2. Full error details are expandable")
|
||
print("3. Error details can be copied to clipboard")
|
||
print("4. Better formatting and readability")
|
||
print("\nPlease reload the page (Ctrl+F5) to see the changes")
|