commit
7a46f5a528
240
WebUI/index.html
240
WebUI/index.html
@ -9,135 +9,128 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" defer></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" defer></script>
|
||||||
<script src="main.js" defer></script>
|
<script src="main.js" defer></script>
|
||||||
<script src="https://cdn.socket.io/socket.io-3.0.1.min.js"></script>
|
<script src="https://cdn.socket.io/socket.io-3.0.1.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript" defer></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body onload="updateChart(), checkMode(), getStartValues()">
|
<body onload="checkUser(), checkMode(), getStartValues(), updateChart()">
|
||||||
<header>
|
<header>
|
||||||
<h1>ESP-Ventilation</h1>
|
<h1>ABB Ventilation Controller</h1>
|
||||||
<div class="logout">
|
|
||||||
<p id="user"></p>
|
|
||||||
<form id="log_out" method="post" action="/logout">
|
|
||||||
<input id="btn_log_out" type="submit" value="Log out">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<div class="logout">
|
||||||
<div class="modes">
|
<p id="user"></p>
|
||||||
<br>
|
<form id="log_out" method="post" action="/logout">
|
||||||
<div class="buttons">
|
<input id="btn_log_out" type="submit" value="Log out">
|
||||||
|
</form>
|
||||||
<input type="radio" class="custom-radio" id="m_auto" name="mode" value="Automatic" checked="true">
|
</div>
|
||||||
|
<div class="upper">
|
||||||
<label for="m_auto">Automatic</label><br>
|
<main>
|
||||||
</div>
|
<div class="login">
|
||||||
<div class="buttons">
|
<form id="login-form" method="post" action="/">
|
||||||
|
<br>
|
||||||
<input type="radio" class="custom-radio" id="m_man" name="mode" value="Manual">
|
<p id="pwd-warn">Wrong username or password</p>
|
||||||
|
<p id="form-warn">All fields must be filled!</p>
|
||||||
<label for="m_man">Manual</label><br><br>
|
<p>You must log in to change settings<br>Please give your credentials:</p>
|
||||||
</div>
|
<input type="text" name="username" id="username" placeholder="Username" required>
|
||||||
</div>
|
<br><br>
|
||||||
<div class="login">
|
<input type="password" name="password" id="password" placeholder="Password" required>
|
||||||
<form id="login-form" method="post" action="/">
|
<br><br>
|
||||||
<br>
|
<input type="submit" name="btn_login" id="btn_login" value="Login">
|
||||||
<p id="pwd-warn">Wrong username or password</p>
|
<br><br>
|
||||||
<p id="form-warn">All fields must be filled!</p>
|
<p id="acc" style="font-weight:normal">If you don't have an account, please contact your administrator</p>
|
||||||
<p>You must log in to access manual mode<br>Please give your credentials:</p>
|
<br>
|
||||||
<input type="text" name="username" id="username" placeholder="Username" required>
|
</form>
|
||||||
<br><br>
|
|
||||||
<input type="password" name="password" id="password" placeholder="Password" required>
|
|
||||||
<br><br>
|
|
||||||
<input type="submit" name="btn_login" id="btn_login" value="Login">
|
|
||||||
<br>
|
|
||||||
<p id="acc" style="font-weight:normal">If you don't have account, please contact the site administrator</p>
|
|
||||||
<br>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<p id="mon-warn">Fan is not settled in required time!</p>
|
|
||||||
<div class="set_values">
|
|
||||||
<div class="field">
|
|
||||||
<div class="ofield">
|
|
||||||
<div id="pr_div">
|
|
||||||
<h3>Set pressure value</h3>
|
|
||||||
<output class="set_output" id="set_press">10 Pa</output>
|
|
||||||
<input class="slider" id="pressure" type="range" value="10" max="120" oninput="set_press.value = this.value + ' Pa'">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="modes">
|
||||||
<div class="ofield">
|
<div id="buttons">
|
||||||
<div id="sp_div">
|
<input type="radio" class="custom-radio" id="m_auto" name="mode" value="Automatic" checked="true">
|
||||||
<h3>Set fan speed</h3>
|
<label for="m_auto" id="auto_label">Automatic</label><br>
|
||||||
<output class="set_output" id="set_speed">0 %</output>
|
</div>
|
||||||
<input class="slider" id="speed" type="range" value="0" max="100" oninput="set_speed.value = this.value + ' %'" disabled="true">
|
<div id="buttons">
|
||||||
|
<input type="radio" class="custom-radio" id="m_man" name="mode" value="Manual">
|
||||||
|
<label for="m_man" id="man_label">Manual</label><br><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="set_values">
|
||||||
|
<div class="field">
|
||||||
|
<div class="ofield">
|
||||||
|
<div id="pr_div">
|
||||||
|
<h3>Set pressure value</h3>
|
||||||
|
<output class="set_output" id="set_press">0 Pa</output>
|
||||||
|
<input class="slider" id="pressure" type="range" value="0" max="120" oninput="set_press.value = this.value + ' Pa'">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ofield">
|
||||||
|
<div id="sp_div">
|
||||||
|
<h3>Set fan speed</h3>
|
||||||
|
<output class="set_output" id="set_speed">0 %</output>
|
||||||
|
<input class="slider" id="speed" type="range" value="0" max="100" oninput="set_speed.value = this.value + ' %'" disabled="true">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br><br>
|
|
||||||
<div class="get_values">
|
|
||||||
<fieldset id="monitor">
|
|
||||||
<legend style="font-size: 20px;"><b>Monitor</b></legend>
|
|
||||||
<div class="field">
|
|
||||||
<div class="ifield">
|
|
||||||
<h3>Pressure</h3>
|
|
||||||
<output class="get_output" id="get_press">0</output>
|
|
||||||
<h4>Pa</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<div class="ifield">
|
|
||||||
<h3>Fan speed</h3>
|
|
||||||
<output class="get_output" id="get_speed">0</output>
|
|
||||||
<h4>%</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<div class="ifield">
|
|
||||||
<h3>CO2</h3>
|
|
||||||
<output class="get_output" id="get_co">0</output>
|
|
||||||
<h4>ppm</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<div class="ifield">
|
|
||||||
<h3>Temperature</h3>
|
|
||||||
<output class="get_output" id="get_temp">0</output>
|
|
||||||
<h4>℃</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<div class="ifield">
|
|
||||||
<h3>Relative Humidity</h3>
|
|
||||||
<output class="get_output" id="get_rh">0</output>
|
|
||||||
<h4>%</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
|
|
||||||
<aside>
|
|
||||||
<br>
|
|
||||||
<h2>Data History</h2>
|
|
||||||
<br>
|
|
||||||
<div class="chart-container">
|
|
||||||
<span id="chart_warning" style="display:none; color: red;">Not enough data to show the chosen period. Showing all values.</span>
|
|
||||||
<div class="dropdown">
|
|
||||||
<label for="data">Select period:</label>
|
|
||||||
<select name="data" id="data">
|
|
||||||
<option value="0">All</option>
|
|
||||||
<option value="1">10 min</option>
|
|
||||||
<option value="2">30 min</option>
|
|
||||||
<option value="3">60 min</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
<aside>
|
||||||
|
<p id="mon-warn">Fan is not settled in required time!</p>
|
||||||
|
<div class="get_values">
|
||||||
|
<fieldset id="monitor">
|
||||||
|
<legend style="font-size: 20px;"><b>Monitor</b></legend>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ifield">
|
||||||
|
<h3>Pressure</h3>
|
||||||
|
<output class="get_output" id="get_press">0</output>
|
||||||
|
<h4>Pa</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ifield">
|
||||||
|
<h3>Fan speed</h3>
|
||||||
|
<output class="get_output" id="get_speed">0</output>
|
||||||
|
<h4>%</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ifield">
|
||||||
|
<h3>CO2</h3>
|
||||||
|
<output class="get_output" id="get_co">0</output>
|
||||||
|
<h4>ppm</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ifield">
|
||||||
|
<h3>Temperature</h3>
|
||||||
|
<output class="get_output" id="get_temp">0</output>
|
||||||
|
<h4>℃</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ifield">
|
||||||
|
<h3>Relative Humidity</h3>
|
||||||
|
<output class="get_output" id="get_rh">0</output>
|
||||||
|
<h4>%</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
<div class="lower">
|
||||||
|
<div class="chart-container" id="chart-cont">
|
||||||
|
<h2>Data History</h2>
|
||||||
|
<span id="chart_warn">No data found for selected period.</span>
|
||||||
|
<div class="filter">
|
||||||
|
<label>Select period:</label><br>
|
||||||
|
<label for="start-time">Start time:</label>
|
||||||
|
<input type="datetime-local" id="start-time" name="start-time" min="" max="" value="">
|
||||||
|
<label for="end-time">End time:</label>
|
||||||
|
<input type="datetime-local" id="end-time" name="end-time" min="" max="" value="">
|
||||||
|
<button id="btn_reset">Reset</button>
|
||||||
|
</div>
|
||||||
<canvas id="dataChart" width="600px" height="300px"></canvas>
|
<canvas id="dataChart" width="600px" height="300px"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<br><br>
|
<div id="user-table">
|
||||||
<div class="user-table">
|
|
||||||
<h2>User Log History</h2>
|
<h2>User Log History</h2>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@ -151,7 +144,6 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<br><br>
|
</div>
|
||||||
</aside>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -12,7 +12,15 @@ const mqtt = require('mqtt');
|
|||||||
const session = require('express-session');
|
const session = require('express-session');
|
||||||
const bcrypt = require('bcrypt')
|
const bcrypt = require('bcrypt')
|
||||||
|
|
||||||
const client = mqtt.connect('mqtt://127.0.0.1:1883', {clientId: 'node_server', clean: true})
|
const client = mqtt.connect('mqtt://192.168.1.254:1883',
|
||||||
|
{username: 'SmartIotMQTT',
|
||||||
|
password: 'SmartIot',
|
||||||
|
clientId: 'node_server',
|
||||||
|
clean: true,
|
||||||
|
connectTimeout: 8000,
|
||||||
|
reconnectPeriod: 1000,
|
||||||
|
})
|
||||||
|
//const client = mqtt.connect('mqtt://127.0.0.1:1883', {clientId: 'node_server', clean: true})
|
||||||
let newData;
|
let newData;
|
||||||
let user;
|
let user;
|
||||||
let msg;
|
let msg;
|
||||||
@ -46,14 +54,10 @@ function write(data, filePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTime(){
|
function getTime(){
|
||||||
let today = new Date();
|
let day = new Date();
|
||||||
let day = ("0" + today.getDate()).slice(-2);
|
day = new Date(day.getTime() - day.getTimezoneOffset()*60000);
|
||||||
let month = ("0" + (today.getMonth() + 1)).slice(-2);
|
let today = day.toISOString().replace('T', ' ').slice(0,19);
|
||||||
let hours = ("0" + today.getHours()).slice(-2);
|
return today;
|
||||||
let mins = ("0" + today.getMinutes()).slice(-2);
|
|
||||||
let secs = ("0" + today.getSeconds()).slice(-2);
|
|
||||||
let timestamp = (day + '.' + month + '.' + today.getFullYear() + ' ' + hours + '.' + mins + '.' + secs).toString();
|
|
||||||
return timestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client.on('connect', ()=>{
|
client.on('connect', ()=>{
|
||||||
@ -62,14 +66,13 @@ client.on('connect', ()=>{
|
|||||||
|
|
||||||
client.subscribe('controller/status', (err)=>{
|
client.subscribe('controller/status', (err)=>{
|
||||||
if(err){
|
if(err){
|
||||||
console.log('Subscription failed')
|
console.log('Subscription failed ' + err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
io.on('connection', (socket)=>{
|
io.on('connection', (socket)=>{
|
||||||
console.log("User " + socket.id + " connected");
|
console.log("User " + socket.id + " connected");
|
||||||
socket.on('setting', (arg)=> {
|
socket.on('setting', (arg)=> {
|
||||||
let data = JSON.stringify(arg);
|
|
||||||
client.publish("controller/settings", JSON.stringify(arg), { qos: 2, retain: false }, (error)=>{
|
client.publish("controller/settings", JSON.stringify(arg), { qos: 2, retain: false }, (error)=>{
|
||||||
if(error){
|
if(error){
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -80,9 +83,6 @@ io.on('connection', (socket)=>{
|
|||||||
|
|
||||||
client.on('message', async (topic, message) =>{
|
client.on('message', async (topic, message) =>{
|
||||||
newData = JSON.parse(message);
|
newData = JSON.parse(message);
|
||||||
console.log(newData);
|
|
||||||
io.emit('data', newData);
|
|
||||||
|
|
||||||
let info = [];
|
let info = [];
|
||||||
try {
|
try {
|
||||||
info = await read('data.json');
|
info = await read('data.json');
|
||||||
@ -90,7 +90,8 @@ client.on('message', async (topic, message) =>{
|
|||||||
let now = getTime();
|
let now = getTime();
|
||||||
newData['ts'] = now;
|
newData['ts'] = now;
|
||||||
info.push(newData);
|
info.push(newData);
|
||||||
write(info, 'data.json');
|
write(info, 'data.json');
|
||||||
|
io.emit('data', newData);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -98,15 +99,6 @@ app.get('/', (req, res)=>{
|
|||||||
res.sendFile(path.join(__dirname + '/index.html'));
|
res.sendFile(path.join(__dirname + '/index.html'));
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/data', async (req, res) => {
|
|
||||||
try {
|
|
||||||
const data = await read('data.json');
|
|
||||||
res.json(data);
|
|
||||||
} catch (e) {
|
|
||||||
res.status(404).send(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/register', (req,res)=>{
|
app.get('/register', (req,res)=>{
|
||||||
res.send(`
|
res.send(`
|
||||||
<h1>Register</h1>
|
<h1>Register</h1>
|
||||||
@ -132,14 +124,20 @@ app.post('/', async (req,res)=>{
|
|||||||
|
|
||||||
if(bcrypt.compareSync(password, pwd)){
|
if(bcrypt.compareSync(password, pwd)){
|
||||||
let now = getTime();
|
let now = getTime();
|
||||||
|
let d = now.slice(8,10);
|
||||||
|
let m = now.slice(5,7);
|
||||||
|
let y = now.slice(0,4);
|
||||||
|
let t = now.slice(11, 19);
|
||||||
|
let stamp = d + '.' + m + '.' + y + ' ' + t;
|
||||||
|
//console.log(stamp);
|
||||||
req.session.userId = username;
|
req.session.userId = username;
|
||||||
req.session.startTime = now;
|
req.session.startTime = stamp;
|
||||||
console.log('Password is correct');
|
console.log('Password is correct');
|
||||||
user = req.session.userId;
|
user = req.session.userId;
|
||||||
io.emit('user', user);
|
io.emit('user', user);
|
||||||
sesUser = user;
|
sesUser = user;
|
||||||
sesStart = req.session.startTime;
|
sesStart = req.session.startTime;
|
||||||
res.status(205);
|
res.redirect('/');
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
msg = 'wrong';
|
msg = 'wrong';
|
||||||
@ -183,7 +181,12 @@ app.post('/register', async (req,res) =>{
|
|||||||
|
|
||||||
app.post('/logout',async (req, res) =>{
|
app.post('/logout',async (req, res) =>{
|
||||||
let now = getTime();
|
let now = getTime();
|
||||||
req.session.endTime = now;
|
let d = now.slice(8,10);
|
||||||
|
let m = now.slice(5,7);
|
||||||
|
let y = now.slice(0,4);
|
||||||
|
let t = now.slice(11, 19);
|
||||||
|
let stamp = d + '.' + m + '.' + y + ' ' + t;
|
||||||
|
req.session.endTime = stamp;
|
||||||
let sesEnd = req.session.endTime;
|
let sesEnd = req.session.endTime;
|
||||||
let log = [];
|
let log = [];
|
||||||
try {
|
try {
|
||||||
@ -196,6 +199,7 @@ app.post('/logout',async (req, res) =>{
|
|||||||
"Login": sesStart,
|
"Login": sesStart,
|
||||||
"Logout": sesEnd
|
"Logout": sesEnd
|
||||||
}
|
}
|
||||||
|
console.log(newLog);
|
||||||
log.unshift(newLog);
|
log.unshift(newLog);
|
||||||
write(log, 'user_log.json');
|
write(log, 'user_log.json');
|
||||||
|
|
||||||
@ -208,7 +212,7 @@ app.post('/logout',async (req, res) =>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
app.get('/data', async (req, res) => {
|
app.get('/data', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const data = await read('data.json');
|
const data = await read('data.json');
|
||||||
@ -217,6 +221,5 @@ app.get('/data', async (req, res) => {
|
|||||||
res.status(404).send(e);
|
res.status(404).send(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
server.listen(3000, () => console.log('Server listening on port 3000'));
|
server.listen(3000, () => console.log('Server listening on port 3000'));
|
||||||
292
WebUI/main.js
292
WebUI/main.js
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
const automode = document.getElementById('m_auto');
|
const automode = document.getElementById('m_auto');
|
||||||
const manmode = document.getElementById('m_man');
|
const manmode = document.getElementById('m_man');
|
||||||
const s_pressure = document.getElementById('pressure'); //slider
|
const s_pressure = document.getElementById('pressure'); //slider
|
||||||
@ -12,7 +13,10 @@ const canvas = document.getElementById('dataChart');
|
|||||||
const filter = document.getElementById('data');
|
const filter = document.getElementById('data');
|
||||||
const submit = document.getElementById('btn_login');
|
const submit = document.getElementById('btn_login');
|
||||||
const log_out = document.getElementById('btn_log_out');
|
const log_out = document.getElementById('btn_log_out');
|
||||||
let data_miss = false;
|
const start = document.getElementById('start-time');
|
||||||
|
const end = document.getElementById('end-time');
|
||||||
|
const reset = document.getElementById('btn_reset');
|
||||||
|
|
||||||
let user;
|
let user;
|
||||||
let pointerX = -1;
|
let pointerX = -1;
|
||||||
let pointerY = -1;
|
let pointerY = -1;
|
||||||
@ -21,18 +25,23 @@ let lastY = 0;
|
|||||||
let counter = 0;
|
let counter = 0;
|
||||||
let lastSpeed = 0;
|
let lastSpeed = 0;
|
||||||
let notSettled = 0;
|
let notSettled = 0;
|
||||||
|
let day = new Date();
|
||||||
|
day = new Date(day.getTime() - day.getTimezoneOffset()*60000);
|
||||||
|
let today = day.toISOString().slice(0,16);
|
||||||
|
start.value = today.replace('T', ' ') + ':00';
|
||||||
|
end.value = today.replace('T', ' ') + ':00';
|
||||||
|
let start_time = new Date(start.value).getTime();
|
||||||
|
let end_time = new Date(end.value).getTime();
|
||||||
|
|
||||||
const socket = io();
|
const socket = io();
|
||||||
|
|
||||||
socket.on('connection');
|
socket.on('connection');
|
||||||
socket.on('data', (data) =>{
|
socket.on('data', (data) =>{
|
||||||
if(data.auto === true){
|
if(data.error === true){
|
||||||
s_pressure.value = data.setpoint;
|
document.getElementById('mon-warn').style.display = 'block';
|
||||||
document.getElementById('set_press').value = s_pressure.value + ' Pa';
|
|
||||||
}
|
}
|
||||||
if(data.auto === false){
|
else{
|
||||||
s_speed.value = data.setpoint;
|
document.getElementById('mon-warn').style.display = 'none';
|
||||||
document.getElementById('set_speed').value = s_speed.value + ' %';
|
|
||||||
}
|
}
|
||||||
g_pressure.value = data.pressure;
|
g_pressure.value = data.pressure;
|
||||||
g_co.value = data.co2;
|
g_co.value = data.co2;
|
||||||
@ -40,16 +49,14 @@ socket.on('data', (data) =>{
|
|||||||
g_speed.value = data.speed;
|
g_speed.value = data.speed;
|
||||||
g_temp.value = data.temp;
|
g_temp.value = data.temp;
|
||||||
updateChart();
|
updateChart();
|
||||||
checkData();
|
|
||||||
checkFan();
|
|
||||||
circleColor();
|
circleColor();
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('pwd', (data) =>{
|
socket.on('pwd', (data) =>{
|
||||||
if(data){
|
if(data){
|
||||||
automode.checked = true;
|
sessionStorage.setItem('reload', true);
|
||||||
document.getElementById('login-form').style.display = "block";
|
document.location.reload();
|
||||||
document.getElementById('pwd-warn').style.display = "block";
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,6 +66,32 @@ socket.on('user', (data) =>{
|
|||||||
sessionStorage.setItem('loggedIn', 'true');
|
sessionStorage.setItem('loggedIn', 'true');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
reset.addEventListener('click', e =>{
|
||||||
|
e.preventDefault();
|
||||||
|
start.value = today.replace('T', ' ') + ':00';
|
||||||
|
end.value = today.replace('T', ' ') + ':00';
|
||||||
|
start_time = new Date(start.value).getTime();
|
||||||
|
end_time = new Date(end.value).getTime();
|
||||||
|
|
||||||
|
//start.value = today.replace('T', ' ') + ':00';
|
||||||
|
//end.value = today.replace('T', ' ') + ':00';
|
||||||
|
updateChart();
|
||||||
|
})
|
||||||
|
|
||||||
|
start.addEventListener('change', e =>{
|
||||||
|
e.preventDefault();
|
||||||
|
start_time = start.value + ':00';
|
||||||
|
start_time = new Date(start_time).getTime();
|
||||||
|
updateChart();
|
||||||
|
});
|
||||||
|
|
||||||
|
end.addEventListener('change', e =>{
|
||||||
|
e.preventDefault();
|
||||||
|
end_time = end.value + ':00';
|
||||||
|
end_time = new Date(end_time).getTime();
|
||||||
|
updateChart();
|
||||||
|
});
|
||||||
|
|
||||||
s_pressure.addEventListener('input', e =>{
|
s_pressure.addEventListener('input', e =>{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
sendPressure();
|
sendPressure();
|
||||||
@ -70,20 +103,34 @@ s_speed.addEventListener('input', e =>{
|
|||||||
});
|
});
|
||||||
|
|
||||||
automode.addEventListener('click', () =>{
|
automode.addEventListener('click', () =>{
|
||||||
document.getElementById('login-form').style.display = "none";
|
if(!sessionStorage.getItem('loggedIn')){
|
||||||
|
document.getElementById('login-form').style.display = "block";
|
||||||
|
document.getElementsByClassName('modes').style.display = "none";
|
||||||
|
document.getElementsByClassName('set_values').style.display = "none";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
document.getElementById('login-form').style.display = "none";
|
||||||
|
s_pressure.disabled = false;
|
||||||
|
document.getElementById('pr_div').style.opacity = 1;
|
||||||
|
|
||||||
s_pressure.disabled = false;
|
s_speed.disabled = true;
|
||||||
document.getElementById('pr_div').style.opacity = 1;
|
document.getElementById('sp_div').style.opacity = 0.4;
|
||||||
|
}
|
||||||
s_speed.disabled = true;
|
|
||||||
document.getElementById('sp_div').style.opacity = 0.4;
|
|
||||||
})
|
})
|
||||||
|
|
||||||
manmode.addEventListener('click', () =>{
|
manmode.addEventListener('click', () =>{
|
||||||
if(!sessionStorage.getItem('loggedIn')){
|
if(!sessionStorage.getItem('loggedIn')){
|
||||||
document.getElementById('login-form').style.display = "block";
|
document.getElementById('login-form').style.display = "block";
|
||||||
|
document.getElementById('sp_div').style.display = "none";
|
||||||
|
document.getElementById('pr_div').style.display = "none";
|
||||||
|
document.getElementById('m_auto').style.display = "none";
|
||||||
|
document.getElementById('m_man').style.display = "none";
|
||||||
|
document.getElementById('auto_label').style.display = "none";
|
||||||
|
document.getElementById('man_label').style.display = "none";
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
document.getElementById('login-form').style.display = "none";
|
||||||
document.getElementById('sp_div').style.opacity = 1;
|
document.getElementById('sp_div').style.opacity = 1;
|
||||||
s_speed.disabled = false;
|
s_speed.disabled = false;
|
||||||
|
|
||||||
@ -92,11 +139,6 @@ manmode.addEventListener('click', () =>{
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
filter.addEventListener('change', e =>{
|
|
||||||
e.preventDefault();
|
|
||||||
updateChart();
|
|
||||||
})
|
|
||||||
|
|
||||||
submit.addEventListener('click', e =>{
|
submit.addEventListener('click', e =>{
|
||||||
if(document.getElementById('username').value && document.getElementById('password').value){
|
if(document.getElementById('username').value && document.getElementById('password').value){
|
||||||
document.getElementById('login-form').style.display = "none";
|
document.getElementById('login-form').style.display = "none";
|
||||||
@ -111,7 +153,8 @@ document.getElementById('password').addEventListener('click', ()=>{
|
|||||||
document.getElementById('form-warn').style.display = "none";
|
document.getElementById('form-warn').style.display = "none";
|
||||||
});
|
});
|
||||||
|
|
||||||
log_out.addEventListener('click', ()=>{
|
log_out.addEventListener('click', () =>{
|
||||||
|
console.log('log out clicked');
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
})
|
})
|
||||||
@ -155,20 +198,6 @@ function circleColor(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkFan(){
|
|
||||||
if(lastSpeed !== g_speed.value){
|
|
||||||
notSettled += 1;
|
|
||||||
lastSpeed = g_speed.value;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
notSettled = 0;
|
|
||||||
document.getElementById('mon-warn').style.display = 'none';
|
|
||||||
}
|
|
||||||
if(notSettled > 12){
|
|
||||||
document.getElementById('mon-warn').style.display = 'block';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function logOutUser(){
|
function logOutUser(){
|
||||||
if(document.cookie){
|
if(document.cookie){
|
||||||
log_out.click();
|
log_out.click();
|
||||||
@ -182,7 +211,7 @@ document.onmousemove = function(event) {
|
|||||||
setInterval(activityCheck, 1000);
|
setInterval(activityCheck, 1000);
|
||||||
|
|
||||||
function activityCheck() {
|
function activityCheck() {
|
||||||
if(document.cookie){
|
if(sessionStorage.getItem('loggedIn')){
|
||||||
if(pointerX - lastX === 0 && pointerY - lastY === 0){
|
if(pointerX - lastX === 0 && pointerY - lastY === 0){
|
||||||
counter = counter + 1;
|
counter = counter + 1;
|
||||||
}
|
}
|
||||||
@ -197,34 +226,65 @@ function activityCheck() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMode(){
|
function checkUser(){
|
||||||
|
if(sessionStorage.getItem('reload')){
|
||||||
|
document.getElementById('login-form').style.display = "block";
|
||||||
|
document.getElementById('pwd-warn').style.display = "block";
|
||||||
|
sessionStorage.removeItem('reload');
|
||||||
|
}
|
||||||
if(document.cookie && sessionStorage.getItem('loggedIn')){
|
if(document.cookie && sessionStorage.getItem('loggedIn')){
|
||||||
|
document.getElementById('login-form').style.display = "none";
|
||||||
document.getElementById('user').style.display = "block";
|
document.getElementById('user').style.display = "block";
|
||||||
document.getElementById('user').innerHTML = 'Signed in user: ' + localStorage.getItem('user');
|
document.getElementById('user').innerHTML = 'Signed in user: ' + localStorage.getItem('user');
|
||||||
document.getElementById('btn_log_out').style.display = "block";
|
document.getElementById('btn_log_out').style.display = "block";
|
||||||
|
document.getElementById('user').style.display = "block";
|
||||||
|
document.getElementById('user').innerHTML = 'Signed in user: ' + localStorage.getItem('user');
|
||||||
|
document.getElementById('btn_log_out').style.display = "block";
|
||||||
|
document.getElementById('user-table').style.width = "45%";
|
||||||
|
document.getElementById('chart-cont').style.width = "50%";
|
||||||
|
|
||||||
manmode.checked = true;
|
if(manmode.checked = true){
|
||||||
s_pressure.disabled = true;
|
s_pressure.disabled = true;
|
||||||
document.getElementById('pr_div').style.opacity = 0.4;
|
document.getElementById('pr_div').style.opacity = 0.4;
|
||||||
s_speed.disabled = false;
|
s_speed.disabled = false;
|
||||||
|
}
|
||||||
|
if(automode.checked = true){
|
||||||
|
s_speed.disabled = true;
|
||||||
|
document.getElementById('sp_div').style.opacity = 0.4;
|
||||||
|
s_pressure.disabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
automode.checked = true;
|
document.getElementById('login-form').style.display = "block";
|
||||||
s_speed.disabled = true;
|
document.getElementById('sp_div').style.display = "none";
|
||||||
document.getElementById('sp_div').style.opacity = 0.4;
|
document.getElementById('pr_div').style.display = "none";
|
||||||
s_pressure.disabled = false;
|
document.getElementById('m_auto').style.display = "none";
|
||||||
document.getElementById('user').style.display = "none";
|
document.getElementById('m_man').style.display = "none";
|
||||||
document.getElementById('btn_log_out').style.display = "none";
|
document.getElementById('auto_label').style.display = "none";
|
||||||
|
document.getElementById('man_label').style.display = "none";
|
||||||
|
document.getElementById('user-table').style.display = "none";
|
||||||
|
document.getElementById('chart-cont').style.width = "95%";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkData(){
|
function checkMode(){
|
||||||
if(data_miss){
|
if(document.cookie && sessionStorage.getItem('loggedIn')){
|
||||||
document.getElementById('chart_warning').style.display = "block";
|
automode.checked = true;
|
||||||
|
s_speed.disabled = true;
|
||||||
|
document.getElementById('sp_div').style.opacity = 0.4;
|
||||||
|
document.getElementById('pr_div').style.opacity = 1;
|
||||||
|
s_pressure.disabled = false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
document.getElementById('login-form').style.display = "block";
|
||||||
|
document.getElementById('sp_div').style.display = "none";
|
||||||
|
document.getElementById('pr_div').style.display = "none";
|
||||||
|
document.getElementById('m_auto').style.display = "none";
|
||||||
|
document.getElementById('m_man').style.display = "none";
|
||||||
|
document.getElementById('auto_label').style.display = "none";
|
||||||
|
document.getElementById('man_label').style.display = "none";
|
||||||
|
document.getElementById('user-table').style.display = "none";
|
||||||
}
|
}
|
||||||
if(!data_miss){
|
|
||||||
document.getElementById('chart_warning').style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPressure(){
|
function sendPressure(){
|
||||||
@ -237,6 +297,54 @@ function sendSpeed(){
|
|||||||
socket.emit('setting', speed);
|
socket.emit('setting', speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateChart(){
|
||||||
|
async function fetchData(){
|
||||||
|
const response = await fetch('data.json');
|
||||||
|
const data = await response.json();
|
||||||
|
if(data.length !== 0){
|
||||||
|
let min = data[0].ts;
|
||||||
|
let max = data[data.length-1].ts;
|
||||||
|
start.min = min.slice(0, 16);
|
||||||
|
start.max = max.slice(0, 16);
|
||||||
|
end.min = min.slice(0, 16);
|
||||||
|
end.max = max.slice(0, 16);
|
||||||
|
}
|
||||||
|
const datapoints = data.filter(d => {
|
||||||
|
if((end_time-start_time) !== 0){
|
||||||
|
return (new Date(d.ts).getTime() >= start_time && new Date(d.ts).getTime() <= end_time)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return datapoints;
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchData().then(datapoints => {
|
||||||
|
if(datapoints.length === 0)
|
||||||
|
{
|
||||||
|
document.getElementById('chart_warn').style.display = "block";
|
||||||
|
}
|
||||||
|
const time = datapoints.map((index) => {
|
||||||
|
return index.ts;
|
||||||
|
});
|
||||||
|
const co = datapoints.map((index) => {
|
||||||
|
return index.co2;
|
||||||
|
});
|
||||||
|
const pressure = datapoints.map((index) => {
|
||||||
|
return index.pressure;
|
||||||
|
});
|
||||||
|
const rh = datapoints.map((index) => {
|
||||||
|
return index.rh;
|
||||||
|
});
|
||||||
|
myChart.config.data.labels = time;
|
||||||
|
myChart.config.data.datasets[0].data = co;
|
||||||
|
myChart.config.data.datasets[1].data = pressure;
|
||||||
|
myChart.config.data.datasets[2].data = rh;
|
||||||
|
myChart.update();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'CO2',
|
label: 'CO2',
|
||||||
@ -318,73 +426,13 @@ const config = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}//,
|
},
|
||||||
//aspectRatio: 1
|
aspectRatio: 2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const myChart = new Chart(canvas, config);
|
const myChart = new Chart(canvas, config);
|
||||||
|
|
||||||
function updateChart(){
|
|
||||||
async function fetchData(){
|
|
||||||
let datasize = 0;
|
|
||||||
let data_per_min = 12;
|
|
||||||
let datapoints;
|
|
||||||
await fetch('/data')
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data =>{
|
|
||||||
console.log(data.length);
|
|
||||||
datapoints = data.filter((elem, index)=>{
|
|
||||||
switch(parseInt(filter.value))
|
|
||||||
{
|
|
||||||
case 0: //all
|
|
||||||
datasize = data.length;
|
|
||||||
break;
|
|
||||||
case 1: //10min
|
|
||||||
datasize = 10*data_per_min;
|
|
||||||
break;
|
|
||||||
case 2: //30min
|
|
||||||
datasize = 30*data_per_min;
|
|
||||||
break;
|
|
||||||
case 3: //1 hour
|
|
||||||
datasize = 60*data_per_min;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(datasize > data.length){
|
|
||||||
data_miss = true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
data_miss = false;
|
|
||||||
}
|
|
||||||
return index >= data.length -datasize;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return datapoints;
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchData().then(datapoints => {
|
|
||||||
const time = datapoints.map((time) => {
|
|
||||||
return time.ts;
|
|
||||||
});
|
|
||||||
const co = datapoints.map((time) => {
|
|
||||||
return time.co2;
|
|
||||||
});
|
|
||||||
const pressure = datapoints.map((time) => {
|
|
||||||
return time.pressure;
|
|
||||||
});
|
|
||||||
const rh = datapoints.map((time) => {
|
|
||||||
return time.rh;
|
|
||||||
});
|
|
||||||
myChart.config.data.labels = time;
|
|
||||||
myChart.config.data.datasets[0].data = co;
|
|
||||||
myChart.config.data.datasets[1].data = pressure;
|
|
||||||
myChart.config.data.datasets[2].data = rh;
|
|
||||||
myChart.update();
|
|
||||||
checkData();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
fetch('user_log.json')
|
fetch('user_log.json')
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
return res.json();
|
return res.json();
|
||||||
@ -404,8 +452,8 @@ fetch('user_log.json')
|
|||||||
placeholder.innerHTML = out;
|
placeholder.innerHTML = out;
|
||||||
});
|
});
|
||||||
|
|
||||||
function getStartValues(){
|
async function getStartValues(){
|
||||||
fetch('data.json')
|
await fetch('data.json')
|
||||||
.then((res) =>{
|
.then((res) =>{
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
|
|||||||
@ -11,7 +11,7 @@ body {
|
|||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
margin-top: 100px;
|
margin-top: 50px;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -21,11 +21,27 @@ main {
|
|||||||
aside {
|
aside {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #F6FFF8;
|
background-color: #F6FFF8;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upper{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lower{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 150px;
|
height: 100px;
|
||||||
|
color: black;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
padding-top: 40px;
|
padding-top: 40px;
|
||||||
@ -51,12 +67,13 @@ h4{
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown{
|
.filter{
|
||||||
position: relative;
|
font-weight: bolder;
|
||||||
float: right;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logout{
|
.logout{
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
|
margin-top: 35px;
|
||||||
}
|
}
|
||||||
#btn_log_out{
|
#btn_log_out{
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
@ -68,6 +85,14 @@ h4{
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#btn_reset{
|
||||||
|
position: relative;
|
||||||
|
float: right;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #CCE3DE;
|
||||||
|
border: 0.5px solid;
|
||||||
|
}
|
||||||
|
|
||||||
#user{
|
#user{
|
||||||
display: none;
|
display: none;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
@ -77,6 +102,11 @@ h4{
|
|||||||
background-color: red;
|
background-color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login{
|
||||||
|
margin-top: 50px;
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
#login-form:valid #btn_login{
|
#login-form:valid #btn_login{
|
||||||
background-color: mediumseagreen;
|
background-color: mediumseagreen;
|
||||||
}
|
}
|
||||||
@ -89,6 +119,7 @@ h4{
|
|||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#acc{
|
#acc{
|
||||||
@ -96,6 +127,12 @@ h4{
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#chart_warn{
|
||||||
|
display: none;
|
||||||
|
text-align: center;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
#mon-warn{
|
#mon-warn{
|
||||||
height: 20px;
|
height: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -120,9 +157,8 @@ h4{
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
margin: 20px;
|
margin: auto;
|
||||||
padding: 20px;
|
width: 85%;
|
||||||
width: 80%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
@ -176,7 +212,8 @@ fieldset {
|
|||||||
background-color: gray;
|
background-color: gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons{
|
#buttons{
|
||||||
|
display: block;
|
||||||
font-size: 25px;
|
font-size: 25px;
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
width: 12ch;
|
width: 12ch;
|
||||||
@ -186,6 +223,7 @@ fieldset {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.set_values{
|
.set_values{
|
||||||
@ -195,6 +233,10 @@ fieldset {
|
|||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sp_div{
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.get_values{
|
.get_values{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -226,30 +268,32 @@ fieldset {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 150px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-container{
|
#chart-cont{
|
||||||
position: relative;
|
display: block;
|
||||||
width: 700px;
|
width: 90%;
|
||||||
height: 350px;
|
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas{
|
canvas{
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-table{
|
#user-table{
|
||||||
|
display: block;
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
|
width: 50%;
|
||||||
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
table{
|
table{
|
||||||
background-color: #CCE3DE;
|
background-color: #CCE3DE;
|
||||||
width: 700px;
|
width: 90%;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
@ -274,10 +318,13 @@ output {
|
|||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
aside {
|
aside {
|
||||||
margin-top: 100px;
|
margin-top: 50px;
|
||||||
background: #F6FFF8;
|
background: #F6FFF8;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
.lower{
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="radio"] {
|
input[type="radio"] {
|
||||||
|
|||||||
@ -1,15 +1,75 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"id": 15,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 18:51:43",
|
||||||
|
"Logout": "27.10.2022 18:54:01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 14,
|
||||||
|
"UserId": "Jaakko",
|
||||||
|
"Login": "27.10.2022 16:59:26",
|
||||||
|
"Logout": "27.10.2022 17:00:54"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 13,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 16:56:19",
|
||||||
|
"Logout": "27.10.2022 16:59:03"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 16:54:23",
|
||||||
|
"Logout": "27.10.2022 16:54:33"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 11,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 14:18:53",
|
||||||
|
"Logout": "27.10.2022 14:19:30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 14:17:45",
|
||||||
|
"Logout": "27.10.2022 14:18:42"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 14:15:43",
|
||||||
|
"Logout": "27.10.2022 14:16:01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 14:14:49",
|
||||||
|
"Logout": "27.10.2022 14:15:06"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 14:12:33",
|
||||||
|
"Logout": "27.10.2022 14:14:10"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"UserId": "Miisa",
|
||||||
|
"Login": "27.10.2022 13:29:52",
|
||||||
|
"Logout": "27.10.2022 13:30:54"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"UserId": "Miisa",
|
"UserId": "Miisa",
|
||||||
"Login": "25.10.2022 20.19.50",
|
"Login": "27.10.2022 08:10:40",
|
||||||
"Logout": "25.10.2022 20.19.55"
|
"Logout": "27.10.2022 08:11:42"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"UserId": "Miisa",
|
"UserId": "Miisa",
|
||||||
"Login": "25.10.2022 20.18.27",
|
"Login": "27.10.2022 07:55:06",
|
||||||
"Logout": "25.10.2022 20.18.43"
|
"Logout": "27.10.2022 07:56:01"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user