| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009 |
- /**
- * 模板解码模块 - 完整列表迭代方法
- *
- * 此模块使用笛卡尔积方法处理模板表达式的解码。
- * 它依赖于 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 = '<div class="error-item"><strong>错误:</strong> 请输入要解码的表达式</div>';
- 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 = '<div class="error-item"><strong>错误:</strong> 在要解码的表达式中未找到模板</div>';
- 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 = `<div class="error-item">
- <strong>错误:</strong> 以下模板在解码前需要配置:
- ${unconfigured.map(t => `<span class="template-name" style="font-family: monospace;"><${t}/></span>`).join(', ')}
- </div>`;
- 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 = `<div class="success-message">
- ✓ 使用完整列表方法成功解码 ${decodedExpressions.length} 个表达式
- ${decodedExpressions.length > MAX_DISPLAY_RESULTS ?
- `<br>⚠️ 显示前 ${MAX_DISPLAY_RESULTS} 个结果。使用搜索查找特定表达式。` : ''}
- </div>`;
- }
- // 生成模板值的所有组合(笛卡尔积)
- 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 = `
- <input type="text" id="resultsSearchInput" class="results-search-input"
- placeholder="在所有 ${totalCount} 个表达式中搜索...">
- <button id="resultsSearchBtn" class="btn btn-secondary btn-small">搜索</button>
- <button id="resultsClearSearchBtn" class="btn btn-outline btn-small" style="display: none;">清除搜索</button>
- `;
- 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 = `从 <strong>${totalCount}</strong> 个总组合中随机选择了 <strong>${actualSelectedCount}</strong> 个表达式<br>
- <small>显示前 <strong>${expressions.length}</strong> 个结果。下载将包含所有 <strong>${actualSelectedCount}</strong> 个表达式。</small>`;
- } else {
- infoDiv.innerHTML = `从 <strong>${totalCount}</strong> 个总组合中随机选择了 <strong>${expressions.length}</strong> 个表达式`;
- }
- } else if (totalCount && totalCount > expressions.length) {
- infoDiv.innerHTML = `总共生成了 <strong>${totalCount}</strong> 个表达式。
- 显示 <strong>${expressions.length}</strong> 个结果
- ${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 = `<div class="warning-message">
- 未找到匹配 "${searchTerm}" 的表达式
- </div>`;
- } else if (filteredExpressions.length > MAX_DISPLAY_RESULTS) {
- errorsDiv.innerHTML = `<div class="success-message">
- 找到 ${filteredExpressions.length} 个表达式匹配 "${searchTerm}"。
- 显示前 ${MAX_DISPLAY_RESULTS} 个结果。
- </div>`;
- } else {
- errorsDiv.innerHTML = `<div class="success-message">
- 找到 ${filteredExpressions.length} 个表达式匹配 "${searchTerm}"
- </div>`;
- }
- }
- // 清除搜索并显示原始结果
- 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 = `<div class="success-message">
- ✓ 显示总共 ${allDecodedExpressions.length} 个表达式中的前 ${MAX_DISPLAY_RESULTS} 个
- </div>`;
- }
- // 复制单个结果
- function copySingleResult(expression) {
- navigator.clipboard.writeText(expression).then(() => {
- // 显示临时成功消息
- const errorsDiv = document.getElementById('grammarErrors');
- const prevContent = errorsDiv.innerHTML;
- errorsDiv.innerHTML = '<div class="success-message">✓ 已复制到剪贴板</div>';
- setTimeout(() => {
- errorsDiv.innerHTML = prevContent;
- }, 2000);
- });
- }
- // 复制显示的结果
- function copyDisplayedResults() {
- // 复制所有当前显示的表达式
- const expressions = displayedExpressions.join('\n');
- navigator.clipboard.writeText(expressions).then(() => {
- const errorsDiv = document.getElementById('grammarErrors');
- errorsDiv.innerHTML = `<div class="success-message">
- ✓ 已复制 ${displayedExpressions.length} 个显示的表达式到剪贴板
- </div>`;
- });
- }
- // 复制所有结果
- function copyAllResults() {
- // 复制所有生成的表达式
- const expressions = allDecodedExpressions.join('\n');
- navigator.clipboard.writeText(expressions).then(() => {
- const errorsDiv = document.getElementById('grammarErrors');
- errorsDiv.innerHTML = `<div class="success-message">
- ✓ 所有 ${allDecodedExpressions.length} 个表达式已复制到剪贴板
- </div>`;
- }).catch(err => {
- // 处理大剪贴板操作可能出现的错误
- const errorsDiv = document.getElementById('grammarErrors');
- errorsDiv.innerHTML = `<div class="error-item">
- <strong>错误:</strong> 复制到剪贴板失败。数据可能过大。
- 请改用"下载全部"按钮。
- </div>`;
- });
- }
- // 将结果下载为文本文件
- 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 = `<div class="success-message">
- ✓ 已将 ${allDecodedExpressions.length} 个表达式下载为 decoded_expressions.txt
- </div>`;
- }
- // 随机迭代 - 生成全部然后随机选择
- 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 = '<div class="error-item"><strong>错误:</strong> 请输入要解码的表达式</div>';
- 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 = '<div class="error-item"><strong>错误:</strong> 在要解码的表达式中未找到模板</div>';
- 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 = `<div class="error-item">
- <strong>错误:</strong> 以下模板在解码前需要配置:
- ${unconfigured.map(t => `<span class="template-name" style="font-family: monospace;"><${t}/></span>`).join(', ')}
- </div>`;
- return;
- }
- // 计算总组合数
- let totalCombinations = 1;
- templateValues.forEach(values => {
- totalCombinations *= values.length;
- });
- // 验证随机数量
- if (randomCount > totalCombinations) {
- errorsDiv.innerHTML = `<div class="warning-message">
- ⚠️ 请求了 ${randomCount} 个随机表达式,但只有 ${totalCombinations} 个唯一组合存在。
- 改为生成所有 ${totalCombinations} 个表达式。
- </div>`;
- }
- // 生成所有组合(笛卡尔积)
- 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 = `<div class="success-message">
- ✓ 从 ${allExpressions.length} 个总组合中随机选择了 ${selectedExpressions.length} 个表达式<br>
- 📺 显示前 ${MAX_DISPLAY_RESULTS} 个结果。下载将包含所有 ${selectedExpressions.length} 个表达式。
- </div>`;
- } else {
- errorsDiv.innerHTML = `<div class="success-message">
- ✓ 从 ${allExpressions.length} 个总组合中随机选择了 ${selectedExpressions.length} 个表达式
- </div>`;
- }
- }
- // 为 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 = `
- <td><input type="text" class="setting-name-input form-input" placeholder="设置名称"></td>
- <td><input type="text" class="setting-value-input" data-setting="custom" placeholder="值"></td>
- <td><select class="setting-type-select"><option>string</option><option>number</option><option>boolean</option></select></td>
- <td><button class="remove-setting-btn" onclick="removeCustomSetting(this)">移除</button></td>
- `;
- 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 = `<div class="success-message">
- ✓ 已将 ${allCombinations.length} 个表达式配置下载为 expressions_with_settings.json
- </div>`;
- }
- // 全局存储测试结果
- 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 = `
- <h4>随机测试结果</h4>
- <p>从 ${result.totalPossible} 个可能组合中随机选择了表达式 #${result.testedIndex}</p>
- `;
- 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 = `<strong>表达式:</strong> ${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 = '<strong>使用的设置:</strong>';
- 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 = `
- <h4>测试摘要</h4>
- <div class="test-summary-stats">
- <div class="test-summary-stat">
- <div class="test-summary-stat-value">${total}</div>
- <div class="test-summary-stat-label">总测试数</div>
- </div>
- <div class="test-summary-stat" style="color: #28a745;">
- <div class="test-summary-stat-value">${success}</div>
- <div class="test-summary-stat-label">成功</div>
- </div>
- <div class="test-summary-stat" style="color: #dc3545;">
- <div class="test-summary-stat-value">${error}</div>
- <div class="test-summary-stat-label">错误</div>
- </div>
- <div class="test-summary-stat">
- <div class="test-summary-stat-value">${((success / total) * 100).toFixed(1)}%</div>
- <div class="test-summary-stat-label">成功率</div>
- </div>
- </div>
- `;
- 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 = `<div class="success-message">
- ✓ 已下载 ${allTestResults.length} 个表达式的测试结果
- </div>`;
- }
- // 下载带设置的表达式(与"生成并下载"相同)
- 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 = `<div class="success-message">
- ✓ 已将 ${allCombinations.length} 个表达式配置下载为 expressions_with_settings.json
- </div>`;
- }
|