[html]<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Список ролей</title>
    <link rel="stylesheet" type="text/css" href="https://forumstatic.ru/files/001c/b1/c6/77845.css?v=1">
    <style>
        .admin-header {
            display: flex;
            justify-content: flex-end;
            margin-bottom: 15px;
        }
        .admin-btn {
            background: #C0C0B9;
            color: #22281D;
            border: none;
            padding: 6px 12px;
            border-radius: 20px;
            cursor: pointer;
            font-weight: 500;
            font-family: Golos Text;
        }
        .edit-btn {
            background: none;
            border: none;
            cursor: pointer;
            font-size: 12px;
            margin-left: 6px;
            color: #C0C0B9;
            display: inline-block;
        }
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.8);
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        .modal-content {
            background: #22281D;
            padding: 20px;
            border-radius: 12px;
            min-width: 320px;
            border: 1px solid #C0C0B9;
        }
        .modal-content h3 {
            margin-top: 0;
            color: #C0C0B9;
        }
        .modal-content input, .modal-content select {
            width: 100%;
            padding: 6px;
            margin-bottom: 12px;
            background: #2a3323;
            color: #E8E8E8;
            border: 1px solid #C0C0B9;
            border-radius: 4px;
            box-sizing: border-box;
        }
        .modal-content label {
            display: block;
            margin-bottom: 10px;
            color: #E8E8E8;
        }
        .modal-buttons {
            display: flex;
            gap: 10px;
            justify-content: flex-end;
            margin-top: 10px;
        }
        .delete-btn {
            background: #8B0000;
            color: white;
        }
        .roli {
            height: 200px;
            overflow: auto;
        }
        .roli::-webkit-scrollbar {
            width: 3px;
            height: 3px;
        }
    </style>
</head>
<body>

<div class="admin-header" id="adminHeader" style="display: none;">
    <button id="addCastBtn" class="admin-btn">➕ Добавить каст</button>
</div>

<table class="spisok_rol" id="rolesTable">
    <tr>
        <td style="vertical-align: top; width: 50%;" id="colLeft"></td>
        <td style="vertical-align: top; width: 50%;" id="colRight"></td>
    </tr>
</table>

<!-- Модалка для каста -->
<div id="castModal" class="modal">
    <div class="modal-content">
        <h3 id="castModalTitle">Редактировать каст</h3>
        <input type="text" id="castNameInput" placeholder="Название каста">
        <div class="modal-buttons">
            <button id="castSaveBtn" class="admin-btn">Сохранить</button>
            <button id="castDeleteBtn" class="admin-btn delete-btn" style="display:none;">🗑 Удалить каст</button>
            <button id="castCancelBtn" class="admin-btn">Отмена</button>
        </div>
    </div>
</div>

<!-- Модалка для персонажа -->
<div id="roleModal" class="modal">
    <div class="modal-content">
        <h3 id="roleModalTitle">Добавить персонажа</h3>
        <input type="text" id="roleNameEn" placeholder="Английское имя (будет ссылкой)">
        <input type="text" id="roleNameRu" placeholder="Русское имя (будет текстом)">
        <input type="number" id="roleId" placeholder="ID профиля">
        <select id="roleCastSelect"></select>
        <label><input type="checkbox" id="roleIsMain" checked> Основной персонаж</label>
        <div id="mainIdField" style="display:none;">
            <input type="number" id="roleMainId" placeholder="ID основного персонажа">
        </div>
        <div class="modal-buttons">
            <button id="roleSaveBtn" class="admin-btn">Сохранить</button>
            <button id="roleDeleteBtn" class="admin-btn delete-btn" style="display:none;">🗑 Удалить</button>
            <button id="roleCancelBtn" class="admin-btn">Отмена</button>
        </div>
    </div>
</div>

<script>
    let rolesData = {};
    let editCastName = null;
    let editRoleData = null;
    let isAdmin = false;

    // Проверка прав администратора через GroupID
    if (typeof GroupID !== 'undefined' && GroupID === 1) {
        isAdmin = true;
        document.getElementById('adminHeader').style.display = 'flex';
    }

    const letterGroups = [
        { title: 'A B C D E', letters: ['A','B','C','D','E'] },
        { title: 'F G H I J', letters: ['F','G','H','I','J'] },
        { title: 'K L M N O', letters: ['K','L','M','N','O'] },
        { title: 'P Q R S T', letters: ['P','Q','R','S','T'] },
        { title: 'U V W X', letters: ['U','V','W','X'] },
        { title: 'Y Z 1-9', letters: ['Y','Z','#'] }
    ];

    function getLetterGroup(firstLetter) {
        firstLetter = firstLetter.toUpperCase();
        for (let group of letterGroups) {
            if (group.letters.includes(firstLetter)) {
                return group.title;
            }
        }
        return 'Y Z 1-9';
    }

    async function loadData() {
        try {
            const resp = await fetch('https://rvnln.ru/my_api.php');
            const json = await resp.json();
            if (json.success) {
                rolesData = json.data;
                renderTable();
                fillCastSelect();
            }
        } catch(e) { console.error(e); }
    }

    function renderTable() {
        let castsWithLetter = [];
        for (let letter in rolesData) {
            for (let cast in rolesData[letter]) {
                let firstChar = cast.charAt(0).toUpperCase();
                if (/[0-9]/.test(firstChar)) firstChar = '#';
                castsWithLetter.push({
                    name: cast,
                    firstLetter: firstChar,
                    data: rolesData[letter][cast]
                });
            }
        }
       
        castsWithLetter.sort((a, b) => a.name.localeCompare(b.name, 'en'));
       
        let grouped = {};
        for (let group of letterGroups) {
            grouped[group.title] = [];
        }
       
        for (let cast of castsWithLetter) {
            let groupTitle = getLetterGroup(cast.firstLetter);
            if (grouped[groupTitle]) {
                grouped[groupTitle].push(cast);
            } else {
                grouped['Y Z 1-9'].push(cast);
            }
        }
       
        let leftHtml = '';
        let rightHtml = '';
        let isLeft = true;
       
        for (let group of letterGroups) {
            let castsInGroup = grouped[group.title];
            let groupHtml = renderGroup(group.title, castsInGroup);
            if (isLeft) {
                leftHtml += groupHtml;
            } else {
                rightHtml += groupHtml;
            }
            isLeft = !isLeft;
        }
       
        document.getElementById('colLeft').innerHTML = leftHtml;
        document.getElementById('colRight').innerHTML = rightHtml;
    }

    function renderGroup(groupTitle, casts) {
        if (casts.length === 0) {
            return `<div class="zag">${escapeHtml(groupTitle)}</div><br><div class="roli"></div>`;
        }
       
        let castsHtml = '';
        for (let cast of casts) {
            castsHtml += `<div class="nazfandom">${escapeHtml(cast.name)}
                ${isAdmin ? `<button class="edit-btn" onclick="openCastModal('${escapeHtml(cast.name).replace(/'/g, "\\'")}')">⚙️</button>` : ''}
            </div><br>`;
           
            for (let role of (cast.data.roles || [])) {
                castsHtml += `<a href="https://durka.f-rpg.me/profile.php?id=${role.id}" target="_blank">${escapeHtml(role.name_en)}</a> - ${escapeHtml(role.name_ru)}`;
                if (isAdmin) {
                    castsHtml += ` <button class="edit-btn" onclick="openRoleModal(${role.id}, '${escapeHtml(role.name_en).replace(/'/g, "\\'")}', '${escapeHtml(role.name_ru).replace(/'/g, "\\'")}', '${escapeHtml(cast.name).replace(/'/g, "\\'")}')">✏️</button>`;
                }
                castsHtml += `<br>`;
            }
           
            if (isAdmin) {
                castsHtml += `<button class="edit-btn" onclick="openRoleModal(null, null, null, '${escapeHtml(cast.name).replace(/'/g, "\\'")}')">+ Добавить персонажа</button><br>`;
            }
        }
       
        return `<div class="zag">${escapeHtml(groupTitle)}</div><br><div class="roli">${castsHtml}</div>`;
    }

    function escapeHtml(str) {
        if (!str) return '';
        return str.replace(/[&<>]/g, function(m) {
            if (m === '&') return '&amp;';
            if (m === '<') return '&lt;';
            if (m === '>') return '&gt;';
            return m;
        });
    }

    function fillCastSelect() {
        let select = document.getElementById('roleCastSelect');
        if (!select) return;
        select.innerHTML = '';
        let allCasts = [];
        for (let letter in rolesData) {
            for (let cast in rolesData[letter]) {
                allCasts.push(cast);
            }
        }
        allCasts.sort((a, b) => a.localeCompare(b, 'en'));
        for (let cast of allCasts) {
            let opt = document.createElement('option');
            opt.value = cast;
            opt.textContent = cast;
            select.appendChild(opt);
        }
    }

    function openCastModal(castName) {
        editCastName = castName;
        document.getElementById('castModalTitle').textContent = castName ? 'Редактировать каст' : 'Добавить каст';
        document.getElementById('castNameInput').value = castName || '';
        document.getElementById('castDeleteBtn').style.display = castName ? 'inline-block' : 'none';
        document.getElementById('castModal').style.display = 'flex';
    }

    function openRoleModal(id, nameEn, nameRu, castName) {
        editRoleData = id ? { id } : null;
        document.getElementById('roleModalTitle').textContent = id ? 'Редактировать персонажа' : 'Добавить персонажа';
        document.getElementById('roleNameEn').value = nameEn || '';
        document.getElementById('roleNameRu').value = nameRu || '';
        document.getElementById('roleId').value = id || '';
        document.getElementById('roleCastSelect').value = castName;
        document.getElementById('roleIsMain').checked = true;
        document.getElementById('mainIdField').style.display = 'none';
        document.getElementById('roleDeleteBtn').style.display = id ? 'inline-block' : 'none';
        document.getElementById('roleModal').style.display = 'flex';
    }

    function closeModals() {
        document.getElementById('castModal').style.display = 'none';
        document.getElementById('roleModal').style.display = 'none';
    }

    async function apiCall(action, data) {
        let formData = new URLSearchParams({ action, ...data });
        let resp = await fetch('https://rvnln.ru/my_api.php', { method: 'POST', body: formData });
        let json = await resp.json();
        if (!json.success) alert('Ошибка: ' + json.message);
        return json.success;
    }

    document.getElementById('castSaveBtn').onclick = async () => {
        let newName = document.getElementById('castNameInput').value.trim();
        if (!newName) return alert('Введите название каста');
        let ok;
        if (editCastName) {
            ok = await apiCall('edit_cast', { old_name: editCastName, new_name: newName });
        } else {
            ok = await apiCall('add_cast', { name: newName });
        }
        if (ok) {
            closeModals();
            loadData();
        }
    };

    document.getElementById('castDeleteBtn').onclick = async () => {
        if (!confirm(`Удалить каст "${editCastName}" и ВСЕХ персонажей в нём?`)) return;
        let ok = await apiCall('delete_cast', { name: editCastName });
        if (ok) {
            closeModals();
            loadData();
        }
    };

    document.getElementById('castCancelBtn').onclick = closeModals;

    document.getElementById('roleSaveBtn').onclick = async () => {
        let nameEn = document.getElementById('roleNameEn').value.trim();
        let nameRu = document.getElementById('roleNameRu').value.trim();
        let userId = parseInt(document.getElementById('roleId').value);
        let castName = document.getElementById('roleCastSelect').value;
        let isMain = document.getElementById('roleIsMain').checked ? 1 : 0;
        let mainId = document.getElementById('roleMainId').value || null;
       
        if (!nameEn || !userId || !castName) return alert('Заполните английское имя и ID');
        let ok;
        if (editRoleData) {
            ok = await apiCall('edit_character', { user_id: userId, name_en: nameEn, name_ru: nameRu, cast_name: castName });
        } else {
            ok = await apiCall('add_character', { user_id: userId, name_en: nameEn, name_ru: nameRu, cast_name: castName, is_main: isMain, main_id: mainId });
        }
        if (ok) {
            closeModals();
            loadData();
        }
    };

    document.getElementById('roleDeleteBtn').onclick = async () => {
        if (!confirm('Удалить персонажа?')) return;
        if (await apiCall('delete_character', { user_id: editRoleData.id })) {
            closeModals();
            loadData();
        }
    };

    document.getElementById('roleCancelBtn').onclick = closeModals;
    document.getElementById('addCastBtn').onclick = () => openCastModal(null);
    document.getElementById('roleIsMain').onchange = (e) => {
        document.getElementById('mainIdField').style.display = e.target.checked ? 'none' : 'block';
    };

    loadData();
</script>
</body>
</html>[/html]