Initial commit

This commit is contained in:
Popov_Grigorii
2026-07-15 17:17:03 +03:00
commit cc078a2c8d
94 changed files with 76773 additions and 0 deletions
@@ -0,0 +1,44 @@
@page
@model ListmonkIntegration.Pages.Campaigns.IndexModel
@{
ViewData["Title"] = "Управление рассылками";
}
<h1> Управление рассылками</h1>
<hr />
<div class="row">
<div class="col-md-12">
<div class="mb-4">
<a asp-page="/Templates/Create" class="btn btn-primary btn-lg">
Создать шаблон письма
</a>
<a asp-page="/Campaigns/Send" class="btn btn-warning btn-lg">
Отправить письмо
</a>
<a asp-page="/Subscribers/Upload" class="btn btn-success btn-lg">
Загрузить подписчиков
</a>
</div>
<div class="alert alert-info">
<h5>Функционал:</h5>
<ul>
<li>Загрузка Excel файлов с подписчиками</li>
<li>Создание шаблонов писем</li>
<li>Просмотр существующих кампаний</li>
<li>Запуск рассылок</li>
<li>Просмотр статистики</li>
</ul>
</div>
<a asp-page="/Index" class="btn btn-secondary">← На главную</a>
</div>
</div>
@if (TempData["SuccessMessage"] != null)
{
<div class="alert alert-success mt-3">
@TempData["SuccessMessage"]
</div>
}
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ListmonkIntegration.Pages.Campaigns
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
@@ -0,0 +1,96 @@
@page
@model ListmonkIntegration.Pages.Campaigns.SendModel
@{
ViewData["Title"] = "Отправка письма";
}
<h1>Отправка письма</h1>
<hr />
@if (!string.IsNullOrEmpty(Model.ErrorMessage))
{
<div class="alert alert-danger">@Model.ErrorMessage</div>
}
@if (!string.IsNullOrEmpty(Model.SuccessMessage))
{
<div class="alert alert-success">@Model.SuccessMessage</div>
}
<div class="row">
<div class="col-md-8">
<form method="post">
<div class="mb-3">
<label class="form-label">Название кампании</label>
<input type="text" asp-for="CampaignName" class="form-control" required placeholder="Например: Рассылка 08.07.2026" />
</div>
<div class="mb-3">
<label class="form-label">Выберите шаблон письма</label>
<select asp-for="SelectedTemplateId" class="form-select" asp-items="Model.Templates" id="templateSelect" required>
<option value="">-- Выберите шаблон --</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Список получателей</label>
<select asp-for="SelectedListId" class="form-select" asp-items="Model.Lists" required>
<option value="">-- Выберите список --</option>
</select>
<div class="form-text">
<span id="selectedListInfo"></span>
</div>
</div>
<div class="mb-3">
<label class="form-label">Предпросмотр шаблона</label>
<div id="templatePreview" class="border p-3 bg-light" style="min-height: 200px;">
<p class="text-muted">Выберите шаблон для предпросмотра</p>
</div>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary btn-lg">Отправить</button>
<a asp-page="/Campaigns/Index" class="btn btn-secondary">Отмена</a>
</div>
</form>
</div>
</div>
@section Scripts {
<script>
document.getElementById('templateSelect').addEventListener('change', async function() {
const templateId = this.value;
const previewDiv = document.getElementById('templatePreview');
if (templateId) {
previewDiv.innerHTML = '<p class="text-muted">Загрузка...</p>';
try {
const response = await fetch(`/api/templates/${templateId}/preview`);
if (response.ok) {
const data = await response.json();
previewDiv.innerHTML = data.body || '<p class="text-muted">Шаблон пуст</p>';
} else {
previewDiv.innerHTML = '<p class="text-danger">Ошибка загрузки шаблона</p>';
}
} catch (error) {
console.error('Error:', error);
previewDiv.innerHTML = '<p class="text-danger">Ошибка загрузки шаблона</p>';
}
} else {
previewDiv.innerHTML = '<p class="text-muted">Выберите шаблон для предпросмотра</p>';
}
});
document.querySelector('select[asp-for="SelectedListId"]').addEventListener('change', function() {
const select = this;
const infoSpan = document.getElementById('selectedListInfo');
const selectedOption = select.options[select.selectedIndex];
if (selectedOption.value) {
infoSpan.textContent = `Выбран список: ${selectedOption.text}`;
} else {
infoSpan.textContent = '';
}
});
</script>
}
@@ -0,0 +1,108 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using ListmonkIntegration.Services;
namespace ListmonkIntegration.Pages.Campaigns
{
public class SendModel : PageModel
{
private readonly IListmonkService _listmonkService;
private readonly ILogger<SendModel> _logger;
[BindProperty]
public string CampaignName { get; set; } = string.Empty;
[BindProperty]
public int? SelectedTemplateId { get; set; }
[BindProperty]
public int? SelectedListId { get; set; }
public SelectList Templates { get; set; } = new SelectList(Enumerable.Empty<SelectListItem>());
public SelectList Lists { get; set; } = new SelectList(Enumerable.Empty<SelectListItem>());
public string? ErrorMessage { get; set; }
public string? SuccessMessage { get; set; }
public SendModel(IListmonkService listmonkService, ILogger<SendModel> logger)
{
_listmonkService = listmonkService;
_logger = logger;
}
public async Task OnGetAsync()
{
await LoadDataAsync();
}
public async Task<IActionResult> OnPostAsync()
{
if (!SelectedTemplateId.HasValue || !SelectedListId.HasValue || string.IsNullOrWhiteSpace(CampaignName))
{
ErrorMessage = "Çàïîëíèòå âñå ïîëÿ";
await LoadDataAsync();
return Page();
}
try
{
var templates = await _listmonkService.GetTemplatesAsync();
var template = templates.FirstOrDefault(t => t.Id == SelectedTemplateId.Value);
if (template == null)
{
ErrorMessage = "Øàáëîí íå íàéäåí";
await LoadDataAsync();
return Page();
}
var campaignId = await _listmonkService.CreateCampaignAsync(
CampaignName,
SelectedListId.Value,
SelectedTemplateId.Value,
template.Subject
);
var started = await _listmonkService.StartCampaignAsync(campaignId);
if (started)
{
SuccessMessage = $"Êàìïàíèÿ \"{CampaignName}\" óñïåøíî ñîçäàíà è çàïóùåíà!";
_logger.LogInformation($"Campaign {campaignId} started successfully");
}
else
{
ErrorMessage = $"Êàìïàíèÿ ñîçäàíà (ID: {campaignId}), íî íå óäàëîñü çàïóñòèòü";
}
await LoadDataAsync();
return Page();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error sending campaign");
ErrorMessage = $"Îøèáêà: {ex.Message}";
await LoadDataAsync();
return Page();
}
}
private async Task LoadDataAsync()
{
try
{
var templates = await _listmonkService.GetTemplatesAsync();
Templates = new SelectList(templates, "Id", "Name");
var lists = await _listmonkService.GetListsAsync();
Lists = new SelectList(lists, "Id", "Name");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error loading data");
ErrorMessage = $"Îøèáêà çàãðóçêè äàííûõ: {ex.Message}";
}
}
}
}