用户聚合视图
按研究员自动分组,清晰展示每位成员的仿真贡献度。
AdminRecordList.vue 是专为实验室管理员设计的仿真数据监控中心。它集成了复杂的参数矩阵解析与动态图表可视化入口。
用户聚合视图
按研究员自动分组,清晰展示每位成员的仿真贡献度。
参数矩阵解析
支持对 13C NMR、动力学、加热环境等 30+ 维度的参数进行结构化展示。
组件内部将复杂的仿真输入参数划分为四个核心维度:
| 分类 | 涵盖关键参数 | 作用说明 |
|---|---|---|
| 13C NMR 参数 | p0, sigp1 等 | 描述煤的大分子化学结构 |
| 元素分析 | fcar, fhyd 等 | 定义煤样的质量分率上限 |
| 加热数据 | kT, T_max | 模拟实验室反应器物理条件 |
| 动力学参数 | ab, eb0 | 控制化学键断裂与气相析出速率 |
calc_mode 实时过滤特定算法结果。CoalSimCharts 进行全屏渲染。// 作用:把实验室那些奇奇怪怪的科学数字变好看const formatSmartNumber = (val: any) => { const num = parseFloat(val); if (isNaN(num)) return val; // 不是数字就原样返回 // 太大的数字(>10000)或者太小的数字(<0.001)就用科学计数法显示 if (Math.abs(num) >= 10000 || (Math.abs(num) < 0.001 && num !== 0)) return num.toExponential(2).replace('e+', 'e'); // 整数就直接显示,小数就只留三位 return Number.isInteger(num) ? num : num.toFixed(3);};// 作用:从服务器把所有人的实验记录拿过来const fetchRecords = async () => { loading.value = true; try { const res = await axios.get('/admin/records'); // 拿过来后顺便检查一下:如果是字符串就转成 JS 对象,方便后续画图 records.value = res.data.map((r: any) => ({ ...r, input_params: typeof r.input_params === 'string' ? JSON.parse(r.input_params) : r.input_params })); } finally { loading.value = false; }};
// 作用:删掉不想要的记录const deleteRecord = async (id: number) => { const result = await Swal.fire({ title: '确定删除?', icon: 'warning', showCancelButton: true }); if (result.isConfirmed) { await axios.delete(`/admin/records/${id}`); await fetchRecords(); // 删完立刻重新刷新列表 }};// 作用:控制列表“展开/收起”,并且保证页面不卡顿const toggleUser = (name: string) => { const i = expandedUsers.value.indexOf(name); if (i > -1) { expandedUsers.value.splice(i, 1); // 如果是开着的,就关掉 } else { expandedUsers.value.push(name); // 如果是关着的,就打开 if (!recordRenderLimit[name]) recordRenderLimit[name] = 20; // 默认先给看20条,多了不给,怕页面卡 }};
// 作用:只给用户展示“他想看的”和“电脑跑得动的”const filteredRecords = (group: any[], displayName: string) => { const mode = filterModes[displayName] || 'All'; // 选了哪个模式(比如CPD)? const recordsByMode = mode === 'All' ? group : group.filter(r => r.calc_mode === mode); const limit = recordRenderLimit[displayName] || recordsByMode.length; return recordsByMode.slice(0, limit); // 只切出一小块数据给页面显示};// 作用:把数据按人名分好类const groupedByDisplayName = computed(() => records.value.reduce((acc: any, r: any) => { const key = r.display_name || r.username || 'Unknown'; (acc[key] = acc[key] || []).push(r); return acc;}, {}));
// 作用:把分好类的人,按每页8个展示,别一次性全堆出来const paginatedGroups = computed(() => { const names = Object.keys(groupedByDisplayName.value); const start = (currentPage.value - 1) * itemsPerPage; const res: any = {}; names.slice(start, start + itemsPerPage).forEach(name => res[name] = groupedByDisplayName.value[name]); return res;});// 作用:把选中的那条实验数据塞给图表组件,然后把图表弹出来const handleViewCharts = (record: any) => { chartReady.value = false; simResult.headers = record.result.headers; // 表头 simResult.rows = record.result.data_rows; // 数据行 simResult.config = record.input_params; // 仿真参数 chartReady.value = true; showCharts.value = true; // 变!图表弹窗现身};