const $ = (selector, root=document) => root.querySelector(selector); // 自己转义引号:textContent→innerHTML 只处理 & < >,插进 attr="…" 时引号会被用来逃逸出属性。 const escapeHtml = value => String(value??'').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"').replace(/'/g,'''); let currentPage=1; async function getJson(url) { const response=await fetch(url); const data=await response.json(); if(!response.ok) throw new Error(data.message||'数据加载失败'); return data; } async function loadPublicData(page=1) { currentPage=page; const body=$('#publicRows'); body.innerHTML='正在加载数据…'; const q=encodeURIComponent($('#publicSearch').value.trim()), category=encodeURIComponent($('#publicCategory').value); try { const result=await getJson(`/api/public/dashboard?page=${page}&page_size=20&q=${q}&category=${category}`); $('#statTotal').textContent=result.stats.total; $('#statCategories').textContent=result.stats.category_count; $('#statRecent').textContent=result.stats.recent_count; $('#statClarity').textContent=result.stats.average_clarity??'—'; const select=$('#publicCategory'), selected=select.value; select.innerHTML=''+result.categories.map(x=>``).join(''); select.value=selected; body.innerHTML=result.data.length?result.data.map(row=>`${escapeHtml(row.experiment_id)}${row.test_date}${escapeHtml(row.material_category)}${escapeHtml(row.material_name)}${row.material_thickness} mm${row.actual_output_power} W${row.scanning_speed} mm/s${row.is_cut_through?'是':'否'}${row.pattern_clarity_score}`).join(''):'未找到符合条件的数据'; body.querySelectorAll('tr[data-id]').forEach(row=>row.onclick=()=>showDetail(row.dataset.id)); const pages=Math.max(1,Math.ceil(result.pagination.total/result.pagination.page_size)); $('#publicPager').innerHTML=`第 ${page} / ${pages} 页,共 ${result.pagination.total} 条`; $('#publicPager').querySelectorAll('button:not([disabled])').forEach(button=>button.onclick=()=>loadPublicData(Number(button.dataset.page))); } catch(error) { body.innerHTML=`${escapeHtml(error.message)}`; } } const labels={ apparent_density:'表观密度 (g/cm³)',uv_absorption_355nm:'355nm 紫外吸收率 (%)',material_thickness:'材料厚度 (mm)',moisture_content:'含水率 (%)',thermal_conductivity:'热导率 (W/(m·K))',initial_decomposition_temp:'初始分解温度 (℃)',melting_vaporization_temp:'熔点 / 气化温度 (℃)',specific_heat_capacity:'比热容 (J/(kg·K))',carbon_residue_rate:'残炭率 (%)',surface_roughness:'表面粗糙度 (μm)',hardness:'硬度 (邵氏/HV)',actual_output_power:'实际输出功率 (W)',display_current:'设备显示电流 (A)',scanning_speed:'扫描速度 (mm/s)',pulse_frequency:'脉冲频率 (kHz)',pulse_width:'脉冲脉宽 (μs)',defocus_amount:'离焦量 (mm)',scan_line_spacing:'扫描线间距 (mm)',filling_method:'填充方式',processing_size:'加工尺寸',is_cut_through:'是否切透',carbonized_edge_width:'碳化边宽度 (mm)',etching_depth:'蚀刻深度 (μm)',is_fire_smolder:'是否起火 / 阴燃',pattern_clarity_score:'图案清晰度评分',presentation_balance_score:'呈现均衡性评分' }; const physical=['apparent_density','uv_absorption_355nm','material_thickness','moisture_content','thermal_conductivity','initial_decomposition_temp','melting_vaporization_temp','specific_heat_capacity','carbon_residue_rate','surface_roughness','hardness']; const laser=['actual_output_power','display_current','scanning_speed','pulse_frequency','pulse_width','defocus_amount','scan_line_spacing','filling_method','processing_size']; const resultFields=['is_cut_through','carbonized_edge_width','etching_depth','is_fire_smolder','pattern_clarity_score','presentation_balance_score']; function renderGroup(title,fields,data){return `

${title}

${fields.map(key=>{let value=data[key];if(typeof value==='boolean')value=value?'是':'否';if(value===null||value==='')value='未填写';return `
${labels[key]}${escapeHtml(value)}
`}).join('')}
`;} function renderCustomGroup(values){if(!values?.length)return '';return `

扩展数据

${values.map(item=>`
${item.is_active?'':`历史字段 · `}${escapeHtml(item.label)}${escapeHtml(item.display_value||item.raw_value||'未填写')}${item.compatible===false?'历史格式':''}
`).join('')}
`;} function renderImageGroup(images){return `

成品图片

`;} async function showDetail(id){ try{const {data}=await getJson(`/api/public/records/${id}`);$('#publicModalContent').innerHTML=`

EXPERIMENT DETAIL

${escapeHtml(data.experiment_id)}

${escapeHtml(data.test_date)} · ${escapeHtml(data.material_category)} · ${escapeHtml(data.material_name)}

${renderImageGroup(data.images)}${renderGroup('材料物理特性',physical,data)}${renderGroup('激光雕刻参数',laser,data)}${renderGroup('实验结果',resultFields,data)}${renderCustomGroup(data.custom_fields)}
`;ImageViewer.wire($('#publicModalContent'),data.images);$('#publicModal').hidden=false;}catch(error){alert(error.message);} } document.querySelectorAll('[data-close]').forEach(node=>node.onclick=()=>$('#publicModal').hidden=true); $('#publicSearchBtn').onclick=()=>loadPublicData(1); $('#publicSearch').addEventListener('keydown',event=>{if(event.key==='Enter')loadPublicData(1)}); $('#publicCategory').onchange=()=>loadPublicData(1); loadPublicData();