多语言首页

This commit is contained in:
potaser
2026-08-09 06:38:53 +08:00
parent cd3e9a5f22
commit 774490b47f
+99 -6
View File
@@ -999,6 +999,10 @@
padding: 10px;
}
.execution-log-item.assistant .log-content.structured-content {
font-size: 13px;
}
.execution-log-item.assistant .log-content.short-content {
font-size: 13px;
}
@@ -1366,11 +1370,13 @@
<el-divider style="margin: 12px 0;"></el-divider>
<div style="padding:10px; background:#fff; border:1px solid #dcdfe6; border-radius:0px;">
<div @dragover.prevent @drop.prevent="handleLightweightExtensionFolderDrop($event)"
style="padding:10px; background:#fff; border:1px dashed #409EFF; border-radius:0px;">
<div style="display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:8px;">
<el-tooltip content="上传已跑通过的代码和测试数据;执行通过自然语言触发。" placement="top">
<h4 style="margin:0; color:#303133; cursor:help;">{{ t('拓展分析阶段') }}</h4>
</el-tooltip>
<el-button size="small" @click="loadExtensionRuns(); extensionResultDialogVisible = true">{{ t('运行结果') }}</el-button>
</div>
<div style="display:grid; grid-template-columns:72px 1fr; gap:7px; align-items:center; font-size:12px;">
<span>{{ t('已写阶段') }}</span>
@@ -1431,7 +1437,6 @@
<el-button v-if="isLightweightExtensionSelected" size="small" type="success" @click="openLightweightRuntimeCard()">
{{ t('运行已发布') }}
</el-button>
<el-button size="small" @click="loadExtensionRuns(); extensionResultDialogVisible = true">{{ t('运行结果') }}</el-button>
</div>
</div>
@@ -1780,6 +1785,20 @@
📂 Select
</el-button>
</div>
<!-- lightWeightExtensionTest:start -->
<div id="lightweight-extension-test-drop-zone"
style="display:none;margin-top:8px;border:1px dashed #409EFF;padding:10px;font-size:12px;color:#606266;background:#f8fbff;"
@dragover.prevent
@drop.prevent="handleLightweightExtensionFolderDrop($event)">
<div style="font-weight:600;color:#303133;">拖入固定结构拓展包</div>
<div style="margin-top:4px;line-height:1.5;">要求包含 raw_code/run.sh 与 raw_test_data/,系统会自动创建 Job、解析环境并开始 lightweight upload。</div>
<input id="lightweight-extension-test-folder-input" type="file" webkitdirectory directory multiple style="display:none" @change="handleLightweightExtensionFolderPick($event)">
<div style="display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:8px;">
<span>{{ lightweightExtensionTestStatus }}</span>
<el-button size="small" type="success" @click="openLightweightExtensionFolderPicker">选择文件夹</el-button>
</div>
</div>
<!-- lightWeightExtensionTest:end -->
</div>
</div>
@@ -7825,6 +7844,7 @@ RNA-seq KEGG/fgsea 会优先使用物种级 KEGG gene set;没有物种级缓
});
const activeRnaseqScopeId = ref('');
const activeGenotypeScopeId = ref('');
const lightweightExtensionTestStatus = ref('拖入固定结构文件夹,系统将自动创建 Job、解析环境并开始 upload。');
// 对话消息
const messages = ref([]);
@@ -19304,6 +19324,10 @@ compare: [[flesh, peel]]`;
};
const extensionFileKey = (file) => `${file?.name || ''}::${file?.size || 0}::${file?.lastModified || 0}`;
const extensionUploadPath = (file) => {
const relative = String(file?.lightweightRelativePath || '').trim().replace(/^\/+/, '');
return relative || String(file?.name || '').trim();
};
const appendExtensionFiles = (target, files) => {
const current = Array.isArray(target) ? target : [];
const merged = [...current];
@@ -19329,6 +19353,53 @@ compare: [[flesh, peel]]`;
if (selected.length) ElMessage.success(`已选择 ${selected.length} 个测试数据文件`);
event.target.value = '';
};
const handleLightweightExtensionFolderDrop = (event) => {
const droppedFiles = Array.from(event?.dataTransfer?.files || []);
if (!droppedFiles.length) {
ElMessage.warning('未检测到可用文件');
return;
}
const codeExtPattern = /\.(py|r|sh|bash|pl|js|ts|java|c|cc|cpp|go|rs|jl|rb|m|smk|nf|ipynb)$/i;
const dataExtPattern = /\.(fastq|fq|gz|fa|fasta|fna|faa|pep|cds|gff|gff3|gtf|csv|tsv|txt|xlsx|xls|vcf|sam|bam)$/i;
const normalized = droppedFiles.map((file) => {
const relativePath = file.webkitRelativePath || file.name;
if (!file.lightweightRelativePath) {
Object.defineProperty(file, 'lightweightRelativePath', {
value: relativePath,
configurable: true
});
}
return file;
});
const codeFiles = [];
const dataFiles = [];
normalized.forEach((file) => {
const filePath = extensionUploadPath(file).toLowerCase();
if (codeExtPattern.test(filePath)) {
codeFiles.push(file);
} else if (dataExtPattern.test(filePath)) {
dataFiles.push(file);
} else {
codeFiles.push(file);
}
});
extensionBuild.codeFiles = appendExtensionFiles(extensionBuild.codeFiles, codeFiles);
extensionBuild.dataFiles = appendExtensionFiles(extensionBuild.dataFiles, dataFiles);
if (!extensionBuild.displayName) {
const firstPath = normalized[0]?.webkitRelativePath || normalized[0]?.name || '';
const folder = firstPath.includes('/') ? firstPath.split('/')[0] : '';
if (folder) {
extensionBuild.displayName = folder.replace(/[^a-zA-Z0-9_-]+/g, '_');
}
}
ElMessage.success(`已拖入 ${normalized.length} 个文件,已自动填充拓展包`);
};
const removeExtensionFile = (kind, file) => {
const key = extensionFileKey(file);
if (kind === 'code') {
@@ -19363,7 +19434,7 @@ compare: [[flesh, peel]]`;
const value = String(path || '');
if (!value.startsWith('/api/extension-stages') && !value.startsWith('/api/extension-stage-runs')) return value;
const host = window.location.hostname || '127.0.0.1';
return `${window.location.protocol}//${host}:7880${value}`;
return `${window.location.protocol}//${host}:${window.location.port}${value}`;
};
const extensionApiFetch = async (path, options = {}) => fetch(extensionApiUrl(path), options);
const pushExtensionStatus = (message, type = 'info', showDialog = false) => {
@@ -19724,8 +19795,8 @@ compare: [[flesh, peel]]`;
form.append('extension_id', extensionId);
if (hasCommand) form.append('original_command', extensionBuild.command);
form.append('operation_token', token);
extensionBuild.codeFiles.forEach(file => form.append('raw_code_files', file));
extensionBuild.dataFiles.forEach(file => form.append('raw_data_files', file));
extensionBuild.codeFiles.forEach(file => form.append('raw_code_files', file, extensionUploadPath(file)));
extensionBuild.dataFiles.forEach(file => form.append('raw_data_files', file, extensionUploadPath(file)));
if (hasDataPaths) form.append('raw_data_paths', extensionBuild.dataPaths);
const response = await extensionApiFetch('/api/lightweight-extension-stages/upload', { method: 'POST', body: form });
if (!response.ok) throw new Error(await extensionApiError(response, '原始包可复现检查提交失败'));
@@ -22289,7 +22360,7 @@ compare: [[flesh, peel]]`;
addMessage('user', userInput);
ragHistory.value.push({ role: 'user', content: userInput, time: new Date().toLocaleTimeString() });
// 调用当前 bbav5 后端 RAG 代理,随页面端口走同源地址(例如 7880)
// 调用当前 bbav5 后端 RAG 代理,随页面端口走同源地址
const data = await fetchJsonWithTimeout('/api/agent/rag', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -23523,6 +23594,25 @@ compare: [[flesh, peel]]`;
runExtensionStageFromIntent,
extensionOutputIcon,
openExtensionOutput,
// lightWeightExtensionTest
lightweightExtensionTestStatus,
handleLightweightExtensionFolderDrop: (event) => window.LightWeightExtensionTest && window.LightWeightExtensionTest.handleDrop({
jobInfo,
extensionBuild,
createNewJob,
appendExtensionFiles,
buildLightweightExtensionStage,
lightweightExtensionTestStatus,
}, event),
handleLightweightExtensionFolderPick: (event) => window.LightWeightExtensionTest && window.LightWeightExtensionTest.handlePick({
jobInfo,
extensionBuild,
createNewJob,
appendExtensionFiles,
buildLightweightExtensionStage,
lightweightExtensionTestStatus,
}, event),
openLightweightExtensionFolderPicker: () => window.LightWeightExtensionTest && window.LightWeightExtensionTest.openPicker(),
methodologyPaperId,
methodologyFamily,
methodologyBatchDir,
@@ -23761,6 +23851,9 @@ compare: [[flesh, peel]]`;
document.getElementById('app').style.display = 'block';
console.log('App mounted successfully');
</script>
<!-- lightWeightExtensionTest:wiring:start -->
<script src="/lightWeightExtensionTest.js"></script>
<!-- lightWeightExtensionTest:wiring:end -->
<!-- 深度解读弹窗样式 -->
<style>
.interpretation-dialog .el-dialog__body { padding: 0; max-height: 70vh; overflow-y: auto; }