224 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			224 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const sprintf = (...[string, ...args]) => {
 | ||
|     return string.replace(/{(\d+)}/g, (match, number) => args[number] ?? match);
 | ||
| }
 | ||
| 
 | ||
| const getJSON = async url => {
 | ||
| 	const resp = await fetch(url)
 | ||
| 	const json = await resp.json()
 | ||
|     return json;
 | ||
| }
 | ||
| 
 | ||
| const createPopup = async id => {
 | ||
| 	const asics = await getJSON('/api/asictypes')
 | ||
| 
 | ||
| 	asicoptions = ''
 | ||
| 	asics.forEach(elem => {
 | ||
| 		asicoptions += sprintf('<option value="{0}">{1}</option>', elem['key'], elem['value'])
 | ||
| 	})
 | ||
| 
 | ||
| 	document.querySelector('body').innerHTML += sprintf(popup, id, asicoptions, 'content')
 | ||
| }
 | ||
| 
 | ||
| const deletePopup = id => {
 | ||
| 	document.querySelector('#popup-' + id).remove()
 | ||
| }
 | ||
| 
 | ||
| const update = async () => {
 | ||
| 	let inner = await getStats()
 | ||
| 	document.querySelector('.grid').innerHTML = inner
 | ||
| }
 | ||
| 
 | ||
| const datafn = async () => {
 | ||
| 	// return await getJSON('/api/webinit')
 | ||
| }
 | ||
| 
 | ||
| const data = datafn()
 | ||
| 
 | ||
| console.log(data)
 | ||
| 
 | ||
| const cols = 40
 | ||
| const rows = 40
 | ||
| 
 | ||
| 
 | ||
| const css =
 | ||
| 	`<style>
 | ||
| 	@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:wght@400;500;600;700&display=swap');
 | ||
| 
 | ||
| 	* {
 | ||
| 		margin: 0;
 | ||
| 		padding: 0;
 | ||
| 		box-sizing: border-box;
 | ||
| 		font-family: 'Source Code Pro', monospace;
 | ||
| 	}
 | ||
| 
 | ||
| 	body {
 | ||
| 		background: #000;
 | ||
| 	}
 | ||
| 
 | ||
| 	input,
 | ||
| 	select {
 | ||
| 		border: 1px solid #fff;
 | ||
| 		background: #000;
 | ||
| 		color: #fff;
 | ||
| 		padding: 5px 10px;
 | ||
| 	}
 | ||
| 
 | ||
| 	.green {
 | ||
| 		background: #0b0 !important;
 | ||
| 	}
 | ||
| 
 | ||
| 	.yellow {
 | ||
| 		background: #ff0 !important;
 | ||
| 	}
 | ||
| 
 | ||
| 	.red {
 | ||
| 		background: #f11 !important;
 | ||
| 	}
 | ||
| 
 | ||
| 	.darkred {
 | ||
| 		background: #300 !important;
 | ||
| 	}
 | ||
| 
 | ||
| 	.header {
 | ||
| 		height: 60px;
 | ||
| 		background: #222;
 | ||
| 		text-align: center;
 | ||
| 		margin: 0 0 1px 0;
 | ||
| 		display: grid;
 | ||
| 		justify-items: center;
 | ||
| 		align-content: center;
 | ||
| 	}
 | ||
| 
 | ||
| 	.header-info {
 | ||
| 		color: #bbb;
 | ||
| 		font-weight: 700;
 | ||
| 	}
 | ||
| 
 | ||
| 	.grid {
 | ||
| 		display: grid;
 | ||
| 		grid-template-columns: repeat(${cols}, 30px);
 | ||
| 		grid-template-rows: repeat(${rows}, 30px);
 | ||
| 		grid-gap: 1px;
 | ||
| 		margin: auto;
 | ||
| 		width: max-content;
 | ||
| 	}
 | ||
| 
 | ||
| 	.cell {
 | ||
| 		position: relative;
 | ||
| 		background: #111;
 | ||
| 		font-size: 9px;
 | ||
| 	}
 | ||
| 
 | ||
| 	.cell:hover {
 | ||
| 		cursor: pointer;
 | ||
| 	}
 | ||
| 
 | ||
| 	.cell:hover::after {
 | ||
| 		content: '';
 | ||
| 		position: absolute;
 | ||
| 		top: 0;
 | ||
| 		left: 0;
 | ||
| 		width: 100%;
 | ||
| 		height: 100%;
 | ||
| 		pointer-events: none;
 | ||
| 		background: #ffffff33;
 | ||
| 	}
 | ||
| 
 | ||
| 	.popup {
 | ||
| 		position: fixed;
 | ||
| 		top: 0;
 | ||
| 		left: 0;
 | ||
| 		width: 100vw;
 | ||
| 		height: 100vh;
 | ||
| 		display: grid;
 | ||
| 		justify-items: center;
 | ||
| 		align-content: center;
 | ||
| 	}
 | ||
| 
 | ||
| 	.popup-bg {
 | ||
| 		position: absolute;
 | ||
| 		width: 100%;
 | ||
| 		height: 100%;
 | ||
| 		background: #00000033;
 | ||
| 		z-index: 98;
 | ||
| 	}
 | ||
| 
 | ||
| 	.popup-window {
 | ||
| 		position: relative;
 | ||
| 		height: max-content;
 | ||
| 		max-height: 90vh;
 | ||
| 		width: max-content;
 | ||
| 		max-width: 90vw;
 | ||
| 		padding: 40px;
 | ||
| 		background: #222;
 | ||
| 		z-index: 99;
 | ||
| 	}
 | ||
| 	</style>
 | ||
| 	`
 | ||
| 
 | ||
| const header =
 | ||
| 	'<div class="header">'
 | ||
| 		+ '<div class="header-info">'
 | ||
| 			+ 'Всего устройств: {0}, Предупреждений, {1}, Ошибки: {2}, В сети: {3}, Не в сети: {4}'
 | ||
| 		+ '</div>'
 | ||
| 	+ '</div>'
 | ||
| 
 | ||
| 
 | ||
| const cell =
 | ||
| 	'<div class="cell {1}" id="cell-{0}" onclick="createPopup({0})">'
 | ||
| 		+ '{2}'
 | ||
| 	+ '</div>'
 | ||
| 
 | ||
| const grid =
 | ||
| 	'<div class="grid">'
 | ||
| 		+ '{0}'
 | ||
| 	+ '</div>'
 | ||
| 
 | ||
| const popup =
 | ||
| 	'<div class="popup" id="popup-{0}">'
 | ||
| 		+ '<div class="popup-bg" onclick="deletePopup({0})"></div>'
 | ||
| 		+ '<div class="popup-window">'
 | ||
| 			+ '<div class="row">'
 | ||
| 				+ '<select>'
 | ||
| 					+ '<option value="none">Свободно</option>'
 | ||
| 					+ '{1}'
 | ||
| 				+ '</select>'
 | ||
| 				+ '<input type="text" placeholder="Адрес...">'
 | ||
| 			+ '</div>'
 | ||
| 			+ '{2}'
 | ||
| 		+ '</div>'
 | ||
| 	+ '</div>'
 | ||
| 
 | ||
| const getStats = async () => {
 | ||
| 	let cells = ''
 | ||
| 	let info = await getJSON('/curstatus.json')
 | ||
| 	for(let i = 1; i <= cols * rows; i++) {
 | ||
| 		if(info.asics[i]?.status == "ok")
 | ||
| 			cells += sprintf(cell, i, 'green', info.asics[i]?.hashrate)
 | ||
| 		else if(info.asics[i]?.status == "warn")
 | ||
| 			cells += sprintf(cell, i, 'yellow', info.asics[i]?.hashrate)
 | ||
| 		else if(info.asics[i]?.status == "crit")
 | ||
| 			cells += sprintf(cell, i, 'red', info.asics[i]?.hashrate)
 | ||
| 		else if(info.asics[i]?.status == "off")
 | ||
| 			cells += sprintf(cell, i, 'darkred', '')
 | ||
| 		else
 | ||
| 			cells += sprintf(cell, i, '', '')
 | ||
| 	}
 | ||
| 	return cells
 | ||
| }
 | ||
| 
 | ||
| const run = async () => {
 | ||
| 	document.querySelector('body').innerHTML += css
 | ||
| 	document.querySelector('body').innerHTML += sprintf(header)
 | ||
| 
 | ||
| 	let inner = sprintf(grid, await getStats())
 | ||
| 	document.querySelector('body').innerHTML += inner
 | ||
| 
 | ||
| 	setInterval(async () => {
 | ||
| 		await update()
 | ||
| 	}, 10000)
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| run()
 |