чет я не правильно сделал - viewer - надо в другой фунцкции делать?
class EventDispatcher {
    constructor() {
        this.listeners = {};
    }

    on(event, callback) {
        if (!this.listeners[event]) {
            this.listeners[event] = [];
        }
        console.log('callback' + callback);
        this.listeners[event].push(callback);
    }

    emit(event, data) {
        if (this.listeners[event]) {
            this.listeners[event].forEach(callback => callback(data));
        }
    }
}


class WebSocketService extends EventDispatcher {
    constructor(url) {
        super();
        this.url = url;
        this.socket = null;
        this.reconnectInterval = 1000;
    }

    connect() {
        this.socket = new WebSocket(this.url);

        this.socket.onopen = () => {
            this.emit('connected');
            this.send({
                p: "u"
            });
        };

        this.socket.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                this.emit('message', data);
            } catch (e) {
                this.emit('error', e);
            }
        };

        this.socket.onclose = () => {
            this.emit('disconnected');
            setTimeout(() => this.connect(), this.reconnectInterval);
        };

        this.socket.onerror = (error) => {
            this.emit('error', error);
        };
    }

    send(data) {
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(JSON.stringify(data));
        }
    }
}


class MonitorStore {
    constructor() {
        this.history = this.loadHistory();
        this.maxItems = this.getMaxItems();
        this.subscribers = [];
    }

    getMaxItems() {
        const saved = localStorage.getItem('UF_MON');
        return saved ? parseInt(saved) : 125;
    }

    loadHistory() {
        const saved = localStorage.getItem('monitor');
        return saved ? JSON.parse(saved) : [];
    }

    saveHistory() {
        localStorage.setItem('monitor', JSON.stringify(this.history));
    }

    addItem(item) {
        this.history.unshift(item);

        // Remove excess items
        while (this.history.length > this.maxItems) {
            this.history.pop();
        }

        this.saveHistory();
        this.notify(item);
    }

    subscribe(callback) {
        this.subscribers.push(callback);
    }

    notify(item) {
        this.subscribers.forEach(callback => callback(item));
    }
}


class MonitorRenderer {
    constructor(options) {
        this.container = options.container;
        this.secondaryContainer = options.secondaryContainer;
        this.templates = {
            default: this.createDefaultTemplate(),
            button: this.createButtonTemplate()
        };
    }

    createDefaultTemplate() {
        // Возвращает функцию для рендеринга стандартного элемента
        return (data) => {
            // Реализация шаблона как в оригинальном socket_li
            // ...
            let htmlString = '';
            return htmlString;
        };
    }

    createButtonTemplate() {
        return (data) => {
            // Реализация шаблона для кнопок
            // ...
            let htmlString = '';
            return htmlString;
        };
    }

    render(data) {
        let template;
        switch (data.p) {
            case 'btn':
                template = this.templates.button;
                break;
            default:
                template = this.templates.default;
        }

        const element = this.createDOMElement(template(data));
        this.getContainer(data).prepend(element);
    }

    createDOMElement(html) {
        const div = document.createElement('div');
        div.innerHTML = html;
        return div.firstChild;
    }

    getContainer(data) {
        return data.u.c == 0 ? this.secondaryContainer : this.container;
    }
}


class MonitorApp {
    constructor() {
        this.wsService = new WebSocketService('wss://' + window.location.hostname + '/ws');
        this.store = new MonitorStore();

        this.view_mon = '0000000';
        this.monitor = bID('m-1');

        this.renderer = new MonitorRenderer({
            container: document.getElementById('m-1'),
            secondaryContainer: document.getElementById('ws-id-el2')
        });

        this.initialize();
    }

    initialize() {
        this.monbuttons();
        // Подписка на события WebSocket
        this.wsService.on('message', (data) => this.handleMessage(data));

        // Подписка на изменения хранилища
        this.store.subscribe((item) => this.renderer.render(item));

        // Загрузка истории
        this.store.history.forEach(item => this.renderer.render(item));

        // Запуск соединения
        this.wsService.connect();
    };
    monbuttons() {

        const buttons = bTN2('.a-f-btn');

        buttons.forEach(button => {

            button.addEventListener('click', () => {
                const i = button.getAttribute('data-i');
                let z = button.getAttribute('data-z');
                console.log('i ' + i + ' ' + z);
                if (z == 0) {
                    z = '1';
                    button.classList.add('color-in');
                } else {
                    z = '0';
                    button.classList.remove('color-in');
                }
                button.setAttribute('data-z', z);

                let arr = this.view_mon.split('');
                console.log(arr);
                if (i >= 0 && i < arr.length) {
                    arr[i] = z;
                }

                this.view_mon = arr.join('');

                console.log('this.view_mon ' + this.view_mon);
            });

        });
    };

    handleMessage(data) {
        console.log('handleMessage ');
        console.log(data);
        if (data.p === 'ping') return;

        if (data.p === 'contrs') {

        }
        if (data.p === 'auto') {
            //this.viewer(data.m);
            //return;
        }

        this.store.addItem(data);
    }

    viewer(d) {

        let ft = d.ft;

        let status = '';
        let render = 0;
        if (ft[6] === '1') {
            if (this.view_mon[6] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-road-lock color-negative"></span> Блок';
        }
        if (ft[2] === '1') {
            if (this.view_mon[2] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-check color-positive"></span> Разрешен';
        }
        if (ft[3] === '1') {
            if (this.view_mon[3] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-car color-positive"></span> Постоянный';
        }
        if (ft[4] === '1') {
            if (this.view_mon[4] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-clock-rotate-left color-positive"></span> Временный';
        }
        if (ft[5] === '1') {
            if (this.view_mon[5] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-taxi color-positive"></span> Гость';
        }
        if (ft[1] === '1') {
            if (this.view_mon[1] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-lock color-negative"></span> Запрещен';
        }
        if (ft[0] === '1') {
            if (this.view_mon[0] === '1') {
                render = 1;
            }
            status = '<span class="fa-solid fa-ban color-negative"></span> Нет в базе';
        }
        if (render == 1) {
            let n = {
                1: 'Въезд <span class="fa-solid fa-arrow-up color-positive"></span>',
                2: 'Выезд <span class="fa-solid fa-arrow-down color-negative"></span>'
            };

            let tr = '<td><div>' + status + '</div><div>' + d.tm + '</div></td>';
            tr += '<td><div>' + d.terr + '</div><div>' + n[d.in_out] + '</div></td>';
            tr += '<td><div>' + d.company.name + '</div><div> <span class="fa-solid fa-car color-positive"></span>' + d.car.name + ' ' + d.car.marka + ' ' + d.car.comment + '</div></td>';

            let t = document.createElement('tr');
            t.innerHTML = tr;

            this.monitor.append(t);
        }
    };
}

function disp_fullscreen() {
    const elem = document.documentElement;
    if (elem.requestFullscreen) {
        elem.requestFullscreen();
    } else if (elem.mozRequestFullScreen) {
        /* Firefox */
        elem.mozRequestFullScreen();
    } else if (elem.webkitRequestFullscreen) {
        /* Chrome, Safari и Opera */
        elem.webkitRequestFullscreen();
    } else if (elem.msRequestFullscreen) {
        /* IE/Edge */
        elem.msRequestFullscreen();
    }
}

function disp_list() {

    AL(bID('fullscreen'), 'click', disp_fullscreen);

    new MonitorApp();
}