/
Krams
/
nodemon2
Обзор
Документация
Войти
/
Krams
/
nodemon2
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
backend/services/NodeStateService.js
280 строк
10 KB
Иван Новиков
final
25 май 2026, 17:46
25 май 2026, 17:46
2c76ffd
Код
Авторство
О чём код?
import db from '../database.js'; const DEFAULT_COLOR = '#6c757d'; const DEFAULT_BORDER_COLOR = DEFAULT_COLOR; function nowUnix() { return Math.floor(Date.now() / 1000); } function mapStateRow(row) { return { id: row.id, name: row.name, description: row.description, color: row.color || DEFAULT_COLOR, borderColor: row.border_color || DEFAULT_BORDER_COLOR, textColor: row.text_color || null, sortOrder: row.sort_order ?? 0, createdAt: row.created_at, updatedAt: row.updated_at, }; } const SEED_STATES = [ { name: 'Неисправен', description: 'Узел находится в неисправном состоянии.', color: '#E81224', sortOrder: 1 }, { name: 'Работает', description: 'Узел работает и доступен для опроса.', color: '#16C60C', sortOrder: 2 }, { name: 'Нужно обслужить', description: 'Требуется обслуживание узла.', color: '#FFF100', sortOrder: 3 }, { name: 'Отключен от опроса', description: 'Узел исключен из автоматического SSH-опроса.', color: '#6F42C1', sortOrder: 4 }, { name: 'Ожидает ремонта', description: 'Узел ожидает ремонта.', color: '#F7630C', sortOrder: 5 }, { name: 'Готов к установке', description: 'Узел готов к установке/развертыванию.', color: '#886CE4', sortOrder: 6 }, { name: 'Ожидает возврата', description: 'Узел ожидает возврата после операции.', color: '#0078D7', sortOrder: 7 }, { name: 'Системный', description: 'Технологический/системный статус.', color: '#07E2D0', sortOrder: 8 }, { name: 'Линпак', description: 'Узел находится в процессе линпака.', color: '#A6FF00', sortOrder: 9 }, { name: 'Метрики не собираются', description: 'Отсутствуют метрики (нет данных).', color: '#666666', sortOrder: 10 }, ]; export async function ensureNodeStateDefinitionTables() { await new Promise((resolve, reject) => { db.serialize(() => { db.run( `CREATE TABLE IF NOT EXISTS node_state_definition ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, description TEXT NOT NULL, color TEXT NOT NULL DEFAULT '${DEFAULT_COLOR}', border_color TEXT NOT NULL DEFAULT '${DEFAULT_BORDER_COLOR}', text_color TEXT, sort_order INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL )`, [], (err) => { if (err) return reject(err); resolve(); } ); }); }); const hasTextColor = await db.hasColumn('node_state_definition', 'text_color').catch(() => false); if (!hasTextColor) { await new Promise((resolve, reject) => { db.run( `ALTER TABLE node_state_definition ADD COLUMN text_color TEXT`, [], (err) => { if (err) return reject(err); resolve(); } ); }); } const hasBorderColor = await db.hasColumn('node_state_definition', 'border_color').catch(() => false); if (!hasBorderColor) { await new Promise((resolve, reject) => { db.run( `ALTER TABLE node_state_definition ADD COLUMN border_color TEXT`, [], (err) => { if (err) return reject(err); resolve(); } ); }); } await new Promise((resolve, reject) => { db.run( `UPDATE node_state_definition SET border_color = ? WHERE border_color IS NULL OR border_color = '' OR border_color = color`, [DEFAULT_BORDER_COLOR], (err) => { if (err) return reject(err); resolve(); } ); }); const createdAt = nowUnix(); for (const st of SEED_STATES) { const description = String(st.description ?? '').trim(); const name = String(st.name ?? '').trim(); if (!name) continue; const color = String(st.color || DEFAULT_COLOR).trim() || DEFAULT_COLOR; const borderColor = DEFAULT_BORDER_COLOR; const sortOrder = Number.parseInt(st.sortOrder, 10) || 0; const updatedAt = nowUnix(); await new Promise((resolve, reject) => { db.run( `INSERT INTO node_state_definition (name, description, color, border_color, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(name) DO NOTHING`, [name, description, color, borderColor, sortOrder, createdAt, updatedAt], (err) => { if (err) return reject(err); resolve(); } ); }); await new Promise((resolve, reject) => { db.run( `UPDATE node_state_definition SET description = CASE WHEN description = '' THEN ? ELSE description END, color = CASE WHEN color = '' THEN ? ELSE color END, border_color = CASE WHEN border_color IS NULL OR border_color = '' THEN ? ELSE border_color END, sort_order = CASE WHEN sort_order = 0 THEN ? ELSE sort_order END, updated_at = ? WHERE name = ? AND (description = '' OR color = '' OR border_color IS NULL OR border_color = '' OR sort_order = 0)`, [description, color, borderColor, sortOrder, updatedAt, name], (err) => { if (err) return reject(err); resolve(); } ); }); } } export async function getNodeStateDefinitions() { await ensureNodeStateDefinitionTables(); return new Promise((resolve, reject) => { db.all( `SELECT id, name, description, color, border_color, text_color, sort_order, created_at, updated_at FROM node_state_definition ORDER BY sort_order ASC, id ASC`, [], (err, rows) => { if (err) return reject(err); resolve((rows || []).map(mapStateRow)); } ); }); } function normalizeCreatePayload(body = {}) { return { name: String(body.name || '').trim(), description: String(body.description || '').trim(), color: typeof body.color !== 'undefined' ? String(body.color || '').trim() : undefined, borderColor: typeof body.borderColor !== 'undefined' ? String(body.borderColor || '').trim() : undefined, textColor: typeof body.textColor !== 'undefined' ? String(body.textColor || '').trim() : undefined, sortOrder: typeof body.sortOrder !== 'undefined' ? Number.parseInt(body.sortOrder, 10) : undefined, }; } export async function createNodeStateDefinition(body = {}) { await ensureNodeStateDefinitionTables(); const payload = normalizeCreatePayload(body); const name = payload.name; const description = payload.description; const color = payload.color || DEFAULT_COLOR; const borderColor = payload.borderColor || DEFAULT_BORDER_COLOR; const textColor = payload.textColor || null; const sortOrder = Number.isFinite(payload.sortOrder) ? payload.sortOrder : 0; const ts = nowUnix(); return new Promise((resolve, reject) => { db.run( `INSERT INTO node_state_definition (name, description, color, border_color, text_color, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [name, description, color, borderColor, textColor, sortOrder, ts, ts], function onInsert(err) { if (err) return reject(err); db.get( `SELECT id, name, description, color, border_color, text_color, sort_order, created_at, updated_at FROM node_state_definition WHERE id = ?`, [this.lastID], (getErr, row) => { if (getErr) return reject(getErr); resolve(mapStateRow(row)); } ); } ); }); } function normalizeUpdatePayload(body = {}) { return { description: typeof body.description !== 'undefined' ? String(body.description || '').trim() : undefined, color: typeof body.color !== 'undefined' ? String(body.color || '').trim() : undefined, borderColor: typeof body.borderColor !== 'undefined' ? String(body.borderColor || '').trim() : undefined, textColor: typeof body.textColor !== 'undefined' ? String(body.textColor || '').trim() : undefined, sortOrder: typeof body.sortOrder !== 'undefined' ? Number.parseInt(body.sortOrder, 10) : undefined, }; } export async function updateNodeStateDefinitionById(id, body = {}) { await ensureNodeStateDefinitionTables(); const safeId = Number.parseInt(id, 10); if (!Number.isFinite(safeId)) return null; const payload = normalizeUpdatePayload(body); const updates = []; const params = []; if (typeof payload.description !== 'undefined') { updates.push('description = ?'); params.push(payload.description); } if (typeof payload.color !== 'undefined') { updates.push('color = ?'); params.push(payload.color || DEFAULT_COLOR); } if (typeof payload.borderColor !== 'undefined') { updates.push('border_color = ?'); params.push(payload.borderColor || DEFAULT_BORDER_COLOR); } if (typeof payload.textColor !== 'undefined') { updates.push('text_color = ?'); params.push(payload.textColor || null); } if (typeof payload.sortOrder !== 'undefined') { updates.push('sort_order = ?'); params.push(Number.isFinite(payload.sortOrder) ? payload.sortOrder : 0); } if (updates.length === 0) return null; updates.push('updated_at = ?'); params.push(nowUnix()); params.push(safeId); return new Promise((resolve, reject) => { db.run( `UPDATE node_state_definition SET ${updates.join(', ')} WHERE id = ?`, params, function onUpdate(err) { if (err) return reject(err); if (this.changes === 0) return resolve(null); db.get( `SELECT id, name, description, color, border_color, text_color, sort_order, created_at, updated_at FROM node_state_definition WHERE id = ?`, [safeId], (getErr, row) => { if (getErr) return reject(getErr); resolve(mapStateRow(row)); } ); } ); }); } export async function initNodeStateDefinitionStorage() { await ensureNodeStateDefinitionTables(); }