improve UI/UX of the Admin Area

#497
This commit is contained in:
Hamid Reza Mohammadi 2026-08-05 17:58:46 +03:30
parent 5c9720ba1a
commit 8d528ddc13
5 changed files with 174 additions and 218 deletions

View File

@ -1,75 +1,63 @@
@page
@page
@model GanjooRazor.Areas.Admin.Pages.DonationsModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_AdminLayout";
ViewData["Title"] = "کمک‌های مالی";
}
<div class="up-page-header">
<h1>@ViewData["Title"]</h1>
</div>
<h1>@ViewData["Title"]</h1>
<p>@Model.LastMessage</p>
@if (!string.IsNullOrEmpty(Model.LastMessage))
{
<div class="up-alert up-alert--info">@Model.LastMessage</div>
}
@if (!string.IsNullOrEmpty(Model.EmailContent))
{
<textarea rows="5" cols="50">@Model.EmailContent</textarea>
<div class="up-field">
<label>متن ایمیل</label>
<textarea rows="5" cols="50">@Model.EmailContent</textarea>
</div>
}
@if (Model.Donation != null)
{
<form method="post">
<table>
<tr>
<td>
تاریخ:
</td>
<td>
<input type="date" asp-for="Donation.RecordDate" />
</td>
</tr>
<tr>
<td>
مبلغ:
</td>
<td>
<input type="number" asp-for="Donation.Amount" />
</td>
</tr>
<tr>
<td>
واحد:
</td>
<td>
<input asp-for="Donation.Unit" />
</td>
</tr>
<tr>
<td>
اهدا کننده:
</td>
<td>
<input size="50" asp-for="Donation.DonorName" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="ثبت کمک مالی جدید" />
</td>
</tr>
</table>
</form>
<div class="up-card">
<h2 class="up-card__title">کمک مالی جدید</h2>
<form method="post" class="up-form">
<div class="up-field">
<label asp-for="Donation.RecordDate">تاریخ</label>
<input type="date" asp-for="Donation.RecordDate" />
</div>
<div class="up-field">
<label asp-for="Donation.Amount">مبلغ</label>
<input type="number" asp-for="Donation.Amount" />
</div>
<div class="up-field">
<label asp-for="Donation.Unit">واحد</label>
<input asp-for="Donation.Unit" />
</div>
<div class="up-field">
<label asp-for="Donation.DonorName">اهدا کننده</label>
<input size="50" asp-for="Donation.DonorName" />
</div>
<div class="up-form-actions">
<button type="submit" class="up-btn up-btn--success">ثبت کمک مالی جدید</button>
</div>
</form>
</div>
}
<p><a href="/donate" target="_blank">مشاهدهٔ صفحه</a></p>
<p>@Model.ShowAccountInfo</p>
<p><a role="button" onclick="rebuildDonationsPage()" class="actionlink" title="بازسازی صفحهٔ کمک‌ها">بازسازی صفحهٔ کمک‌ها</a></p>
<div class="up-form-actions" style="margin-bottom:var(--up-space-3);">
<a href="/donate" target="_blank" class="up-btn up-btn--ghost">مشاهدهٔ صفحه</a>
<a role="button" onclick="rebuildDonationsPage()" class="up-btn up-btn--ghost" title="بازسازی صفحهٔ کمک‌ها">بازسازی صفحهٔ کمک‌ها</a>
</div>
@if (!string.IsNullOrEmpty(Model.ShowAccountInfo))
{
<p class="up-hint">@Model.ShowAccountInfo</p>
}
@if (Model.Donations != null)
{
@ -78,9 +66,7 @@
<th>تاریخ</th>
<th>مبلغ</th>
<th>اهدا کننده</th>
<th>
#
</th>
<th>#</th>
</tr>
@foreach (var donation in Model.Donations)
{
@ -89,9 +75,9 @@
<td>@donation.AmountString</td>
<td>@donation.DonorName</td>
<td>
<a role="button" href="/Admin/DonationEdit/?id=@donation.Id" class="actionlink" title="ویرایش">✎</a>
<a role="button" onclick="deleteItem(@donation.Id, 'کمک')" class="actionlink" title="حذف">🗑</a>
<a role="button" href="/Admin/Donations?id=@donation.Id" class="actionlink" title="تولید محتوای پیام">#</a>
<a role="button" href="/Admin/DonationEdit/?id=@donation.Id" class="up-icon-btn" title="ویرایش" aria-label="ویرایش این کمک مالی">✎</a>
<a role="button" onclick="deleteItem(@donation.Id, 'کمک')" class="up-icon-btn" title="حذف" aria-label="حذف این کمک مالی">🗑</a>
<a role="button" href="/Admin/Donations?id=@donation.Id" class="up-icon-btn" title="تولید محتوای پیام" aria-label="تولید محتوای پیام">#</a>
</td>
</tr>
}

View File

@ -1,63 +1,52 @@
@page
@page
@model GanjooRazor.Areas.Admin.Pages.ExpensesModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_AdminLayout";
ViewData["Title"] = "هزینه‌ها";
}
<div class="up-page-header">
<h1>@ViewData["Title"]</h1>
</div>
<h1>@ViewData["Title"]</h1>
@if (!string.IsNullOrEmpty(Model.LastMessage))
{
<div class="up-alert up-alert--info">@Model.LastMessage</div>
}
<p>@Model.LastMessage</p>
<div class="up-card">
<h2 class="up-card__title">هزینهٔ جدید</h2>
<form method="post" class="up-form">
<div class="up-field">
<label asp-for="Expense.ExpenseDate">تاریخ</label>
<input type="date" asp-for="Expense.ExpenseDate" />
</div>
<div class="up-field">
<label asp-for="Expense.Amount">مبلغ</label>
<input type="number" asp-for="Expense.Amount" />
</div>
<div class="up-field">
<label asp-for="Expense.Unit">واحد</label>
<input asp-for="Expense.Unit" />
</div>
<div class="up-field">
<label asp-for="Expense.Description">شرح</label>
<input asp-for="Expense.Description" />
</div>
<div class="up-form-actions">
<button type="submit" class="up-btn up-btn--success">ثبت هزینهٔ جدید</button>
</div>
</form>
</div>
<form method="post">
<table>
<tr>
<td>
تاریخ:
</td>
<td>
<input type="date" asp-for="Expense.ExpenseDate" />
</td>
</tr>
<tr>
<td>
مبلغ:
</td>
<td>
<input type="number" asp-for="Expense.Amount" />
</td>
</tr>
<tr>
<td>
واحد:
</td>
<td>
<input asp-for="Expense.Unit" />
</td>
</tr>
<tr>
<td>
شرح:
</td>
<td>
<input size="50" asp-for="Expense.Description" />
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="ثبت هزینهٔ جدید" />
</td>
</tr>
</table>
</form>
<p><a href="/donate" target="_blank">مشاهدهٔ صفحه</a></p>
<p>@Model.ShowAccountInfo</p>
<p><a role="button" onclick="rebuildDonationsPage()" class="actionlink" title="بازسازی صفحهٔ کمک‌ها">بازسازی صفحهٔ کمک‌ها</a></p>
<div class="up-form-actions" style="margin-bottom:var(--up-space-3);">
<a href="/donate" target="_blank" class="up-btn up-btn--ghost">مشاهدهٔ صفحه</a>
<a role="button" onclick="rebuildDonationsPage()" class="up-btn up-btn--ghost" title="بازسازی صفحهٔ کمک‌ها">بازسازی صفحهٔ کمک‌ها</a>
</div>
@if (!string.IsNullOrEmpty(Model.ShowAccountInfo))
{
<p class="up-hint">@Model.ShowAccountInfo</p>
}
@if (Model.Expenses != null)
{
@ -66,9 +55,7 @@
<th>تاریخ</th>
<th>مبلغ</th>
<th>شرح</th>
<th>
#
</th>
<th>#</th>
</tr>
@foreach (var expense in Model.Expenses)
{
@ -77,12 +64,10 @@
<td>@RMuseum.Services.Implementation.LanguageUtils.FormatMoney(expense.Amount)</td>
<td>@expense.Description</td>
<td>
<a role="button" href="/Admin/ExpenseEdit/?id=@expense.Id" class="actionlink" title="ویرایش">✎</a>
<a role="button" onclick="deleteItem(@expense.Id, 'هزینه')" class="actionlink" title="حذف">🗑</a>
<a role="button" href="/Admin/ExpenseEdit/?id=@expense.Id" class="up-icon-btn" title="ویرایش" aria-label="ویرایش این هزینه">✎</a>
<a role="button" onclick="deleteItem(@expense.Id, 'هزینه')" class="up-icon-btn" title="حذف" aria-label="حذف این هزینه">🗑</a>
</td>
</tr>
}
</table>
}

View File

@ -1,27 +1,29 @@
@page
@page
@model GanjooRazor.Areas.Admin.Pages.LongRunningJobsModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_AdminLayout";
ViewData["Title"] = "کارهای جاری";
}
<div class="up-page-header">
<h1>@ViewData["Title"]</h1>
</div>
<h1>@ViewData["Title"]</h1>
<p>@Model.LastMessage</p>
@if (!string.IsNullOrEmpty(Model.LastMessage))
{
<div class="up-alert up-alert--info">@Model.LastMessage</div>
}
<script>
function cleanUpJobs() {
if (!confirm('آیا از حذف همهٔ کارهای موفق و ناموفق تکمیل شده اطمینان دارید؟'))
return;
async function cleanUpJobs() {
var ok = await upConfirm('آیا از حذف همهٔ کارهای موفق و ناموفق تکمیل شده اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "POST",
url: '?handler=CleanupJobs',
error: function () {
alert('خطا رخ داد.')
upToast('خطا رخ داد.', 'error');
},
success: function () {
location.reload();
@ -29,30 +31,30 @@
});
}
function deleteLongRunningJob(id) {
if (!confirm('آیا از حذف این کار اطمینان دارید؟'))
return;
async function deleteLongRunningJob(id) {
var ok = await upConfirm('آیا از حذف این کار اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "DELETE",
url: '',
data: {
id: id
data: { id: id },
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
var jobIdBlockId = '#tr-' + id;
$(jobIdBlockId).remove();
$('#tr-' + id).remove();
},
});
}
</script>
@if (Model.Jobs != null)
{
<div class="up-form-actions" style="margin-bottom:var(--up-space-3);">
<a role="button" onclick="cleanUpJobs()" class="up-btn up-btn--ghost" title="حذف کارهای قدیمی">حذف کارهای قدیمی <i class="noindent-info-button delete-icon"></i></a>
</div>
<table>
<tr>
<th>کار</th>
@ -64,11 +66,6 @@
<th>خطا</th>
<th>#</th>
</tr>
<tr>
<td colspan="8">
<a role="button" onclick="cleanUpJobs()" class="pagebutton" title="حذف کارهای قدیمی">حذف کارهای قدیمی <i class="noindent-info-button delete-icon"></i></a>
</td>
</tr>
@foreach (var job in Model.Jobs)
{
<tr id="tr-@job.Id">
@ -79,20 +76,15 @@
<td>@job.LastUpdate</td>
<td>@job.Succeeded</td>
<td>@job.Exception</td>
<td><a role="button" onclick="deleteLongRunningJob('@job.Id')" class="actionlink" title="حذف"><i class="noindent-info-button delete-icon"></i></a></td>
</tr>
}
@if (Model.Jobs.Length > 0)
{
<tr>
<td colspan="8">
<a role="button" onclick="cleanUpJobs()" class="pagebutton" title="حذف کارهای قدیمی">حذف کارهای قدیمی <i class="noindent-info-button delete-icon"></i></a>
</td>
<td><a role="button" onclick="deleteLongRunningJob('@job.Id')" class="up-icon-btn" title="حذف" aria-label="حذف این کار"><i class="noindent-info-button delete-icon"></i></a></td>
</tr>
}
</table>
@if (Model.Jobs.Length > 0)
{
<div class="up-form-actions" style="margin-top:var(--up-space-3);">
<a role="button" onclick="cleanUpJobs()" class="up-btn up-btn--ghost" title="حذف کارهای قدیمی">حذف کارهای قدیمی <i class="noindent-info-button delete-icon"></i></a>
</div>
}
}

View File

@ -1,19 +1,24 @@
@page
@page
@model GanjooRazor.Areas.Admin.Pages.PoetsModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_AdminLayout";
ViewData["Title"] = "مدیریت سخنوران";
}
<div class="up-page-header">
<h1>@ViewData["Title"]</h1>
</div>
<h1>@ViewData["Title"]</h1>
<p>@Model.LastMessage</p>
@if (!string.IsNullOrEmpty(Model.LastMessage))
{
<div class="up-alert up-alert--info">@Model.LastMessage</div>
}
<script>
function savePoetMeta(id, name) {
if (!confirm('آیا از ذخیرهٔ اطلاعات سال تولد و وفات و ترتیب برای ' + name + ' اطمینان دارید؟'))
return;
async function savePoetMeta(id, name) {
var ok = await upConfirm('آیا از ذخیرهٔ اطلاعات سال تولد و وفات و ترتیب برای ' + name + ' اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "POST",
url: '?handler=SavePoetMeta',
@ -28,36 +33,36 @@
deathlocation: $('#death-place-' + String(id)).val(),
},
error: function (e) {
if (e.responseText == null)
alert(e);
else
alert(e.responseText);
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function () {
alert('انجام شد.');
upToast('انجام شد.', 'success');
},
});
}
function savePoetsMeta() {
if (!confirm('آیا از به‌روزرسانی گروه‌بندی بر اساس قرن اطمینان دارید؟'))
return;
async function savePoetsMeta() {
var ok = await upConfirm('آیا از به‌روزرسانی گروه‌بندی بر اساس قرن اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "POST",
url: '?handler=UpdatePeriods',
success: function () {
alert('انجام شد.');
upToast('انجام شد.', 'success');
},
error: function (e) {
if (e.responseText == null)
alert(e);
else
alert(e.responseText);
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
});
}
</script>
<div class="up-form-actions" style="margin-bottom:var(--up-space-3);">
<a href="/Admin/Poet" class="up-btn up-btn--success">سخنور جدید</a>
<a role="button" onclick="savePoetsMeta()" class="up-btn up-btn--ghost">ذخیرهٔ گروه‌بندی بر اساس قرن</a>
</div>
<table>
<tr>
<th>نام سخنور</th>
@ -65,14 +70,6 @@
<th>درگذشته</th>
<th>چسبانی</th>
</tr>
<tr>
<td colspan="4"><a href="/Admin/Poet">سخنور جدید</a></td>
</tr>
<tr>
<td colspan="4">
<a role="button" onclick="savePoetsMeta()" class="actionlink">ذخیرهٔ گروه‌بندی بر اساس قرن</a>
</td>
</tr>
@foreach (var poet in Model.Poets)
{
@ -90,7 +87,6 @@
{
<input type="checkbox" name="@($"birth-valid-{poet.Id}")" id="@($"birth-valid-{poet.Id}")" />
}
</td>
<td>
<input type="text" name="@($"death-{poet.Id}")" id="@($"death-{poet.Id}")" value="@poet.DeathYearInLHijri" />
@ -103,7 +99,6 @@
<input type="checkbox" name="@($"death-valid-{poet.Id}")" id="@($"death-valid-{poet.Id}")" />
}
</td>
<td>
<input type="text" name="@($"pinorder-{poet.Id}")" id="@($"pinorder-{poet.Id}")" value="@poet.PinOrder" />
</td>
@ -125,7 +120,6 @@
{
<option value="@location.Name">@location.Name</option>
}
}
}
</select>
@ -160,17 +154,12 @@
</tr>
<tr>
<td colspan="4">
<a role="button" onclick="savePoetMeta(@poet.Id, '@poet.Nickname')" class="actionlink">ذخیرهٔ @poet.Nickname</a>
<a role="button" onclick="savePoetMeta(@poet.Id, '@poet.Nickname')" class="up-btn up-btn--success up-btn--sm">ذخیرهٔ @poet.Nickname</a>
</td>
</tr>
}
</table>
<table>
<tr>
<td><a role="button" onclick="exportAll()" class="actionlink">sqlite</a></td>
</tr>
</table>
<div class="up-form-actions" style="margin-top:var(--up-space-3);">
<a role="button" onclick="exportAll()" class="up-btn up-btn--ghost">sqlite</a>
</div>

View File

@ -53,18 +53,20 @@
url: $(urlInput).val(),
active: $(activeInput).is(":checked")
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function() {
alert('آگاهی به درستی ویرایش شد.')
upToast('آگاهی به درستی ویرایش شد.', 'success');
},
});
}
function deleteBanner(bannerId) {
if (!confirm('آیا از حذف این آگاهی اطمینان دارید؟'))
return;
async function deleteBanner(bannerId) {
var ok = await upConfirm('آیا از حذف این آگاهی اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "DELETE",
@ -72,6 +74,9 @@
data: {
id: bannerId
},
error: function (e) {
upToast(e.responseText || 'خطا رخ داد.', 'error');
},
success: function() {
var bannerIdBlockId = '#tr-' + bannerId;
$(bannerIdBlockId).remove();
@ -79,9 +84,9 @@
});
}
function rebuildDonationsPage() {
if (!confirm('آیا از بازسازی صفحهٔ کمک‌ها اطمینان دارید؟'))
return;
async function rebuildDonationsPage() {
var ok = await upConfirm('آیا از بازسازی صفحهٔ کمک‌ها اطمینان دارید؟');
if (!ok) return;
var url = '?handler=RebuildPage';
@ -89,21 +94,20 @@
type: "POST",
url: url,
error: function() {
alert('خطا رخ داد.')
upToast('خطا رخ داد.', 'error');
},
success: function() {
alert('صفحه به درستی بازسازی شد.')
upToast('صفحه به درستی بازسازی شد.', 'success');
},
});
}
function deleteItem(itemId, itemName) {
if (!confirm('آیا از حذف این ' + itemName + ' اطمینان دارید؟'))
return;
async function deleteItem(itemId, itemName) {
var ok = await upConfirm('آیا از حذف این ' + itemName + ' اطمینان دارید؟');
if (!ok) return;
$.ajax({
type: "DELETE",
@ -112,7 +116,7 @@
id: itemId
},
error: function() {
alert('خطا رخ داد.');
upToast('خطا رخ داد.', 'error');
},
success: function() {
location.reload();
@ -339,9 +343,9 @@
function exportAll() {
if (!confirm('آیا از تولید مجدد همهٔ فایلهای گنجور رومیزی اطمینان دارید؟'))
return;
async function exportAll() {
var ok = await upConfirm('آیا از تولید مجدد همهٔ فایلهای گنجور رومیزی اطمینان دارید؟');
if (!ok) return;
var url = '?handler=ExportAll';
@ -349,10 +353,10 @@
type: "POST",
url: url,
error: function() {
alert('خطا رخ داد.')
upToast('خطا رخ داد.', 'error');
},
success: function() {
alert('فرایند تولید مجدد همهٔ فایلهای گنجور رومیزی شروع شد.')
upToast('فرایند تولید مجدد همهٔ فایلهای گنجور رومیزی شروع شد.', 'success');
},
});