/** * 模板解码模块 - 完整列表迭代方法 * * 此模块使用笛卡尔积方法处理模板表达式的解码。 * 它依赖于 script.js 中定义的全局 'templates' 变量 * * 函数列表: * - decodeTemplates(): 解码模板的主函数 * - generateCombinations(): 使用笛卡尔积生成所有可能的组合 * - displayDecodedResults(): 显示解码结果 * - searchResults(): 在所有解码结果中搜索 * - copySingleResult(): 复制单个结果到剪贴板 * - copyAllResults(): 复制所有结果到剪贴板 * - downloadResults(): 将结果下载为文本文件 */ // 全局变量,用于存储所有解码后的表达式以供搜索 let allDecodedExpressions = []; let displayedExpressions = []; const MAX_DISPLAY_RESULTS = 999; // 使用完整列表方法解码模板 function decodeTemplates() { const editor = document.getElementById('expressionEditor'); const expression = editor.value.trim(); const errorsDiv = document.getElementById('grammarErrors'); // 检查表达式是否为空 if (!expression) { errorsDiv.innerHTML = '
错误: 请输入要解码的表达式
'; return; } // 首先,检测所有模板 const templateRegex = /<(\w+)\/>/g; const matches = [...expression.matchAll(templateRegex)]; const uniqueTemplates = [...new Set(matches.map(match => match[1]))]; // 检查是否有要解码的模板 if (uniqueTemplates.length === 0) { errorsDiv.innerHTML = '
错误: 在要解码的表达式中未找到模板
'; return; } // 检查是否所有模板都已配置 const unconfigured = []; const templateValues = new Map(); uniqueTemplates.forEach(templateName => { const template = templates.get(templateName); if (!template || !template.variables || template.variables.length === 0) { unconfigured.push(templateName); } else { templateValues.set(templateName, template.variables); } }); // 如果有任何模板未配置,显示错误 if (unconfigured.length > 0) { errorsDiv.innerHTML = `
错误: 以下模板在解码前需要配置: ${unconfigured.map(t => `<${t}/>`).join(', ')}
`; return; } // 计算总组合数 let totalCombinations = 1; templateValues.forEach(values => { totalCombinations *= values.length; }); // 如果组合数过多,发出警告 if (totalCombinations > 1000) { if (!confirm(`这将生成 ${totalCombinations} 个表达式。可能需要一些时间。继续吗?`)) { return; } } // 生成所有组合(笛卡尔积) const combinations = generateCombinations(templateValues); // 生成解码后的表达式 const decodedExpressions = combinations.map(combination => { let decodedExpression = expression; combination.forEach(({template, value}) => { const regex = new RegExp(`<${template}/>`, 'g'); decodedExpression = decodedExpression.replace(regex, value); }); return decodedExpression; }); // 全局存储所有表达式 allDecodedExpressions = decodedExpressions; // 显示结果(限制为 MAX_DISPLAY_RESULTS) displayDecodedResults(decodedExpressions.slice(0, MAX_DISPLAY_RESULTS), decodedExpressions.length); // 清除错误并显示成功信息 errorsDiv.innerHTML = `
✓ 使用完整列表方法成功解码 ${decodedExpressions.length} 个表达式 ${decodedExpressions.length > MAX_DISPLAY_RESULTS ? `
⚠️ 显示前 ${MAX_DISPLAY_RESULTS} 个结果。使用搜索查找特定表达式。` : ''}
`; } // 生成模板值的所有组合(笛卡尔积) function generateCombinations(templateValues) { const templates = Array.from(templateValues.keys()); if (templates.length === 0) return []; const combinations = []; function generate(index, current) { if (index === templates.length) { combinations.push([...current]); return; } const template = templates[index]; const values = templateValues.get(template); for (const value of values) { current.push({template, value}); generate(index + 1, current); current.pop(); } } generate(0, []); return combinations; } // 显示解码结果 function displayDecodedResults(expressions, totalCount = null, isRandom = false) { const resultsList = document.getElementById('resultsList'); // 清除之前的结果 resultsList.innerHTML = ''; // 如果结果数量超过显示数量,添加搜索框(仅用于完整迭代) if (!isRandom && totalCount && totalCount > MAX_DISPLAY_RESULTS) { const searchContainer = document.createElement('div'); searchContainer.className = 'results-search-container'; searchContainer.innerHTML = ` `; resultsList.appendChild(searchContainer); // 为搜索添加事件监听器 document.getElementById('resultsSearchBtn').addEventListener('click', searchResults); document.getElementById('resultsSearchInput').addEventListener('keypress', (e) => { if (e.key === 'Enter') searchResults(); }); document.getElementById('resultsClearSearchBtn').addEventListener('click', clearSearch); } // 添加关于结果数量的信息 if (expressions.length > 0) { const infoDiv = document.createElement('div'); infoDiv.className = 'results-info'; if (isRandom) { // 对于随机结果,显示实际选择的数量与总组合数的对比 const actualSelectedCount = allDecodedExpressions.length; if (actualSelectedCount > expressions.length) { infoDiv.innerHTML = `从 ${totalCount} 个总组合中随机选择了 ${actualSelectedCount} 个表达式
显示前 ${expressions.length} 个结果。下载将包含所有 ${actualSelectedCount} 个表达式。`; } else { infoDiv.innerHTML = `从 ${totalCount} 个总组合中随机选择了 ${expressions.length} 个表达式`; } } else if (totalCount && totalCount > expressions.length) { infoDiv.innerHTML = `总共生成了 ${totalCount} 个表达式。 显示 ${expressions.length} 个结果 ${expressions.length === MAX_DISPLAY_RESULTS ? '(前999个)' : '(已过滤)'}。`; } else { infoDiv.textContent = `使用完整列表迭代生成了 ${expressions.length} 个表达式`; } resultsList.appendChild(infoDiv); } // 全局存储显示的表达式 displayedExpressions = expressions; // 添加每个表达式 expressions.forEach((expr, index) => { const resultItem = document.createElement('div'); resultItem.className = 'result-item'; const number = document.createElement('span'); number.className = 'result-number'; number.textContent = `${index + 1}.`; const expression = document.createElement('span'); expression.className = 'result-expression'; expression.textContent = expr; resultItem.appendChild(number); resultItem.appendChild(expression); // 复制按钮已禁用 // resultItem.appendChild(copyBtn); resultsList.appendChild(resultItem); }); // 显示结果标签页并更新徽章 const resultsTab = document.getElementById('resultsTab'); const resultsBadge = document.getElementById('resultsBadge'); resultsTab.style.display = 'flex'; resultsBadge.textContent = totalCount || expressions.length; // 导航到结果页面 navigateToPage('results'); } // 在所有结果中搜索 function searchResults() { const searchInput = document.getElementById('resultsSearchInput'); const searchTerm = searchInput.value.trim().toLowerCase(); if (!searchTerm) { // 如果搜索为空,再次显示前1000个 displayDecodedResults(allDecodedExpressions.slice(0, MAX_DISPLAY_RESULTS), allDecodedExpressions.length); return; } // 根据搜索词过滤所有表达式 const filteredExpressions = allDecodedExpressions.filter(expr => expr.toLowerCase().includes(searchTerm) ); // 显示过滤后的结果(仍然限制为 MAX_DISPLAY_RESULTS) displayDecodedResults(filteredExpressions.slice(0, MAX_DISPLAY_RESULTS), allDecodedExpressions.length); // 显示清除按钮 document.getElementById('resultsClearSearchBtn').style.display = 'inline-block'; // 更新信息消息 const errorsDiv = document.getElementById('grammarErrors'); if (filteredExpressions.length === 0) { errorsDiv.innerHTML = `
未找到匹配 "${searchTerm}" 的表达式
`; } else if (filteredExpressions.length > MAX_DISPLAY_RESULTS) { errorsDiv.innerHTML = `
找到 ${filteredExpressions.length} 个表达式匹配 "${searchTerm}"。 显示前 ${MAX_DISPLAY_RESULTS} 个结果。
`; } else { errorsDiv.innerHTML = `
找到 ${filteredExpressions.length} 个表达式匹配 "${searchTerm}"
`; } } // 清除搜索并显示原始结果 function clearSearch() { document.getElementById('resultsSearchInput').value = ''; document.getElementById('resultsClearSearchBtn').style.display = 'none'; displayDecodedResults(allDecodedExpressions.slice(0, MAX_DISPLAY_RESULTS), allDecodedExpressions.length); const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 显示总共 ${allDecodedExpressions.length} 个表达式中的前 ${MAX_DISPLAY_RESULTS} 个
`; } // 复制单个结果 function copySingleResult(expression) { navigator.clipboard.writeText(expression).then(() => { // 显示临时成功消息 const errorsDiv = document.getElementById('grammarErrors'); const prevContent = errorsDiv.innerHTML; errorsDiv.innerHTML = '
✓ 已复制到剪贴板
'; setTimeout(() => { errorsDiv.innerHTML = prevContent; }, 2000); }); } // 复制显示的结果 function copyDisplayedResults() { // 复制所有当前显示的表达式 const expressions = displayedExpressions.join('\n'); navigator.clipboard.writeText(expressions).then(() => { const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 已复制 ${displayedExpressions.length} 个显示的表达式到剪贴板
`; }); } // 复制所有结果 function copyAllResults() { // 复制所有生成的表达式 const expressions = allDecodedExpressions.join('\n'); navigator.clipboard.writeText(expressions).then(() => { const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 所有 ${allDecodedExpressions.length} 个表达式已复制到剪贴板
`; }).catch(err => { // 处理大剪贴板操作可能出现的错误 const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
错误: 复制到剪贴板失败。数据可能过大。 请改用"下载全部"按钮。
`; }); } // 将结果下载为文本文件 function downloadResults() { // 下载表达式(全部或随机选择) const expressions = allDecodedExpressions.join('\n'); const blob = new Blob([expressions], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'decoded_expressions.txt'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 已将 ${allDecodedExpressions.length} 个表达式下载为 decoded_expressions.txt
`; } // 随机迭代 - 生成全部然后随机选择 function randomIteration() { const editor = document.getElementById('expressionEditor'); const expression = editor.value.trim(); const errorsDiv = document.getElementById('grammarErrors'); const randomCountInput = document.getElementById('randomCount'); const randomCount = parseInt(randomCountInput.value) || 10; // 检查表达式是否为空 if (!expression) { errorsDiv.innerHTML = '
错误: 请输入要解码的表达式
'; return; } // 首先,检测所有模板 const templateRegex = /<(\w+)\/>/g; const matches = [...expression.matchAll(templateRegex)]; const uniqueTemplates = [...new Set(matches.map(match => match[1]))]; // 检查是否有要解码的模板 if (uniqueTemplates.length === 0) { errorsDiv.innerHTML = '
错误: 在要解码的表达式中未找到模板
'; return; } // 检查是否所有模板都已配置 const unconfigured = []; const templateValues = new Map(); uniqueTemplates.forEach(templateName => { const template = templates.get(templateName); if (!template || !template.variables || template.variables.length === 0) { unconfigured.push(templateName); } else { templateValues.set(templateName, template.variables); } }); // 如果有任何模板未配置,显示错误 if (unconfigured.length > 0) { errorsDiv.innerHTML = `
错误: 以下模板在解码前需要配置: ${unconfigured.map(t => `<${t}/>`).join(', ')}
`; return; } // 计算总组合数 let totalCombinations = 1; templateValues.forEach(values => { totalCombinations *= values.length; }); // 验证随机数量 if (randomCount > totalCombinations) { errorsDiv.innerHTML = `
⚠️ 请求了 ${randomCount} 个随机表达式,但只有 ${totalCombinations} 个唯一组合存在。 改为生成所有 ${totalCombinations} 个表达式。
`; } // 生成所有组合(笛卡尔积) const combinations = generateCombinations(templateValues); // 生成所有解码后的表达式 const allExpressions = combinations.map(combination => { let decodedExpression = expression; combination.forEach(({template, value}) => { const regex = new RegExp(`<${template}/>`, 'g'); decodedExpression = decodedExpression.replace(regex, value); }); return decodedExpression; }); // 随机选择请求数量的表达式 const selectedExpressions = []; const actualCount = Math.min(randomCount, allExpressions.length); if (actualCount === allExpressions.length) { // 如果请求全部或更多,直接返回全部 selectedExpressions.push(...allExpressions); } else { // 无放回随机选择 const indices = new Set(); while (indices.size < actualCount) { indices.add(Math.floor(Math.random() * allExpressions.length)); } indices.forEach(index => { selectedExpressions.push(allExpressions[index]); }); } // 全局存储所有选择的表达式以供下载(不受显示限制) allDecodedExpressions = selectedExpressions; // 对于显示,限制为 MAX_DISPLAY_RESULTS,但保留完整集合以供下载 const displayExpressions = selectedExpressions.slice(0, MAX_DISPLAY_RESULTS); // 显示结果(显示有限,但下载计数完整) displayDecodedResults(displayExpressions, allExpressions.length, true); // 清除错误并显示成功信息,明确说明显示与下载的区别 if (selectedExpressions.length > MAX_DISPLAY_RESULTS) { errorsDiv.innerHTML = `
✓ 从 ${allExpressions.length} 个总组合中随机选择了 ${selectedExpressions.length} 个表达式
📺 显示前 ${MAX_DISPLAY_RESULTS} 个结果。下载将包含所有 ${selectedExpressions.length} 个表达式。
`; } else { errorsDiv.innerHTML = `
✓ 从 ${allExpressions.length} 个总组合中随机选择了 ${selectedExpressions.length} 个表达式
`; } } // 为 Next Move 打开设置模态框 function openSettingsModal() { const modal = document.getElementById('settingsModal'); modal.style.display = 'block'; updateTotalCombinations(); // 为设置输入添加事件监听器 document.querySelectorAll('.setting-value-input').forEach(input => { input.addEventListener('input', updateTotalCombinations); }); // 为添加设置按钮添加事件监听器 document.getElementById('addSettingBtn').addEventListener('click', addCustomSetting); // 为测试周期滑块添加事件监听器 const testPeriodSlider = document.querySelector('.test-period-slider'); if (testPeriodSlider) { testPeriodSlider.addEventListener('input', updateTestPeriodValue); // 初始化显示值 updateTestPeriodValue(); } } // 关闭设置模态框 function closeSettingsModal() { const modal = document.getElementById('settingsModal'); modal.style.display = 'none'; } // 更新测试周期值显示 function updateTestPeriodValue() { const slider = document.querySelector('.test-period-slider'); const valueDisplay = document.getElementById('testPeriodValue'); if (slider && valueDisplay) { const totalMonths = parseInt(slider.value); const years = Math.floor(totalMonths / 12); const months = totalMonths % 12; const periodValue = `P${years}Y${months}M`; valueDisplay.textContent = periodValue; // 更新滑块的 value 属性,以便 parseSettingValues 可以读取 slider.setAttribute('data-period-value', periodValue); } } // 添加自定义设置行 function addCustomSetting() { const tbody = document.getElementById('settingsTableBody'); const row = document.createElement('tr'); row.className = 'custom-setting-row'; row.innerHTML = ` `; tbody.appendChild(row); // 为新输入添加事件监听器 row.querySelector('.setting-value-input').addEventListener('input', updateTotalCombinations); row.querySelector('.setting-name-input').addEventListener('input', updateTotalCombinations); } // 移除自定义设置行 function removeCustomSetting(button) { button.closest('tr').remove(); updateTotalCombinations(); } // 计算总组合数 function updateTotalCombinations() { let totalCombinations = allDecodedExpressions.length; // 获取所有设置及其值 const settingInputs = document.querySelectorAll('.setting-value-input'); settingInputs.forEach(input => { const values = input.value.split(',').map(v => v.trim()).filter(v => v !== ''); if (values.length > 1) { totalCombinations *= values.length; } }); document.getElementById('totalCombinations').textContent = totalCombinations.toLocaleString(); } // 解析设置值(处理逗号分隔的值) function parseSettingValues() { const settings = {}; const variations = {}; const types = {}; // 获取预定义设置 const settingRows = document.querySelectorAll('#settingsTableBody tr'); settingRows.forEach(row => { const nameCell = row.cells[0]; // 使用选择器或输入框获取值 let input = row.querySelector('.setting-value-input'); if (input) { let settingName; // 检查是否为自定义设置 const nameInput = row.querySelector('.setting-name-input'); if (nameInput) { settingName = nameInput.value.trim(); if (!settingName) return; // 如果没有名称,跳过 } else { settingName = nameCell.textContent.trim(); } // 获取类型 const typeSelect = row.querySelector('.setting-type-select'); const type = typeSelect ? typeSelect.value : 'string'; types[settingName] = type; // 对于选择下拉框,以不同方式获取值 let values = []; if (input.tagName === 'SELECT') { values = [input.value]; } else if (input.type === 'range' && settingName === 'testPeriod') { // 测试周期滑块的特别处理 const periodValue = input.getAttribute('data-period-value') || 'P0Y0M'; values = [periodValue]; } else { values = input.value.split(',').map(v => v.trim()).filter(v => v !== ''); } // 根据类型转换值 const convertedValues = values.map(v => { if (type === 'number') { const num = parseFloat(v); return isNaN(num) ? v : num; } else if (type === 'boolean') { if (typeof v === 'boolean') return v; if (typeof v === 'string') { if (v.toLowerCase() === 'true') return true; if (v.toLowerCase() === 'false') return false; } return false; } else { return v; } }); if (convertedValues.length === 0) { // 如果没有值,使用空字符串 settings[settingName] = ''; } else if (convertedValues.length === 1) { // 单个值 settings[settingName] = convertedValues[0]; } else { // 多个值 - 存储以供迭代 variations[settingName] = convertedValues; settings[settingName] = convertedValues[0]; // 默认为第一个值 } } }); return { settings, variations, types }; } // 生成所有设置组合 function generateSettingCombinations(baseSettings, variations) { const variationKeys = Object.keys(variations); if (variationKeys.length === 0) { return [baseSettings]; } const combinations = []; function generate(index, current) { if (index === variationKeys.length) { combinations.push({...current}); return; } const key = variationKeys[index]; const values = variations[key]; for (const value of values) { current[key] = value; generate(index + 1, current); } } generate(0, {...baseSettings}); return combinations; } // 将设置应用到表达式 function applySettings() { const { settings, variations, types } = parseSettingValues(); // 始终包含 instrumentType 和 language settings.instrumentType = settings.instrumentType || "EQUITY"; settings.language = settings.language || "FASTEXPR"; // 生成所有设置组合 const settingCombinations = generateSettingCombinations(settings, variations); // 创建所有表达式-设置组合 const allCombinations = []; allDecodedExpressions.forEach(expr => { settingCombinations.forEach(settingCombo => { const fullExpression = { type: "REGULAR", settings: settingCombo, regular: expr.replace(/\n/g, '') // 移除换行符 }; allCombinations.push(JSON.stringify(fullExpression, null, 2)); }); }); // 创建 JSON 数组 const jsonContent = '[\n' + allCombinations.join(',\n') + '\n]'; // 下载带设置的表达式 const blob = new Blob([jsonContent], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'expressions_with_settings.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); // 关闭模态框并显示成功信息 closeSettingsModal(); const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 已将 ${allCombinations.length} 个表达式配置下载为 expressions_with_settings.json
`; } // 全局存储测试结果 let allTestResults = []; // 使用 BRAIN API 生成并测试表达式 async function generateAndTest() { const { settings, variations, types } = parseSettingValues(); // 检查用户是否使用正确方法登录到 BRAIN if (!window.brainAPI || !window.brainAPI.isConnectedToBrain()) { alert('在测试表达式之前,请先连接到 BRAIN。'); return; } // 从全局变量获取会话 ID const sessionId = brainSessionId; if (!sessionId) { alert('未找到 BRAIN 会话。请重新连接到 BRAIN。'); return; } // 始终包含 instrumentType 和 language settings.instrumentType = settings.instrumentType || "EQUITY"; settings.language = settings.language || "FASTEXPR"; // 生成所有设置组合 const settingCombinations = generateSettingCombinations(settings, variations); // 创建所有表达式-设置组合 const allCombinations = []; allDecodedExpressions.forEach(expr => { settingCombinations.forEach(settingCombo => { const fullExpression = { type: "REGULAR", settings: settingCombo, regular: expr.replace(/\n/g, '') // 移除换行符 }; allCombinations.push(fullExpression); }); }); // 随机选择一个表达式进行测试 const randomIndex = Math.floor(Math.random() * allCombinations.length); const testExpression = allCombinations[randomIndex]; // 关闭设置模态框并打开测试结果模态框 closeSettingsModal(); openBrainTestResultsModal(); // 显示进度 const progressDiv = document.getElementById('brainTestProgress'); const progressBarFill = document.getElementById('progressBarFill'); const progressText = document.getElementById('progressText'); const resultsDiv = document.getElementById('brainTestResults'); progressDiv.style.display = 'block'; resultsDiv.innerHTML = ''; allTestResults = []; // 测试单个随机选择的表达式 progressText.textContent = `正在测试表达式 ${randomIndex + 1},共 ${allCombinations.length} 个(随机选择)...`; progressBarFill.style.width = '50%'; try { const response = await fetch('/api/test-expression', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Session-ID': sessionId }, body: JSON.stringify(testExpression) }); const result = await response.json(); // 存储结果 const testResult = { expression: testExpression.regular, settings: testExpression.settings, success: result.success, status: result.status || (result.success ? 'SUCCESS' : 'ERROR'), message: result.message || result.error || '未知错误', details: result, totalPossible: allCombinations.length, testedIndex: randomIndex + 1 }; allTestResults.push(testResult); // 更新进度 progressBarFill.style.width = '100%'; progressText.textContent = '测试完成!'; // 短暂延迟后隐藏进度 setTimeout(() => { progressDiv.style.display = 'none'; // 显示结果 displaySingleTestResult(testResult); // 显示下载按钮 document.getElementById('downloadTestResultsBtn').style.display = 'inline-block'; document.getElementById('downloadExpressionWithSettingsBtn').style.display = 'inline-block'; }, 500); } catch (error) { const testResult = { expression: testExpression.regular, settings: testExpression.settings, success: false, status: 'ERROR', message: `网络错误: ${error.message}`, details: { error: error.message }, totalPossible: allCombinations.length, testedIndex: randomIndex + 1 }; allTestResults.push(testResult); progressDiv.style.display = 'none'; displaySingleTestResult(testResult); document.getElementById('downloadTestResultsBtn').style.display = 'inline-block'; document.getElementById('downloadExpressionWithSettingsBtn').style.display = 'inline-block'; } } // 显示单个测试结果 function displaySingleTestResult(result) { const resultsDiv = document.getElementById('brainTestResults'); // 添加摘要信息 const summaryDiv = document.createElement('div'); summaryDiv.className = 'test-summary'; summaryDiv.innerHTML = `

随机测试结果

从 ${result.totalPossible} 个可能组合中随机选择了表达式 #${result.testedIndex}

`; resultsDiv.appendChild(summaryDiv); // 添加测试结果 const resultItem = document.createElement('div'); resultItem.className = `test-result-item ${result.success && result.status !== 'ERROR' ? 'success' : 'error'}`; const expressionDiv = document.createElement('div'); expressionDiv.className = 'test-result-expression'; expressionDiv.innerHTML = `表达式: ${result.expression}`; // 按照笔记本中的样子显示消息 const messageDiv = document.createElement('div'); messageDiv.className = 'test-result-message'; messageDiv.style.whiteSpace = 'pre-wrap'; messageDiv.style.fontFamily = 'monospace'; messageDiv.style.backgroundColor = '#f5f5f5'; messageDiv.style.padding = '10px'; messageDiv.style.borderRadius = '4px'; messageDiv.style.marginTop = '10px'; // 格式化消息 - 如果是完整的响应对象,美观地显示它 if (result.details && result.details.full_response) { const fullResponse = result.details.full_response; // 如果是具有预期结构的对象,美观地格式化它 if (typeof fullResponse === 'object' && fullResponse.id && fullResponse.type && fullResponse.status) { // 格式化为 Python 字典输出 messageDiv.textContent = JSON.stringify(fullResponse, null, 2).replace(/"/g, "'"); } else if (typeof fullResponse === 'object') { // 对于其他对象,直接字符串化它们 messageDiv.textContent = JSON.stringify(fullResponse, null, 2); } else { // 对于非对象,显示消息字符串 messageDiv.textContent = result.message; } } else { // 回退到简单消息 messageDiv.textContent = result.message; } resultItem.appendChild(expressionDiv); resultItem.appendChild(messageDiv); // 添加设置信息 const settingsDiv = document.createElement('div'); settingsDiv.className = 'test-result-message'; settingsDiv.innerHTML = '使用的设置:'; const settingsList = document.createElement('ul'); settingsList.style.margin = '5px 0'; settingsList.style.paddingLeft = '20px'; for (const [key, value] of Object.entries(result.settings)) { const li = document.createElement('li'); li.textContent = `${key}: ${value}`; settingsList.appendChild(li); } settingsDiv.appendChild(settingsList); resultItem.appendChild(settingsDiv); resultsDiv.appendChild(resultItem); } // 旧函数名的兼容性包装器 function addTestResultToDisplay(result, index) { // 如果不存在,向结果添加索引信息 if (!result.testedIndex) { result.testedIndex = index; } if (!result.totalPossible) { result.totalPossible = allDecodedExpressions.length; } displaySingleTestResult(result); } // 显示测试摘要(保持兼容性) function showTestSummary(total, success, error) { const resultsDiv = document.getElementById('brainTestResults'); const summaryDiv = document.createElement('div'); summaryDiv.className = 'test-summary'; summaryDiv.innerHTML = `

测试摘要

${total}
总测试数
${success}
成功
${error}
错误
${((success / total) * 100).toFixed(1)}%
成功率
`; resultsDiv.insertBefore(summaryDiv, resultsDiv.firstChild); } // 打开测试结果模态框 function openBrainTestResultsModal() { const modal = document.getElementById('brainTestResultsModal'); modal.style.display = 'block'; } // 关闭测试结果模态框 function closeBrainTestResultsModal() { const modal = document.getElementById('brainTestResultsModal'); modal.style.display = 'none'; } // 下载测试结果 function downloadTestResults() { const results = allTestResults.map(result => ({ expression: result.expression, settings: result.settings, status: result.status, message: result.message, details: result.details })); const jsonContent = JSON.stringify(results, null, 2); const blob = new Blob([jsonContent], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'brain_test_results.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 已下载 ${allTestResults.length} 个表达式的测试结果
`; } // 下载带设置的表达式(与"生成并下载"相同) function downloadExpressionWithSettings() { // 从模态框获取当前设置(与 applySettings 相同的逻辑) const { settings, variations, types } = parseSettingValues(); // 始终包含 instrumentType 和 language settings.instrumentType = settings.instrumentType || "EQUITY"; settings.language = settings.language || "FASTEXPR"; // 生成所有设置组合 const settingCombinations = generateSettingCombinations(settings, variations); // 创建所有表达式-设置组合 const allCombinations = []; allDecodedExpressions.forEach(expr => { settingCombinations.forEach(settingCombo => { const fullExpression = { type: "REGULAR", settings: settingCombo, regular: expr.replace(/\n/g, '') // 移除换行符 }; allCombinations.push(JSON.stringify(fullExpression, null, 2)); }); }); // 创建 JSON 数组 const jsonContent = '[\n' + allCombinations.join(',\n') + '\n]'; // 下载带设置的表达式 const blob = new Blob([jsonContent], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'expressions_with_settings.json'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); const errorsDiv = document.getElementById('grammarErrors'); errorsDiv.innerHTML = `
✓ 已将 ${allCombinations.length} 个表达式配置下载为 expressions_with_settings.json
`; }