Files
IoTManagerWeb/src/pages/Config.svelte

300 lines
9.7 KiB
Svelte
Raw Normal View History

<script>
import Card from "../components/Card.svelte";
2022-02-07 16:36:43 +01:00
import CrossIcon from "../svg/Cross.svelte";
import OpenIcon from "../svg/Open.svelte";
import Alarm from "../components/Alarm.svelte";
export let configJson;
export let widgetsJson;
export let itemsJson;
2022-09-29 23:34:21 +02:00
export let scenarioTxt;
export let show;
2022-02-07 02:08:21 +01:00
let itemsJsonBind = 0;
2022-11-26 17:39:23 +01:00
let debug = false;
2022-02-07 02:08:21 +01:00
export let saveConfig = () => {};
2022-02-16 00:11:57 +01:00
export let rebootEsp = () => {};
2022-09-28 17:26:33 +02:00
//export let cleanLogs = () => {};
2022-09-29 00:56:22 +02:00
let exportJson = {};
2022-02-07 02:08:21 +01:00
function elementsDropdownChange() {
for (let i = 0; i < itemsJson.length; i++) {
let item = Object.assign({}, itemsJson[i]);
if (itemsJsonBind === item.num) {
delete item.num;
delete item.name;
2022-09-18 19:26:23 +02:00
item.id = item.id + randomInteger(0, 100);
2022-02-07 02:08:21 +01:00
configJson.push(item);
configJson = configJson;
itemsJsonBind = 0;
if (debug) console.log("[i]", "item added");
break;
}
}
}
2022-09-18 19:26:23 +02:00
function randomInteger(min, max) {
// получить случайное число от (min-0.5) до (max+0.5)
let rand = min - 0.5 + Math.random() * (max - min + 1);
return Math.round(rand);
}
2022-02-07 02:08:21 +01:00
function deleteLineFromConfig(num) {
for (let i = 0; i < configJson.length; i++) {
if (num === i) {
configJson.splice(i, 1);
configJson = configJson;
if (debug) console.log("[i]", "item " + num + " deleted from config");
break;
}
}
}
2022-09-29 23:34:21 +02:00
$: scenarioTxt, windowHeight();
let height;
2022-09-29 23:34:21 +02:00
function windowHeight() {
2022-09-29 23:34:21 +02:00
let scenStr = scenarioTxt;
2022-09-30 23:48:56 +02:00
height = scenStr.split("\n").length + 1;
}
2022-09-29 00:56:22 +02:00
// Function to download data to a file
2022-09-30 23:48:56 +02:00
function saveFile2(data, filename, type) {
2022-09-29 00:56:22 +02:00
var file = new Blob([data], { type: type });
if (window.navigator.msSaveOrOpenBlob)
// IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
else {
// Others
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
2022-09-30 23:48:56 +02:00
2022-09-29 00:56:22 +02:00
setTimeout(function () {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
2022-09-30 23:48:56 +02:00
function saveFile(data, filename, type) {
var file = new Blob([data], { type: type });
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveOrOpenBlob(file, filename);
} else {
const a = document.createElement("a");
document.body.appendChild(a);
const url = window.URL.createObjectURL(file);
a.href = url;
a.download = filename;
a.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}, 0);
}
}
2022-09-29 00:56:22 +02:00
const syntaxHighlight = (json) => {
try {
json = JSON.stringify(JSON.parse(json), null, 4);
} catch (e) {
return json;
}
json = json.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
json = json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
return match;
});
return json;
};
function createExportFile() {
exportJson.mark = "iotm";
2022-09-29 00:56:22 +02:00
exportJson.config = configJson;
2022-09-30 23:48:56 +02:00
let exportAsText = syntaxHighlight(JSON.stringify(exportJson));
exportAsText = exportAsText + "\n\nscenario=>" + scenarioTxt;
saveFile(exportAsText, "export.json", "application/json");
2022-09-29 00:56:22 +02:00
}
let template = null;
let files = null;
const alertErr = "Файл не является файлом конфигурации";
2022-09-29 23:34:21 +02:00
const alertOk = "Применить конфигурацию?\nне забудьте нажать кнопку 'сохранить на устройстве'";
$: if (files) {
const fileText = files[0].text();
fileText.then((text) => {
template = text;
2022-09-30 23:48:56 +02:00
if (!template.includes("scenario=>")) {
window.alert(alertErr);
return;
}
let jsonPart = selectToMarker(template, "scenario=>");
let txtPart = deleteBeforeDelimiter(template, "scenario=>");
if (!IsJsonParse(jsonPart)) {
window.alert(alertErr);
2022-09-30 23:48:56 +02:00
return;
}
let json = JSON.parse(jsonPart);
if (json.mark !== "iotm") {
window.alert(alertErr);
return;
}
if (window.confirm(alertOk)) {
configJson = [];
scenarioTxt = "";
configJson = json.config;
scenarioTxt = txtPart;
console.log("config updated");
2022-09-29 00:56:22 +02:00
}
});
files = null;
}
function reset() {
files = null;
document.getElementById("formFile").value = "";
2022-09-29 00:56:22 +02:00
}
function IsJsonParse(str) {
try {
JSON.parse(str);
} catch (e) {
if (debug) console.log("[e]", "json parce error: ", str);
return false;
}
return true;
}
2022-09-30 23:48:56 +02:00
function selectToMarker(str, found) {
let p = str.indexOf(found);
return str.substring(0, p);
}
function deleteBeforeDelimiter(str, found) {
let p = str.indexOf(found) + found.length;
return str.substring(p);
}
2022-12-14 00:52:42 +01:00
export let moduleOrder = (id, key, value) => {};
</script>
{#if show}
<div class="grd-2col1">
2022-02-23 01:38:43 +01:00
<Card title="Конфигуратор">
<div class="grd-2col2">
<select class="slct-lg" bind:value={itemsJsonBind} on:change={() => elementsDropdownChange()}>
{#each itemsJson as item}
{#if item.header}
<optgroup label={item.header} />
{/if}
{#if !item.header}
<option value={item.num}>
{item.name}
</option>
{/if}
{/each}
</select>
<select class="slct-lg"><option>{"Выберите пресет"}</option></select>
</div>
<table class="tbl">
<thead class="bg-gray-100">
<tr class="txt-sz txt-pad">
<th class="tbl-hd">Тип</th>
<th class="tbl-hd">Id</th>
<th class="tbl-hd">Виджет</th>
<th class="tbl-hd">Вкладка</th>
<th class="tbl-hd">Название</th>
<th class="tbl-hd w-7" />
<th class="tbl-hd w-7" />
</tr>
</thead>
<tbody class="bg-white">
{#each configJson as element, i}
<tr class="txt-sz txt-pad align-middle">
<td class="tbl-bdy-lg">{element.subtype}</td>
<td class="tbl-bdy-lg"><input bind:value={element.id} class="ipt-lg w-full" type="text" /></td>
<td class="tbl-bdy-lg"
><select bind:value={element.widget} class="ipt-lg w-full">
{#each widgetsJson as select}
<option value={select.name}>
{select.label}
</option>
{/each}
</select></td>
<td class="tbl-bdy-lg"><input bind:value={element.page} class="ipt-lg w-full" type="text" /></td>
<td class="tbl-bdy-lg"><input bind:value={element.descr} class="ipt-lg w-full" type="text" /></td>
2022-09-13 22:44:37 +02:00
<td class="tbl-bdy-lg"><OpenIcon click={() => (element.show = !element.show)} /></td>
<td class="tbl-bdy-lg"><CrossIcon click={() => deleteLineFromConfig(i)} /></td>
</tr>
2022-09-13 22:44:37 +02:00
{#if element.show}
{#each Object.entries(element) as [key, param]}
2022-09-14 18:20:07 +02:00
{#if key != "type" && key != "subtype" && key != "id" && key != "widget" && key != "page" && key != "descr" && key != "show"}
<tr class="txt-sz txt-pad">
<td />
<td />
<td />
2022-12-14 00:52:42 +01:00
{#if key.startsWith("btn")}
<td class="tbl-bdy-sm text-right">
<button on:click={() => moduleOrder(element.id, key.substring(4), element[key])} class="h-3 sm:h-6 md:h-6 lg:h-6 xl:h-6 2xl:h-6 w-auto bg-blue-100 inline-flex items-center border border-gray-300 hover:bg-blue-200">{key.substring(4)}</button>
</td>
{#if element[key] != "nil"}
<td class="tbl-bdy-sm text-center">
<input bind:value={element[key]} class="ipt-sm w-full" type="text" />
</td>
{/if}
{:else}
<td class="tbl-bdy-sm text-right">
<p class="txt-ita">{key}</p>
</td>
<td class="tbl-bdy-sm text-center">
<input bind:value={element[key]} class="ipt-sm w-full" type="text" />
</td>
{/if}
</tr>
{/if}
{/each}
<!--<br />-->
{/if}
{/each}
</tbody>
</table>
2022-02-23 01:38:43 +01:00
</Card>
<Card title="Сценарии">
2022-09-29 23:34:21 +02:00
<textarea bind:value={scenarioTxt} rows={height} class="px-2 bg-gray-50 border-2 border-gray-200 rounded text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-indigo-500 w-full" />
</Card>
2022-02-23 01:38:43 +01:00
</div>
<div class="grd-1col1">
<Card>
2022-02-18 19:48:15 +01:00
<div class="grd-2col1">
2022-09-29 23:34:21 +02:00
<button class="btn-lg" on:click={() => saveConfig()}>{"Сохранить на устройстве"}</button>
<button class="btn-lg" on:click={() => rebootEsp()}>{"Перезагрузить устройство"}</button>
<button class="btn-lg" on:click={() => createExportFile()}>{"Экспорт конфигурации"}</button>
2022-09-29 15:32:13 +02:00
<label on:click={() => reset()} class="btn-lg cursor-pointer select-none">
<input bind:files accept="application/JSON" type="file" id="formFile" />
2022-09-29 23:34:21 +02:00
{"Импорт конфигурации"}
2022-09-29 00:56:22 +02:00
</label>
2022-02-18 19:48:15 +01:00
</div>
</Card>
</div>
{:else}
<Alarm title="Загрузка..." />
{/if}