Добавлена поддержка администраторов и логирования
Внесены изменения в класс `Program`: - Инициализация логгера с выводом в консоль и файл. - Загрузка списка администраторов из базы данных при запуске бота. - Метод для сохранения администратора в базе данных при авторизации. - Обновлен метод `UpdateReportStatus` для уведомления администраторов об изменении статуса заявки. - Добавлены методы для создания и загрузки таблицы администраторов. - Изменено форматирование сообщений с использованием emoji для статусов и приоритетов. - Обновлены SQL-запросы для работы с новыми полями и логикой в базе данных.
This commit is contained in:
parent
8092d54ff8
commit
fa790e52d7
302
Program.cs
302
Program.cs
@ -39,7 +39,7 @@ class Program
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.WriteTo.Console()
|
.WriteTo.Console()
|
||||||
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
|
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
|
||||||
@ -49,21 +49,25 @@ class Program
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
_botClient = new TelegramBotClient(_botToken);
|
_botClient = new TelegramBotClient(_botToken);
|
||||||
var me = await _botClient.GetMe();
|
var me = await _botClient.GetMe();
|
||||||
Log.Information($"Бот {me.FirstName} запущен! ID: {me.Id}");
|
Log.Information($"Бот {me.FirstName} запущен! ID: {me.Id}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"Ошибка при подключении к Telegram API: {ex.Message}");
|
Log.Error($"Ошибка при подключении к Telegram API: {ex.Message}");
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создание базы данных и таблицы, если они не существуют
|
// Создание базы данных и таблицы, если они не существуют
|
||||||
await CreateDatabaseIfNotExists();
|
await CreateDatabaseIfNotExists();
|
||||||
|
|
||||||
|
// Загрузка списка администраторов из базы данных
|
||||||
|
await LoadAdminsFromDatabase();
|
||||||
|
Log.Information($"Загружено {admins.Count} администраторов из базы данных");
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
Log.Information("Начало получения обновлений...");
|
Log.Information("Начало получения обновлений...");
|
||||||
|
|
||||||
@ -200,7 +204,7 @@ class Program
|
|||||||
if (callbackQuery?.Message?.MessageId != null)
|
if (callbackQuery?.Message?.MessageId != null)
|
||||||
{
|
{
|
||||||
int messageId = callbackQuery.Message.MessageId;
|
int messageId = callbackQuery.Message.MessageId;
|
||||||
await UpdateReportStatus(reportId, newStatus);
|
await UpdateReportStatus(reportId, newStatus, chatId);
|
||||||
await ShowReportDetails(botClient, chatId, reportId, messageId);
|
await ShowReportDetails(botClient, chatId, reportId, messageId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,13 +241,15 @@ class Program
|
|||||||
var message = update.Message;
|
var message = update.Message;
|
||||||
Log.Information($"Получено сообщение от {message.Chat.Id}: {message.Text}");
|
Log.Information($"Получено сообщение от {message.Chat.Id}: {message.Text}");
|
||||||
|
|
||||||
// Обработка команды /admin для авторизации
|
|
||||||
if (message.Text.StartsWith("/admin"))
|
if (message.Text.StartsWith("/admin"))
|
||||||
{
|
{
|
||||||
string[] parts = message.Text.Split(' ');
|
string[] parts = message.Text.Split(' ');
|
||||||
if (parts.Length == 2 && parts[1] == adminPassword)
|
if (parts.Length == 2 && parts[1] == adminPassword)
|
||||||
{
|
{
|
||||||
admins.Add(message.Chat.Id);
|
admins.Add(message.Chat.Id);
|
||||||
|
// Сохраняем администратора в базу данных
|
||||||
|
await SaveAdminToDatabase(message.Chat.Id);
|
||||||
|
|
||||||
var authMessage = await botClient.SendMessage(message.Chat.Id, "✅ Вы авторизованы как администратор!");
|
var authMessage = await botClient.SendMessage(message.Chat.Id, "✅ Вы авторизованы как администратор!");
|
||||||
Log.Information($"Новый администратор: {message.Chat.Id}");
|
Log.Information($"Новый администратор: {message.Chat.Id}");
|
||||||
await Task.Delay(2000);
|
await Task.Delay(2000);
|
||||||
@ -534,6 +540,9 @@ class Program
|
|||||||
string status = reader.GetString(4);
|
string status = reader.GetString(4);
|
||||||
string dateCreated = reader.GetDateTime(5).ToString("yyyy-MM-dd HH:mm:ss");
|
string dateCreated = reader.GetDateTime(5).ToString("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
string priorityEmoji = GetPriorityEmoji(priority);
|
||||||
|
string statusEmoji = GetStatusEmoji(status);
|
||||||
|
|
||||||
var statusButtons = new InlineKeyboardMarkup(new[]
|
var statusButtons = new InlineKeyboardMarkup(new[]
|
||||||
{
|
{
|
||||||
new[]
|
new[]
|
||||||
@ -557,11 +566,11 @@ class Program
|
|||||||
});
|
});
|
||||||
|
|
||||||
string newText = $"Заявка #{reportId}\n\n" +
|
string newText = $"Заявка #{reportId}\n\n" +
|
||||||
$"Приоритет: {priority}\n" +
|
$"Приоритет: {priorityEmoji} {priority}\n" +
|
||||||
$"Кабинет: {room}\n" +
|
$"Кабинет: {room}\n" +
|
||||||
$"Описание: {description}\n" +
|
$"Описание: {description}\n" +
|
||||||
$"ФИО: {reporterName}\n" +
|
$"ФИО: {reporterName}\n" +
|
||||||
$"Статус: {status}\n" +
|
$"Статус: {statusEmoji} {status}\n" +
|
||||||
$"Дата создания: {dateCreated}";
|
$"Дата создания: {dateCreated}";
|
||||||
|
|
||||||
await botClient.SendMessage(
|
await botClient.SendMessage(
|
||||||
@ -585,25 +594,44 @@ class Program
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static async Task UpdateReportStatus(long reportId, string newStatus)
|
private static async Task UpdateReportStatus(long reportId, string newStatus, long changerId)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
try
|
||||||
{
|
{
|
||||||
await connection.OpenAsync();
|
string oldStatus = "";
|
||||||
var command = connection.CreateCommand();
|
|
||||||
command.CommandText = "UPDATE Reports SET Status = @status WHERE Id = @id";
|
// Сначала получаем текущий статус
|
||||||
command.Parameters.AddWithValue("@status", newStatus);
|
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
||||||
command.Parameters.AddWithValue("@id", reportId);
|
{
|
||||||
await command.ExecuteNonQueryAsync();
|
await connection.OpenAsync();
|
||||||
|
var getStatusCommand = connection.CreateCommand();
|
||||||
|
getStatusCommand.CommandText = "SELECT Status FROM Reports WHERE Id = @id";
|
||||||
|
getStatusCommand.Parameters.AddWithValue("@id", reportId);
|
||||||
|
oldStatus = (string)await getStatusCommand.ExecuteScalarAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если статус не изменился, прерываем выполнение
|
||||||
|
if (oldStatus == newStatus) return;
|
||||||
|
|
||||||
|
// Обновляем статус
|
||||||
|
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
||||||
|
{
|
||||||
|
await connection.OpenAsync();
|
||||||
|
var command = connection.CreateCommand();
|
||||||
|
command.CommandText = "UPDATE Reports SET Status = @status WHERE Id = @id";
|
||||||
|
command.Parameters.AddWithValue("@status", newStatus);
|
||||||
|
command.Parameters.AddWithValue("@id", reportId);
|
||||||
|
await command.ExecuteNonQueryAsync();
|
||||||
|
|
||||||
|
// Уведомляем администраторов об изменении статуса
|
||||||
|
await NotifyAdminsAboutStatusChange(reportId, newStatus, oldStatus, changerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Ошибка при обновлении статуса заявки: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Error($"Ошибка: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task SaveReportToDatabase(long chatId, Report report)
|
private static async Task SaveReportToDatabase(long chatId, Report report)
|
||||||
{
|
{
|
||||||
@ -620,15 +648,19 @@ class Program
|
|||||||
@"
|
@"
|
||||||
INSERT INTO Reports (ChatId, Priority, Room, Description, ReporterName, Status)
|
INSERT INTO Reports (ChatId, Priority, Room, Description, ReporterName, Status)
|
||||||
VALUES (@ChatId, @Priority, @Room, @Description, @ReporterName, 'ожидает');
|
VALUES (@ChatId, @Priority, @Room, @Description, @ReporterName, 'ожидает');
|
||||||
";
|
SELECT last_insert_rowid();
|
||||||
|
";
|
||||||
insertCommand.Parameters.AddWithValue("@ChatId", chatId);
|
insertCommand.Parameters.AddWithValue("@ChatId", chatId);
|
||||||
insertCommand.Parameters.AddWithValue("@Priority", report.Priority);
|
insertCommand.Parameters.AddWithValue("@Priority", report.Priority);
|
||||||
insertCommand.Parameters.AddWithValue("@Room", report.Room);
|
insertCommand.Parameters.AddWithValue("@Room", report.Room);
|
||||||
insertCommand.Parameters.AddWithValue("@Description", report.Description);
|
insertCommand.Parameters.AddWithValue("@Description", report.Description);
|
||||||
insertCommand.Parameters.AddWithValue("@ReporterName", report.ReporterName);
|
insertCommand.Parameters.AddWithValue("@ReporterName", report.ReporterName);
|
||||||
|
|
||||||
await insertCommand.ExecuteNonQueryAsync();
|
long reportId = Convert.ToInt64(await insertCommand.ExecuteScalarAsync());
|
||||||
Log.Information($"Заявка от пользователя {chatId} успешно сохранена.");
|
Log.Information($"Заявка от пользователя {chatId} успешно сохранена с ID {reportId}.");
|
||||||
|
|
||||||
|
// Уведомляем администраторов о новой заявке
|
||||||
|
await NotifyAdminsAboutNewReport(reportId, report);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -639,6 +671,7 @@ class Program
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Обновляем метод CreateDatabaseIfNotExists
|
||||||
private static async Task CreateDatabaseIfNotExists()
|
private static async Task CreateDatabaseIfNotExists()
|
||||||
{
|
{
|
||||||
string connectionString = "Data Source=bot.db"; // Путь к вашей базе данных
|
string connectionString = "Data Source=bot.db"; // Путь к вашей базе данных
|
||||||
@ -693,7 +726,7 @@ class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создаем таблицу, если её не существует
|
// Создаем таблицу Reports, если её не существует
|
||||||
var createTableCommand = connection.CreateCommand();
|
var createTableCommand = connection.CreateCommand();
|
||||||
createTableCommand.CommandText =
|
createTableCommand.CommandText =
|
||||||
@"
|
@"
|
||||||
@ -707,15 +740,17 @@ class Program
|
|||||||
DateCreated DATETIME DEFAULT CURRENT_TIMESTAMP,
|
DateCreated DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
Status TEXT DEFAULT 'ожидает'
|
Status TEXT DEFAULT 'ожидает'
|
||||||
);
|
);
|
||||||
";
|
";
|
||||||
await createTableCommand.ExecuteNonQueryAsync();
|
await createTableCommand.ExecuteNonQueryAsync();
|
||||||
|
|
||||||
Log.Information("Таблица Reports успешно создана (если её не было).");
|
Log.Information("Таблица Reports успешно создана (если её не было).");
|
||||||
|
|
||||||
|
// Создаем таблицу администраторов
|
||||||
|
await CreateAdminsTableIfNotExists();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"Ошибка при создании таблицы в базе данных: {ex.Message}");
|
Log.Error($"Ошибка при создании таблиц в базе данных: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -725,6 +760,7 @@ class Program
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static Dictionary<long, int> userReportSteps = new Dictionary<long, int>();
|
private static Dictionary<long, int> userReportSteps = new Dictionary<long, int>();
|
||||||
private static Dictionary<long, Report> userReports = new Dictionary<long, Report>();
|
private static Dictionary<long, Report> userReports = new Dictionary<long, Report>();
|
||||||
|
|
||||||
@ -744,4 +780,210 @@ class Program
|
|||||||
Log.Error($"StackTrace: {exception.StackTrace}");
|
Log.Error($"StackTrace: {exception.StackTrace}");
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
// Добавим метод для создания таблицы администраторов
|
||||||
|
private static async Task CreateAdminsTableIfNotExists()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
||||||
|
{
|
||||||
|
await connection.OpenAsync();
|
||||||
|
var command = connection.CreateCommand();
|
||||||
|
command.CommandText = @"
|
||||||
|
CREATE TABLE IF NOT EXISTS Admins (
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ChatId INTEGER NOT NULL UNIQUE
|
||||||
|
);";
|
||||||
|
await command.ExecuteNonQueryAsync();
|
||||||
|
Log.Information("Таблица Admins успешно создана (если её не было).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Ошибка при создании таблицы Admins: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для сохранения администратора в базу данных
|
||||||
|
private static async Task SaveAdminToDatabase(long chatId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
||||||
|
{
|
||||||
|
await connection.OpenAsync();
|
||||||
|
|
||||||
|
// Проверяем, существует ли уже такой админ
|
||||||
|
var checkCommand = connection.CreateCommand();
|
||||||
|
checkCommand.CommandText = "SELECT COUNT(*) FROM Admins WHERE ChatId = @chatId";
|
||||||
|
checkCommand.Parameters.AddWithValue("@chatId", chatId);
|
||||||
|
int count = Convert.ToInt32(await checkCommand.ExecuteScalarAsync());
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
// Добавляем нового админа
|
||||||
|
var insertCommand = connection.CreateCommand();
|
||||||
|
insertCommand.CommandText = "INSERT INTO Admins (ChatId) VALUES (@chatId)";
|
||||||
|
insertCommand.Parameters.AddWithValue("@chatId", chatId);
|
||||||
|
await insertCommand.ExecuteNonQueryAsync();
|
||||||
|
Log.Information($"Администратор {chatId} добавлен в базу данных");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Ошибка при сохранении администратора в базу данных: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для загрузки администраторов из базы данных
|
||||||
|
private static async Task LoadAdminsFromDatabase()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
||||||
|
{
|
||||||
|
await connection.OpenAsync();
|
||||||
|
var command = connection.CreateCommand();
|
||||||
|
command.CommandText = "SELECT ChatId FROM Admins";
|
||||||
|
|
||||||
|
using (var reader = await command.ExecuteReaderAsync())
|
||||||
|
{
|
||||||
|
while (await reader.ReadAsync())
|
||||||
|
{
|
||||||
|
long adminId = reader.GetInt64(0);
|
||||||
|
admins.Add(adminId);
|
||||||
|
Log.Information($"Загружен администратор с ID: {adminId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.Information($"Загружено {admins.Count} администраторов из базы данных");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Ошибка при загрузке администраторов из базы данных: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для уведомления администраторов о новой заявке
|
||||||
|
private static async Task NotifyAdminsAboutNewReport(long reportId, Report report)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var adminId in admins)
|
||||||
|
{
|
||||||
|
var statusEmoji = GetPriorityEmoji(report.Priority);
|
||||||
|
var keyboard = new InlineKeyboardMarkup(new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
InlineKeyboardButton.WithCallbackData("📝 Посмотреть детали", $"report_{reportId}"),
|
||||||
|
InlineKeyboardButton.WithCallbackData("📋 Все заявки", "view_reports")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await _botClient.SendMessage(
|
||||||
|
chatId: adminId,
|
||||||
|
text: $"{statusEmoji} <b>Новая заявка #{reportId}</b>\n\n" +
|
||||||
|
$"<b>Приоритет:</b> {report.Priority}\n" +
|
||||||
|
$"<b>Кабинет:</b> {report.Room}\n" +
|
||||||
|
$"<b>Описание:</b> {report.Description}\n" +
|
||||||
|
$"<b>От:</b> {report.ReporterName}",
|
||||||
|
parseMode: ParseMode.Html,
|
||||||
|
replyMarkup: keyboard
|
||||||
|
);
|
||||||
|
Log.Information($"Уведомление о новой заявке #{reportId} отправлено администратору {adminId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Ошибка при отправке уведомлений администраторам о новой заявке: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для уведомления администраторов об изменении статуса заявки
|
||||||
|
private static async Task NotifyAdminsAboutStatusChange(long reportId, string newStatus, string oldStatus, long changerId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Получаем данные о заявке
|
||||||
|
string description = "";
|
||||||
|
string priority = "";
|
||||||
|
string room = "";
|
||||||
|
|
||||||
|
using (var connection = new SqliteConnection("Data Source=bot.db"))
|
||||||
|
{
|
||||||
|
await connection.OpenAsync();
|
||||||
|
var command = connection.CreateCommand();
|
||||||
|
command.CommandText = "SELECT Description, Priority, Room FROM Reports WHERE Id = @id";
|
||||||
|
command.Parameters.AddWithValue("@id", reportId);
|
||||||
|
|
||||||
|
using (var reader = await command.ExecuteReaderAsync())
|
||||||
|
{
|
||||||
|
if (await reader.ReadAsync())
|
||||||
|
{
|
||||||
|
description = reader.GetString(0);
|
||||||
|
priority = reader.GetString(1);
|
||||||
|
room = reader.GetString(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var adminId in admins)
|
||||||
|
{
|
||||||
|
// Не уведомляем админа, который сам изменил статус
|
||||||
|
if (adminId == changerId) continue;
|
||||||
|
|
||||||
|
string statusEmoji = GetStatusEmoji(newStatus);
|
||||||
|
var keyboard = new InlineKeyboardMarkup(new[]
|
||||||
|
{
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
InlineKeyboardButton.WithCallbackData("📝 Посмотреть детали", $"report_{reportId}")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await _botClient.SendMessage(
|
||||||
|
chatId: adminId,
|
||||||
|
text: $"{statusEmoji} <b>Обновление статуса заявки #{reportId}</b>\n\n" +
|
||||||
|
$"<b>Приоритет:</b> {priority}\n" +
|
||||||
|
$"<b>Кабинет:</b> {room}\n" +
|
||||||
|
$"<b>Статус изменен:</b> {oldStatus} ➡️ {newStatus}\n\n" +
|
||||||
|
$"<b>Фрагмент описания:</b> {description.Substring(0, Math.Min(50, description.Length))}...",
|
||||||
|
parseMode: ParseMode.Html,
|
||||||
|
replyMarkup: keyboard
|
||||||
|
);
|
||||||
|
Log.Information($"Уведомление об изменении статуса заявки #{reportId} отправлено администратору {adminId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Ошибка при отправке уведомлений об изменении статуса: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вспомогательный метод для получения emoji в зависимости от приоритета
|
||||||
|
private static string GetPriorityEmoji(string priority)
|
||||||
|
{
|
||||||
|
return priority.ToLower() switch
|
||||||
|
{
|
||||||
|
"high" or "высокий" => "🔴",
|
||||||
|
"medium" or "средний" => "🟠",
|
||||||
|
"low" or "низкий" => "🟢",
|
||||||
|
_ => "ℹ️"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вспомогательный метод для получения emoji в зависимости от статуса
|
||||||
|
private static string GetStatusEmoji(string status)
|
||||||
|
{
|
||||||
|
return status.ToLower() switch
|
||||||
|
{
|
||||||
|
"ожидает" => "🟡",
|
||||||
|
"в работе" => "🔵",
|
||||||
|
"закрыта" => "🟢",
|
||||||
|
_ => "ℹ️"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user