create-iking-admin
Version:
金合技术中台脚手架
375 lines (363 loc) • 10.9 kB
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>