whole project pushed
This commit is contained in:
116
Views/Panel/AddNews.cshtml
Normal file
116
Views/Panel/AddNews.cshtml
Normal file
@ -0,0 +1,116 @@
|
||||
@model boilerplate.Controllers.PanelController.AddNewsViewModel
|
||||
@{
|
||||
ViewBag.Title = Model.News.News_ID == 0 ? "افزودن خبر جدید" : "ویرایش خبر";
|
||||
Layout = "~/Views/_PanelSideBar.cshtml";
|
||||
}
|
||||
|
||||
@section Heads {
|
||||
<!-- Add CSS for Select2 library -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
||||
<script src="https://cdn.ckeditor.com/4.16.2/standard/ckeditor.js"></script>
|
||||
}
|
||||
|
||||
<div class="card card-custom">
|
||||
<div class="card-header">
|
||||
<h3 class="card-label">@ViewBag.Title</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@using (Html.BeginForm("AddNews", "Panel", FormMethod.Post, new { enctype = "multipart/form-data" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
@Html.HiddenFor(model => model.News.News_ID)
|
||||
@Html.HiddenFor(model => model.News.News_IMG)
|
||||
|
||||
if (!ViewData.ModelState.IsValid)
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
@Html.ValidationSummary(false)
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="form-group">
|
||||
<label>عنوان خبر</label>
|
||||
@Html.EditorFor(model => model.News.News_Title, new { htmlAttributes = new { @class = "form-control" } })
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>دستهبندیها</label>
|
||||
<select name="selectedCategories" class="form-control select2-categories" multiple="multiple">
|
||||
@{
|
||||
var selectedCategories = (Model.News.News_Category ?? "").Split(',');
|
||||
}
|
||||
@foreach (var category in Model.AllCategories)
|
||||
{
|
||||
<option value="@category.Item_Title" @(selectedCategories.Contains(category.Item_Title) ? "selected" : "")>@category.Item_Title</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>تگها</label>
|
||||
<select name="selectedTags" class="form-control select2-tags" multiple="multiple">
|
||||
@{
|
||||
var selectedTags = (Model.News.News_Tag ?? "").Split(',');
|
||||
}
|
||||
@foreach (var tag in Model.AllTags)
|
||||
{
|
||||
<option value="@tag.Item_Title" @(selectedTags.Contains(tag.Item_Title) ? "selected" : "")>@tag.Item_Title</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>خلاصه خبر</label>
|
||||
@Html.TextAreaFor(model => model.News.News_Summary, new { @class = "form-control", rows = 3 })
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>توضیحات کامل</label>
|
||||
@Html.TextAreaFor(model => model.News.News_Description, new { @class = "form-control", id = "newsDescriptionEditor" })
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>تصویر شاخص خبر</label>
|
||||
<input type="file" name="imageFile" class="form-control-file" accept="image/*" />
|
||||
@if (!string.IsNullOrEmpty(Model.News.News_IMG))
|
||||
{
|
||||
<div class="mt-2">
|
||||
<span>تصویر فعلی:</span>
|
||||
<img src="~/Media/News/@Model.News.News_IMG" style="width: 150px; height: auto;" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-right">
|
||||
<button type="submit" class="btn btn-primary mr-2">ذخیره</button>
|
||||
<a href="@Url.Action("NewsList", "Panel")" class="btn btn-secondary">انصراف</a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Script {
|
||||
<!-- کتابخانه Select2 (فرض بر این است که jQuery در لایوت اصلی شما لود شده است) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
// --- FIXED: Separate initialization for Categories and Tags ---
|
||||
|
||||
// Initialize Select2 for CATEGORIES (without the ability to add new ones)
|
||||
$('.select2-categories').select2({
|
||||
placeholder: "یک یا چند دسته بندی انتخاب کنید",
|
||||
dir: "rtl"
|
||||
});
|
||||
|
||||
// Initialize Select2 for TAGS (NOW also without the ability to add new ones)
|
||||
$('.select2-tags').select2({
|
||||
placeholder: "یک یا چند تگ انتخاب کنید",
|
||||
dir: "rtl"
|
||||
// The 'tags: true' option has been removed
|
||||
});
|
||||
|
||||
// Initialize CKEditor
|
||||
CKEDITOR.replace('newsDescriptionEditor', { language: 'fa' });
|
||||
});
|
||||
</script>
|
||||
}
|
||||
300
Views/Panel/ClientManagement.cshtml
Normal file
300
Views/Panel/ClientManagement.cshtml
Normal file
@ -0,0 +1,300 @@
|
||||
@model IEnumerable<boilerplate.Models.Client>
|
||||
@{
|
||||
ViewBag.Title = "مدیریت مشتریان";
|
||||
Layout = "~/Views/_PanelSideBar.cshtml";
|
||||
var currentUser = Session["User"] as boilerplate.Models.User;
|
||||
}
|
||||
|
||||
<div class="card card-custom">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">@ViewBag.Title</h3>
|
||||
<div class="card-toolbar">
|
||||
<button type="button" class="btn btn-success font-weight-bolder mr-2" onclick="exportClients(event)">
|
||||
<i class="fa fa-file-excel"></i>
|
||||
خروجی اکسل
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary font-weight-bolder" data-toggle="modal" data-target="#importModal">
|
||||
<i class="fa fa-file-import"></i>
|
||||
ورود از اکسل
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>نام</th>
|
||||
<th>نام خانوادگی</th>
|
||||
<th>شماره تلفن</th>
|
||||
<th>نام کاربری</th>
|
||||
<th>ایمیل</th>
|
||||
<th>عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var client in Model)
|
||||
{
|
||||
<tr id="client-row-@client.Client_Id">
|
||||
<td data-prop="Client_Name">@client.Client_Name</td>
|
||||
<td data-prop="Client_LastName">@client.Client_LastName</td>
|
||||
<td data-prop="Client_PhoneNumber">@client.Client_PhoneNumber</td>
|
||||
<td data-prop="Client_UserName">@client.Client_UserName</td>
|
||||
<td data-prop="Client_Email">@client.Client_Email</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-clean btn-icon" title="ویرایش" onclick="openEditModal(@client.Client_Id)">
|
||||
<i class="fa fa-edit text-primary"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-clean btn-icon" title="حذف" onclick="deleteClient(@client.Client_Id)">
|
||||
<i class="fa fa-trash text-danger"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal for Excel Upload -->
|
||||
<div class="modal fade" id="importModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">ورود مشتریان از فایل اکسل</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>فایل اکسل خود را انتخاب کنید. ستونها باید به ترتیب زیر باشند: نام، نام خانوادگی، شماره تلفن، نام کاربری، ایمیل.</p>
|
||||
<input type="file" id="excelFileInput" class="form-control-file" accept=".xlsx" />
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">انصراف</button>
|
||||
<button type="button" class="btn btn-primary" id="importButton" onclick="importClients(event)">بارگذاری</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- *** ADDED: Modal for Editing a Client *** -->
|
||||
<div class="modal fade" id="editClientModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">ویرایش اطلاعات مشتری</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editClientForm">
|
||||
<input type="hidden" id="editClientId" />
|
||||
<div class="form-group">
|
||||
<label>نام</label>
|
||||
<input type="text" id="editClientName" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>نام خانوادگی</label>
|
||||
<input type="text" id="editClientLastName" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>شماره تلفن</label>
|
||||
<input type="text" id="editClientPhone" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>نام کاربری</label>
|
||||
<input type="text" id="editClientUsername" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>ایمیل</label>
|
||||
<input type="email" id="editClientEmail" class="form-control" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">انصراف</button>
|
||||
<button type="button" class="btn btn-primary" id="saveChangesBtn" onclick="saveChanges()">ذخیره تغییرات</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@section Script {
|
||||
<script>
|
||||
const authData = {
|
||||
UserId: @(currentUser?.User_Id ?? 0),
|
||||
Token: "@(currentUser?.User_Token ?? "")"
|
||||
};
|
||||
|
||||
// *** FIXED: Re-added the full logic for importClients ***
|
||||
function importClients(event) {
|
||||
const fileInput = document.getElementById('excelFileInput');
|
||||
if (fileInput.files.length === 0) {
|
||||
toastr.error("لطفاً یک فایل اکسل انتخاب کنید.");
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("Auth", JSON.stringify(authData));
|
||||
formData.append("ExcelFile", fileInput.files[0]);
|
||||
|
||||
const importBtn = event.target;
|
||||
importBtn.disabled = true;
|
||||
importBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> در حال بارگذاری...';
|
||||
|
||||
fetch('/api/Client/Import', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.Status === "Success") {
|
||||
toastr.success(data.Message || "فایل با موفقیت بارگذاری شد.");
|
||||
setTimeout(() => location.reload(), 2000);
|
||||
} else {
|
||||
toastr.error("خطا در بارگذاری فایل: " + (data.Message || data.Status));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
toastr.error("خطا در برقراری ارتباط با سرور.");
|
||||
})
|
||||
.finally(() => {
|
||||
importBtn.disabled = false;
|
||||
importBtn.innerHTML = 'بارگذاری';
|
||||
$('#importModal').modal('hide');
|
||||
});
|
||||
}
|
||||
|
||||
// *** FIXED: Re-added the full logic for exportClients ***
|
||||
function exportClients(event) {
|
||||
const exportBtn = event.target;
|
||||
exportBtn.disabled = true;
|
||||
exportBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> در حال آماده سازی...';
|
||||
|
||||
fetch('/api/Client/Export', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(authData)
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) return response.blob();
|
||||
throw new Error('Network response was not ok.');
|
||||
})
|
||||
.then(blob => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = url;
|
||||
a.download = `Clients_${new Date().toISOString().slice(0, 10)}.xlsx`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
toastr.success("فایل اکسل آماده دانلود است.");
|
||||
})
|
||||
.catch(error => {
|
||||
toastr.error("خطا در ساخت فایل اکسل.");
|
||||
})
|
||||
.finally(() => {
|
||||
exportBtn.disabled = false;
|
||||
exportBtn.innerHTML = '<i class="fa fa-file-excel"></i> خروجی اکسل';
|
||||
});
|
||||
}
|
||||
|
||||
// Function to open the edit modal and fetch client data
|
||||
function openEditModal(clientId) {
|
||||
fetch(`/api/Client/Get/${clientId}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(authData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(client => {
|
||||
$('#editClientId').val(client.Client_Id);
|
||||
$('#editClientName').val(client.Client_Name);
|
||||
$('#editClientLastName').val(client.Client_LastName);
|
||||
$('#editClientPhone').val(client.Client_PhoneNumber);
|
||||
$('#editClientUsername').val(client.Client_UserName);
|
||||
$('#editClientEmail').val(client.Client_Email);
|
||||
|
||||
$('#editClientModal').modal('show');
|
||||
})
|
||||
.catch(error => toastr.error("خطا در دریافت اطلاعات مشتری."));
|
||||
}
|
||||
|
||||
// Function to save the changes from the edit modal
|
||||
function saveChanges() {
|
||||
const saveBtn = document.getElementById('saveChangesBtn');
|
||||
saveBtn.disabled = true;
|
||||
saveBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> در حال ذخیره...';
|
||||
|
||||
const clientData = {
|
||||
Client_Id: parseInt($('#editClientId').val()),
|
||||
Client_Name: $('#editClientName').val(),
|
||||
Client_LastName: $('#editClientLastName').val(),
|
||||
Client_PhoneNumber: $('#editClientPhone').val(),
|
||||
Client_UserName: $('#editClientUsername').val(),
|
||||
Client_Email: $('#editClientEmail').val()
|
||||
};
|
||||
|
||||
const updateModel = {
|
||||
Auth: authData,
|
||||
Client: clientData
|
||||
};
|
||||
|
||||
fetch('/api/Client/Update', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(updateModel)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.Status === "Success") {
|
||||
toastr.success("اطلاعات مشتری با موفقیت ویرایش شد.");
|
||||
const row = $(`#client-row-${clientData.Client_Id}`);
|
||||
row.find('[data-prop="Client_Name"]').text(clientData.Client_Name);
|
||||
row.find('[data-prop="Client_LastName"]').text(clientData.Client_LastName);
|
||||
row.find('[data-prop="Client_PhoneNumber"]').text(clientData.Client_PhoneNumber);
|
||||
row.find('[data-prop="Client_UserName"]').text(clientData.Client_UserName);
|
||||
row.find('[data-prop="Client_Email"]').text(clientData.Client_Email);
|
||||
$('#editClientModal').modal('hide');
|
||||
} else {
|
||||
toastr.error("خطا در ویرایش: " + (data.Message || data.Status));
|
||||
}
|
||||
})
|
||||
.catch(error => toastr.error("خطا در برقراری ارتباط با سرور."))
|
||||
.finally(() => {
|
||||
saveBtn.disabled = false;
|
||||
saveBtn.innerHTML = 'ذخیره تغییرات';
|
||||
});
|
||||
}
|
||||
|
||||
// JavaScript function to delete a client
|
||||
function deleteClient(clientId) {
|
||||
if (!confirm("آیا از حذف این مشتری مطمئن هستید؟")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteAuthData = { ...authData, Id: clientId };
|
||||
|
||||
fetch('/api/Client/Delete', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(deleteAuthData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.Status === "Success") {
|
||||
toastr.success("مشتری با موفقیت حذف شد.");
|
||||
$("#client-row-" + clientId).fadeOut(500, function() { $(this).remove(); });
|
||||
} else {
|
||||
toastr.error("خطا در حذف مشتری: " + (data.Message || data.Status));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
toastr.error("خطا در برقراری ارتباط با سرور.");
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@ -70,22 +70,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 form-group">
|
||||
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0">
|
||||
@*<div class="col-lg-6 form-group">
|
||||
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0" style="height:144px;">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center p-5">
|
||||
<div class="mr-6">
|
||||
<i class="fa fa-comments text-primary icon-3x"></i>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<a href="~/panel/Chats" class="text-gray text-hover-primary font-weight-bold font-size-h4 mb-3">
|
||||
<a href="" class="text-gray text-hover-primary font-weight-bold font-size-h4 mb-3">
|
||||
تالار گفتگو
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>*@
|
||||
@*<div class="col-lg-4 form-group">
|
||||
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0">
|
||||
<div class="card-body">
|
||||
@ -118,6 +118,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 form-group">
|
||||
<div class="card card-custom wave wave-animate-slow wave-primary mb-8 mb-lg-0">
|
||||
<div class="card-body" style="height:143px;">
|
||||
<div class="d-flex align-items-center p-5">
|
||||
<div class="mr-6">
|
||||
<i class="fa fa-newspaper text-primary icon-3x"></i>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<a href="~/panel/NewsList" class="text-gray text-hover-primary font-weight-bold font-size-h4 mb-3">مدیریت اخبار</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
@ -128,4 +143,5 @@
|
||||
</div>
|
||||
}
|
||||
@section Script{
|
||||
|
||||
}
|
||||
|
||||
122
Views/Panel/Items.cshtml
Normal file
122
Views/Panel/Items.cshtml
Normal file
@ -0,0 +1,122 @@
|
||||
@model IEnumerable<boilerplate.Models.Item>
|
||||
@{
|
||||
ViewBag.Title = ViewBag.PageTitle;
|
||||
Layout = "~/Views/_PanelSideBar.cshtml";
|
||||
var itemType = (int)ViewBag.ItemType;
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<!-- Add New Item Form -->
|
||||
<div class="col-md-4">
|
||||
<div class="card card-custom">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">افزودن آیتم جدید</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@using (Html.BeginForm("AddItem", "Panel", FormMethod.Post))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
@Html.Hidden("Item_Type", itemType)
|
||||
<div class="form-group">
|
||||
<label>@ViewBag.NewItemLabel</label>
|
||||
<input type="text" name="Item_Title" class="form-control" required />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">افزودن</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List of Existing Items -->
|
||||
<div class="col-md-8">
|
||||
<div class="card card-custom">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">@ViewBag.PageTitle</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>نام</th>
|
||||
<th style="width: 120px;">عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr id="item-@item.Item_Id">
|
||||
<td>
|
||||
<span id="title-text-@item.Item_Id">@item.Item_Title</span>
|
||||
<input type="text" id="title-input-@item.Item_Id" class="form-control d-none" value="@item.Item_Title" />
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-clean btn-icon" title="ویرایش" id="edit-btn-@item.Item_Id" onclick="editItem(@item.Item_Id)">
|
||||
<i class="fa fa-edit text-primary"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-clean btn-icon d-none" title="ذخیره" id="save-btn-@item.Item_Id" onclick="saveItem(@item.Item_Id)">
|
||||
<i class="fa fa-save text-success"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-clean btn-icon" title="حذف" onclick="deleteItem(@item.Item_Id)">
|
||||
<i class="fa fa-trash text-danger"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Script {
|
||||
<script>
|
||||
function editItem(id) {
|
||||
// مخفی کردن متن و نمایش کادر ویرایش
|
||||
$('#title-text-' + id).addClass('d-none');
|
||||
$('#title-input-' + id).removeClass('d-none').focus();
|
||||
|
||||
// مخفی کردن دکمه ویرایش و نمایش دکمه ذخیره
|
||||
$('#edit-btn-' + id).addClass('d-none');
|
||||
$('#save-btn-' + id).removeClass('d-none');
|
||||
}
|
||||
|
||||
function saveItem(id) {
|
||||
var newTitle = $('#title-input-' + id).val();
|
||||
|
||||
if (!newTitle.trim()) {
|
||||
toastr.error("نام نمی تواند خالی باشد.");
|
||||
return;
|
||||
}
|
||||
|
||||
$.post("@Url.Action("UpdateItem", "Panel")", { id: id, newTitle: newTitle }, function(data) {
|
||||
if (data.success) {
|
||||
// آپدیت متن و بازگشت به حالت نمایش
|
||||
$('#title-text-' + id).text(newTitle).removeClass('d-none');
|
||||
$('#title-input-' + id).addClass('d-none');
|
||||
|
||||
$('#edit-btn-' + id).removeClass('d-none');
|
||||
$('#save-btn-' + id).addClass('d-none');
|
||||
toastr.success("آیتم با موفقیت ویرایش شد.");
|
||||
} else {
|
||||
toastr.error("خطا در ویرایش: " + (data.message || ""));
|
||||
}
|
||||
}).fail(function() {
|
||||
toastr.error("خطا در برقراری ارتباط با سرور.");
|
||||
});
|
||||
}
|
||||
|
||||
function deleteItem(id) {
|
||||
if (confirm("آیا از حذف این آیتم مطمئن هستید؟")) {
|
||||
$.post("@Url.Action("DeleteItem", "Panel")", { id: id }, function(data) {
|
||||
if (data.success) {
|
||||
$("#item-" + id).fadeOut();
|
||||
toastr.success("آیتم با موفقیت حذف شد.");
|
||||
} else {
|
||||
toastr.error("خطا در حذف آیتم.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@ -128,7 +128,12 @@
|
||||
toastr.success('ورود با موفقیت انجام شد !!!');
|
||||
setTimeout(function () {
|
||||
if (Return == '') {
|
||||
location.href = "Index";
|
||||
if (data.role == 'Admin') {
|
||||
location.href = "Index";
|
||||
}
|
||||
else {
|
||||
location.href = '@Url.Action("AllNews", "Home")';
|
||||
}
|
||||
} else {
|
||||
location.href = Return;
|
||||
}
|
||||
@ -150,7 +155,6 @@
|
||||
}).always(function () {
|
||||
});
|
||||
} else {
|
||||
|
||||
toastr.error('کد تایید را وارد کنید.');
|
||||
}
|
||||
}
|
||||
|
||||
77
Views/Panel/NewsList.cshtml
Normal file
77
Views/Panel/NewsList.cshtml
Normal file
@ -0,0 +1,77 @@
|
||||
@model IEnumerable<boilerplate.Models.News>
|
||||
@{
|
||||
ViewBag.Title = "لیست اخبار";
|
||||
Layout = "~/Views/_PanelSideBar.cshtml";
|
||||
}
|
||||
|
||||
<div class="card card-custom">
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<h3 class="card-label">@ViewBag.Title</h3>
|
||||
</div>
|
||||
<div class="card-toolbar">
|
||||
<a href="@Url.Action("AddNews", "Panel")" class="btn btn-primary font-weight-bolder">
|
||||
<i class="fa fa-plus"></i>
|
||||
افزودن خبر جدید
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>تصویر</th>
|
||||
<th>عنوان خبر</th>
|
||||
<th>خلاصه</th>
|
||||
<th>تاریخ ایجاد</th>
|
||||
<th>عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model)
|
||||
{
|
||||
<tr id="news-row-@item.News_ID">
|
||||
<td>
|
||||
<img src="~/Media/News/@item.News_IMG" alt="News Image" style="width: 100px; height: auto; border-radius: 8px;"
|
||||
onerror="this.onerror=null;this.src='/Media/default-image.png';" />
|
||||
</td>
|
||||
<td>@item.News_Title</td>
|
||||
<td>@item.News_Summary</td>
|
||||
<td>
|
||||
@(item.News_CreateDate > DateTime.MinValue ? new boilerplate.Models.Functions().ConvertToPersianDate(item.News_CreateDate) : "")
|
||||
</td>
|
||||
<td>
|
||||
<a href="@Url.Action("AddNews", "Panel", new { id = item.News_ID })" class="btn btn-sm btn-clean btn-icon" title="ویرایش">
|
||||
<i class="fa fa-edit text-primary"></i>
|
||||
</a>
|
||||
<button class="btn btn-sm btn-clean btn-icon" title="حذف" onclick="deleteNews(@item.News_ID)">
|
||||
<i class="fa fa-trash text-danger"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Script {
|
||||
<script>
|
||||
function deleteNews(id) {
|
||||
if (confirm("آیا از حذف این خبر مطمئن هستید؟ این عملیات قابل بازگشت نیست.")) {
|
||||
$.post("@Url.Action("DeleteNews", "Panel")", { id: id }, function(data) {
|
||||
if (data.success) {
|
||||
$("#news-row-" + id).fadeOut(500, function() { $(this).remove(); });
|
||||
toastr.success("خبر با موفقیت حذف شد.");
|
||||
} else {
|
||||
toastr.error("خطا در حذف خبر. " + (data.message || ""));
|
||||
}
|
||||
}).fail(function() {
|
||||
toastr.error("خطا در برقراری ارتباط با سرور.");
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@ -6,7 +6,6 @@
|
||||
ViewBag.Title = Model.User_Id == 0 ? "کاربر جدید" : Model.User_Name + " " + Model.User_Family;
|
||||
Layout = "~/Views/_PanelSideBar.cshtml";
|
||||
Functions functions = new Functions();
|
||||
|
||||
}
|
||||
<form autocomplete="off">
|
||||
<div class="row">
|
||||
@ -165,6 +164,13 @@
|
||||
تنظیمات
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox-list mb-3">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="chkAccess" value="ManageItems" @(Model.User_Access != null && Model.User_Access.Contains("ManageItems") ? "checked" : "") />
|
||||
<span></span>
|
||||
مدیریت دستهبندی و تگ
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -219,6 +225,14 @@
|
||||
});
|
||||
|
||||
function Save() {
|
||||
// --- ADDED: Client-side validation for image on new users ---
|
||||
var isNew = (Id === 0);
|
||||
var fileInput = $("#fuImage")[0];
|
||||
if (isNew && fileInput.files.length === 0) {
|
||||
toastr.error("لطفاً یک تصویر برای کاربر انتخاب کنید.");
|
||||
return; // Stop the function if image is missing
|
||||
}
|
||||
|
||||
let Phone = $("#txtPhone").val().trim();
|
||||
if (Phone.length) {
|
||||
let Access = "";
|
||||
@ -238,7 +252,7 @@
|
||||
$("#btnSave").css("opacity", 0.5);
|
||||
$("#btnSave").attr("onclick", "");
|
||||
let model = {
|
||||
Auth: { UserId: UserId, Token: Token },
|
||||
Auth: { UserId: @User.User_Id, Token: "@User.User_Token" },
|
||||
Id: Id,
|
||||
Name: $("#txtName").val().trim(),
|
||||
Family: $("#txtFamily").val().trim(),
|
||||
@ -255,12 +269,18 @@
|
||||
ajax.addEventListener("load", function (event) {
|
||||
$("#btnSave").css("opacity", 1);
|
||||
let data = JSON.parse(event.target.responseText);
|
||||
|
||||
if (data.Status == "Success") {
|
||||
toastr.success("ذخیره سازی با موفقیت انجام شد");
|
||||
setTimeout(function () {
|
||||
location.href = `../Panel/User/${data.Result}`;
|
||||
}, 1500);
|
||||
} else {
|
||||
}
|
||||
else if (data.Status == "DuplicatePhone") {
|
||||
$("#btnSave").attr("onclick", "Save()"); // Re-enable button
|
||||
toastr.error("این شماره تلفن قبلاً در سیستم ثبت شده است!");
|
||||
}
|
||||
else {
|
||||
$("#btnSave").attr("onclick", "Save()");
|
||||
console.log(data);
|
||||
toastr.warning("خطا هنگام ذخیره سازی اطلاعات");
|
||||
@ -291,7 +311,7 @@
|
||||
confirmButtonText: 'بله'
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.post("../api/User/Delete", { Id: Id, UserId: UserId, Token: Token }).done(function (data) {
|
||||
$.post("../api/User/Delete", { Id: Id, UserId: @User.User_Id, Token: "@User.User_Token" }).done(function (data) {
|
||||
if (data.Status == "Success") {
|
||||
$(".btns").remove();
|
||||
toastr.success("حذف با موفقیت انجام شد");
|
||||
|
||||
Reference in New Issue
Block a user