刘硕
Committed by BaiFu

feat: api 隐藏可选

给api添加了隐藏选项
@@ -83,19 +83,38 @@ @@ -83,19 +83,38 @@
83 } 83 }
84 84
85 .config-password-toggle { 85 .config-password-toggle {
86 - padding: 8px 14px; 86 + padding: 8px 12px;
87 border: 2px solid #000000; 87 border: 2px solid #000000;
88 background-color: #ffffff; 88 background-color: #ffffff;
89 cursor: pointer; 89 cursor: pointer;
90 - font-size: 12px;  
91 - font-weight: bold; 90 + font-size: 0;
92 transition: all 0.3s ease; 91 transition: all 0.3s ease;
  92 + display: flex;
  93 + align-items: center;
  94 + justify-content: center;
  95 + min-width: 44px;
  96 + min-height: 38px;
  97 + }
  98 +
  99 + .config-password-toggle svg {
  100 + width: 20px;
  101 + height: 20px;
  102 + stroke: #000000;
  103 + fill: none;
  104 + stroke-width: 2;
  105 + stroke-linecap: round;
  106 + stroke-linejoin: round;
  107 + transition: stroke 0.3s ease;
93 } 108 }
94 109
95 .config-password-toggle:hover, 110 .config-password-toggle:hover,
96 .config-password-toggle.revealed { 111 .config-password-toggle.revealed {
97 background-color: #000000; 112 background-color: #000000;
98 - color: #ffffff; 113 + }
  114 +
  115 + .config-password-toggle:hover svg,
  116 + .config-password-toggle.revealed svg {
  117 + stroke: #ffffff;
99 } 118 }
100 119
101 .search-box { 120 .search-box {
@@ -1163,7 +1182,7 @@ @@ -1163,7 +1182,7 @@
1163 title: 'Insight Agent', 1182 title: 'Insight Agent',
1164 subtitle: '负责洞察分析的模型配置', 1183 subtitle: '负责洞察分析的模型配置',
1165 fields: [ 1184 fields: [
1166 - { key: 'INSIGHT_ENGINE_API_KEY', label: 'API Key' }, 1185 + { key: 'INSIGHT_ENGINE_API_KEY', label: 'API Key', type: 'password' },
1167 { key: 'INSIGHT_ENGINE_BASE_URL', label: 'Base URL' }, 1186 { key: 'INSIGHT_ENGINE_BASE_URL', label: 'Base URL' },
1168 { key: 'INSIGHT_ENGINE_MODEL_NAME', label: '模型名称' } 1187 { key: 'INSIGHT_ENGINE_MODEL_NAME', label: '模型名称' }
1169 ] 1188 ]
@@ -1172,7 +1191,7 @@ @@ -1172,7 +1191,7 @@
1172 title: 'Media Agent', 1191 title: 'Media Agent',
1173 subtitle: '媒体内容理解与生成模型', 1192 subtitle: '媒体内容理解与生成模型',
1174 fields: [ 1193 fields: [
1175 - { key: 'MEDIA_ENGINE_API_KEY', label: 'API Key' }, 1194 + { key: 'MEDIA_ENGINE_API_KEY', label: 'API Key', type: 'password' },
1176 { key: 'MEDIA_ENGINE_BASE_URL', label: 'Base URL' }, 1195 { key: 'MEDIA_ENGINE_BASE_URL', label: 'Base URL' },
1177 { key: 'MEDIA_ENGINE_MODEL_NAME', label: '模型名称' } 1196 { key: 'MEDIA_ENGINE_MODEL_NAME', label: '模型名称' }
1178 ] 1197 ]
@@ -1181,7 +1200,7 @@ @@ -1181,7 +1200,7 @@
1181 title: 'Query Agent', 1200 title: 'Query Agent',
1182 subtitle: '负责搜索与信息汇总的模型配置', 1201 subtitle: '负责搜索与信息汇总的模型配置',
1183 fields: [ 1202 fields: [
1184 - { key: 'QUERY_ENGINE_API_KEY', label: 'API Key' }, 1203 + { key: 'QUERY_ENGINE_API_KEY', label: 'API Key', type: 'password' },
1185 { key: 'QUERY_ENGINE_BASE_URL', label: 'Base URL' }, 1204 { key: 'QUERY_ENGINE_BASE_URL', label: 'Base URL' },
1186 { key: 'QUERY_ENGINE_MODEL_NAME', label: '模型名称' } 1205 { key: 'QUERY_ENGINE_MODEL_NAME', label: '模型名称' }
1187 ] 1206 ]
@@ -1190,7 +1209,7 @@ @@ -1190,7 +1209,7 @@
1190 title: 'Report Agent', 1209 title: 'Report Agent',
1191 subtitle: '报告生成使用的模型配置', 1210 subtitle: '报告生成使用的模型配置',
1192 fields: [ 1211 fields: [
1193 - { key: 'REPORT_ENGINE_API_KEY', label: 'API Key' }, 1212 + { key: 'REPORT_ENGINE_API_KEY', label: 'API Key', type: 'password' },
1194 { key: 'REPORT_ENGINE_BASE_URL', label: 'Base URL' }, 1213 { key: 'REPORT_ENGINE_BASE_URL', label: 'Base URL' },
1195 { key: 'REPORT_ENGINE_MODEL_NAME', label: '模型名称' } 1214 { key: 'REPORT_ENGINE_MODEL_NAME', label: '模型名称' }
1196 ] 1215 ]
@@ -1199,7 +1218,7 @@ @@ -1199,7 +1218,7 @@
1199 title: 'Forum Host', 1218 title: 'Forum Host',
1200 subtitle: '多智能体协同使用的模型配置', 1219 subtitle: '多智能体协同使用的模型配置',
1201 fields: [ 1220 fields: [
1202 - { key: 'FORUM_HOST_API_KEY', label: 'API Key' }, 1221 + { key: 'FORUM_HOST_API_KEY', label: 'API Key', type: 'password' },
1203 { key: 'FORUM_HOST_BASE_URL', label: 'Base URL' }, 1222 { key: 'FORUM_HOST_BASE_URL', label: 'Base URL' },
1204 { key: 'FORUM_HOST_MODEL_NAME', label: '模型名称' } 1223 { key: 'FORUM_HOST_MODEL_NAME', label: '模型名称' }
1205 ] 1224 ]
@@ -1208,7 +1227,7 @@ @@ -1208,7 +1227,7 @@
1208 title: 'Keyword Optimizer', 1227 title: 'Keyword Optimizer',
1209 subtitle: 'SQL / 关键词优化模型配置', 1228 subtitle: 'SQL / 关键词优化模型配置',
1210 fields: [ 1229 fields: [
1211 - { key: 'KEYWORD_OPTIMIZER_API_KEY', label: 'API Key' }, 1230 + { key: 'KEYWORD_OPTIMIZER_API_KEY', label: 'API Key', type: 'password' },
1212 { key: 'KEYWORD_OPTIMIZER_BASE_URL', label: 'Base URL' }, 1231 { key: 'KEYWORD_OPTIMIZER_BASE_URL', label: 'Base URL' },
1213 { key: 'KEYWORD_OPTIMIZER_MODEL_NAME', label: '模型名称' } 1232 { key: 'KEYWORD_OPTIMIZER_MODEL_NAME', label: '模型名称' }
1214 ] 1233 ]
@@ -1217,8 +1236,8 @@ @@ -1217,8 +1236,8 @@
1217 title: '外部检索工具', 1236 title: '外部检索工具',
1218 subtitle: '联动搜索引擎、网站抓取等在线服务', 1237 subtitle: '联动搜索引擎、网站抓取等在线服务',
1219 fields: [ 1238 fields: [
1220 - { key: 'TAVILY_API_KEY', label: 'Tavily API Key' },  
1221 - { key: 'BOCHA_WEB_SEARCH_API_KEY', label: 'Bocha API Key' } 1239 + { key: 'TAVILY_API_KEY', label: 'Tavily API Key', type: 'password' },
  1240 + { key: 'BOCHA_WEB_SEARCH_API_KEY', label: 'Bocha API Key', type: 'password' }
1222 ] 1241 ]
1223 } 1242 }
1224 ]; 1243 ];
@@ -1251,6 +1270,9 @@ @@ -1251,6 +1270,9 @@
1251 checkStatus(); 1270 checkStatus();
1252 setInterval(checkStatus, 5000); 1271 setInterval(checkStatus, 5000);
1253 1272
  1273 + // 初始化密码切换功能(事件委托,只需调用一次)
  1274 + attachConfigPasswordToggles();
  1275 +
1254 // 初始化Report Engine锁定状态检查 1276 // 初始化Report Engine锁定状态检查
1255 checkReportLockStatus(); 1277 checkReportLockStatus();
1256 reportLockCheckInterval = setInterval(checkReportLockStatus, 10000); // 每10秒检查一次 1278 reportLockCheckInterval = setInterval(checkReportLockStatus, 10000); // 每10秒检查一次
@@ -1520,10 +1542,19 @@ @@ -1520,10 +1542,19 @@
1520 autocomplete="off" 1542 autocomplete="off"
1521 > 1543 >
1522 `; 1544 `;
  1545 + // 眼睛图标 - 闭眼状态(默认隐藏密码)
  1546 + const eyeOffIcon = `
  1547 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  1548 + <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
  1549 + <line x1="1" y1="1" x2="23" y2="23"></line>
  1550 + </svg>
  1551 + `;
1523 control = ` 1552 control = `
1524 <div class="config-password-wrapper"> 1553 <div class="config-password-wrapper">
1525 ${inputElement} 1554 ${inputElement}
1526 - <button type="button" class="config-password-toggle" data-target="${field.key}">显示</button> 1555 + <button type="button" class="config-password-toggle" data-target="${field.key}" title="显示/隐藏密码">
  1556 + ${eyeOffIcon}
  1557 + </button>
1527 </div> 1558 </div>
1528 `; 1559 `;
1529 } else { 1560 } else {
@@ -1562,24 +1593,57 @@ @@ -1562,24 +1593,57 @@
1562 }).join(''); 1593 }).join('');
1563 1594
1564 container.innerHTML = sections; 1595 container.innerHTML = sections;
1565 - attachConfigPasswordToggles(); 1596 + // 不再需要每次调用 attachConfigPasswordToggles
  1597 + // 事件委托已在页面初始化时设置
1566 } 1598 }
1567 1599
1568 function attachConfigPasswordToggles() { 1600 function attachConfigPasswordToggles() {
1569 - const toggles = document.querySelectorAll('.config-password-toggle');  
1570 - toggles.forEach(toggle => { 1601 + // 定义眼睛图标的SVG
  1602 + const eyeOffIcon = `
  1603 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  1604 + <path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
  1605 + <line x1="1" y1="1" x2="23" y2="23"></line>
  1606 + </svg>
  1607 + `;
  1608 + const eyeOnIcon = `
  1609 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  1610 + <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
  1611 + <circle cx="12" cy="12" r="3"></circle>
  1612 + </svg>
  1613 + `;
  1614 +
  1615 + // 使用事件委托,只在容器上绑定一次事件
  1616 + const container = document.getElementById('configFormContainer');
  1617 + if (!container) {
  1618 + return;
  1619 + }
  1620 +
  1621 + // 防止重复绑定
  1622 + if (container.dataset.passwordToggleAttached === 'true') {
  1623 + return;
  1624 + }
  1625 +
  1626 + container.addEventListener('click', (event) => {
  1627 + // 查找是否点击了密码切换按钮或其内部的SVG
  1628 + const toggle = event.target.closest('.config-password-toggle');
  1629 + if (!toggle) {
  1630 + return;
  1631 + }
  1632 +
1571 const key = toggle.dataset.target; 1633 const key = toggle.dataset.target;
1572 - const input = document.querySelector(`.config-field-input[data-config-key="${key}"]`); 1634 + const input = container.querySelector(`.config-field-input[data-config-key="${key}"]`);
1573 if (!input) { 1635 if (!input) {
1574 return; 1636 return;
1575 } 1637 }
1576 - toggle.addEventListener('click', () => {  
1577 - const reveal = input.getAttribute('type') === 'password';  
1578 - input.setAttribute('type', reveal ? 'text' : 'password');  
1579 - toggle.textContent = reveal ? '隐藏' : '显示';  
1580 - toggle.classList.toggle('revealed', reveal);  
1581 - }); 1638 +
  1639 + const reveal = input.getAttribute('type') === 'password';
  1640 + input.setAttribute('type', reveal ? 'text' : 'password');
  1641 + toggle.innerHTML = reveal ? eyeOnIcon : eyeOffIcon;
  1642 + toggle.classList.toggle('revealed', reveal);
1582 }); 1643 });
  1644 +
  1645 + // 标记已绑定,防止重复
  1646 + container.dataset.passwordToggleAttached = 'true';
1583 } 1647 }
1584 1648
1585 function collectConfigUpdates() { 1649 function collectConfigUpdates() {