UNPKG

create-iking-admin

Version:

金合技术中台脚手架

375 lines (363 loc) 10.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title></title> </head> <style> body { overflow-wrap: break-word; font-size: 18px; } h3 { font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-weight: normal; } </style> <body></body> <script type="module"> import { createEffect, createResource, onMount } from 'https://esm.sh/solid-js' import html from 'https://esm.sh/solid-js/html' import * as echarts from 'https://cdn.jsdelivr.net/npm/echarts@5.3.3/dist/echarts.esm.min.js' import { UnicodeRange } from 'https://esm.sh/@japont/unicode-range@1.0.0' import { render } from 'https://esm.sh/solid-js/web' const getFontData = nameTable => Object.fromEntries( Object.entries(nameTable).map(([key, val]) => { return [key, typeof val === 'string' ? val : val.en] }) ) function _formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes' const k = 1024 const dm = decimals < 0 ? 0 : decimals const sizes = [ 'Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ] const i = Math.floor(Math.log(bytes) / Math.log(k)) return ( `${parseFloat((bytes / k ** i).toFixed(dm)) } ${ sizes[i]}` ) } const range = [ ['基本汉字', 0x4E00, 0x9FA5], ['基本汉字补充', 0x9FA6, 0x9FFF], ['扩展A', 0x3400, 0x4DBF], ['扩展B', 0x20000, 0x2A6DF], ['扩展C', 0x2A700, 0x2B738], ['扩展D', 0x2B740, 0x2B81D], ['扩展E', 0x2B820, 0x2CEA1], ['扩展F', 0x2CEB0, 0x2EBE0], ['扩展G', 0x30000, 0x3134A], ['康熙部首', 0x2F00, 0x2FD5], ['部首扩展', 0x2E80, 0x2EF3], ['兼容汉字', 0xF900, 0xFAD9], ['兼容扩展', 0x2F800, 0x2FA1D], ['PUA(GBK)部件', 0xE815, 0xE86F], ['部件扩展', 0xE400, 0xE5E8], ['PUA增补', 0xE600, 0xE6CF], ['汉字笔画', 0x31C0, 0x31E3], ['汉字结构', 0x2FF0, 0x2FFB], ['汉语注音', 0x3105, 0x312F], ['注音扩展', 0x31A0, 0x31BA], ['〇', 0x3007, 0x3007] ] const RangeAnalyze = data => { const total = data.reduce((col, cur) => { if (cur.chars.startsWith('U+')) { return ( col + String.fromCharCode( ...UnicodeRange.parse(cur.chars.split(',')) ) ) } return col + cur.chars }, '') const result = range.map(([name, min, max]) => { let exist = '' let voids = '' for (let i = min; i <= max; i++) { const char = String.fromCharCode(i) const isExist = total.includes(char) if (isExist) exist += char else voids += char } return [name, exist, voids] }) return html` <table style="width:80%;margin:auto;padding:1rem"> <thead> <tr> <th>位置</th> <th>存在</th> <th>不存在</th> <th>覆盖率</th> </tr> </thead> ${result.map(([name, exist, voids]) => { const coverage = (exist.length * 100) / (exist.length + voids.length) return html` <tr> <td>${name}</td> <td>${exist.length}</td> <td>${voids.length}</td> <td>${coverage.toFixed(2)}%</td> </tr> ` })} </table> ` } const TimeAnalyze = (record, message) => { record.pop() // 最后一个记录是没有用的 const total = record.reduce( (col, cur) => col + cur.end - cur.start, 0 ) let chartDom // console.log(record, total); onMount(() => { // 问就是渲染代价太大,等 1000ms 让浏览器冷静一下 setTimeout(() => { const myChart = echarts.init(chartDom) const option = { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, title: { text: '打包时间分布图', subtext: `时间为 ms; 总时间 ${total} ms;\n${message.fontFamily}` }, legend: { top: '15%' }, grid: { left: '10%', right: '10%', bottom: '30%', top: '30%' }, xAxis: { type: 'value' }, yAxis: { type: 'category', data: ['时间轴'] }, series: record.map(i => { return { name: i.name, type: 'bar', stack: 'total', label: { show: true }, emphasis: { focus: 'series' }, data: [ parseFloat((i.end - i.start).toFixed(1)) ] } }) } option && myChart.setOption(option) }, 1500) }) return html`<div ref=${function (dom) { chartDom = dom }} style="width: 600px;height:400px;margin:auto" ></div>` } const DataAnalyze = (data, message) => { const total = data.reduce((col, cur) => col + cur.size, 0) // console.log(data, total); let chartDom onMount(() => { // 问就是渲染代价太大,等 1000ms 让浏览器冷静一下 setTimeout(() => { const myChart = echarts.init(chartDom) const option = { tooltip: { trigger: 'item', formatter(data) { return ( `第 ${data.dataIndex + 1} 分包\n${ data.data.name }\n${ _formatBytes(data.data.value)}` ) } }, title: { text: message.fontFamily, subtext: `总共 ${ data.length } 分包; 总大小 ${_formatBytes( total )} 点击跳转查看;`, left: 'center' }, series: [ { name: '分包信息', type: 'pie', radius: ['40%', '70%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 10, borderColor: '#fff', borderWidth: 2 }, emphasis: { label: { show: true, fontSize: '18', fontWeight: 'bold' } }, labelLine: { show: true }, label: { show: true, minMargin: 5, edgeDistance: 10, lineHeight: 15, formatter(data) { return ( `${( (data.data.value * 100) / total ).toFixed(2)}%` ) } }, data: data.map(i => ({ value: i.size, name: i.name.slice(0, 7), hash: i.name })) } ] } option && myChart.setOption(option) myChart.on('click', data => { document .getElementById(data.data.hash) .scrollIntoView() }) }, 300) }) return html`<div ref=${function (dom) { chartDom = dom }} style="width: 600px;height:600px;margin:auto" ></div>` } const CharList = data => { return data.map(i => { const chars = i.chars.startsWith('U+') ? String.fromCharCode( ...UnicodeRange.parse(i.chars.split(',')) ) : i.chars return html`<div> <h3 id="${i.name}"> 分片名称 ${i.name} | 分片大小 ${_formatBytes(i.size)} </h3> <p>${chars}</p> </div>` }) } const BaseMessage = message => { return html` <table style="margin:auto"> ${Object.entries(message).map(i => { return html` <tr> <td>${i[0].en}</td> <td>${i[1].en}</td> </tr> ` })} </table> ` } const App = () => { const [data] = createResource(() => fetch('./reporter.json') .then(res => res.json()) .then(res => { res.message = res.message.windows || res.message.macintosh return res }) ) createEffect(() => { if (data()) { document.body.style.fontFamily = `"${ getFontData(data().message).fontFamily || getFontData(data().message).preferredFamily }"` document.querySelector('title').textContent = getFontData( data().message ).fontFamily const link = document.createElement('link') link.rel = 'stylesheet' link.href = `./${data().config.cssFileName || 'result'}.css` document.head.appendChild(link) } }) const content = () => html` <div> ${RangeAnalyze( data().data, getFontData(data().message) )} ${DataAnalyze(data().data, getFontData(data().message))} ${TimeAnalyze( data().record, getFontData(data().message) )} ${BaseMessage(getFontData(data().message))} </div> ${CharList(data().data)}` return html`<div> ${() => (data.loading ? '<div>加载中</div>' : content())} </div>` } render(App, document.body) </script> </html>