poe-svelte-ui-lib 1.44.1 → 1.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
- Поля группы `CFG` (меняется префиксом в настройках), привязывать переменные не нужно
|
|
12
12
|
- «Сохранить» отправляет изменённые поля одним пакетом `SET ModCfg`
|
|
13
13
|
- 🔌 «Перезагрузить» — команда `SET Restart`
|
|
14
|
+
- ♻️ «Сброс настроек» — после подтверждения команда `SET RstNVS`: прошивка очищает NVS и перезагружается, все настройки возвращаются к заводским
|
|
14
15
|
|
|
15
16
|
## Ключи
|
|
16
17
|
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
|
|
28
29
|
## Особенности
|
|
29
30
|
|
|
30
|
-
Смарт-виджет информации об устройстве. Как и `WidgetWiFi`, не привязывается к одной произвольной переменной устройства — работает с фиксированным набором полей, соответствующих реальной прошивочной конвенции (`main_config.c`, группа `CFG`, ProdFactory-ESP): `DevSN`, `DevID`, `DevFW`, `RunCnt`, `StaIP`, `ApIP` — только чтение; `DevName`, `HostName`, `WebUser`, `WebPsw` — редактируются локально и сохраняются одним пакетом по кнопке "Сохранить". Отдельная кнопка "Перезагрузить" рядом с заголовком вызывает `onRestart` немедленно (не входит в пакет сохранения полей). Реальное имя поля устройства для каждого ключа можно переопределить через `keys` (по умолчанию совпадает с именем ключа). Компонент ничего не знает про DeviceStore/WebSocket — только `value`/`onSave`/`onRestart`.
|
|
31
|
+
Смарт-виджет информации об устройстве. Как и `WidgetWiFi`, не привязывается к одной произвольной переменной устройства — работает с фиксированным набором полей, соответствующих реальной прошивочной конвенции (`main_config.c`, группа `CFG`, ProdFactory-ESP): `DevSN`, `DevID`, `DevFW`, `RunCnt`, `StaIP`, `ApIP` — только чтение; `DevName`, `HostName`, `WebUser`, `WebPsw` — редактируются локально и сохраняются одним пакетом по кнопке "Сохранить". Отдельная кнопка "Перезагрузить" рядом с заголовком вызывает `onRestart` немедленно (не входит в пакет сохранения полей). Реальное имя поля устройства для каждого ключа можно переопределить через `keys` (по умолчанию совпадает с именем ключа). Внизу — «Сброс настроек» (`onFactoryReset`): все настройки к заводским, только после подтверждения в окне поверх виджета; без колбэка кнопка не показывается. Компонент ничего не знает про DeviceStore/WebSocket — только `value`/`onSave`/`onRestart`/`onFactoryReset`.
|
|
31
32
|
|
|
32
33
|
- Серийный номер устройства обычно длинный (например `00.00.000-00_0000AC670000B22B00007428:DBC5`) — в разметке занимает отдельную строку, чтобы не обрезаться в узкой сетке.
|
|
33
34
|
- `WebPsw` в реальном устройстве исторически передаётся обычным текстом; в виджете сделан `type="password"` для консистентности с остальным обликом конструктора.
|
|
@@ -44,6 +45,8 @@
|
|
|
44
45
|
| `persistKey` | `string` | `undefined` | Ключ для сохранения состояния `collapsed` в `localStorage` — при заданном ключе состояние сворачивания переживает перезагрузку страницы |
|
|
45
46
|
| `onSave` | `(info: IWidgetDeviceInfoConfig) => void` | `undefined` | Срабатывает при нажатии "Сохранить" — редактируемые поля одним пакетом |
|
|
46
47
|
| `onRestart` | `() => void` | `undefined` | Срабатывает при нажатии "Перезагрузить" |
|
|
48
|
+
| `onFactoryReset` | `() => void` | `undefined` | Срабатывает после подтверждения «Сброс настроек»; без колбэка кнопки нет |
|
|
49
|
+
| `resetCommand` | `{ header?: string; argument?: string }` | `SET` / `RstNVS` | Команда сброса настроек — для приложения, сам компонент её не отправляет |
|
|
47
50
|
|
|
48
51
|
### IWidgetDeviceInfoConfig
|
|
49
52
|
|
|
@@ -98,7 +101,7 @@
|
|
|
98
101
|
| `component` | `UIComponent & { properties: Partial<IWidgetDeviceInfoProps> }` | Объект компонента с его свойствами |
|
|
99
102
|
| `onPropertyChange` | `(updates: Partial<{ properties?: string \| object; name?: string; access?: string }>) => void` | Коллбэк для обновления свойств компонента |
|
|
100
103
|
|
|
101
|
-
Панель содержит заголовок, мастер-цвет (через общий `WidgetAccentPicker.svelte`), префикс прошивочной группы (ID), переопределение имени поля устройства для каждого ключа `IWidgetDeviceInfoConfig` (по умолчанию совпадает с именем ключа)
|
|
104
|
+
Панель содержит заголовок, мастер-цвет (через общий `WidgetAccentPicker.svelte`), префикс прошивочной группы (ID), переопределение имени поля устройства для каждого ключа `IWidgetDeviceInfoConfig` (по умолчанию совпадает с именем ключа) команду перезагрузки (Header/Argument, по умолчанию `SET`/`Restart`) и команду сброса настроек (по умолчанию `SET`/`RstNVS`).
|
|
102
105
|
|
|
103
106
|
### Что настраивается
|
|
104
107
|
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
Фиксированный набор полей (см. IWidgetDeviceInfoConfig в types.ts), соответствует реальной
|
|
3
3
|
прошивочной конвенции (main_config.c, группа "CFG", ProdFactory-ESP):
|
|
4
4
|
DevSN/DevID/DevFW/RunCnt — только чтение; DevName/HostName/WebUser/WebPsw — сохраняются
|
|
5
|
-
одним
|
|
5
|
+
одним пакетом; «Сброс настроек» — с подтверждением, все настройки к заводским. Ничего не знает про DeviceStore/WebSocket —
|
|
6
|
+
value/onSave/onRestart/onFactoryReset. -->
|
|
6
7
|
<script lang="ts">
|
|
7
8
|
import { T } from "../locales/i18n"
|
|
8
9
|
import { untrack } from "svelte"
|
|
9
|
-
import { slide } from "svelte/transition"
|
|
10
|
+
import { fade, scale, slide } from "svelte/transition"
|
|
10
11
|
import { twMerge } from "tailwind-merge"
|
|
11
12
|
import * as UI from ".."
|
|
12
13
|
import type { IWidgetDeviceInfoConfig, IWidgetDeviceInfoProps } from "../types"
|
|
@@ -25,8 +26,15 @@
|
|
|
25
26
|
persistKey,
|
|
26
27
|
onSave = () => {},
|
|
27
28
|
onRestart = () => {},
|
|
29
|
+
onFactoryReset,
|
|
28
30
|
}: IWidgetDeviceInfoProps = $props()
|
|
29
31
|
|
|
32
|
+
let confirmReset = $state(false)
|
|
33
|
+
const factoryReset = () => {
|
|
34
|
+
confirmReset = false
|
|
35
|
+
onFactoryReset?.()
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
let accentStyle = $derived(widgetAccentStyle(componentClass ?? ""))
|
|
31
39
|
|
|
32
40
|
let info: IWidgetDeviceInfoConfig = $state(
|
|
@@ -80,7 +88,10 @@
|
|
|
80
88
|
}
|
|
81
89
|
</script>
|
|
82
90
|
|
|
83
|
-
<div
|
|
91
|
+
<div
|
|
92
|
+
class={twMerge("relative flex w-full flex-col gap-4 rounded-2xl border border-(--hairline-color) bg-(--container-color) p-4", wrapperClass)}
|
|
93
|
+
style={accentStyle}
|
|
94
|
+
>
|
|
84
95
|
<!-- Заголовок -->
|
|
85
96
|
<WidgetHeader icon={CpuIcon} label={label?.name || $T("widget.info.title")} bind:collapsed>
|
|
86
97
|
{#snippet right()}
|
|
@@ -128,6 +139,41 @@
|
|
|
128
139
|
{/if}
|
|
129
140
|
<UI.Button wrapperClass="w-40" componentClass="bg-accent" content={{ name: $T("widget.common.save") }} disabled={!isDirty} onClick={save} />
|
|
130
141
|
</div>
|
|
142
|
+
|
|
143
|
+
<!-- Сброс всех настроек к заводским — отдельно от сохранения, только с подтверждением -->
|
|
144
|
+
{#if onFactoryReset}
|
|
145
|
+
<div class="flex items-center justify-between gap-3 border-t border-(--hairline-color) pt-3">
|
|
146
|
+
<span class="text-[12px] text-(--muted-color)">{$T("widget.info.factory_reset_hint")}</span>
|
|
147
|
+
<UI.Button
|
|
148
|
+
wrapperClass="w-auto shrink-0"
|
|
149
|
+
componentClass="bg-red px-3"
|
|
150
|
+
content={{ name: $T("widget.info.factory_reset") }}
|
|
151
|
+
onClick={() => (confirmReset = true)}
|
|
152
|
+
/>
|
|
153
|
+
</div>
|
|
154
|
+
{/if}
|
|
155
|
+
</div>
|
|
156
|
+
{/if}
|
|
157
|
+
|
|
158
|
+
{#if confirmReset}
|
|
159
|
+
<!-- Подтверждение локально к виджету, как удаление файла у WidgetFileSystem -->
|
|
160
|
+
<div class="absolute inset-0 z-10 flex items-center justify-center rounded-2xl bg-black/40 backdrop-blur-[2px]" transition:fade={{ duration: 150 }}>
|
|
161
|
+
<div
|
|
162
|
+
class="flex w-full max-w-96 flex-col gap-3 rounded-[16px] border border-(--hairline-color) bg-(--back-color) p-4 shadow-(--elevation-3)"
|
|
163
|
+
transition:scale={{ duration: 150, start: 0.96 }}
|
|
164
|
+
>
|
|
165
|
+
<h4 class="text-[15px] font-semibold">{$T("widget.info.factory_reset_title")}</h4>
|
|
166
|
+
<p class="text-[13px] text-(--muted-color)">{$T("widget.info.factory_reset_text")}</p>
|
|
167
|
+
<div class="flex gap-2">
|
|
168
|
+
<UI.Button
|
|
169
|
+
wrapperClass="flex-1"
|
|
170
|
+
componentClass="bg-transparent"
|
|
171
|
+
content={{ name: $T("widget.common.cancel") }}
|
|
172
|
+
onClick={() => (confirmReset = false)}
|
|
173
|
+
/>
|
|
174
|
+
<UI.Button wrapperClass="flex-1" componentClass="bg-red" content={{ name: $T("widget.info.factory_reset") }} onClick={factoryReset} />
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
131
177
|
</div>
|
|
132
178
|
{/if}
|
|
133
179
|
</div>
|
|
@@ -29,18 +29,18 @@
|
|
|
29
29
|
{/each}
|
|
30
30
|
{/snippet}
|
|
31
31
|
|
|
32
|
-
{#snippet
|
|
32
|
+
{#snippet WidgetCommand(path: "restartCommand" | "resetCommand", defaultArgument: string)}
|
|
33
33
|
<UI.Select
|
|
34
34
|
label={{ name: $T("widget.common.packet_header") }}
|
|
35
35
|
type="buttons"
|
|
36
36
|
options={$optionsStore.HEADER_OPTIONS}
|
|
37
|
-
value={$optionsStore.HEADER_OPTIONS.find((o) => o.value === (component.properties
|
|
38
|
-
onUpdate={(option) => updateProperty(
|
|
37
|
+
value={$optionsStore.HEADER_OPTIONS.find((o) => o.value === (component.properties[path]?.header || "SET"))}
|
|
38
|
+
onUpdate={(option) => updateProperty(`${path}.header`, (option as IOption<string>).value as string, component, onPropertyChange)}
|
|
39
39
|
/>
|
|
40
40
|
<UI.Input
|
|
41
41
|
label={{ name: $T("widget.common.argument") }}
|
|
42
|
-
value={component.properties
|
|
43
|
-
onUpdate={(value) => updateProperty(
|
|
42
|
+
value={component.properties[path]?.argument ?? defaultArgument}
|
|
43
|
+
onUpdate={(value) => updateProperty(`${path}.argument`, value as string, component, onPropertyChange)}
|
|
44
44
|
/>
|
|
45
45
|
{/snippet}
|
|
46
46
|
|
|
@@ -61,6 +61,9 @@
|
|
|
61
61
|
{@render WidgetKeys()}
|
|
62
62
|
</PropsGroup>
|
|
63
63
|
<PropsGroup label={$T("widget.info.restart_command")}>
|
|
64
|
-
{@render
|
|
64
|
+
{@render WidgetCommand("restartCommand", "Restart")}
|
|
65
|
+
</PropsGroup>
|
|
66
|
+
<PropsGroup label={$T("widget.info.reset_command")}>
|
|
67
|
+
{@render WidgetCommand("resetCommand", "RstNVS")}
|
|
65
68
|
</PropsGroup>
|
|
66
69
|
</div>
|
|
@@ -103,9 +103,9 @@ const translations = {
|
|
|
103
103
|
"🎯 **用途**\n设备网络的完整配置:模式、连接路由器、自身接入点。\n\n📦 **数据包**\n- `CFG` 分组的字段(可通过设置中的前缀更改),无需绑定变量\n- 字段在本地编辑,「保存」以一个 `SET ModCfg` 数据包发送已修改的字段\n- 🔍 扫描网络 —— `GET APsList`,找到的网络出现在 SSID 列表中\n\n🔑 **键**\n- `WiFiMode` —— 数字:`0` 关闭、`1` 客户端、`2` 接入点、`3` 两者\n- `StaSSID`、`StaPSK` —— 字符串:路由器网络和密码\n- `StaticIP` —— 数字:`0` DHCP、`1` 静态地址\n- `StaIP`、`StaMS`、`StaGW` —— 字符串:客户端地址、掩码、网关\n- `ApSSID`、`ApPSK` —— 字符串:自身接入点名称和密码\n- `ApIP`、`ApMS`、`ApGW` —— 字符串:接入点地址、掩码、网关\n\n✨ **特点**\n- 仅启用接入点时组件会提醒:设备可能从局域网中消失\n\n⚙️ **设置**\n- 分组前缀(ID)、字段名覆盖、主色",
|
|
104
104
|
],
|
|
105
105
|
"component.info.WidgetDeviceInfo": [
|
|
106
|
-
"🎯 **Назначение**\nПаспорт устройства и его основные настройки.\n\n📦 **Пакет данных**\n- Поля группы `CFG` (меняется префиксом в настройках), привязывать переменные не нужно\n- «Сохранить» отправляет изменённые поля одним пакетом `SET ModCfg`\n- 🔌 «Перезагрузить» — команда `SET Restart`\n\n🔑 **Ключи**\n- `DevSN` — строка: серийный номер, только чтение\n- `DevID` — строка: код изделия, только чтение\n- `DevFW` — число: версия ПО, только чтение\n- `RunCnt` — число: счётчик запусков, только чтение\n- `StaIP`, `ApIP` — строки: текущие адреса клиента и точки доступа, только чтение\n- `DevName` — строка: имя устройства\n- `HostName` — строка: сетевое имя\n- `WebUser`, `WebPsw` — строки: логин и пароль веб-интерфейса\n\n⚙️ **Настройки**\n- Префикс группы (ID), мастер-цвет",
|
|
107
|
-
'🎯 **Purpose**\nDevice passport and its main settings.\n\n📦 **Data packet**\n- Fields of the `CFG` group (changed by the prefix in settings), no variable binding needed\n- "Save" sends the changed fields in one `SET ModCfg` packet\n- 🔌 "Restart" — the `SET Restart` command\n\n🔑 **Keys**\n- `DevSN` — string: serial number, read only\n- `DevID` — string: product code, read only\n- `DevFW` — number: firmware version, read only\n- `RunCnt` — number: boot counter, read only\n- `StaIP`, `ApIP` — strings: current client and access point addresses, read only\n- `DevName` — string: device name\n- `HostName` — string: network host name\n- `WebUser`, `WebPsw` — strings: web interface login and password\n\n⚙️ **Settings**\n- Group prefix (ID), master color',
|
|
108
|
-
"🎯 **用途**\n设备档案及其主要设置。\n\n📦 **数据包**\n- `CFG` 分组的字段(可通过设置中的前缀更改),无需绑定变量\n- 「保存」以一个 `SET ModCfg` 数据包发送已修改的字段\n- 🔌「重启」—— `SET Restart` 命令\n\n🔑 **键**\n- `DevSN` —— 字符串:序列号,只读\n- `DevID` —— 字符串:产品代码,只读\n- `DevFW` —— 数字:固件版本,只读\n- `RunCnt` —— 数字:启动计数,只读\n- `StaIP`、`ApIP` —— 字符串:客户端和接入点的当前地址,只读\n- `DevName` —— 字符串:设备名称\n- `HostName` —— 字符串:网络主机名\n- `WebUser`、`WebPsw` —— 字符串:Web 界面登录名和密码\n\n⚙️ **设置**\n- 分组前缀(ID)、主色",
|
|
106
|
+
"🎯 **Назначение**\nПаспорт устройства и его основные настройки.\n\n📦 **Пакет данных**\n- Поля группы `CFG` (меняется префиксом в настройках), привязывать переменные не нужно\n- «Сохранить» отправляет изменённые поля одним пакетом `SET ModCfg`\n- ♻️ «Сброс настроек» — после подтверждения команда `SET RstNVS`, все настройки к заводским, прибор перезагружается\n- 🔌 «Перезагрузить» — команда `SET Restart`\n\n🔑 **Ключи**\n- `DevSN` — строка: серийный номер, только чтение\n- `DevID` — строка: код изделия, только чтение\n- `DevFW` — число: версия ПО, только чтение\n- `RunCnt` — число: счётчик запусков, только чтение\n- `StaIP`, `ApIP` — строки: текущие адреса клиента и точки доступа, только чтение\n- `DevName` — строка: имя устройства\n- `HostName` — строка: сетевое имя\n- `WebUser`, `WebPsw` — строки: логин и пароль веб-интерфейса\n\n⚙️ **Настройки**\n- Префикс группы (ID), мастер-цвет",
|
|
107
|
+
'🎯 **Purpose**\nDevice passport and its main settings.\n\n📦 **Data packet**\n- Fields of the `CFG` group (changed by the prefix in settings), no variable binding needed\n- "Save" sends the changed fields in one `SET ModCfg` packet\n- ♻️ "Factory reset" — after confirmation the `SET RstNVS` command, all settings return to factory defaults and the device restarts\n- 🔌 "Restart" — the `SET Restart` command\n\n🔑 **Keys**\n- `DevSN` — string: serial number, read only\n- `DevID` — string: product code, read only\n- `DevFW` — number: firmware version, read only\n- `RunCnt` — number: boot counter, read only\n- `StaIP`, `ApIP` — strings: current client and access point addresses, read only\n- `DevName` — string: device name\n- `HostName` — string: network host name\n- `WebUser`, `WebPsw` — strings: web interface login and password\n\n⚙️ **Settings**\n- Group prefix (ID), master color',
|
|
108
|
+
"🎯 **用途**\n设备档案及其主要设置。\n\n📦 **数据包**\n- `CFG` 分组的字段(可通过设置中的前缀更改),无需绑定变量\n- 「保存」以一个 `SET ModCfg` 数据包发送已修改的字段\n- ♻️「恢复出厂设置」—— 确认后发送 `SET RstNVS` 命令,所有设置恢复为出厂默认值,设备重启\n- 🔌「重启」—— `SET Restart` 命令\n\n🔑 **键**\n- `DevSN` —— 字符串:序列号,只读\n- `DevID` —— 字符串:产品代码,只读\n- `DevFW` —— 数字:固件版本,只读\n- `RunCnt` —— 数字:启动计数,只读\n- `StaIP`、`ApIP` —— 字符串:客户端和接入点的当前地址,只读\n- `DevName` —— 字符串:设备名称\n- `HostName` —— 字符串:网络主机名\n- `WebUser`、`WebPsw` —— 字符串:Web 界面登录名和密码\n\n⚙️ **设置**\n- 分组前缀(ID)、主色",
|
|
109
109
|
],
|
|
110
110
|
"component.info.WidgetFileSystem": [
|
|
111
111
|
'🎯 **Назначение**\nПамять устройства, список файлов, удаление и закачка.\n\n📦 **Пакет данных**\n- Один объект `CFG.FS` (префикс и имя поля меняются в настройках), привязывать переменные не нужно\n- 🔄 «Обновить» — `GET FS`\n- «Удалить» — `SET FS` с `Op: Delete` после подтверждения\n- Закачка — `SET FS` с `Op` `UploadStart` → `UploadChunk` → `UploadDone`\n\n🔑 **Ключи**\n- `Total`, `Used`, `Free` — числа, байт: объём, занято, свободно\n- `List` — массив `[{ "Name", "Size" }]`: полный путь файла и размер в байтах\n- `Upload` — объект `{ "Name", "Size", "Progress" }`, есть только во время закачки; `Progress` — 0–100\n\n✨ **Особенности**\n- Полоса занятости оранжевая от 75%, красная от 90%\n- Закачка с другого клиента тоже видна\n- Имя файла — не длиннее 31 символа (ограничение прошивки, задаётся в настройках)\n\n⚙️ **Настройки**\n- Префикс группы (ID), поле состояния ФС, аргумент команд, мастер-цвет\n- Допустимые файлы (фильтр в окне выбора), максимальная длина имени',
|
|
@@ -754,5 +754,14 @@ const translations = {
|
|
|
754
754
|
"constructor.texts.buttons": ["Кнопка", "Button", "按钮"],
|
|
755
755
|
"ui.graph.values": ["Значения", "Values", "数值"],
|
|
756
756
|
"ui.graph.refresh": ["Развёртка", "Refresh rate", "刷新率"],
|
|
757
|
+
"widget.info.factory_reset": ["Сброс настроек", "Factory reset", "恢复出厂设置"],
|
|
758
|
+
"widget.info.factory_reset_hint": ["Все настройки к заводским", "All settings to factory defaults", "所有设置恢复为出厂默认值"],
|
|
759
|
+
"widget.info.factory_reset_title": ["Сбросить все настройки?", "Reset all settings?", "重置所有设置?"],
|
|
760
|
+
"widget.info.factory_reset_text": [
|
|
761
|
+
"Все настройки прибора — Wi-Fi, имя, пароль Web, настройки модулей — вернутся к заводским, прибор перезагрузится. Связь по Wi-Fi может пропасть.",
|
|
762
|
+
"All device settings — Wi-Fi, name, Web password, module settings — return to factory defaults and the device restarts. The Wi-Fi connection may be lost.",
|
|
763
|
+
"设备的所有设置(Wi-Fi、名称、Web 密码、模块设置)将恢复为出厂默认值,设备将重启。Wi-Fi 连接可能会断开。",
|
|
764
|
+
],
|
|
765
|
+
"widget.info.reset_command": ["Команда сброса настроек", "Factory reset command", "恢复出厂命令"],
|
|
757
766
|
};
|
|
758
767
|
export default translations;
|
package/dist/types.d.ts
CHANGED
|
@@ -525,10 +525,15 @@ export interface IWidgetDeviceInfoProps {
|
|
|
525
525
|
header?: string;
|
|
526
526
|
argument?: string;
|
|
527
527
|
};
|
|
528
|
+
resetCommand?: {
|
|
529
|
+
header?: string;
|
|
530
|
+
argument?: string;
|
|
531
|
+
};
|
|
528
532
|
collapsed?: boolean;
|
|
529
533
|
persistKey?: string;
|
|
530
534
|
onSave?: (info: IWidgetDeviceInfoConfig) => void;
|
|
531
535
|
onRestart?: () => void;
|
|
536
|
+
onFactoryReset?: () => void;
|
|
532
537
|
}
|
|
533
538
|
export interface IWidgetFileSystemFile {
|
|
534
539
|
Name: string;
|