divan/GanjooRazor/Areas/Admin/Pages/CatUtils.cshtml
2026-09-27 14:03:38 +03:30

777 lines
24 KiB
Plaintext

@page
@model GanjooRazor.Areas.Admin.Pages.CatUtilsModel
@using DNTPersianUtils.Core
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_AdminLayout";
ViewData["Title"] = "مدیریت بخش";
}
<div class="up-page-header">
<h1>@ViewData["Title"]</h1>
</div>
<script>
async function deleteRelatedImage(targetUrl){
var ok = await upConfirm('آیا از حذف تصویر منتهی به نشانی زیر اطمینان دارید؟\r\n'+targetUrl);
if (!ok) return;
var url = '?handler=RemNaskbanImage';
$.ajax({
type: "POST",
url: url,
data: {
url: targetUrl
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('انجام شد!', 'success')
},
});
}
async function reslugCat(catId) {
var ok = await upConfirm('آیا از تولید مجدد نشانی‌های شعرهای بخش اطمینان دارید؟');
if (!ok) return;
var url = '?handler=BatchReSlugCatPoems';
$.ajax({
type: "POST",
url: url,
data: {
id: catId
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('انجام شد!', 'success')
},
});
}
async function startTocGenerationForSubCats(catId) {
var ok = await upConfirm('آیا از شروع کار تولید مجدد فهرست همهٔ زیربخشها اطمینان دارید؟');
if (!ok) return;
var url = '?handler=StartGeneratingSubCatsTOC';
$.ajax({
type: "POST",
url: url,
data: {
id: catId
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('کار تولید مجدد فهرست همهٔ زیربخشهای بخش شروع شد.', 'success')
},
});
}
async function tagCatWithRhymes(catId) {
var ok = await upConfirm('آیا از شروع کار قافیه‌یابی اطمینان دارید؟');
if (!ok) return;
var url = '?handler=StartRhymeAnalysis';
$.ajax({
type: "POST",
url: url,
data: {
id: catId
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('کار قافیه‌یابی بخش شروع شد.', 'success')
},
});
}
async function tagCatWithRhythms(catId) {
var ok = await upConfirm('آیا از شروع کار وزن‌یابی یا وزن‌گذاری اطمینان دارید؟');
if (!ok) return;
var url = '?handler=StartRhythmAnalysis';
$.ajax({
type: "POST",
url: url,
data: {
id: catId,
rhythm: $('#rhythm').val()
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('کار وزن‌یابی یا وزن‌گذاری بخش شروع شد.', 'success')
},
});
}
async function regenRelatedSections(catId) {
var ok = await upConfirm('آیا از شروع کار بازسازی قطعات مرتبط بخش اطمینان دارید؟');
if (!ok) return;
var url = '?handler=StartRegeneratingRelatedSections';
$.ajax({
type: "POST",
url: url,
data: {
id: catId,
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('کار بازسازی قطعات مرتبط بخش شروع شد.', 'success')
},
});
}
async function tagPoemsWithLanguage(catId) {
var lang = document.getElementById('cat-poem-language').value;
if(lang == '')
lang = 'fa-IR';
var ok = await upConfirm(lang);
if (ok) {
var url = '?handler=SetCategoryLanguageTag';
$.ajax({
type: "POST",
url: url,
data: {
id: catId,
language: lang
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('انجام شد.', 'success')
},
});
}
}
async function tagPoemsWithFormat(catId) {
var format = document.getElementById('cat-poem-format').value;
var ok = await upConfirm(format);
if (ok) {
var url = '?handler=SetCategoryPoemFormat';
$.ajax({
type: "POST",
url: url,
data: {
id: catId,
format: format
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('انجام شد.', 'success')
},
});
}
}
function onSwitchPoemsSelections(){
var value = document.getElementById('poems-select-switch').checked;
var checkboxes = document.getElementsByClassName('poemSelect');
for(var i = 0; i < checkboxes.length; i++){
checkboxes[i].checked = value;
}
}
async function deleteSelectedPoems(){
var ok = await upConfirm('آیا از حذف شعرهای انتخاب شده اطمینان دارید؟');
if (!ok) return;
var checkboxes = document.getElementsByClassName('poemSelect');
for(var i = 0; i < checkboxes.length; i++){
if(checkboxes[i].checked){
var dataValue = checkboxes[i].getAttribute("data-value");
$.ajax({
type: "DELETE",
url: '?handler=Poem',
data: {
id: dataValue
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
var poemBlockId = '#tr-' + dataValue;
$(poemBlockId).remove();
},
});
}
}
}
async function tagPoemsWithDigitalTag(catId) {
var tag = document.getElementById('digital-source-url-slug').value;
var name = document.getElementById('digital-source-name').value;
var ok = await upConfirm('آیا از برچسب‌گذاری اشعار این بخش با منبع دیجیتال با نشانی '+tag+' اطمینان دارید؟');
if (!ok) return;
var url = '?handler=SetCategoryDigitalSourceTag';
$.ajax({
type: "POST",
url: url,
data: {
id: catId,
tag: tag,
name: name
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('انجام شد.', 'success')
},
});
}
</script>
@if (!string.IsNullOrEmpty(Model.LastMessage))
{
<div class="up-alert up-alert--info">@Html.Raw(Model.LastMessage)</div>
}
@if (Model.PageInformation != null)
{
<div class="up-card">
<p><a href="@Model.PageInformation.FullUrl">@Model.PageInformation.FullTitle</a></p>
<p class="up-hint">@Model.Cat.Cat.Id</p>
</div>
}
@if (Model.Cat != null)
{
<h2>زیربخش‌ها</h2>
<table>
@foreach (var cat in Model.Cat.Cat.Children)
{
<tr>
<td>
<a href="/Admin/CatUtils?url=@cat.FullUrl">@cat.Title</a>
</td>
</tr>
}
</table>
<a href="/Admin/CatUtils?url=@Model.Cat.Cat.FullUrl&images=1" class="up-btn up-btn--ghost up-btn--sm">نمایش تصاویر نسکبان</a>
<h2>اشعار بخش</h2>
<table>
<tr>
<th>
عنوان
</th>
<th>
ابتدا
</th>
<th>
وزن اول
</th>
<th>
قافیه
</th>
<th>
<input type="checkbox" id="poems-select-switch" onclick="onSwitchPoemsSelections()" />
</th>
</tr>
@foreach (var poem in Model.Cat.Cat.Poems)
{
<tr id="tr-@poem.Id">
<td>
<a href="/Admin/ModifyPage?id=@poem.Id">@poem.Title</a>
</td>
<td>
@poem.Excerpt
</td>
@if (poem.MainSections.Length <= 1)
{
<td>
@if(poem.MainSections.Length == 1 && @poem.MainSections[0].GanjoorMetre != null)
{
@poem.MainSections[0].GanjoorMetre.Rhythm
}
</td>
<td>
@if(poem.MainSections.Length == 1)
{
@poem.MainSections[0].RhymeLetters
}
</td>
}
else
{
<td colspan="2">
<table>
<tr>
<th>
ابتدای بخش
</th>
<th>
وزن اول
</th>
<th>
قافیه
</th>
</tr>
@foreach (var s in poem.MainSections)
{
<tr>
<td>
@s.Excerpt
</td>
<td>
@if (s.GanjoorMetre != null)
{
@s.GanjoorMetre.Rhythm
}
</td>
<td>
@s.RhymeLetters
</td>
</tr>
}
</table>
</td>
}
<td>
<input type="checkbox" id="select-@poem.Id" data-value="@poem.Id" class="poemSelect" />
</td>
</tr>
@if(Model.PoemRelatedImages.Any(r => r.PoemId == poem.Id && r.TargetPageUrl.Contains("https://naskban.ir")))
{
<tr>
<td colspan="5">
<img src="@Model.PoemRelatedImages.Where(r => r.PoemId == poem.Id && r.TargetPageUrl.Contains("https://naskban.ir")).First().ThumbnailImageUrl" />
<br />
<p><a role="button" onclick="deleteRelatedImage('@Model.PoemRelatedImages.Where(r => r.PoemId == poem.Id && r.TargetPageUrl.Contains("https://naskban.ir")).First().TargetPageUrl')" class="up-btn up-btn--ghost up-btn--sm">حذف این تصویر</a></p>
</td>
</tr>
}
}
<tr>
<td colspan="5">
<p><a role="button" onclick="deleteSelectedPoems()" class="up-btn up-btn--ghost up-btn--sm">حذف شعرهای انتخاب شده</a></p>
</td>
</tr>
</table>
<p><a href="/Admin/ModifyPage?id=@Model.PageInformation.Id" class="up-btn up-btn--ghost up-btn--sm">ویرایش صفحهٔ متناظر</a></p>
<p><a role="button" onclick="startTocGenerationForSubCats(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">شروع تولید مجدد فهرست همهٔ زیربخشها</a></p>
<p><a role="button" onclick="tagCatWithRhymes(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">شروع قافیه‌یابی</a></p>
<table>
<tr>
<td colspan="2">
<input type="text" name="rhythm" id="rhythm" list="rythms" size="50" />
<datalist id="rythms">
@if (Model.Rhythms != null)
@foreach (var rhythm in Model.Rhythms)
{
<option value="@rhythm.Rhythm">@rhythm.Rhythm</option>
}
</datalist>
<p><a role="button" onclick="tagCatWithRhythms(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">شروع وزن‌یابی یا وزن‌گذاری</a></p>
</td>
</tr>
<tr>
<td>شناسه:</td>
<td>@Model.Cat.Cat.Id</td>
</tr>
</table>
<table>
<tr>
<td>
<span class="inputlabel">زبان اشعار بخش</span>
</td>
<td>
<select id="cat-poem-language">
@foreach (var lang in Model.Languages)
{
@if(lang.Code == "fa-IR")
{
<option value="">@lang.Name</option>
}
else
{
<option value="@lang.Code">@lang.Name</option>
}
}
</select>
</td>
</tr>
<tr>
<td colspan="2">
<p><a role="button" onclick="tagPoemsWithLanguage(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">تعیین زبان</a></p>
</td>
</tr>
</table>
<table>
<tr>
<td>
<span class="inputlabel">قالب اشعار بخش</span>
</td>
<td>
<select id="cat-poem-format">
@foreach (var poemFormat in System.Enum.GetValues(typeof(RMuseum.Models.Ganjoor.GanjoorPoemFormat)))
{
<option value="@poemFormat">@RMuseum.Services.Implementation.GanjoorPoemFormatConvertor.GetString((RMuseum.Models.Ganjoor.GanjoorPoemFormat)poemFormat)</option>
}
</select>
</td>
</tr>
<tr>
<td colspan="2">
<p><a role="button" onclick="tagPoemsWithFormat(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">تعیین قالب</a></p>
</td>
</tr>
</table>
}
<h2>تغییر عنوان گروهی</h2>
@if (Model.RenamingOutput != null)
{
<table>
@foreach (var item in Model.RenamingOutput)
{
<tr>
<td>
@item
</td>
</tr>
}
</table>
}
<form method="post">
@Html.AntiForgeryToken()
<table>
<tr>
<td>
شروع عنوان:
</td>
<td>
<input asp-for="NamingModel.StartWithNotIncludingSpaces" />
</td>
</tr>
<tr>
<td>
کاراکترهای حذفی از عنوان
</td>
<td>
<input asp-for="NamingModel.RemoveSetOfCharacters" />
</td>
</tr>
<tr>
<td>
حذف الگوی قبلی از عنوان
</td>
<td>
<input asp-for="NamingModel.RemovePreviousPattern" />
</td>
</tr>
<tr>
<td>
شبیه‌سازی
</td>
<td>
<input asp-for="NamingModel.Simulate" />
</td>
</tr>
<tr>
<td>
<input type="submit" value="تغییر نام گروهی" class="up-btn up-btn--success" />
</td>
<td>
<input type="submit" id="renameSubcats" name="renameSubcats" value="برای زیربخش‌ها" class="up-btn up-btn--ghost" />
</td>
</tr>
</table>
</form>
<h2>الگوهای شماره‌گذاری</h2>
<script>
async function deleteNumbering(itemId, itemName) {
var ok = await upConfirm('آیا از حذف الگوی شماره‌گذاری ' + itemName + ' اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "DELETE",
url: '',
data: {
id: itemId
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
location.reload();
return false;
},
});
}
async function recountNumbering(itemId, itemName) {
var ok = await upConfirm('آیا از شمارش مجدد الگوی شماره‌گذاری ' + itemName + ' اطمینان دارید؟');
if (!ok) return;
var url = '?handler=Recount';
$.ajax({
type: "POST",
url: url,
data: {
id: itemId
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('شمارش مجدد شروع شد.', 'success')
},
});
}
async function regenMissingNumbering() {
var ok = await upConfirm('آیا از تولید الگوهای شماره‌گذاری ناموجود اطمینان دارید؟');
if (!ok) return;
var url = '?handler=RegenerateNumberings';
$.ajax({
type: "POST",
url: url,
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
upToast('تولید الگوهای شماره‌گذاری ناموجود شروع شد.', 'success')
},
});
}
</script>
<table>
<tr>
<th>
نام
</th>
<th>
ابتدا
</th>
<th>
انتها
</th>
<th>
شمارش
</th>
<th>
#
</th>
</tr>
@foreach (var numbering in Model.Numberings)
{
<tr>
<td>
@numbering.Name
</td>
<td>
@numbering.StartCatId
</td>
<td>
@numbering.EndCatId
</td>
<td>
@if (numbering.LastCountingDate != DateTime.MinValue)
{
@numbering.LastCountingDate.ToLongPersianDateTimeString()
}
</td>
<td>
<a role="button" onclick="deleteNumbering(@numbering.Id, '@numbering.Name')" class="up-btn up-btn--ghost up-btn--sm" title="حذف">🗑</a>
<a role="button" onclick="recountNumbering(@numbering.Id, '@numbering.Name')" class="up-btn up-btn--ghost up-btn--sm" title="شمارش مجدد">⟳</a>
</td>
</tr>
}
<tr>
<td colspan="5">
<a role="button" onclick="regenMissingNumbering()" class="up-btn up-btn--ghost up-btn--sm" title="تولید کلی الگوهای ناموجود">تولید کلی الگوهای ناموجود</a>
</td>
</tr>
</table>
<form method="post" action="?Handler=Numbering&url=@Model.Cat.Cat.FullUrl">
@Html.AntiForgeryToken()
<table>
<tr>
<td>
عنوان:
</td>
<td>
<input asp-for="NumberingModel.Name" />
</td>
</tr>
<tr>
<td>
شناسهٔ ابتدا
</td>
<td>
<input asp-for="NumberingModel.StartCatId" />
</td>
</tr>
<tr>
<td>
شناسهٔ انتها
</td>
<td>
<input asp-for="NumberingModel.EndCatId" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="ایجاد الگوی شماره‌گذاری" class="up-btn up-btn--success" />
</td>
</tr>
</table>
</form>
<h2>ابرداده‌های دیگر بخش</h2>
<form method="post" action="?Handler=UpdateCatMeta&url=@Model.Cat.Cat.FullUrl">
@Html.AntiForgeryToken()
<table>
<tr>
<td>
نام کتاب:
</td>
<td>
<input asp-for="CatMeta.BookName" />
</td>
</tr>
<tr>
<td>
تصویر کتاب:
</td>
<td>
<input asp-for="CatMeta.NewImage" />
</td>
</tr>
<tr>
<td>
گردآوری نقشه‌های زیربخش‌ها
</td>
<td>
<input asp-for="CatMeta.SumUpSubsGeoLocations" />
</td>
</tr>
<tr>
<td>
نام نقشه
</td>
<td>
<input asp-for="CatMeta.MapName" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="به‌روزرسانی ابرداده‌های دیگر" class="up-btn up-btn--success" />
</td>
</tr>
</table>
</form>
<table>
<tr>
<td>بارگذاری پایگاه داده‌ها شامل یک دسته‌بندی از اشعار:</td>
<td>
<form method="post" enctype="multipart/form-data" action="/Admin/CatUtils?Handler=UploadDb&url=@Model.Cat.Cat.FullUrl">
@Html.AntiForgeryToken()
<input type="file" asp-for="SQLiteDb" />
<input type="submit" value="بارگذاری" class="up-btn up-btn--success" />
</form>
</td>
</tr>
</table>
<p><a href="/Admin/CatTrans?id=@Model.Cat.Cat.Id" class="up-btn up-btn--ghost up-btn--sm">انتقال بخش</a></p>
<p><a href="/Admin/CatDel?id=@Model.Cat.Cat.Id" class="up-btn up-btn--danger up-btn--sm">حذف بخش</a></p>
<p><a role="button" onclick="regenRelatedSections(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm" title="بازسازی قطعات مرتبط">بازسازی قطعات مرتبط</a></p>
<p><a role="button" onclick="reslugCat(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">تولید مجدد نشانی‌های اشعار بخش</a></p>
<table>
<tr>
<td>
<span class="inputlabel">اسلاگ منبع دیجیتال بخش</span>
</td>
<td>
<input id="digital-source-url-slug" value="" />
</td>
</tr>
<tr>
<td>
<span class="inputlabel">نام منبع دیجیتال بخش (فقط برای منبع جدید)</span>
</td>
<td>
<input id="digital-source-name" value="" />
</td>
</tr>
<tr>
<td colspan="2">
<p><a role="button" onclick="tagPoemsWithDigitalTag(@Model.Cat.Cat.Id)" class="up-btn up-btn--ghost up-btn--sm">تعیین منبع</a></p>
</td>
</tr>
</table>