Files
VnUtest/garrysmod/gamemodes/militaryrp/plugins/serverlogs/cl_plugin.lua
2026-03-31 10:27:04 +03:00

344 lines
12 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local PLUGIN = PLUGIN
-- Цветовая схема
local COLOR_BG_DARK = Color(3, 5, 4)
local COLOR_BG_MEDIUM = Color(8, 12, 10)
local COLOR_BG_LIGHT = Color(12, 18, 14)
local COLOR_PRIMARY = Color(27, 94, 32)
local COLOR_PRIMARY_DARK = Color(15, 60, 18)
local COLOR_ACCENT = Color(56, 102, 35)
local COLOR_TEXT_PRIMARY = Color(165, 214, 167)
local COLOR_TEXT_SECONDARY = Color(102, 187, 106)
local COLOR_BORDER = Color(15, 60, 18, 60)
-- Локальное хранилище логов
local clientLogs = {}
local isLoadingLogs = false
-- Сетевой получатель для открытия меню (из команды Helix)
net.Receive("ixServerLogs_OpenMenu", function()
PLUGIN:OpenLogsMenu()
end)
-- Получение логов с сервера
function PLUGIN:RequestLogs(filters)
if isLoadingLogs then return end
isLoadingLogs = true
clientLogs = {}
net.Start("ixServerLogs_Request")
net.WriteTable(filters or {})
net.SendToServer()
end
-- Получение ответа с логами
net.Receive("ixServerLogs_Response", function()
local isFirst = net.ReadUInt(2) == 1
local logs = net.ReadTable()
if isFirst then
clientLogs = {}
end
for _, log in ipairs(logs) do
table.insert(clientLogs, log)
end
isLoadingLogs = false
-- Обновляем UI если открыто
if IsValid(PLUGIN.logsFrame) and IsValid(PLUGIN.logsList) then
PLUGIN:UpdateLogsList()
end
end)
-- Главное меню логов
function PLUGIN:OpenLogsMenu()
if IsValid(self.logsFrame) then
self.logsFrame:Remove()
end
local scrW, scrH = ScrW(), ScrH()
local frame = vgui.Create("DFrame")
frame:SetSize(scrW * 0.9, scrH * 0.85)
frame:Center()
frame:SetTitle("")
frame:SetDraggable(true)
frame:ShowCloseButton(false)
frame:MakePopup()
frame.Paint = function(s, w, h)
-- Основной фон
draw.RoundedBox(8, 0, 0, w, h, COLOR_BG_DARK)
-- Верхняя панель
draw.RoundedBoxEx(8, 0, 0, w, 60, COLOR_BG_MEDIUM, true, true, false, false)
-- Акцентная линия
surface.SetDrawColor(COLOR_PRIMARY)
surface.DrawRect(0, 60, w, 3)
-- Заголовок
draw.SimpleText("◆ ЛОГИ СЕРВЕРА", "ixMenuButtonFont", w/2, 20, COLOR_ACCENT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
draw.SimpleText("СИСТЕМА МОНИТОРИНГА СОБЫТИЙ", "ixSmallFont", w/2, 43, COLOR_TEXT_SECONDARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
-- Рамка
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 2)
end
-- Кнопка закрытия
local closeBtn = vgui.Create("DButton", frame)
closeBtn:SetSize(40, 40)
closeBtn:SetPos(frame:GetWide() - 50, 10)
closeBtn:SetText("")
closeBtn.Paint = function(s, w, h)
local col = s:IsHovered() and Color(200, 50, 50) or Color(150, 50, 50)
draw.RoundedBox(4, 0, 0, w, h, col)
surface.SetDrawColor(255, 255, 255)
surface.DrawLine(w*0.3, h*0.3, w*0.7, h*0.7)
surface.DrawLine(w*0.7, h*0.3, w*0.3, h*0.7)
end
closeBtn.DoClick = function()
frame:Close()
end
-- Панель фильтров
local filterPanel = vgui.Create("DPanel", frame)
filterPanel:SetSize(250, frame:GetTall() - 80)
filterPanel:SetPos(10, 70)
filterPanel.Paint = function(s, w, h)
draw.RoundedBox(6, 0, 0, w, h, COLOR_BG_MEDIUM)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
end
-- Заголовок фильтров
local filterHeader = vgui.Create("DLabel", filterPanel)
filterHeader:SetPos(10, 10)
filterHeader:SetFont("ixSmallFont")
filterHeader:SetText("⚙ ФИЛЬТРЫ")
filterHeader:SetTextColor(COLOR_TEXT_PRIMARY)
filterHeader:SizeToContents()
-- Категории
local categoryLabel = vgui.Create("DLabel", filterPanel)
categoryLabel:SetPos(10, 40)
categoryLabel:SetFont("DermaDefault")
categoryLabel:SetText("Категория:")
categoryLabel:SetTextColor(COLOR_TEXT_SECONDARY)
categoryLabel:SizeToContents()
local categoryBox = vgui.Create("DComboBox", filterPanel)
categoryBox:SetPos(10, 60)
categoryBox:SetSize(230, 30)
categoryBox:SetValue("Все категории")
categoryBox:AddChoice("Все категории")
for catID, cat in SortedPairs(self.LOG_CATEGORIES) do
categoryBox:AddChoice(cat.icon .. " " .. cat.name, catID)
end
categoryBox.Paint = function(s, w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_BG_LIGHT)
surface.SetDrawColor(COLOR_PRIMARY)
surface.DrawOutlinedRect(0, 0, w, h, 1)
end
-- Поиск
local searchLabel = vgui.Create("DLabel", filterPanel)
searchLabel:SetPos(10, 100)
searchLabel:SetFont("DermaDefault")
searchLabel:SetText("Поиск:")
searchLabel:SetTextColor(COLOR_TEXT_SECONDARY)
searchLabel:SizeToContents()
local searchBox = vgui.Create("DTextEntry", filterPanel)
searchBox:SetPos(10, 120)
searchBox:SetSize(230, 30)
searchBox:SetPlaceholderText("Введите текст для поиска...")
searchBox.Paint = function(s, w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_BG_LIGHT)
surface.SetDrawColor(COLOR_PRIMARY)
surface.DrawOutlinedRect(0, 0, w, h, 1)
s:DrawTextEntryText(COLOR_TEXT_PRIMARY, COLOR_ACCENT, COLOR_TEXT_PRIMARY)
end
-- Лимит
local limitLabel = vgui.Create("DLabel", filterPanel)
limitLabel:SetPos(10, 160)
limitLabel:SetFont("DermaDefault")
limitLabel:SetText("Количество записей:")
limitLabel:SetTextColor(COLOR_TEXT_SECONDARY)
limitLabel:SizeToContents()
local limitSlider = vgui.Create("DNumSlider", filterPanel)
limitSlider:SetPos(10, 180)
limitSlider:SetSize(230, 30)
limitSlider:SetMin(10)
limitSlider:SetMax(500)
limitSlider:SetDecimals(0)
limitSlider:SetValue(100)
limitSlider:SetText("")
-- Кнопка применить фильтры
local applyBtn = vgui.Create("DButton", filterPanel)
applyBtn:SetPos(10, 230)
applyBtn:SetSize(230, 40)
applyBtn:SetText("")
applyBtn.Paint = function(s, w, h)
local col = s:IsHovered() and COLOR_ACCENT or COLOR_PRIMARY
draw.RoundedBox(4, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
draw.SimpleText("🔍 ПРИМЕНИТЬ", "ixSmallFont", w/2, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
applyBtn.DoClick = function()
local filters = {
limit = limitSlider:GetValue()
}
local _, catID = categoryBox:GetSelected()
if catID then
filters.category = catID
end
local searchText = searchBox:GetValue()
if searchText and searchText ~= "" then
filters.search = searchText
end
self:RequestLogs(filters)
end
-- Кнопка очистить логи
local clearBtn = vgui.Create("DButton", filterPanel)
clearBtn:SetPos(10, 280)
clearBtn:SetSize(230, 40)
clearBtn:SetText("")
clearBtn.Paint = function(s, w, h)
local col = s:IsHovered() and Color(200, 50, 50) or Color(150, 50, 50)
draw.RoundedBox(4, 0, 0, w, h, col)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
draw.SimpleText("🗑 ОЧИСТИТЬ ЛОГИ", "ixSmallFont", w/2, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
clearBtn.DoClick = function()
Derma_Query(
"Вы уверены что хотите очистить все логи?",
"Подтверждение",
"Да",
function()
net.Start("ixServerLogs_Clear")
net.SendToServer()
clientLogs = {}
self:UpdateLogsList()
end,
"Нет"
)
end
-- Панель логов
local logsPanel = vgui.Create("DPanel", frame)
logsPanel:SetSize(frame:GetWide() - 280, frame:GetTall() - 80)
logsPanel:SetPos(270, 70)
logsPanel.Paint = function(s, w, h)
draw.RoundedBox(6, 0, 0, w, h, COLOR_BG_MEDIUM)
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
end
-- Заголовок логов
local logsHeader = vgui.Create("DPanel", logsPanel)
logsHeader:SetSize(logsPanel:GetWide(), 40)
logsHeader:Dock(TOP)
logsHeader.Paint = function(s, w, h)
draw.RoundedBoxEx(6, 0, 0, w, h, COLOR_PRIMARY_DARK, true, true, false, false)
draw.SimpleText("📋 ЗАПИСИ ЛОГОВ", "ixSmallFont", 10, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
draw.SimpleText("Всего: " .. #clientLogs, "DermaDefault", w - 10, h/2, COLOR_TEXT_SECONDARY, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
end
-- Список логов
local logsList = vgui.Create("DScrollPanel", logsPanel)
logsList:Dock(FILL)
logsList:DockMargin(5, 5, 5, 5)
local sbar = logsList:GetVBar()
sbar:SetHideButtons(true)
function sbar:Paint(w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_BG_DARK)
end
function sbar.btnGrip:Paint(w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_PRIMARY)
end
self.logsFrame = frame
self.logsList = logsList
self.logsHeader = logsHeader
-- Загружаем логи
self:RequestLogs({limit = 100})
end
-- Обновление списка логов
function PLUGIN:UpdateLogsList()
if not IsValid(self.logsList) then return end
self.logsList:Clear()
if #clientLogs == 0 then
local noLogs = vgui.Create("DLabel", self.logsList)
noLogs:SetText("Логи не найдены")
noLogs:SetFont("ixSmallFont")
noLogs:SetTextColor(COLOR_TEXT_SECONDARY)
noLogs:SizeToContents()
noLogs:Dock(TOP)
noLogs:DockMargin(10, 10, 10, 0)
return
end
-- Обновляем заголовок
if IsValid(self.logsHeader) then
self.logsHeader.Paint = function(s, w, h)
draw.RoundedBoxEx(6, 0, 0, w, h, COLOR_PRIMARY_DARK, true, true, false, false)
draw.SimpleText("📋 ЗАПИСИ ЛОГОВ", "ixSmallFont", 10, h/2, COLOR_TEXT_PRIMARY, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
draw.SimpleText("Всего: " .. #clientLogs, "DermaDefault", w - 10, h/2, COLOR_TEXT_SECONDARY, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER)
end
end
for _, log in ipairs(clientLogs) do
local logEntry = vgui.Create("DPanel", self.logsList)
logEntry:SetTall(60)
logEntry:Dock(TOP)
logEntry:DockMargin(5, 5, 5, 0)
local category = self.LOG_CATEGORIES[log.category]
local categoryColor = category and category.color or color_white
logEntry.Paint = function(s, w, h)
draw.RoundedBox(4, 0, 0, w, h, COLOR_BG_LIGHT)
-- Боковая полоска категории
draw.RoundedBoxEx(4, 0, 0, 5, h, categoryColor, true, false, true, false)
-- Рамка
surface.SetDrawColor(COLOR_BORDER)
surface.DrawOutlinedRect(0, 0, w, h, 1)
-- Время
draw.SimpleText(log.timeString, "DermaDefault", 15, 8, COLOR_TEXT_SECONDARY, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
-- Категория
local catText = category and (category.icon .. " " .. category.name) or log.category
draw.SimpleText(catText, "DermaDefault", 15, 25, categoryColor, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
-- Сообщение
draw.SimpleText(log.message, "ixSmallFont", 15, 43, COLOR_TEXT_PRIMARY, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
end
end
end