mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 10:42:25 +08:00
✨ 新增設定常用提示詞
This commit is contained in:
parent
91e99a69fd
commit
fdaf8aecbd
@ -260,6 +260,44 @@
|
|||||||
"aiSummary": "Test Web UI Functionality\n\n🎯 **Test Items:**\n- Web UI server startup and operation\n- WebSocket real-time communication\n- Feedback submission functionality\n- Image upload and preview\n- Command execution functionality\n- Smart Ctrl+V image pasting\n- Multi-language interface functionality\n\n📋 **Test Steps:**\n1. Test image upload (drag-drop, file selection, clipboard)\n2. Press Ctrl+V in text box to test smart pasting\n3. Try switching languages (Traditional Chinese/Simplified Chinese/English)\n4. Test command execution functionality\n5. Submit feedback and images\n\nPlease test these features and provide feedback!",
|
"aiSummary": "Test Web UI Functionality\n\n🎯 **Test Items:**\n- Web UI server startup and operation\n- WebSocket real-time communication\n- Feedback submission functionality\n- Image upload and preview\n- Command execution functionality\n- Smart Ctrl+V image pasting\n- Multi-language interface functionality\n\n📋 **Test Steps:**\n1. Test image upload (drag-drop, file selection, clipboard)\n2. Press Ctrl+V in text box to test smart pasting\n3. Try switching languages (Traditional Chinese/Simplified Chinese/English)\n4. Test command execution functionality\n5. Submit feedback and images\n\nPlease test these features and provide feedback!",
|
||||||
"terminalWelcome": "Welcome to Interactive Feedback Terminal\n========================================\nProject Directory: {sessionId}\nEnter commands and press Enter or click Execute button\nSupported commands: ls, dir, pwd, cat, type, etc.\n\n$ "
|
"terminalWelcome": "Welcome to Interactive Feedback Terminal\n========================================\nProject Directory: {sessionId}\nEnter commands and press Enter or click Execute button\nSupported commands: ls, dir, pwd, cat, type, etc.\n\n$ "
|
||||||
},
|
},
|
||||||
|
"prompts": {
|
||||||
|
"management": {
|
||||||
|
"title": "Prompt Templates Management",
|
||||||
|
"description": "Manage your frequently used prompt templates for quick selection during feedback input",
|
||||||
|
"addNew": "Add New Prompt",
|
||||||
|
"edit": "Edit",
|
||||||
|
"delete": "Delete",
|
||||||
|
"confirmDelete": "Are you sure you want to delete this prompt?",
|
||||||
|
"emptyState": "No prompt templates created yet",
|
||||||
|
"emptyHint": "Click the 'Add New Prompt' button above to create your first prompt template",
|
||||||
|
"created": "Created",
|
||||||
|
"lastUsed": "Last Used",
|
||||||
|
"notFound": "Prompt not found",
|
||||||
|
"addSuccess": "Prompt added successfully",
|
||||||
|
"updateSuccess": "Prompt updated successfully",
|
||||||
|
"deleteSuccess": "Prompt deleted successfully"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"selectPrompt": "Select Prompt Template",
|
||||||
|
"useLastPrompt": "Use Last Prompt",
|
||||||
|
"noPrompts": "No prompt templates available, please add one in settings first",
|
||||||
|
"noLastPrompt": "No recently used prompt available",
|
||||||
|
"lastPromptApplied": "Last used prompt applied successfully",
|
||||||
|
"promptNotFound": "Prompt not found",
|
||||||
|
"promptApplied": "Prompt applied: "
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"addTitle": "Add New Prompt",
|
||||||
|
"editTitle": "Edit Prompt",
|
||||||
|
"nameLabel": "Prompt Name",
|
||||||
|
"contentLabel": "Prompt Content",
|
||||||
|
"namePlaceholder": "Enter prompt name...",
|
||||||
|
"contentPlaceholder": "Enter prompt content...",
|
||||||
|
"save": "Save",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"emptyFields": "Please fill in all required fields"
|
||||||
|
}
|
||||||
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"title": "ℹ️ About",
|
"title": "ℹ️ About",
|
||||||
"description": "A powerful MCP server that provides human-in-the-loop interactive feedback functionality for AI-assisted development tools. Supports Web UI interface, with rich features including image upload, command execution, multi-language support, and more.",
|
"description": "A powerful MCP server that provides human-in-the-loop interactive feedback functionality for AI-assisted development tools. Supports Web UI interface, with rich features including image upload, command execution, multi-language support, and more.",
|
||||||
|
@ -260,6 +260,44 @@
|
|||||||
"aiSummary": "测试 Web UI 功能\n\n🎯 **功能测试项目:**\n- Web UI 服务器启动和运行\n- WebSocket 实时通讯\n- 反馈提交功能\n- 图片上传和预览\n- 命令执行功能\n- 智能 Ctrl+V 图片粘贴\n- 多语言界面功能\n\n📋 **测试步骤:**\n1. 测试图片上传(拖拽、选择文件、剪贴板)\n2. 在文本框内按 Ctrl+V 测试智能粘贴\n3. 尝试切换语言(繁中/简中/英文)\n4. 测试命令执行功能\n5. 提交反馈和图片\n\n请测试这些功能并提供反馈!",
|
"aiSummary": "测试 Web UI 功能\n\n🎯 **功能测试项目:**\n- Web UI 服务器启动和运行\n- WebSocket 实时通讯\n- 反馈提交功能\n- 图片上传和预览\n- 命令执行功能\n- 智能 Ctrl+V 图片粘贴\n- 多语言界面功能\n\n📋 **测试步骤:**\n1. 测试图片上传(拖拽、选择文件、剪贴板)\n2. 在文本框内按 Ctrl+V 测试智能粘贴\n3. 尝试切换语言(繁中/简中/英文)\n4. 测试命令执行功能\n5. 提交反馈和图片\n\n请测试这些功能并提供反馈!",
|
||||||
"terminalWelcome": "欢迎使用交互反馈终端\n========================================\n项目目录: {sessionId}\n输入命令后按 Enter 或点击执行按钮\n支持的命令: ls, dir, pwd, cat, type 等\n\n$ "
|
"terminalWelcome": "欢迎使用交互反馈终端\n========================================\n项目目录: {sessionId}\n输入命令后按 Enter 或点击执行按钮\n支持的命令: ls, dir, pwd, cat, type 等\n\n$ "
|
||||||
},
|
},
|
||||||
|
"prompts": {
|
||||||
|
"management": {
|
||||||
|
"title": "常用提示词管理",
|
||||||
|
"description": "管理您的常用提示词模板,可在反馈输入时快速选用",
|
||||||
|
"addNew": "新增提示词",
|
||||||
|
"edit": "编辑",
|
||||||
|
"delete": "删除",
|
||||||
|
"confirmDelete": "确定要删除此提示词吗?",
|
||||||
|
"emptyState": "尚未建立任何常用提示词",
|
||||||
|
"emptyHint": "点击上方「新增提示词」按钮开始建立您的第一个提示词模板",
|
||||||
|
"created": "建立于",
|
||||||
|
"lastUsed": "最近使用",
|
||||||
|
"notFound": "找不到指定的提示词",
|
||||||
|
"addSuccess": "提示词已新增",
|
||||||
|
"updateSuccess": "提示词已更新",
|
||||||
|
"deleteSuccess": "提示词已删除"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"selectPrompt": "选择常用提示词",
|
||||||
|
"useLastPrompt": "使用上次提示词",
|
||||||
|
"noPrompts": "尚无常用提示词,请先在设置中新增",
|
||||||
|
"noLastPrompt": "尚无最近使用的提示词",
|
||||||
|
"lastPromptApplied": "已套用上次使用的提示词",
|
||||||
|
"promptNotFound": "找不到指定的提示词",
|
||||||
|
"promptApplied": "已套用提示词:"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"addTitle": "新增提示词",
|
||||||
|
"editTitle": "编辑提示词",
|
||||||
|
"nameLabel": "提示词名称",
|
||||||
|
"contentLabel": "提示词内容",
|
||||||
|
"namePlaceholder": "请输入提示词名称...",
|
||||||
|
"contentPlaceholder": "请输入提示词内容...",
|
||||||
|
"save": "保存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"emptyFields": "请填写所有必填栏位"
|
||||||
|
}
|
||||||
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"title": "ℹ️ 关于",
|
"title": "ℹ️ 关于",
|
||||||
"description": "一个强大的 MCP 服务器,为 AI 辅助开发工具提供人在回路的交互反馈功能。支持 Web UI 界面,并具备图片上传、命令执行、多语言等丰富功能。",
|
"description": "一个强大的 MCP 服务器,为 AI 辅助开发工具提供人在回路的交互反馈功能。支持 Web UI 界面,并具备图片上传、命令执行、多语言等丰富功能。",
|
||||||
|
@ -265,6 +265,44 @@
|
|||||||
"aiSummary": "測試 Web UI 功能\n\n🎯 **功能測試項目:**\n- Web UI 服務器啟動和運行\n- WebSocket 即時通訊\n- 回饋提交功能\n- 圖片上傳和預覽\n- 命令執行功能\n- 智能 Ctrl+V 圖片貼上\n- 多語言介面功能\n\n📋 **測試步驟:**\n1. 測試圖片上傳(拖拽、選擇檔案、剪貼簿)\n2. 在文字框內按 Ctrl+V 測試智能貼上\n3. 嘗試切換語言(繁中/簡中/英文)\n4. 測試命令執行功能\n5. 提交回饋和圖片\n\n請測試這些功能並提供回饋!",
|
"aiSummary": "測試 Web UI 功能\n\n🎯 **功能測試項目:**\n- Web UI 服務器啟動和運行\n- WebSocket 即時通訊\n- 回饋提交功能\n- 圖片上傳和預覽\n- 命令執行功能\n- 智能 Ctrl+V 圖片貼上\n- 多語言介面功能\n\n📋 **測試步驟:**\n1. 測試圖片上傳(拖拽、選擇檔案、剪貼簿)\n2. 在文字框內按 Ctrl+V 測試智能貼上\n3. 嘗試切換語言(繁中/簡中/英文)\n4. 測試命令執行功能\n5. 提交回饋和圖片\n\n請測試這些功能並提供回饋!",
|
||||||
"terminalWelcome": "歡迎使用互動回饋終端\n========================================\n專案目錄: {sessionId}\n輸入命令後按 Enter 或點擊執行按鈕\n支援的命令: ls, dir, pwd, cat, type 等\n\n$ "
|
"terminalWelcome": "歡迎使用互動回饋終端\n========================================\n專案目錄: {sessionId}\n輸入命令後按 Enter 或點擊執行按鈕\n支援的命令: ls, dir, pwd, cat, type 等\n\n$ "
|
||||||
},
|
},
|
||||||
|
"prompts": {
|
||||||
|
"management": {
|
||||||
|
"title": "常用提示詞管理",
|
||||||
|
"description": "管理您的常用提示詞模板,可在回饋輸入時快速選用",
|
||||||
|
"addNew": "新增提示詞",
|
||||||
|
"edit": "編輯",
|
||||||
|
"delete": "刪除",
|
||||||
|
"confirmDelete": "確定要刪除此提示詞嗎?",
|
||||||
|
"emptyState": "尚未建立任何常用提示詞",
|
||||||
|
"emptyHint": "點擊上方「新增提示詞」按鈕開始建立您的第一個提示詞模板",
|
||||||
|
"created": "建立於",
|
||||||
|
"lastUsed": "最近使用",
|
||||||
|
"notFound": "找不到指定的提示詞",
|
||||||
|
"addSuccess": "提示詞已新增",
|
||||||
|
"updateSuccess": "提示詞已更新",
|
||||||
|
"deleteSuccess": "提示詞已刪除"
|
||||||
|
},
|
||||||
|
"buttons": {
|
||||||
|
"selectPrompt": "選擇常用提示詞",
|
||||||
|
"useLastPrompt": "使用上次提示詞",
|
||||||
|
"noPrompts": "尚無常用提示詞,請先在設定中新增",
|
||||||
|
"noLastPrompt": "尚無最近使用的提示詞",
|
||||||
|
"lastPromptApplied": "已套用上次使用的提示詞",
|
||||||
|
"promptNotFound": "找不到指定的提示詞",
|
||||||
|
"promptApplied": "已套用提示詞:"
|
||||||
|
},
|
||||||
|
"modal": {
|
||||||
|
"addTitle": "新增提示詞",
|
||||||
|
"editTitle": "編輯提示詞",
|
||||||
|
"nameLabel": "提示詞名稱",
|
||||||
|
"contentLabel": "提示詞內容",
|
||||||
|
"namePlaceholder": "請輸入提示詞名稱...",
|
||||||
|
"contentPlaceholder": "請輸入提示詞內容...",
|
||||||
|
"save": "儲存",
|
||||||
|
"cancel": "取消",
|
||||||
|
"emptyFields": "請填寫所有必填欄位"
|
||||||
|
}
|
||||||
|
},
|
||||||
"about": {
|
"about": {
|
||||||
"title": "ℹ️ 關於",
|
"title": "ℹ️ 關於",
|
||||||
"description": "一個強大的 MCP 伺服器,為 AI 輔助開發工具提供人在回路的互動回饋功能。支援 Web UI 介面,並具備圖片上傳、命令執行、多語言等豐富功能。",
|
"description": "一個強大的 MCP 伺服器,為 AI 輔助開發工具提供人在回路的互動回饋功能。支援 Web UI 介面,並具備圖片上傳、命令執行、多語言等豐富功能。",
|
||||||
|
444
src/mcp_feedback_enhanced/web/static/css/prompt-management.css
Normal file
444
src/mcp_feedback_enhanced/web/static/css/prompt-management.css
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
/**
|
||||||
|
* 提示詞管理功能樣式
|
||||||
|
* ===================
|
||||||
|
*
|
||||||
|
* 包含提示詞管理相關的所有 UI 樣式
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ===== 提示詞彈窗樣式 ===== */
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 10000;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay.hide {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
max-height: 80vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transform: scale(0.9) translateY(20px);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-container.modal-large {
|
||||||
|
max-width: 700px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay.show .modal-container {
|
||||||
|
transform: scale(1) translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px 12px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 24px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close-btn:hover {
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 20px;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
border-radius: 0 0 12px 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 提示詞表單樣式 ===== */
|
||||||
|
|
||||||
|
.prompt-form .input-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-form .input-group:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-form .text-input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-form input[type="text"].text-input {
|
||||||
|
height: 40px !important;
|
||||||
|
min-height: 40px !important;
|
||||||
|
max-height: 40px !important;
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-form textarea.text-input {
|
||||||
|
min-height: 200px !important;
|
||||||
|
height: 200px !important;
|
||||||
|
padding: 12px !important;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 提示詞列表樣式 ===== */
|
||||||
|
|
||||||
|
.prompt-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item {
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item:hover {
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
background: rgba(0, 122, 204, 0.05);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 122, 204, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item-name {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item-date {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item-content {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.4;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item-used {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-style: italic;
|
||||||
|
padding: 40px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 設定頁籤中的提示詞管理樣式 ===== */
|
||||||
|
|
||||||
|
.prompt-management-section {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-management-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-management-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-add-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-item {
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-item:hover {
|
||||||
|
border-color: rgba(0, 122, 204, 0.5);
|
||||||
|
background: rgba(0, 122, 204, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-info {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-content {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.3;
|
||||||
|
max-height: 40px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-meta {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-action-btn {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-action-btn:hover {
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
color: var(--accent-color);
|
||||||
|
background: rgba(0, 122, 204, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-action-btn.delete:hover {
|
||||||
|
border-color: #dc3545;
|
||||||
|
color: #dc3545;
|
||||||
|
background: rgba(220, 53, 69, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== input-group 按鈕樣式 ===== */
|
||||||
|
|
||||||
|
.prompt-input-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-btn {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-btn:hover {
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
background: rgba(0, 122, 204, 0.1);
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-btn:disabled:hover {
|
||||||
|
border-color: var(--border-color);
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 響應式設計 ===== */
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.modal-container {
|
||||||
|
width: 95%;
|
||||||
|
max-height: 90vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 12px 16px;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-management-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-item {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-actions {
|
||||||
|
margin-top: 8px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-btn {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 動畫效果 ===== */
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-settings-item,
|
||||||
|
.prompt-item {
|
||||||
|
animation: fadeIn 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 無障礙改進 ===== */
|
||||||
|
|
||||||
|
.prompt-item:focus,
|
||||||
|
.prompt-action-btn:focus,
|
||||||
|
.prompt-input-btn:focus {
|
||||||
|
outline: 2px solid var(--accent-color);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== 深色主題適配 ===== */
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.modal-overlay {
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-item:hover,
|
||||||
|
.prompt-settings-item:hover {
|
||||||
|
background: rgba(0, 122, 204, 0.1);
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,12 @@
|
|||||||
this.settingsManager = null;
|
this.settingsManager = null;
|
||||||
this.uiManager = null;
|
this.uiManager = null;
|
||||||
|
|
||||||
|
// 提示詞管理器
|
||||||
|
this.promptManager = null;
|
||||||
|
this.promptModal = null;
|
||||||
|
this.promptSettingsUI = null;
|
||||||
|
this.promptInputButtons = null;
|
||||||
|
|
||||||
// 應用程式狀態
|
// 應用程式狀態
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.pendingSubmission = null;
|
this.pendingSubmission = null;
|
||||||
@ -182,16 +188,17 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 9. 初始化提示詞管理器
|
||||||
|
self.initializePromptManagers();
|
||||||
|
|
||||||
|
// 10. 應用設定到 UI
|
||||||
// 8. 應用設定到 UI
|
|
||||||
self.settingsManager.applyToUI();
|
self.settingsManager.applyToUI();
|
||||||
|
|
||||||
// 8. 初始化各個管理器
|
// 11. 初始化各個管理器
|
||||||
self.uiManager.initTabs();
|
self.uiManager.initTabs();
|
||||||
self.imageHandler.init();
|
self.imageHandler.init();
|
||||||
|
|
||||||
// 9. 建立 WebSocket 連接
|
// 12. 建立 WebSocket 連接
|
||||||
self.webSocketManager.connect();
|
self.webSocketManager.connect();
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
@ -369,7 +376,54 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化提示詞管理器
|
||||||
|
*/
|
||||||
|
FeedbackApp.prototype.initializePromptManagers = function() {
|
||||||
|
console.log('📝 初始化提示詞管理器...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 檢查提示詞模組是否已載入
|
||||||
|
if (!window.MCPFeedback.Prompt) {
|
||||||
|
console.warn('⚠️ 提示詞模組未載入,跳過初始化');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 初始化提示詞管理器
|
||||||
|
this.promptManager = new window.MCPFeedback.Prompt.PromptManager({
|
||||||
|
settingsManager: this.settingsManager
|
||||||
|
});
|
||||||
|
this.promptManager.init();
|
||||||
|
|
||||||
|
// 2. 初始化提示詞彈窗
|
||||||
|
this.promptModal = new window.MCPFeedback.Prompt.PromptModal();
|
||||||
|
|
||||||
|
// 3. 初始化設定頁籤 UI
|
||||||
|
this.promptSettingsUI = new window.MCPFeedback.Prompt.PromptSettingsUI({
|
||||||
|
promptManager: this.promptManager,
|
||||||
|
promptModal: this.promptModal
|
||||||
|
});
|
||||||
|
this.promptSettingsUI.init('#promptManagementContainer');
|
||||||
|
|
||||||
|
// 4. 初始化輸入按鈕
|
||||||
|
this.promptInputButtons = new window.MCPFeedback.Prompt.PromptInputButtons({
|
||||||
|
promptManager: this.promptManager,
|
||||||
|
promptModal: this.promptModal
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化輸入按鈕到所有回饋輸入區域
|
||||||
|
const inputContainers = [
|
||||||
|
'#feedbackText', // 回饋分頁
|
||||||
|
'#combinedFeedbackText' // 工作區分頁
|
||||||
|
];
|
||||||
|
this.promptInputButtons.init(inputContainers);
|
||||||
|
|
||||||
|
console.log('✅ 提示詞管理器初始化完成');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 提示詞管理器初始化失敗:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 處理 WebSocket 開啟
|
* 處理 WebSocket 開啟
|
||||||
|
@ -0,0 +1,384 @@
|
|||||||
|
/**
|
||||||
|
* MCP Feedback Enhanced - 提示詞輸入按鈕模組
|
||||||
|
* ==========================================
|
||||||
|
*
|
||||||
|
* 處理 input-group 區域的提示詞功能按鈕
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// 確保命名空間存在
|
||||||
|
window.MCPFeedback = window.MCPFeedback || {};
|
||||||
|
window.MCPFeedback.Prompt = window.MCPFeedback.Prompt || {};
|
||||||
|
|
||||||
|
const Utils = window.MCPFeedback.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示詞輸入按鈕管理器
|
||||||
|
*/
|
||||||
|
function PromptInputButtons(options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// 依賴注入
|
||||||
|
this.promptManager = options.promptManager || null;
|
||||||
|
this.promptModal = options.promptModal || null;
|
||||||
|
|
||||||
|
// UI 元素
|
||||||
|
this.containers = [];
|
||||||
|
this.selectButtons = [];
|
||||||
|
this.lastUsedButtons = [];
|
||||||
|
|
||||||
|
// 狀態
|
||||||
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
console.log('🔘 PromptInputButtons 初始化完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化輸入按鈕
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.init = function(containerSelectors) {
|
||||||
|
if (!Array.isArray(containerSelectors)) {
|
||||||
|
containerSelectors = [containerSelectors];
|
||||||
|
}
|
||||||
|
|
||||||
|
let successCount = 0;
|
||||||
|
|
||||||
|
containerSelectors.forEach((selector, index) => {
|
||||||
|
const container = document.querySelector(selector);
|
||||||
|
if (container) {
|
||||||
|
this.containers.push(container);
|
||||||
|
this.createButtons(container, index);
|
||||||
|
successCount++;
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ 找不到提示詞按鈕容器:', selector);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (successCount > 0) {
|
||||||
|
// 設置事件監聽器
|
||||||
|
this.setupEventListeners();
|
||||||
|
|
||||||
|
// 更新按鈕狀態
|
||||||
|
this.updateButtonStates();
|
||||||
|
|
||||||
|
this.isInitialized = true;
|
||||||
|
console.log('✅ PromptInputButtons 初始化完成,成功創建', successCount, '組按鈕');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error('❌ 沒有成功創建任何提示詞按鈕');
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建按鈕
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.createButtons = function(container, index) {
|
||||||
|
const buttonsHtml = `
|
||||||
|
<div class="prompt-input-buttons">
|
||||||
|
<button type="button" class="prompt-input-btn select-prompt-btn" data-container-index="${index}">
|
||||||
|
<span>📝</span>
|
||||||
|
<span data-i18n="prompts.buttons.selectPrompt">選擇常用提示詞</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="prompt-input-btn last-prompt-btn" data-container-index="${index}">
|
||||||
|
<span>🔄</span>
|
||||||
|
<span data-i18n="prompts.buttons.useLastPrompt">使用上次提示詞</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 在 input-group 的 label 後面插入按鈕
|
||||||
|
const inputGroup = container.closest('.input-group') || container;
|
||||||
|
const label = inputGroup.querySelector('.input-label');
|
||||||
|
|
||||||
|
if (label) {
|
||||||
|
label.insertAdjacentHTML('afterend', buttonsHtml);
|
||||||
|
} else {
|
||||||
|
inputGroup.insertAdjacentHTML('afterbegin', buttonsHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 獲取按鈕引用
|
||||||
|
const buttonContainer = inputGroup.querySelector('.prompt-input-buttons');
|
||||||
|
if (buttonContainer) {
|
||||||
|
this.selectButtons.push(buttonContainer.querySelector('.select-prompt-btn'));
|
||||||
|
this.lastUsedButtons.push(buttonContainer.querySelector('.last-prompt-btn'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設置事件監聽器
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.setupEventListeners = function() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
// 選擇提示詞按鈕事件
|
||||||
|
this.selectButtons.forEach(function(button) {
|
||||||
|
if (button) {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
const containerIndex = parseInt(button.getAttribute('data-container-index'));
|
||||||
|
self.handleSelectPrompt(containerIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用上次提示詞按鈕事件
|
||||||
|
this.lastUsedButtons.forEach(function(button) {
|
||||||
|
if (button) {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
const containerIndex = parseInt(button.getAttribute('data-container-index'));
|
||||||
|
self.handleUseLastPrompt(containerIndex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 設置提示詞管理器回調
|
||||||
|
if (this.promptManager) {
|
||||||
|
this.promptManager.addPromptsChangeCallback(function() {
|
||||||
|
self.updateButtonStates();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.promptManager.addLastUsedChangeCallback(function() {
|
||||||
|
self.updateButtonStates();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 設置彈窗回調
|
||||||
|
if (this.promptModal) {
|
||||||
|
this.promptModal.onSelect = function(promptId) {
|
||||||
|
self.handlePromptSelected(promptId);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理選擇提示詞
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.handleSelectPrompt = function(containerIndex) {
|
||||||
|
if (!this.promptManager || !this.promptModal) {
|
||||||
|
console.error('❌ PromptManager 或 PromptModal 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompts = this.promptManager.getPromptsSortedByUsage();
|
||||||
|
|
||||||
|
if (prompts.length === 0) {
|
||||||
|
this.showError(this.t('prompts.buttons.noPrompts', '尚無常用提示詞,請先在設定中新增'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 記錄當前容器索引,用於後續插入文字
|
||||||
|
this.currentContainerIndex = containerIndex;
|
||||||
|
|
||||||
|
// 顯示選擇彈窗
|
||||||
|
this.promptModal.showSelectModal(prompts);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理使用上次提示詞
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.handleUseLastPrompt = function(containerIndex) {
|
||||||
|
if (!this.promptManager) {
|
||||||
|
console.error('❌ PromptManager 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastPrompt = this.promptManager.getLastUsedPrompt();
|
||||||
|
|
||||||
|
if (!lastPrompt) {
|
||||||
|
this.showError(this.t('prompts.buttons.noLastPrompt', '尚無最近使用的提示詞'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入提示詞內容
|
||||||
|
this.insertPromptContent(containerIndex, lastPrompt);
|
||||||
|
|
||||||
|
// 更新使用記錄
|
||||||
|
this.promptManager.usePrompt(lastPrompt.id);
|
||||||
|
|
||||||
|
this.showSuccess(this.t('prompts.buttons.lastPromptApplied', '已套用上次使用的提示詞'));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理提示詞選擇完成
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.handlePromptSelected = function(promptId) {
|
||||||
|
if (!this.promptManager) {
|
||||||
|
console.error('❌ PromptManager 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = this.promptManager.getPromptById(promptId);
|
||||||
|
if (!prompt) {
|
||||||
|
this.showError(this.t('prompts.buttons.promptNotFound', '找不到指定的提示詞'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 插入提示詞內容
|
||||||
|
this.insertPromptContent(this.currentContainerIndex, prompt);
|
||||||
|
|
||||||
|
// 更新使用記錄
|
||||||
|
this.promptManager.usePrompt(promptId);
|
||||||
|
|
||||||
|
this.showSuccess(this.t('prompts.buttons.promptApplied', '已套用提示詞:') + prompt.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入提示詞內容到輸入框
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.insertPromptContent = function(containerIndex, prompt) {
|
||||||
|
if (containerIndex < 0 || containerIndex >= this.containers.length) {
|
||||||
|
console.error('❌ 無效的容器索引:', containerIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = this.containers[containerIndex];
|
||||||
|
|
||||||
|
// 檢查容器本身是否是輸入元素
|
||||||
|
let textarea = null;
|
||||||
|
if (container.tagName === 'TEXTAREA' || container.tagName === 'INPUT') {
|
||||||
|
textarea = container;
|
||||||
|
} else {
|
||||||
|
// 如果不是,則在容器內查找
|
||||||
|
textarea = container.querySelector('textarea') || container.querySelector('input[type="text"]');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!textarea) {
|
||||||
|
console.error('❌ 找不到輸入框,容器:', container);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 獲取當前內容和游標位置
|
||||||
|
const currentContent = textarea.value;
|
||||||
|
const cursorPosition = textarea.selectionStart;
|
||||||
|
|
||||||
|
// 決定插入方式
|
||||||
|
let newContent;
|
||||||
|
let newCursorPosition;
|
||||||
|
|
||||||
|
if (currentContent.trim() === '') {
|
||||||
|
// 如果輸入框為空,直接插入
|
||||||
|
newContent = prompt.content;
|
||||||
|
newCursorPosition = prompt.content.length;
|
||||||
|
} else {
|
||||||
|
// 如果有內容,在游標位置插入
|
||||||
|
const beforeCursor = currentContent.substring(0, cursorPosition);
|
||||||
|
const afterCursor = currentContent.substring(cursorPosition);
|
||||||
|
|
||||||
|
// 添加適當的分隔符
|
||||||
|
const separator = beforeCursor.endsWith('\n') || beforeCursor === '' ? '' : '\n\n';
|
||||||
|
|
||||||
|
newContent = beforeCursor + separator + prompt.content + afterCursor;
|
||||||
|
newCursorPosition = beforeCursor.length + separator.length + prompt.content.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新內容
|
||||||
|
textarea.value = newContent;
|
||||||
|
|
||||||
|
// 設置游標位置
|
||||||
|
textarea.focus();
|
||||||
|
textarea.setSelectionRange(newCursorPosition, newCursorPosition);
|
||||||
|
|
||||||
|
// 觸發 input 事件,確保其他監聽器能夠響應
|
||||||
|
const inputEvent = new Event('input', { bubbles: true });
|
||||||
|
textarea.dispatchEvent(inputEvent);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新按鈕狀態
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.updateButtonStates = function() {
|
||||||
|
if (!this.promptManager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompts = this.promptManager.getAllPrompts();
|
||||||
|
const lastPrompt = this.promptManager.getLastUsedPrompt();
|
||||||
|
|
||||||
|
// 更新選擇提示詞按鈕
|
||||||
|
this.selectButtons.forEach(function(button) {
|
||||||
|
if (button) {
|
||||||
|
button.disabled = prompts.length === 0;
|
||||||
|
|
||||||
|
if (prompts.length === 0) {
|
||||||
|
button.title = '尚無常用提示詞';
|
||||||
|
} else {
|
||||||
|
button.title = `選擇常用提示詞 (${prompts.length} 個可用)`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新使用上次提示詞按鈕
|
||||||
|
this.lastUsedButtons.forEach(function(button) {
|
||||||
|
if (button) {
|
||||||
|
button.disabled = !lastPrompt;
|
||||||
|
|
||||||
|
if (!lastPrompt) {
|
||||||
|
button.title = '尚無最近使用的提示詞';
|
||||||
|
} else {
|
||||||
|
button.title = `使用上次提示詞:${lastPrompt.name}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示成功訊息
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.showSuccess = function(message) {
|
||||||
|
if (window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.showMessage) {
|
||||||
|
window.MCPFeedback.Utils.showMessage(message, 'success');
|
||||||
|
} else {
|
||||||
|
console.log('✅', message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示錯誤訊息
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.showError = function(message) {
|
||||||
|
if (window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.showMessage) {
|
||||||
|
window.MCPFeedback.Utils.showMessage(message, 'error');
|
||||||
|
} else {
|
||||||
|
alert(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 翻譯函數
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.t = function(key, fallback) {
|
||||||
|
if (window.i18nManager && typeof window.i18nManager.t === 'function') {
|
||||||
|
return window.i18nManager.t(key, fallback);
|
||||||
|
}
|
||||||
|
return fallback || key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 銷毀按鈕
|
||||||
|
*/
|
||||||
|
PromptInputButtons.prototype.destroy = function() {
|
||||||
|
// 移除所有按鈕容器
|
||||||
|
this.containers.forEach(function(container) {
|
||||||
|
const buttonContainer = container.querySelector('.prompt-input-buttons');
|
||||||
|
if (buttonContainer) {
|
||||||
|
buttonContainer.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 清空引用
|
||||||
|
this.containers = [];
|
||||||
|
this.selectButtons = [];
|
||||||
|
this.lastUsedButtons = [];
|
||||||
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
console.log('🗑️ PromptInputButtons 已銷毀');
|
||||||
|
};
|
||||||
|
|
||||||
|
// 將 PromptInputButtons 加入命名空間
|
||||||
|
window.MCPFeedback.Prompt.PromptInputButtons = PromptInputButtons;
|
||||||
|
|
||||||
|
console.log('✅ PromptInputButtons 模組載入完成');
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,361 @@
|
|||||||
|
/**
|
||||||
|
* MCP Feedback Enhanced - 提示詞管理模組
|
||||||
|
* =====================================
|
||||||
|
*
|
||||||
|
* 處理常用提示詞的儲存、管理和操作
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// 確保命名空間和依賴存在
|
||||||
|
window.MCPFeedback = window.MCPFeedback || {};
|
||||||
|
window.MCPFeedback.Prompt = window.MCPFeedback.Prompt || {};
|
||||||
|
const Utils = window.MCPFeedback.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示詞管理器建構函數
|
||||||
|
*/
|
||||||
|
function PromptManager(options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// 設定管理器引用
|
||||||
|
this.settingsManager = options.settingsManager || null;
|
||||||
|
|
||||||
|
// 預設提示詞設定
|
||||||
|
this.defaultPromptSettings = {
|
||||||
|
prompts: [],
|
||||||
|
lastUsedPromptId: null,
|
||||||
|
promptCounter: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 當前提示詞設定
|
||||||
|
this.currentPromptSettings = Utils.deepClone(this.defaultPromptSettings);
|
||||||
|
|
||||||
|
// 回調函數列表
|
||||||
|
this.onPromptsChangeCallbacks = [];
|
||||||
|
this.onLastUsedChangeCallbacks = [];
|
||||||
|
|
||||||
|
// 向後相容的單一回調
|
||||||
|
if (options.onPromptsChange) {
|
||||||
|
this.onPromptsChangeCallbacks.push(options.onPromptsChange);
|
||||||
|
}
|
||||||
|
if (options.onLastUsedChange) {
|
||||||
|
this.onLastUsedChangeCallbacks.push(options.onLastUsedChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ PromptManager 初始化完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化提示詞管理器
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.init = function() {
|
||||||
|
if (this.settingsManager) {
|
||||||
|
// 從設定管理器載入提示詞資料
|
||||||
|
this.loadFromSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📋 PromptManager 初始化完成,提示詞數量:', this.currentPromptSettings.prompts.length);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加提示詞變更回調
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.addPromptsChangeCallback = function(callback) {
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
this.onPromptsChangeCallbacks.push(callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加最近使用變更回調
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.addLastUsedChangeCallback = function(callback) {
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
this.onLastUsedChangeCallbacks.push(callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 觸發提示詞變更回調
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.triggerPromptsChangeCallbacks = function() {
|
||||||
|
const prompts = this.currentPromptSettings.prompts;
|
||||||
|
this.onPromptsChangeCallbacks.forEach(function(callback) {
|
||||||
|
try {
|
||||||
|
callback(prompts);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 提示詞變更回調執行失敗:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 觸發最近使用變更回調
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.triggerLastUsedChangeCallbacks = function(prompt) {
|
||||||
|
this.onLastUsedChangeCallbacks.forEach(function(callback) {
|
||||||
|
try {
|
||||||
|
callback(prompt);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 最近使用變更回調執行失敗:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 從設定管理器載入提示詞資料
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.loadFromSettings = function() {
|
||||||
|
if (!this.settingsManager) {
|
||||||
|
console.warn('⚠️ SettingsManager 未設定,無法載入提示詞資料');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const promptSettings = this.settingsManager.get('promptSettings');
|
||||||
|
if (promptSettings) {
|
||||||
|
this.currentPromptSettings = this.mergePromptSettings(this.defaultPromptSettings, promptSettings);
|
||||||
|
console.log('📥 從設定載入提示詞資料:', this.currentPromptSettings.prompts.length, '個提示詞');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 儲存提示詞資料到設定管理器
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.saveToSettings = function() {
|
||||||
|
if (!this.settingsManager) {
|
||||||
|
console.warn('⚠️ SettingsManager 未設定,無法儲存提示詞資料');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.settingsManager.set('promptSettings', this.currentPromptSettings);
|
||||||
|
console.log('💾 提示詞資料已儲存');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ 儲存提示詞資料失敗:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合併提示詞設定
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.mergePromptSettings = function(defaultSettings, userSettings) {
|
||||||
|
const merged = Utils.deepClone(defaultSettings);
|
||||||
|
|
||||||
|
if (userSettings.prompts && Array.isArray(userSettings.prompts)) {
|
||||||
|
merged.prompts = userSettings.prompts;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userSettings.lastUsedPromptId) {
|
||||||
|
merged.lastUsedPromptId = userSettings.lastUsedPromptId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof userSettings.promptCounter === 'number') {
|
||||||
|
merged.promptCounter = userSettings.promptCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.addPrompt = function(name, content) {
|
||||||
|
if (!name || !content) {
|
||||||
|
throw new Error('提示詞名稱和內容不能為空');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查名稱是否重複
|
||||||
|
if (this.getPromptByName(name)) {
|
||||||
|
throw new Error('提示詞名稱已存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = {
|
||||||
|
id: this.generatePromptId(),
|
||||||
|
name: name.trim(),
|
||||||
|
content: content.trim(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
lastUsedAt: null
|
||||||
|
};
|
||||||
|
|
||||||
|
this.currentPromptSettings.prompts.push(prompt);
|
||||||
|
this.saveToSettings();
|
||||||
|
|
||||||
|
// 觸發回調
|
||||||
|
this.triggerPromptsChangeCallbacks();
|
||||||
|
|
||||||
|
console.log('➕ 新增提示詞:', prompt.name);
|
||||||
|
return prompt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.updatePrompt = function(id, name, content) {
|
||||||
|
if (!name || !content) {
|
||||||
|
throw new Error('提示詞名稱和內容不能為空');
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = this.getPromptById(id);
|
||||||
|
if (!prompt) {
|
||||||
|
throw new Error('找不到指定的提示詞');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 檢查名稱是否與其他提示詞重複
|
||||||
|
const existingPrompt = this.getPromptByName(name);
|
||||||
|
if (existingPrompt && existingPrompt.id !== id) {
|
||||||
|
throw new Error('提示詞名稱已存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt.name = name.trim();
|
||||||
|
prompt.content = content.trim();
|
||||||
|
|
||||||
|
this.saveToSettings();
|
||||||
|
|
||||||
|
// 觸發回調
|
||||||
|
this.triggerPromptsChangeCallbacks();
|
||||||
|
|
||||||
|
console.log('✏️ 更新提示詞:', prompt.name);
|
||||||
|
return prompt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刪除提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.deletePrompt = function(id) {
|
||||||
|
const index = this.currentPromptSettings.prompts.findIndex(p => p.id === id);
|
||||||
|
if (index === -1) {
|
||||||
|
throw new Error('找不到指定的提示詞');
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = this.currentPromptSettings.prompts[index];
|
||||||
|
this.currentPromptSettings.prompts.splice(index, 1);
|
||||||
|
|
||||||
|
// 如果刪除的是最近使用的提示詞,清除記錄
|
||||||
|
if (this.currentPromptSettings.lastUsedPromptId === id) {
|
||||||
|
this.currentPromptSettings.lastUsedPromptId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveToSettings();
|
||||||
|
|
||||||
|
// 觸發回調
|
||||||
|
this.triggerPromptsChangeCallbacks();
|
||||||
|
|
||||||
|
console.log('🗑️ 刪除提示詞:', prompt.name);
|
||||||
|
return prompt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用提示詞(更新最近使用記錄)
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.usePrompt = function(id) {
|
||||||
|
const prompt = this.getPromptById(id);
|
||||||
|
if (!prompt) {
|
||||||
|
throw new Error('找不到指定的提示詞');
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt.lastUsedAt = new Date().toISOString();
|
||||||
|
this.currentPromptSettings.lastUsedPromptId = id;
|
||||||
|
|
||||||
|
this.saveToSettings();
|
||||||
|
|
||||||
|
// 觸發回調
|
||||||
|
this.triggerLastUsedChangeCallbacks(prompt);
|
||||||
|
|
||||||
|
console.log('🎯 使用提示詞:', prompt.name);
|
||||||
|
return prompt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 獲取所有提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.getAllPrompts = function() {
|
||||||
|
return [...this.currentPromptSettings.prompts];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根據 ID 獲取提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.getPromptById = function(id) {
|
||||||
|
return this.currentPromptSettings.prompts.find(p => p.id === id) || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根據名稱獲取提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.getPromptByName = function(name) {
|
||||||
|
return this.currentPromptSettings.prompts.find(p => p.name === name) || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 獲取最近使用的提示詞
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.getLastUsedPrompt = function() {
|
||||||
|
if (!this.currentPromptSettings.lastUsedPromptId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.getPromptById(this.currentPromptSettings.lastUsedPromptId);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 獲取按使用時間排序的提示詞列表
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.getPromptsSortedByUsage = function() {
|
||||||
|
const prompts = [...this.currentPromptSettings.prompts];
|
||||||
|
return prompts.sort((a, b) => {
|
||||||
|
// 最近使用的排在前面
|
||||||
|
if (!a.lastUsedAt && !b.lastUsedAt) {
|
||||||
|
return new Date(b.createdAt) - new Date(a.createdAt);
|
||||||
|
}
|
||||||
|
if (!a.lastUsedAt) return 1;
|
||||||
|
if (!b.lastUsedAt) return -1;
|
||||||
|
return new Date(b.lastUsedAt) - new Date(a.lastUsedAt);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成提示詞 ID
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.generatePromptId = function() {
|
||||||
|
this.currentPromptSettings.promptCounter++;
|
||||||
|
return 'prompt_' + this.currentPromptSettings.promptCounter + '_' + Date.now();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置所有提示詞資料
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.resetAllPrompts = function() {
|
||||||
|
this.currentPromptSettings = Utils.deepClone(this.defaultPromptSettings);
|
||||||
|
this.saveToSettings();
|
||||||
|
|
||||||
|
// 觸發回調
|
||||||
|
this.triggerPromptsChangeCallbacks();
|
||||||
|
|
||||||
|
console.log('🔄 重置所有提示詞資料');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 獲取提示詞統計資訊
|
||||||
|
*/
|
||||||
|
PromptManager.prototype.getStatistics = function() {
|
||||||
|
const prompts = this.currentPromptSettings.prompts;
|
||||||
|
const usedPrompts = prompts.filter(p => p.lastUsedAt);
|
||||||
|
|
||||||
|
return {
|
||||||
|
total: prompts.length,
|
||||||
|
used: usedPrompts.length,
|
||||||
|
unused: prompts.length - usedPrompts.length,
|
||||||
|
lastUsed: this.getLastUsedPrompt()
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 將 PromptManager 加入命名空間
|
||||||
|
window.MCPFeedback.Prompt.PromptManager = PromptManager;
|
||||||
|
|
||||||
|
console.log('✅ PromptManager 模組載入完成');
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,458 @@
|
|||||||
|
/**
|
||||||
|
* MCP Feedback Enhanced - 提示詞彈窗管理模組
|
||||||
|
* ==========================================
|
||||||
|
*
|
||||||
|
* 處理提示詞新增、編輯、選擇的彈窗介面
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// 確保命名空間存在
|
||||||
|
window.MCPFeedback = window.MCPFeedback || {};
|
||||||
|
window.MCPFeedback.Prompt = window.MCPFeedback.Prompt || {};
|
||||||
|
|
||||||
|
const Utils = window.MCPFeedback.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示詞彈窗管理器
|
||||||
|
*/
|
||||||
|
function PromptModal(options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// 彈窗選項
|
||||||
|
this.enableEscapeClose = options.enableEscapeClose !== false;
|
||||||
|
this.enableBackdropClose = options.enableBackdropClose !== false;
|
||||||
|
|
||||||
|
// 當前彈窗引用
|
||||||
|
this.currentModal = null;
|
||||||
|
this.keydownHandler = null;
|
||||||
|
|
||||||
|
// 回調函數
|
||||||
|
this.onSave = options.onSave || null;
|
||||||
|
this.onSelect = options.onSelect || null;
|
||||||
|
this.onCancel = options.onCancel || null;
|
||||||
|
|
||||||
|
console.log('🔍 PromptModal 初始化完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示新增提示詞彈窗
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.showAddModal = function() {
|
||||||
|
const modalData = {
|
||||||
|
type: 'add',
|
||||||
|
title: this.t('prompts.modal.addTitle', '新增提示詞'),
|
||||||
|
prompt: {
|
||||||
|
name: '',
|
||||||
|
content: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createAndShowModal(modalData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示編輯提示詞彈窗
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.showEditModal = function(prompt) {
|
||||||
|
if (!prompt) {
|
||||||
|
console.error('❌ 編輯提示詞時缺少提示詞資料');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalData = {
|
||||||
|
type: 'edit',
|
||||||
|
title: this.t('prompts.modal.editTitle', '編輯提示詞'),
|
||||||
|
prompt: {
|
||||||
|
id: prompt.id,
|
||||||
|
name: prompt.name,
|
||||||
|
content: prompt.content
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createAndShowModal(modalData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示選擇提示詞彈窗
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.showSelectModal = function(prompts) {
|
||||||
|
if (!prompts || !Array.isArray(prompts)) {
|
||||||
|
console.error('❌ 選擇提示詞時缺少提示詞列表');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const modalData = {
|
||||||
|
type: 'select',
|
||||||
|
title: this.t('prompts.buttons.selectPrompt', '選擇常用提示詞'),
|
||||||
|
prompts: prompts
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createAndShowModal(modalData);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建並顯示彈窗
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.createAndShowModal = function(modalData) {
|
||||||
|
// 如果已有彈窗,先關閉
|
||||||
|
if (this.currentModal) {
|
||||||
|
this.closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 創建彈窗 HTML
|
||||||
|
const modalHtml = this.createModalHTML(modalData);
|
||||||
|
|
||||||
|
// 插入到頁面中
|
||||||
|
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
||||||
|
|
||||||
|
// 獲取彈窗元素
|
||||||
|
this.currentModal = document.getElementById('promptModal');
|
||||||
|
|
||||||
|
// 設置事件監聽器
|
||||||
|
this.setupEventListeners(modalData);
|
||||||
|
|
||||||
|
// 添加顯示動畫
|
||||||
|
this.showModal();
|
||||||
|
|
||||||
|
// 聚焦到第一個輸入框
|
||||||
|
this.focusFirstInput();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建彈窗 HTML
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.createModalHTML = function(modalData) {
|
||||||
|
const modalId = 'promptModal';
|
||||||
|
|
||||||
|
if (modalData.type === 'select') {
|
||||||
|
return this.createSelectModalHTML(modalId, modalData);
|
||||||
|
} else {
|
||||||
|
return this.createEditModalHTML(modalId, modalData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建編輯彈窗 HTML
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.createEditModalHTML = function(modalId, modalData) {
|
||||||
|
return `
|
||||||
|
<div id="${modalId}" class="modal-overlay">
|
||||||
|
<div class="modal-container">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">${Utils.escapeHtml(modalData.title)}</h3>
|
||||||
|
<button type="button" class="modal-close-btn" aria-label="關閉">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="promptForm" class="prompt-form">
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="promptName" class="input-label">${this.t('prompts.modal.nameLabel', '提示詞名稱')}</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="promptName"
|
||||||
|
class="text-input"
|
||||||
|
value="${Utils.escapeHtml(modalData.prompt.name)}"
|
||||||
|
placeholder="${this.t('prompts.modal.namePlaceholder', '請輸入提示詞名稱...')}"
|
||||||
|
required
|
||||||
|
maxlength="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="promptContent" class="input-label">${this.t('prompts.modal.contentLabel', '提示詞內容')}</label>
|
||||||
|
<textarea
|
||||||
|
id="promptContent"
|
||||||
|
class="text-input"
|
||||||
|
placeholder="${this.t('prompts.modal.contentPlaceholder', '請輸入提示詞內容...')}"
|
||||||
|
required
|
||||||
|
rows="8"
|
||||||
|
style="min-height: 200px; resize: vertical;"
|
||||||
|
>${Utils.escapeHtml(modalData.prompt.content)}</textarea>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary modal-cancel-btn">
|
||||||
|
${this.t('prompts.modal.cancel', '取消')}
|
||||||
|
</button>
|
||||||
|
<button type="submit" form="promptForm" class="btn btn-primary modal-save-btn">
|
||||||
|
${this.t('prompts.modal.save', '儲存')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建選擇彈窗 HTML
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.createSelectModalHTML = function(modalId, modalData) {
|
||||||
|
const promptsHtml = modalData.prompts.map(prompt => `
|
||||||
|
<div class="prompt-item" data-prompt-id="${prompt.id}">
|
||||||
|
<div class="prompt-item-header">
|
||||||
|
<h4 class="prompt-item-name">${Utils.escapeHtml(prompt.name)}</h4>
|
||||||
|
<span class="prompt-item-date">${this.formatDate(prompt.createdAt)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="prompt-item-content">${Utils.escapeHtml(this.truncateText(prompt.content, 100))}</div>
|
||||||
|
${prompt.lastUsedAt ? `<div class="prompt-item-used">最近使用:${this.formatDate(prompt.lastUsedAt)}</div>` : ''}
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div id="${modalId}" class="modal-overlay">
|
||||||
|
<div class="modal-container modal-large">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">${Utils.escapeHtml(modalData.title)}</h3>
|
||||||
|
<button type="button" class="modal-close-btn" aria-label="關閉">×</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="prompt-list">
|
||||||
|
${promptsHtml || '<div class="empty-state">尚無常用提示詞</div>'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary modal-cancel-btn">
|
||||||
|
${this.t('prompts.modal.cancel', '取消')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設置事件監聽器
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.setupEventListeners = function(modalData) {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
// 關閉按鈕
|
||||||
|
const closeBtn = this.currentModal.querySelector('.modal-close-btn');
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', function() {
|
||||||
|
self.closeModal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消按鈕
|
||||||
|
const cancelBtn = this.currentModal.querySelector('.modal-cancel-btn');
|
||||||
|
if (cancelBtn) {
|
||||||
|
cancelBtn.addEventListener('click', function() {
|
||||||
|
self.closeModal();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 背景點擊關閉
|
||||||
|
if (this.enableBackdropClose) {
|
||||||
|
this.currentModal.addEventListener('click', function(e) {
|
||||||
|
if (e.target === self.currentModal) {
|
||||||
|
self.closeModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ESC 鍵關閉
|
||||||
|
if (this.enableEscapeClose) {
|
||||||
|
this.keydownHandler = function(e) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
self.closeModal();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('keydown', this.keydownHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根據彈窗類型設置特定事件
|
||||||
|
if (modalData.type === 'select') {
|
||||||
|
this.setupSelectModalEvents();
|
||||||
|
} else {
|
||||||
|
this.setupEditModalEvents(modalData);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設置編輯彈窗事件
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.setupEditModalEvents = function(modalData) {
|
||||||
|
const self = this;
|
||||||
|
const form = this.currentModal.querySelector('#promptForm');
|
||||||
|
|
||||||
|
if (form) {
|
||||||
|
form.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
self.handleFormSubmit(modalData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設置選擇彈窗事件
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.setupSelectModalEvents = function() {
|
||||||
|
const self = this;
|
||||||
|
const promptItems = this.currentModal.querySelectorAll('.prompt-item');
|
||||||
|
|
||||||
|
promptItems.forEach(function(item) {
|
||||||
|
item.addEventListener('click', function() {
|
||||||
|
const promptId = item.getAttribute('data-prompt-id');
|
||||||
|
self.handlePromptSelect(promptId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理表單提交
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.handleFormSubmit = function(modalData) {
|
||||||
|
const nameInput = this.currentModal.querySelector('#promptName');
|
||||||
|
const contentInput = this.currentModal.querySelector('#promptContent');
|
||||||
|
|
||||||
|
if (!nameInput || !contentInput) {
|
||||||
|
console.error('❌ 找不到表單輸入元素');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = nameInput.value.trim();
|
||||||
|
const content = contentInput.value.trim();
|
||||||
|
|
||||||
|
if (!name || !content) {
|
||||||
|
this.showError(this.t('prompts.modal.emptyFields', '請填寫所有必填欄位'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const promptData = {
|
||||||
|
name: name,
|
||||||
|
content: content
|
||||||
|
};
|
||||||
|
|
||||||
|
if (modalData.type === 'edit') {
|
||||||
|
promptData.id = modalData.prompt.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 觸發保存回調
|
||||||
|
if (this.onSave) {
|
||||||
|
try {
|
||||||
|
this.onSave(promptData, modalData.type);
|
||||||
|
this.closeModal();
|
||||||
|
} catch (error) {
|
||||||
|
this.showError(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理提示詞選擇
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.handlePromptSelect = function(promptId) {
|
||||||
|
if (this.onSelect) {
|
||||||
|
this.onSelect(promptId);
|
||||||
|
}
|
||||||
|
this.closeModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示彈窗動畫
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.showModal = function() {
|
||||||
|
if (!this.currentModal) return;
|
||||||
|
|
||||||
|
// 添加顯示類觸發動畫
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.currentModal.classList.add('show');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 關閉彈窗
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.closeModal = function() {
|
||||||
|
if (!this.currentModal) return;
|
||||||
|
|
||||||
|
// 移除鍵盤事件監聽器
|
||||||
|
if (this.keydownHandler) {
|
||||||
|
document.removeEventListener('keydown', this.keydownHandler);
|
||||||
|
this.keydownHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加關閉動畫
|
||||||
|
this.currentModal.classList.add('hide');
|
||||||
|
|
||||||
|
// 延遲移除元素
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.currentModal) {
|
||||||
|
this.currentModal.remove();
|
||||||
|
this.currentModal = null;
|
||||||
|
}
|
||||||
|
}, 300); // 與 CSS 動畫時間一致
|
||||||
|
|
||||||
|
// 觸發取消回調
|
||||||
|
if (this.onCancel) {
|
||||||
|
this.onCancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 聚焦到第一個輸入框
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.focusFirstInput = function() {
|
||||||
|
if (!this.currentModal) return;
|
||||||
|
|
||||||
|
const firstInput = this.currentModal.querySelector('input, textarea');
|
||||||
|
if (firstInput) {
|
||||||
|
setTimeout(() => {
|
||||||
|
firstInput.focus();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示錯誤訊息
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.showError = function(message) {
|
||||||
|
if (window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.showMessage) {
|
||||||
|
window.MCPFeedback.Utils.showMessage(message, 'error');
|
||||||
|
} else {
|
||||||
|
alert(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 翻譯函數
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.t = function(key, fallback) {
|
||||||
|
if (window.i18nManager && typeof window.i18nManager.t === 'function') {
|
||||||
|
return window.i18nManager.t(key, fallback);
|
||||||
|
}
|
||||||
|
return fallback || key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.formatDate = function(dateString) {
|
||||||
|
if (!dateString) return '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
||||||
|
} catch (error) {
|
||||||
|
return dateString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截斷文字
|
||||||
|
*/
|
||||||
|
PromptModal.prototype.truncateText = function(text, maxLength) {
|
||||||
|
if (!text || text.length <= maxLength) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text.substring(0, maxLength) + '...';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 將 PromptModal 加入命名空間
|
||||||
|
window.MCPFeedback.Prompt.PromptModal = PromptModal;
|
||||||
|
|
||||||
|
console.log('✅ PromptModal 模組載入完成');
|
||||||
|
|
||||||
|
})();
|
@ -0,0 +1,370 @@
|
|||||||
|
/**
|
||||||
|
* MCP Feedback Enhanced - 提示詞設定 UI 模組
|
||||||
|
* =========================================
|
||||||
|
*
|
||||||
|
* 處理設定頁籤中的提示詞管理介面
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// 確保命名空間存在
|
||||||
|
window.MCPFeedback = window.MCPFeedback || {};
|
||||||
|
window.MCPFeedback.Prompt = window.MCPFeedback.Prompt || {};
|
||||||
|
|
||||||
|
const Utils = window.MCPFeedback.Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示詞設定 UI 管理器
|
||||||
|
*/
|
||||||
|
function PromptSettingsUI(options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// 依賴注入
|
||||||
|
this.promptManager = options.promptManager || null;
|
||||||
|
this.promptModal = options.promptModal || null;
|
||||||
|
|
||||||
|
// UI 元素
|
||||||
|
this.container = null;
|
||||||
|
this.promptList = null;
|
||||||
|
this.addButton = null;
|
||||||
|
|
||||||
|
// 狀態
|
||||||
|
this.isInitialized = false;
|
||||||
|
|
||||||
|
console.log('🎨 PromptSettingsUI 初始化完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化設定 UI
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.init = function(containerSelector) {
|
||||||
|
this.container = document.querySelector(containerSelector);
|
||||||
|
if (!this.container) {
|
||||||
|
console.error('❌ 找不到提示詞設定容器:', containerSelector);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 創建 UI 結構
|
||||||
|
this.createUI();
|
||||||
|
|
||||||
|
// 設置事件監聽器
|
||||||
|
this.setupEventListeners();
|
||||||
|
|
||||||
|
// 載入提示詞列表
|
||||||
|
this.refreshPromptList();
|
||||||
|
|
||||||
|
this.isInitialized = true;
|
||||||
|
console.log('✅ PromptSettingsUI 初始化完成');
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建 UI 結構
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.createUI = function() {
|
||||||
|
const html = `
|
||||||
|
<div class="prompt-management-section">
|
||||||
|
<div class="prompt-management-header">
|
||||||
|
<h4 class="prompt-management-title" data-i18n="prompts.management.title">
|
||||||
|
📝 常用提示詞管理
|
||||||
|
</h4>
|
||||||
|
<button type="button" class="btn btn-primary prompt-add-btn" id="promptAddBtn">
|
||||||
|
<span data-i18n="prompts.management.addNew">新增提示詞</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="prompt-management-description" data-i18n="prompts.management.description">
|
||||||
|
管理您的常用提示詞模板,可在回饋輸入時快速選用
|
||||||
|
</div>
|
||||||
|
<div class="prompt-settings-list" id="promptSettingsList">
|
||||||
|
<!-- 提示詞列表將在這裡動態生成 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.container.insertAdjacentHTML('beforeend', html);
|
||||||
|
|
||||||
|
// 獲取 UI 元素引用
|
||||||
|
this.promptList = this.container.querySelector('#promptSettingsList');
|
||||||
|
this.addButton = this.container.querySelector('#promptAddBtn');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設置事件監聽器
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.setupEventListeners = function() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
// 新增按鈕事件
|
||||||
|
if (this.addButton) {
|
||||||
|
this.addButton.addEventListener('click', function() {
|
||||||
|
self.handleAddPrompt();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 設置提示詞管理器回調
|
||||||
|
if (this.promptManager) {
|
||||||
|
this.promptManager.addPromptsChangeCallback(function(prompts) {
|
||||||
|
console.log('🎨 提示詞列表變更,重新渲染 UI');
|
||||||
|
self.refreshPromptList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 設置彈窗回調
|
||||||
|
if (this.promptModal) {
|
||||||
|
this.promptModal.onSave = function(promptData, type) {
|
||||||
|
self.handlePromptSave(promptData, type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新提示詞列表
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.refreshPromptList = function() {
|
||||||
|
if (!this.promptList || !this.promptManager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompts = this.promptManager.getAllPrompts();
|
||||||
|
|
||||||
|
if (prompts.length === 0) {
|
||||||
|
this.promptList.innerHTML = this.createEmptyStateHTML();
|
||||||
|
} else {
|
||||||
|
this.promptList.innerHTML = prompts.map(prompt =>
|
||||||
|
this.createPromptItemHTML(prompt)
|
||||||
|
).join('');
|
||||||
|
|
||||||
|
// 設置項目事件監聽器
|
||||||
|
this.setupPromptItemEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新翻譯
|
||||||
|
this.updateTranslations();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建空狀態 HTML
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.createEmptyStateHTML = function() {
|
||||||
|
return `
|
||||||
|
<div class="empty-state">
|
||||||
|
<div style="font-size: 48px; margin-bottom: 12px;">📝</div>
|
||||||
|
<div data-i18n="prompts.management.emptyState">
|
||||||
|
尚未建立任何常用提示詞
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px; color: var(--text-secondary); margin-top: 8px;" data-i18n="prompts.management.emptyHint">
|
||||||
|
點擊上方「新增提示詞」按鈕開始建立您的第一個提示詞模板
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 創建提示詞項目 HTML
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.createPromptItemHTML = function(prompt) {
|
||||||
|
const createdDate = this.formatDate(prompt.createdAt);
|
||||||
|
const lastUsedDate = prompt.lastUsedAt ? this.formatDate(prompt.lastUsedAt) : null;
|
||||||
|
const truncatedContent = this.truncateText(prompt.content, 80);
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="prompt-settings-item" data-prompt-id="${prompt.id}">
|
||||||
|
<div class="prompt-settings-info">
|
||||||
|
<div class="prompt-settings-name">${Utils.escapeHtml(prompt.name)}</div>
|
||||||
|
<div class="prompt-settings-content">${Utils.escapeHtml(truncatedContent)}</div>
|
||||||
|
<div class="prompt-settings-meta">
|
||||||
|
<span data-i18n="prompts.management.created">建立於</span>: ${createdDate}
|
||||||
|
${lastUsedDate ? `| <span data-i18n="prompts.management.lastUsed">最近使用</span>: ${lastUsedDate}` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="prompt-settings-actions">
|
||||||
|
<button type="button" class="prompt-action-btn edit-btn" data-prompt-id="${prompt.id}" data-i18n="prompts.management.edit">
|
||||||
|
編輯
|
||||||
|
</button>
|
||||||
|
<button type="button" class="prompt-action-btn delete-btn delete" data-prompt-id="${prompt.id}" data-i18n="prompts.management.delete">
|
||||||
|
刪除
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 設置提示詞項目事件監聽器
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.setupPromptItemEvents = function() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
// 編輯按鈕事件
|
||||||
|
const editButtons = this.promptList.querySelectorAll('.edit-btn');
|
||||||
|
editButtons.forEach(function(button) {
|
||||||
|
button.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
const promptId = button.getAttribute('data-prompt-id');
|
||||||
|
self.handleEditPrompt(promptId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 刪除按鈕事件
|
||||||
|
const deleteButtons = this.promptList.querySelectorAll('.delete-btn');
|
||||||
|
deleteButtons.forEach(function(button) {
|
||||||
|
button.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
const promptId = button.getAttribute('data-prompt-id');
|
||||||
|
self.handleDeletePrompt(promptId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理新增提示詞
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.handleAddPrompt = function() {
|
||||||
|
if (!this.promptModal) {
|
||||||
|
console.error('❌ PromptModal 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.promptModal.showAddModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理編輯提示詞
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.handleEditPrompt = function(promptId) {
|
||||||
|
if (!this.promptManager || !this.promptModal) {
|
||||||
|
console.error('❌ PromptManager 或 PromptModal 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = this.promptManager.getPromptById(promptId);
|
||||||
|
if (!prompt) {
|
||||||
|
this.showError(this.t('prompts.management.notFound', '找不到指定的提示詞'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.promptModal.showEditModal(prompt);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理刪除提示詞
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.handleDeletePrompt = function(promptId) {
|
||||||
|
if (!this.promptManager) {
|
||||||
|
console.error('❌ PromptManager 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = this.promptManager.getPromptById(promptId);
|
||||||
|
if (!prompt) {
|
||||||
|
this.showError(this.t('prompts.management.notFound', '找不到指定的提示詞'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmMessage = this.t('prompts.management.confirmDelete', '確定要刪除此提示詞嗎?') +
|
||||||
|
'\n\n' + prompt.name;
|
||||||
|
|
||||||
|
if (confirm(confirmMessage)) {
|
||||||
|
try {
|
||||||
|
this.promptManager.deletePrompt(promptId);
|
||||||
|
this.showSuccess(this.t('prompts.management.deleteSuccess', '提示詞已刪除'));
|
||||||
|
} catch (error) {
|
||||||
|
this.showError(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 處理提示詞保存
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.handlePromptSave = function(promptData, type) {
|
||||||
|
if (!this.promptManager) {
|
||||||
|
console.error('❌ PromptManager 未設定');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (type === 'add') {
|
||||||
|
this.promptManager.addPrompt(promptData.name, promptData.content);
|
||||||
|
this.showSuccess(this.t('prompts.management.addSuccess', '提示詞已新增'));
|
||||||
|
} else if (type === 'edit') {
|
||||||
|
this.promptManager.updatePrompt(promptData.id, promptData.name, promptData.content);
|
||||||
|
this.showSuccess(this.t('prompts.management.updateSuccess', '提示詞已更新'));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw error; // 重新拋出錯誤,讓彈窗處理
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新翻譯
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.updateTranslations = function() {
|
||||||
|
if (window.i18nManager && typeof window.i18nManager.applyTranslations === 'function') {
|
||||||
|
window.i18nManager.applyTranslations();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示成功訊息
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.showSuccess = function(message) {
|
||||||
|
if (window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.showMessage) {
|
||||||
|
window.MCPFeedback.Utils.showMessage(message, 'success');
|
||||||
|
} else {
|
||||||
|
console.log('✅', message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 顯示錯誤訊息
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.showError = function(message) {
|
||||||
|
if (window.MCPFeedback && window.MCPFeedback.Utils && window.MCPFeedback.Utils.showMessage) {
|
||||||
|
window.MCPFeedback.Utils.showMessage(message, 'error');
|
||||||
|
} else {
|
||||||
|
alert(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 翻譯函數
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.t = function(key, fallback) {
|
||||||
|
if (window.i18nManager && typeof window.i18nManager.t === 'function') {
|
||||||
|
return window.i18nManager.t(key, fallback);
|
||||||
|
}
|
||||||
|
return fallback || key;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.formatDate = function(dateString) {
|
||||||
|
if (!dateString) return '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
|
||||||
|
} catch (error) {
|
||||||
|
return dateString;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截斷文字
|
||||||
|
*/
|
||||||
|
PromptSettingsUI.prototype.truncateText = function(text, maxLength) {
|
||||||
|
if (!text || text.length <= maxLength) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text.substring(0, maxLength) + '...';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 將 PromptSettingsUI 加入命名空間
|
||||||
|
window.MCPFeedback.Prompt.PromptSettingsUI = PromptSettingsUI;
|
||||||
|
|
||||||
|
console.log('✅ PromptSettingsUI 模組載入完成');
|
||||||
|
|
||||||
|
})();
|
@ -204,6 +204,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTML 轉義函數
|
||||||
|
* @param {string} text - 要轉義的文字
|
||||||
|
* @returns {string} 轉義後的文字
|
||||||
|
*/
|
||||||
|
escapeHtml: function(text) {
|
||||||
|
if (typeof text !== 'string') {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.textContent = text;
|
||||||
|
return div.innerHTML;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 常數定義
|
* 常數定義
|
||||||
*/
|
*/
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<title>{{ title }}</title>
|
<title>{{ title }}</title>
|
||||||
<link rel="stylesheet" href="/static/css/styles.css">
|
<link rel="stylesheet" href="/static/css/styles.css">
|
||||||
<link rel="stylesheet" href="/static/css/session-management.css">
|
<link rel="stylesheet" href="/static/css/session-management.css">
|
||||||
|
<link rel="stylesheet" href="/static/css/prompt-management.css">
|
||||||
<style>
|
<style>
|
||||||
/* 僅保留必要的頁面特定樣式和響應式調整 */
|
/* 僅保留必要的頁面特定樣式和響應式調整 */
|
||||||
|
|
||||||
@ -751,6 +752,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 提示詞管理卡片 -->
|
||||||
|
<div class="settings-card">
|
||||||
|
<div class="settings-card-header">
|
||||||
|
<h3 class="settings-card-title" data-i18n="prompts.management.title">📝 常用提示詞管理</h3>
|
||||||
|
</div>
|
||||||
|
<div class="settings-card-body" id="promptManagementContainer">
|
||||||
|
<!-- 提示詞管理 UI 將在這裡動態生成 -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 重置設定卡片 -->
|
<!-- 重置設定卡片 -->
|
||||||
<div class="settings-card">
|
<div class="settings-card">
|
||||||
<div class="settings-card-header">
|
<div class="settings-card-header">
|
||||||
@ -880,6 +891,12 @@
|
|||||||
<script src="/static/js/modules/session/session-ui-renderer.js?v=2025010510"></script>
|
<script src="/static/js/modules/session/session-ui-renderer.js?v=2025010510"></script>
|
||||||
<script src="/static/js/modules/session/session-details-modal.js?v=2025010510"></script>
|
<script src="/static/js/modules/session/session-details-modal.js?v=2025010510"></script>
|
||||||
|
|
||||||
|
<!-- 提示詞管理模組 -->
|
||||||
|
<script src="/static/js/modules/prompt/prompt-manager.js?v=2025010510"></script>
|
||||||
|
<script src="/static/js/modules/prompt/prompt-modal.js?v=2025010510"></script>
|
||||||
|
<script src="/static/js/modules/prompt/prompt-settings-ui.js?v=2025010510"></script>
|
||||||
|
<script src="/static/js/modules/prompt/prompt-input-buttons.js?v=2025010510"></script>
|
||||||
|
|
||||||
<!-- 其他模組 -->
|
<!-- 其他模組 -->
|
||||||
<script src="/static/js/modules/utils.js?v=2025010510"></script>
|
<script src="/static/js/modules/utils.js?v=2025010510"></script>
|
||||||
<script src="/static/js/modules/tab-manager.js?v=2025010510"></script>
|
<script src="/static/js/modules/tab-manager.js?v=2025010510"></script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user