Switch control and schedules to JSON payloads

This commit is contained in:
Artem Kokos
2026-05-16 10:29:54 +07:00
parent 13fba2fa44
commit 15529961d6
8 changed files with 1171 additions and 748 deletions

View File

@@ -386,9 +386,9 @@
},
getGroupName(tid) { const g = this.groups[tid]; return g ? g.name : null; },
async request(path, method = 'GET', params = null, body = null) {
async request(path, { method = 'GET', query = null, body = null } = {}) {
let url = path;
if (params) url += `?${new URLSearchParams(params).toString()}`;
if (query) url += `?${new URLSearchParams(query).toString()}`;
try {
const r = await fetch(url, { method, headers: { 'X-API-Key': this.apiKey, 'Content-Type': 'application/json' }, body: body ? JSON.stringify(body) : null });
if (r.status === 403) {
@@ -432,7 +432,7 @@
} finally { this.isFetching = false; }
},
async control(id, params) { await this.request(`/control/group/${id}`, 'POST', params); },
async control(id, params) { await this.request(`/control/group/${id}`, { method: 'POST', body: params }); },
toggleGroup(id, state) { if (this.sliders[id]) this.sliders[id].state = state; this.control(id, { state }); },
setBrightness(id, val) { if (this.sliders[id]) this.sliders[id].brightness = val; this.control(id, { brightness: val }); },
setTemp(id, val) { if (this.sliders[id]) this.sliders[id].temp = val; this.control(id, { temp: val }); },
@@ -440,18 +440,18 @@
setColor(id, hex) { this.control(id, { r: parseInt(hex.slice(1,3),16), g: parseInt(hex.slice(3,5),16), b: parseInt(hex.slice(5,7),16) }); },
async createGroup() {
const res = await this.request('/devices/groups', 'POST', null, { id: this.newGroup.id, name: this.newGroup.name, macs: this.newGroup.macs });
const res = await this.request('/devices/groups', { method: 'POST', body: { id: this.newGroup.id, name: this.newGroup.name, macs: this.newGroup.macs } });
if (res) { this.toast(`Группа "${this.newGroup.name}" создана`, 'success'); this.newGroup = { id: '', name: '', macs: [] }; await this.fetchData(); this.tab = 'control'; }
},
async deleteGroup(id) {
const name = this.groups[id]?.name || id;
if (confirm(`Удалить группу "${name}"?`)) { await this.request(`/devices/groups/${id}`, 'DELETE'); this.toast(`Удалена`, 'success'); await this.fetchData(); }
if (confirm(`Удалить группу "${name}"?`)) { await this.request(`/devices/groups/${id}`, { method: 'DELETE' }); this.toast(`Удалена`, 'success'); await this.fetchData(); }
},
async rescan() {
this.isRescanning = true; await this.request('/devices/rescan', 'POST'); this.toast('Сканирование...', 'info');
this.isRescanning = true; await this.request('/devices/rescan', { method: 'POST' }); this.toast('Сканирование...', 'info');
setTimeout(async () => { await this.fetchData(); this.isRescanning = false; this.toast(`Найдено ${this.devices.length} устройств`, 'success'); }, 3000);
},
async blink(id) { await this.request(`/control/device/${id}/blink`, 'POST'); },
async blink(id) { await this.request(`/control/device/${id}/blink`, { method: 'POST' }); },
async syncGroupStatuses() {
if (this.isLoadingStatus) return; this.isLoadingStatus = true;
@@ -471,13 +471,13 @@
async fetchTasks() { const d = await this.request('/schedules/tasks'); if (d) this.tasks = d.tasks || []; },
async addSchedule() {
if (!this.newTask.target_id) { this.toast('Выберите группу', 'error'); return; }
const res = await this.request('/schedules/cron', 'POST', { target_id: this.newTask.target_id, hour: this.taskHour, minute: this.taskMin, is_group: true, state: this.newTask.state });
const res = await this.request('/schedules/cron', { method: 'POST', body: { target_id: this.newTask.target_id, hour: this.taskHour, minute: this.taskMin, is_group: true, state: this.newTask.state } });
if (res) { this.toast(`${this.taskHour}:${this.taskMin} добавлено`, 'success'); this.fetchTasks(); }
},
async deleteTask(id) { await this.request(`/schedules/${id}`, 'DELETE'); this.toast('Отменено', 'success'); this.fetchTasks(); },
async deleteTask(id) { await this.request(`/schedules/${id}`, { method: 'DELETE' }); this.toast('Отменено', 'success'); this.fetchTasks(); },
async setTimer4h(id) {
await this.toggleGroup(id, true);
const res = await this.request('/schedules/once', 'POST', { target_id: id, hours_from_now: 4, is_group: true, state: false });
const res = await this.request('/schedules/once', { method: 'POST', body: { target_id: id, hours_from_now: 4, is_group: true, state: false } });
if (res) { this.toast('Таймер 4ч', 'success'); this.fetchTasks(); }
},
@@ -489,7 +489,7 @@
async createApiKey() {
const name = this.newKeyName.trim();
if (!name) return;
const res = await this.request('/api-keys', 'POST', { name, is_admin: this.newKeyAdmin });
const res = await this.request('/api-keys', { method: 'POST', query: { name, is_admin: this.newKeyAdmin } });
if (res) {
this.lastCreatedKey = res.key;
this.newKeyName = '';
@@ -500,13 +500,13 @@
},
async revokeApiKey(key, name) {
if (confirm(`Отозвать ключ "${name}"?`)) {
await this.request('/api-keys/revoke', 'POST', null, { key });
await this.request('/api-keys/revoke', { method: 'POST', body: { key } });
this.toast(`Ключ "${name}" отозван`, 'success');
this.fetchApiKeys();
}
},
async activateApiKey(key, name) {
await this.request('/api-keys/activate', 'POST', null, { key });
await this.request('/api-keys/activate', { method: 'POST', body: { key } });
this.toast(`Ключ "${name}" активирован`, 'success');
this.fetchApiKeys();
},
@@ -516,12 +516,12 @@
// ─── Статистика ──────────────────────────────
async fetchStats() {
const data = await this.request(`/stats/summary`, 'GET', { days: this.statsDays });
const data = await this.request(`/stats/summary`, { query: { days: this.statsDays } });
if (data) this.statsData = data.groups || [];
await this.fetchEventLog();
},
async fetchEventLog() {
const data = await this.request('/stats/log', 'GET', { limit: 100 });
const data = await this.request('/stats/log', { query: { limit: 100 } });
if (data) this.eventLog = data;
},
formatTime(iso) {