Implement camera bug report system with CRUD operations and logging
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
|
||||
namespace ServiceHost.Areas.AdminNew.Pages.BugReport
|
||||
{
|
||||
public class BugReportPageModel : PageModel
|
||||
{
|
||||
protected readonly ICameraBugReportApplication _bugReportApplication;
|
||||
|
||||
public BugReportPageModel(ICameraBugReportApplication bugReportApplication)
|
||||
{
|
||||
_bugReportApplication = bugReportApplication;
|
||||
}
|
||||
|
||||
public List<CameraBugReportViewModel> BugReports { get; set; } = new();
|
||||
public CameraBugReportDetailViewModel BugReportDetails { get; set; }
|
||||
|
||||
protected List<CameraBugReportViewModel> GetBugReportsList(CameraBugReportSearchModel searchModel)
|
||||
{
|
||||
return _bugReportApplication.GetAll(searchModel);
|
||||
}
|
||||
|
||||
protected CameraBugReportDetailViewModel GetBugReportDetails(long id)
|
||||
{
|
||||
return _bugReportApplication.GetDetails(id);
|
||||
}
|
||||
|
||||
protected bool IsExist(long id)
|
||||
{
|
||||
return _bugReportApplication.IsExist(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
ServiceHost/Areas/AdminNew/Pages/BugReport/Delete.cshtml
Normal file
52
ServiceHost/Areas/AdminNew/Pages/BugReport/Delete.cshtml
Normal file
@@ -0,0 +1,52 @@
|
||||
@page "{id:long}"
|
||||
@model ServiceHost.Areas.AdminNew.Pages.BugReport.DeleteModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "حذف گزارش خرابی";
|
||||
}
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<a asp-page="./Index" class="btn btn-secondary mb-3">بازگشت</a>
|
||||
|
||||
@if (Model.BugReportDetails != null)
|
||||
{
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h5 class="mb-0">تأیید حذف</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-warning">
|
||||
<strong>هشدار:</strong> آیا مطمئن هستید که میخواهید این گزارش خرابی را حذف کنید؟ این عمل غیرقابل بازگشت است.
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>عنوان:</strong></label>
|
||||
<p>@Model.BugReportDetails.Title</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>کاربر:</strong></label>
|
||||
<p>@Model.BugReportDetails.UserEmail</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>تاریخ گزارش:</strong></label>
|
||||
<p>@Model.BugReportDetails.CreationDate.ToString("yyyy-MM-dd HH:mm:ss")</p>
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="id" value="@Model.BugReportDetails.Id" />
|
||||
<button type="submit" class="btn btn-danger">حذف</button>
|
||||
<a asp-page="./Index" class="btn btn-secondary">انصراف</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
گزارش خرابی یافت نشد
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
33
ServiceHost/Areas/AdminNew/Pages/BugReport/Delete.cshtml.cs
Normal file
33
ServiceHost/Areas/AdminNew/Pages/BugReport/Delete.cshtml.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
namespace ServiceHost.Areas.AdminNew.Pages.BugReport;
|
||||
|
||||
public class DeleteModel : BugReportPageModel
|
||||
{
|
||||
public DeleteModel(ICameraBugReportApplication bugReportApplication) : base(bugReportApplication)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnGet(long id)
|
||||
{
|
||||
BugReportDetails = GetBugReportDetails(id);
|
||||
if (BugReportDetails == null)
|
||||
{
|
||||
TempData["ErrorMessage"] = "گزارش خرابی یافت نشد";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public IActionResult OnPost(long id)
|
||||
{
|
||||
var result = _bugReportApplication.Delete(id);
|
||||
if (result.IsSuccedded)
|
||||
{
|
||||
TempData["SuccessMessage"] = result.Message;
|
||||
return RedirectToPage("./Index");
|
||||
}
|
||||
|
||||
TempData["ErrorMessage"] = result.Message;
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
238
ServiceHost/Areas/AdminNew/Pages/BugReport/Details.cshtml
Normal file
238
ServiceHost/Areas/AdminNew/Pages/BugReport/Details.cshtml
Normal file
@@ -0,0 +1,238 @@
|
||||
@page "{id:long}"
|
||||
@model ServiceHost.Areas.AdminNew.Pages.BugReport.DetailsModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "جزئیات گزارش خرابی";
|
||||
}
|
||||
|
||||
@if (Model.BugReportDetails == null)
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
گزارش خرابی یافت نشد
|
||||
</div>
|
||||
<a asp-page="./Index" class="btn btn-secondary">بازگشت</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="container-fluid mt-4">
|
||||
<a asp-page="./Index" class="btn btn-secondary mb-3">بازگشت</a>
|
||||
|
||||
<div class="row">
|
||||
<!-- معلومات اصلی -->
|
||||
<div class="col-md-8">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">@Model.BugReportDetails.Title</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-3">کاربر:</dt>
|
||||
<dd class="col-sm-9">@Model.BugReportDetails.UserEmail</dd>
|
||||
|
||||
<dt class="col-sm-3">نوع:</dt>
|
||||
<dd class="col-sm-9">
|
||||
<span class="badge bg-info">@Model.BugReportDetails.Type</span>
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-3">اولویت:</dt>
|
||||
<dd class="col-sm-9">
|
||||
@switch (Model.BugReportDetails.Priority)
|
||||
{
|
||||
case CameraBugPriority.Critical:
|
||||
<span class="badge bg-danger">بحرانی</span>
|
||||
break;
|
||||
case CameraBugPriority.High:
|
||||
<span class="badge bg-warning">بالا</span>
|
||||
break;
|
||||
case CameraBugPriority.Medium:
|
||||
<span class="badge bg-primary">متوسط</span>
|
||||
break;
|
||||
case CameraBugPriority.Low:
|
||||
<span class="badge bg-success">پایین</span>
|
||||
break;
|
||||
}
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-3">وضعیت:</dt>
|
||||
<dd class="col-sm-9">
|
||||
@switch (Model.BugReportDetails.Status)
|
||||
{
|
||||
case CameraBugReportStatus.Open:
|
||||
<span class="badge bg-secondary">باز</span>
|
||||
break;
|
||||
case CameraBugReportStatus.InProgress:
|
||||
<span class="badge bg-warning">در حال بررسی</span>
|
||||
break;
|
||||
case CameraBugReportStatus.Fixed:
|
||||
<span class="badge bg-info">رفع شده</span>
|
||||
break;
|
||||
case CameraBugReportStatus.Closed:
|
||||
<span class="badge bg-success">بسته شده</span>
|
||||
break;
|
||||
case CameraBugReportStatus.Reopened:
|
||||
<span class="badge bg-danger">مجدداً باز</span>
|
||||
break;
|
||||
}
|
||||
</dd>
|
||||
|
||||
<dt class="col-sm-3">تاریخ گزارش:</dt>
|
||||
<dd class="col-sm-9">@Model.BugReportDetails.CreationDate.ToString("yyyy-MM-dd HH:mm:ss")</dd>
|
||||
|
||||
<dt class="col-sm-3">آخرین بهروزرسانی:</dt>
|
||||
<dd class="col-sm-9">@(Model.BugReportDetails.UpdateDate?.ToString("yyyy-MM-dd HH:mm:ss") ?? "-")</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- توضیحات -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<h6 class="mb-0">توضیحات</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>@Html.Raw(Model.BugReportDetails.Description.Replace(Environment.NewLine, "<br>"))</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stack Trace -->
|
||||
@if (!string.IsNullOrEmpty(Model.BugReportDetails.StackTrace))
|
||||
{
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h6 class="mb-0">Stack Trace</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre style="background-color: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto;">@Model.BugReportDetails.StackTrace</pre>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- لاگها -->
|
||||
@if (Model.BugReportDetails.Logs != null && Model.BugReportDetails.Logs.Count > 0)
|
||||
{
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-warning">
|
||||
<h6 class="mb-0">لاگها (@Model.BugReportDetails.Logs.Count)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled">
|
||||
@foreach (var log in Model.BugReportDetails.Logs)
|
||||
{
|
||||
<li style="padding: 5px 0; border-bottom: 1px solid #eee;">
|
||||
<small>@log</small>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- عکسها -->
|
||||
@if (Model.BugReportDetails.Screenshots != null && Model.BugReportDetails.Screenshots.Count > 0)
|
||||
{
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h6 class="mb-0">عکسهای ضمیمه شده (@Model.BugReportDetails.Screenshots.Count)</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
@foreach (var screenshot in Model.BugReportDetails.Screenshots)
|
||||
{
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card">
|
||||
<img src="data:image/jpeg;base64,@screenshot.Base64Data" class="card-img-top" style="max-height: 300px; object-fit: cover;">
|
||||
<div class="card-footer">
|
||||
<small class="text-muted">@screenshot.FileName</small><br>
|
||||
<small class="text-muted">@screenshot.UploadDate.ToString("yyyy-MM-dd HH:mm")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- معلومات دستگاه -->
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h6 class="mb-0">معلومات دستگاه</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row" style="font-size: 0.9rem;">
|
||||
<dt class="col-6">مدل:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.DeviceModel</dd>
|
||||
|
||||
<dt class="col-6">سیستمعامل:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.OsVersion</dd>
|
||||
|
||||
<dt class="col-6">پلتفرم:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.Platform</dd>
|
||||
|
||||
<dt class="col-6">سازنده:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.Manufacturer</dd>
|
||||
|
||||
<dt class="col-6">شناسه دستگاه:</dt>
|
||||
<dd class="col-6"><small>@Model.BugReportDetails.DeviceId</small></dd>
|
||||
|
||||
<dt class="col-6">وضوح صفحه:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.ScreenResolution</dd>
|
||||
|
||||
<dt class="col-6">حافظه:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.MemoryInMB MB</dd>
|
||||
|
||||
<dt class="col-6">ذخیرهسازی:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.StorageInMB MB</dd>
|
||||
|
||||
<dt class="col-6">باتری:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.BatteryLevel %</dd>
|
||||
|
||||
<dt class="col-6">شارژ گیر:</dt>
|
||||
<dd class="col-6">@(Model.BugReportDetails.IsCharging ? "بله" : "خیر")</dd>
|
||||
|
||||
<dt class="col-6">شبکه:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.NetworkType</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- معلومات برنامه -->
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<h6 class="mb-0">معلومات برنامه</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<dl class="row" style="font-size: 0.9rem;">
|
||||
<dt class="col-6">نسخه:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.AppVersion</dd>
|
||||
|
||||
<dt class="col-6">بیلد:</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.BuildNumber</dd>
|
||||
|
||||
<dt class="col-6">پکیج:</dt>
|
||||
<dd class="col-6"><small>@Model.BugReportDetails.PackageName</small></dd>
|
||||
|
||||
<dt class="col-6">نسخه (Flavor):</dt>
|
||||
<dd class="col-6">@Model.BugReportDetails.Flavor</dd>
|
||||
|
||||
<dt class="col-6">نصب:</dt>
|
||||
<dd class="col-6"><small>@Model.BugReportDetails.InstallTime.ToString("yyyy-MM-dd")</small></dd>
|
||||
|
||||
<dt class="col-6">آپدیت:</dt>
|
||||
<dd class="col-6"><small>@Model.BugReportDetails.LastUpdateTime.ToString("yyyy-MM-dd")</small></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- عملیات -->
|
||||
<div class="mt-3">
|
||||
<a asp-page="./Edit" asp-route-id="@Model.BugReportDetails.Id" class="btn btn-warning w-100">ویرایش وضعیت و اولویت</a>
|
||||
<a asp-page="./Delete" asp-route-id="@Model.BugReportDetails.Id" class="btn btn-danger w-100 mt-2" onclick="return confirm('آیا مطمئن هستید؟');">حذف</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
19
ServiceHost/Areas/AdminNew/Pages/BugReport/Details.cshtml.cs
Normal file
19
ServiceHost/Areas/AdminNew/Pages/BugReport/Details.cshtml.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
|
||||
namespace ServiceHost.Areas.AdminNew.Pages.BugReport;
|
||||
|
||||
public class DetailsModel : BugReportPageModel
|
||||
{
|
||||
public DetailsModel(ICameraBugReportApplication bugReportApplication) : base(bugReportApplication)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnGet(long id)
|
||||
{
|
||||
BugReportDetails = GetBugReportDetails(id);
|
||||
if (BugReportDetails == null)
|
||||
{
|
||||
TempData["ErrorMessage"] = "گزارش خرابی یافت نشد";
|
||||
}
|
||||
}
|
||||
}
|
||||
75
ServiceHost/Areas/AdminNew/Pages/BugReport/Edit.cshtml
Normal file
75
ServiceHost/Areas/AdminNew/Pages/BugReport/Edit.cshtml
Normal file
@@ -0,0 +1,75 @@
|
||||
@page "{id:long}"
|
||||
@model ServiceHost.Areas.AdminNew.Pages.BugReport.EditModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "ویرایش گزارش خرابی";
|
||||
}
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<a asp-page="./Details" asp-route-id="@Model.Id" class="btn btn-secondary mb-3">بازگشت</a>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-warning text-white">
|
||||
<h5 class="mb-0">ویرایش وضعیت و اولویت</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (Model.BugReportDetail != null)
|
||||
{
|
||||
<form method="post">
|
||||
<input type="hidden" asp-for="Id" />
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>عنوان:</strong></label>
|
||||
<p>@Model.BugReportDetail.Title</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>کاربر:</strong></label>
|
||||
<p>@Model.BugReportDetail.UserEmail</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="Priority" class="form-label">اولویت</label>
|
||||
<select id="Priority" asp-for="Priority" class="form-control">
|
||||
<option value="1" selected="@(Model.Priority == CameraBugPriority.Critical)">بحرانی</option>
|
||||
<option value="2" selected="@(Model.Priority == CameraBugPriority.High)">بالا</option>
|
||||
<option value="3" selected="@(Model.Priority == CameraBugPriority.Medium)">متوسط</option>
|
||||
<option value="4" selected="@(Model.Priority == CameraBugPriority.Low)">پایین</option>
|
||||
</select>
|
||||
<span asp-validation-for="Priority" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="Status" class="form-label">وضعیت</label>
|
||||
<select id="Status" asp-for="Status" class="form-control">
|
||||
<option value="1" selected="@(Model.Status == CameraBugReportStatus.Open)">باز</option>
|
||||
<option value="2" selected="@(Model.Status == CameraBugReportStatus.InProgress)">در حال بررسی</option>
|
||||
<option value="3" selected="@(Model.Status == CameraBugReportStatus.Fixed)">رفع شده</option>
|
||||
<option value="4" selected="@(Model.Status == CameraBugReportStatus.Closed)">بسته شده</option>
|
||||
<option value="5" selected="@(Model.Status == CameraBugReportStatus.Reopened)">مجدداً باز</option>
|
||||
</select>
|
||||
<span asp-validation-for="Status" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button type="submit" class="btn btn-success">ذخیره تغییرات</button>
|
||||
<a asp-page="./Details" asp-route-id="@Model.Id" class="btn btn-secondary">انصراف</a>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
گزارش خرابی یافت نشد
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
62
ServiceHost/Areas/AdminNew/Pages/BugReport/Edit.cshtml.cs
Normal file
62
ServiceHost/Areas/AdminNew/Pages/BugReport/Edit.cshtml.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
|
||||
namespace ServiceHost.Areas.AdminNew.Pages.BugReport
|
||||
{
|
||||
public class EditModel : BugReportPageModel
|
||||
{
|
||||
public EditModel(ICameraBugReportApplication cameraBugReportApplication) : base(cameraBugReportApplication)
|
||||
{
|
||||
}
|
||||
|
||||
[BindProperty]
|
||||
public long Id { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public CameraBugPriority Priority { get; set; }
|
||||
|
||||
[BindProperty]
|
||||
public CameraBugReportStatus Status { get; set; }
|
||||
|
||||
public CameraBugReportDetailViewModel BugReportDetail { get; set; }
|
||||
|
||||
public void OnGet(long id)
|
||||
{
|
||||
BugReportDetail = GetBugReportDetails(id);
|
||||
if (BugReportDetail != null)
|
||||
{
|
||||
Id = BugReportDetail.Id;
|
||||
Priority = BugReportDetail.Priority;
|
||||
Status = BugReportDetail.Status;
|
||||
}
|
||||
else
|
||||
{
|
||||
TempData["ErrorMessage"] = "گزارش خرابی یافت نشد";
|
||||
}
|
||||
}
|
||||
|
||||
public IActionResult OnPost()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return Page();
|
||||
|
||||
var command = new EditCameraBugReportCommand()
|
||||
{
|
||||
Id = Id,
|
||||
Priority = Priority,
|
||||
Status = Status
|
||||
};
|
||||
|
||||
var result = _bugReportApplication.Edit(command);
|
||||
if (result.IsSuccedded)
|
||||
{
|
||||
TempData["SuccessMessage"] = result.Message;
|
||||
return RedirectToPage("./Details", new { id = Id });
|
||||
}
|
||||
|
||||
TempData["ErrorMessage"] = result.Message;
|
||||
return Page();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
181
ServiceHost/Areas/AdminNew/Pages/BugReport/Index.cshtml
Normal file
181
ServiceHost/Areas/AdminNew/Pages/BugReport/Index.cshtml
Normal file
@@ -0,0 +1,181 @@
|
||||
@page
|
||||
@model ServiceHost.Areas.AdminNew.Pages.BugReport.IndexModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "مدیریت گزارشهای خرابی";
|
||||
}
|
||||
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">لیست گزارشهای خرابی</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- فیلترها -->
|
||||
<form method="get" class="row g-3 mb-4">
|
||||
<div class="col-md-3">
|
||||
<label for="searchTerm" class="form-label">جستجو</label>
|
||||
<input type="text" class="form-control" id="searchTerm" name="searchTerm" value="@Model.SearchTerm" placeholder="عنوان، توضیحات، ایمیل...">
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
<label for="typeFilter" class="form-label">نوع</label>
|
||||
<select class="form-control" id="typeFilter" name="typeFilter">
|
||||
<option value="">همه</option>
|
||||
<option value="1" selected="@(Model.TypeFilter == 1)">کرش</option>
|
||||
<option value="2" selected="@(Model.TypeFilter == 2)">مشکل UI</option>
|
||||
<option value="3" selected="@(Model.TypeFilter == 3)">عملکرد</option>
|
||||
<option value="4" selected="@(Model.TypeFilter == 4)">فیچر</option>
|
||||
<option value="5" selected="@(Model.TypeFilter == 5)">شبکه</option>
|
||||
<option value="6" selected="@(Model.TypeFilter == 6)">دوربین</option>
|
||||
<option value="7" selected="@(Model.TypeFilter == 7)">تشخیص چهره</option>
|
||||
<option value="8" selected="@(Model.TypeFilter == 8)">دیتابیس</option>
|
||||
<option value="9" selected="@(Model.TypeFilter == 9)">لاگین</option>
|
||||
<option value="10" selected="@(Model.TypeFilter == 10)">سایر</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
<label for="priorityFilter" class="form-label">اولویت</label>
|
||||
<select class="form-control" id="priorityFilter" name="priorityFilter">
|
||||
<option value="">همه</option>
|
||||
<option value="1" selected="@(Model.PriorityFilter == 1)">بحرانی</option>
|
||||
<option value="2" selected="@(Model.PriorityFilter == 2)">بالا</option>
|
||||
<option value="3" selected="@(Model.PriorityFilter == 3)">متوسط</option>
|
||||
<option value="4" selected="@(Model.PriorityFilter == 4)">پایین</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2">
|
||||
<label for="statusFilter" class="form-label">وضعیت</label>
|
||||
<select class="form-control" id="statusFilter" name="statusFilter">
|
||||
<option value="">همه</option>
|
||||
<option value="1" selected="@(Model.StatusFilter == 1)">باز</option>
|
||||
<option value="2" selected="@(Model.StatusFilter == 2)">در حال بررسی</option>
|
||||
<option value="3" selected="@(Model.StatusFilter == 3)">رفع شده</option>
|
||||
<option value="4" selected="@(Model.StatusFilter == 4)">بسته شده</option>
|
||||
<option value="5" selected="@(Model.StatusFilter == 5)">مجدداً باز</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary w-100">جستجو</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- جدول -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>عنوان</th>
|
||||
<th>کاربر</th>
|
||||
<th>نوع</th>
|
||||
<th>اولویت</th>
|
||||
<th>وضعیت</th>
|
||||
<th>دستگاه</th>
|
||||
<th>نسخه</th>
|
||||
<th>تاریخ</th>
|
||||
<th>عملیات</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (Model.BugReports.Count > 0)
|
||||
{
|
||||
@foreach (var report in Model.BugReports)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<strong>@Html.DisplayFor(modelItem => report.Title)</strong>
|
||||
</td>
|
||||
<td>
|
||||
<small>@report.UserEmail</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info">@report.Type</span>
|
||||
</td>
|
||||
<td>
|
||||
@switch (report.Priority)
|
||||
{
|
||||
case CameraBugPriority.Critical:
|
||||
<span class="badge bg-danger">بحرانی</span>
|
||||
break;
|
||||
case CameraBugPriority.High:
|
||||
<span class="badge bg-warning">بالا</span>
|
||||
break;
|
||||
case CameraBugPriority.Medium:
|
||||
<span class="badge bg-primary">متوسط</span>
|
||||
break;
|
||||
case CameraBugPriority.Low:
|
||||
<span class="badge bg-success">پایین</span>
|
||||
break;
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@switch (report.Status)
|
||||
{
|
||||
case CameraBugReportStatus.Open:
|
||||
<span class="badge bg-secondary">باز</span>
|
||||
break;
|
||||
case CameraBugReportStatus.InProgress:
|
||||
<span class="badge bg-warning">در حال بررسی</span>
|
||||
break;
|
||||
case CameraBugReportStatus.Fixed:
|
||||
<span class="badge bg-info">رفع شده</span>
|
||||
break;
|
||||
case CameraBugReportStatus.Closed:
|
||||
<span class="badge bg-success">بسته شده</span>
|
||||
break;
|
||||
case CameraBugReportStatus.Reopened:
|
||||
<span class="badge bg-danger">مجدداً باز</span>
|
||||
break;
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
<small>@report.DeviceModel</small>
|
||||
</td>
|
||||
<td>
|
||||
<small>@report.AppVersion</small>
|
||||
</td>
|
||||
<td>
|
||||
<small>@report.CreationDate.ToString("yyyy-MM-dd HH:mm")</small>
|
||||
</td>
|
||||
<td>
|
||||
<a asp-page="./Details" asp-route-id="@report.Id" class="btn btn-sm btn-info">مشاهده</a>
|
||||
<a asp-page="./Edit" asp-route-id="@report.Id" class="btn btn-sm btn-warning">ویرایش</a>
|
||||
<a asp-page="./Delete" asp-route-id="@report.Id" class="btn btn-sm btn-danger" onclick="return confirm('آیا مطمئن هستید؟');">حذف</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<tr>
|
||||
<td colspan="9" class="text-center text-muted py-4">
|
||||
هیچ گزارش خرابی یافت نشد
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.table-hover tbody tr:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.badge {
|
||||
padding: 0.35rem 0.65rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
43
ServiceHost/Areas/AdminNew/Pages/BugReport/Index.cshtml.cs
Normal file
43
ServiceHost/Areas/AdminNew/Pages/BugReport/Index.cshtml.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
|
||||
namespace ServiceHost.Areas.AdminNew.Pages.BugReport
|
||||
{
|
||||
public class IndexModel : BugReportPageModel
|
||||
{
|
||||
public IndexModel(ICameraBugReportApplication bugReportApplication) : base(bugReportApplication)
|
||||
{
|
||||
}
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public int? TypeFilter { get; set; }
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public int? PriorityFilter { get; set; }
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public int? StatusFilter { get; set; }
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public string SearchTerm { get; set; }
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public int PageNumber { get; set; } = 1;
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
var searchModel = new CameraBugReportSearchModel()
|
||||
{
|
||||
Type = TypeFilter.HasValue ? (CameraBugReportType)TypeFilter.Value : null,
|
||||
Priority = PriorityFilter.HasValue ? (CameraBugPriority)PriorityFilter.Value : null,
|
||||
Status = StatusFilter.HasValue ? (CameraBugReportStatus)StatusFilter.Value : null,
|
||||
SearchTerm = SearchTerm ?? "",
|
||||
PageNumber = PageNumber > 0 ? PageNumber : 1,
|
||||
PageSize = 10
|
||||
};
|
||||
|
||||
BugReports = GetBugReportsList(searchModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using CompanyManagment.App.Contracts.RollCallEmployee;
|
||||
using CompanyManagment.App.Contracts.RollCallService;
|
||||
using CompanyManagment.App.Contracts.Employee;
|
||||
using CompanyManagment.App.Contracts.EmployeeFaceEmbedding;
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace ServiceHost.Areas.Camera.Controllers;
|
||||
@@ -38,6 +39,7 @@ public class CameraController : CameraBaseController
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly HttpClient _faceEmbeddingHttpClient;
|
||||
private readonly IAndroidApkVersionApplication _androidApkVersionApplication;
|
||||
private readonly ICameraBugReportApplication _cameraBugReportApplication;
|
||||
|
||||
public CameraController(IWebHostEnvironment webHostEnvironment,
|
||||
IConfiguration configuration,
|
||||
@@ -50,7 +52,10 @@ public class CameraController : CameraBaseController
|
||||
IAccountApplication accountApplication,
|
||||
IPasswordHasher passwordHasher,
|
||||
ICameraAccountApplication cameraAccountApplication,
|
||||
IEmployeeFaceEmbeddingApplication employeeFaceEmbeddingApplication, IHttpClientFactory httpClientFactory, IAndroidApkVersionApplication androidApkVersionApplication)
|
||||
IEmployeeFaceEmbeddingApplication employeeFaceEmbeddingApplication,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
IAndroidApkVersionApplication androidApkVersionApplication,
|
||||
ICameraBugReportApplication cameraBugReportApplication)
|
||||
{
|
||||
_webHostEnvironment = webHostEnvironment;
|
||||
_configuration = configuration;
|
||||
@@ -66,6 +71,7 @@ public class CameraController : CameraBaseController
|
||||
_employeeFaceEmbeddingApplication = employeeFaceEmbeddingApplication;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
_androidApkVersionApplication = androidApkVersionApplication;
|
||||
_cameraBugReportApplication = cameraBugReportApplication;
|
||||
_faceEmbeddingHttpClient = httpClientFactory.CreateClient();
|
||||
_faceEmbeddingHttpClient.BaseAddress = new Uri("http://localhost:8000/");
|
||||
_workshopId= authHelper.GetWorkshopId();
|
||||
@@ -335,12 +341,84 @@ public class CameraController : CameraBaseController
|
||||
_accountApplication.Logout();
|
||||
return new JsonResult(new { isSuccess = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ارسال گزارش خرابی از طرف دوربین
|
||||
/// </summary>
|
||||
[HttpPost("bug-report")]
|
||||
[AllowAnonymous]
|
||||
public IActionResult SubmitBugReport([FromBody] SubmitBugReportRequest request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(new { success = false, message = "دادههای ارسالی معتبر نیستند" });
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var command = new CreateCameraBugReportCommand
|
||||
{
|
||||
Title = request.Title,
|
||||
Description = request.Description,
|
||||
UserEmail = request.UserEmail,
|
||||
AccountId = request.AccountId,
|
||||
DeviceModel = request.DeviceInfo?.DeviceModel,
|
||||
OsVersion = request.DeviceInfo?.OsVersion,
|
||||
Platform = request.DeviceInfo?.Platform,
|
||||
Manufacturer = request.DeviceInfo?.Manufacturer,
|
||||
DeviceId = request.DeviceInfo?.DeviceId,
|
||||
ScreenResolution = request.DeviceInfo?.ScreenResolution,
|
||||
MemoryInMB = request.DeviceInfo?.MemoryInMB ?? 0,
|
||||
StorageInMB = request.DeviceInfo?.StorageInMB ?? 0,
|
||||
BatteryLevel = request.DeviceInfo?.BatteryLevel ?? 0,
|
||||
IsCharging = request.DeviceInfo?.IsCharging ?? false,
|
||||
NetworkType = request.DeviceInfo?.NetworkType,
|
||||
AppVersion = request.AppInfo?.AppVersion,
|
||||
BuildNumber = request.AppInfo?.BuildNumber,
|
||||
PackageName = request.AppInfo?.PackageName,
|
||||
InstallTime = request.AppInfo?.InstallTime ?? DateTime.Now,
|
||||
LastUpdateTime = request.AppInfo?.LastUpdateTime ?? DateTime.Now,
|
||||
Flavor = request.AppInfo?.Flavor,
|
||||
Type = (CameraBugReportType)request.Type,
|
||||
Priority = (CameraBugPriority)request.Priority,
|
||||
StackTrace = request.StackTrace,
|
||||
Logs = request.Logs,
|
||||
Screenshots = request.Screenshots
|
||||
};
|
||||
|
||||
var result = _cameraBugReportApplication.Create(command);
|
||||
|
||||
if (result.IsSuccedded)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
message = result.Message ?? "گزارش خرابی با موفقیت ارسال شد"
|
||||
});
|
||||
}
|
||||
|
||||
return BadRequest(new
|
||||
{
|
||||
success = false,
|
||||
message = result.Message ?? "خطا در ارسال گزارش خرابی"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new
|
||||
{
|
||||
success = false,
|
||||
message = $"خطا در ارسال گزارش خرابی: {ex.Message}"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RollCallExitRequest:RollCallEnterRequest
|
||||
{
|
||||
public long FlagId { get; set; }
|
||||
}
|
||||
|
||||
public class RollCallEnterRequest
|
||||
{
|
||||
public long EmployeeId { get; set; }
|
||||
@@ -352,4 +430,53 @@ public class CameraFlagRequest
|
||||
{
|
||||
public long EmployeeId { get; set; }
|
||||
public long WorkshopId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// درخواست ارسال گزارش خرابی از طرف دوربین
|
||||
/// </summary>
|
||||
public class SubmitBugReportRequest
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string UserEmail { get; set; }
|
||||
public long? AccountId { get; set; }
|
||||
public int Type { get; set; } // BugReportType enum value
|
||||
public int Priority { get; set; } // BugPriority enum value
|
||||
public string StackTrace { get; set; }
|
||||
public List<string> Logs { get; set; }
|
||||
public List<string> Screenshots { get; set; } // Base64 encoded images
|
||||
public DeviceInfoRequest DeviceInfo { get; set; }
|
||||
public AppInfoRequest AppInfo { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// اطلاعات دستگاه
|
||||
/// </summary>
|
||||
public class DeviceInfoRequest
|
||||
{
|
||||
public string DeviceModel { get; set; }
|
||||
public string OsVersion { get; set; }
|
||||
public string Platform { get; set; }
|
||||
public string Manufacturer { get; set; }
|
||||
public string DeviceId { get; set; }
|
||||
public string ScreenResolution { get; set; }
|
||||
public int MemoryInMB { get; set; }
|
||||
public int StorageInMB { get; set; }
|
||||
public int BatteryLevel { get; set; }
|
||||
public bool IsCharging { get; set; }
|
||||
public string NetworkType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// اطلاعات برنامه
|
||||
/// </summary>
|
||||
public class AppInfoRequest
|
||||
{
|
||||
public string AppVersion { get; set; }
|
||||
public string BuildNumber { get; set; }
|
||||
public string PackageName { get; set; }
|
||||
public DateTime InstallTime { get; set; }
|
||||
public DateTime LastUpdateTime { get; set; }
|
||||
public string Flavor { get; set; }
|
||||
}
|
||||
|
||||
105
ServiceHost/Controllers/BugReportController.cs
Normal file
105
ServiceHost/Controllers/BugReportController.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using CompanyManagment.App.Contracts.CameraBugReport;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ServiceHost.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class BugReportController : ControllerBase
|
||||
{
|
||||
private readonly ICameraBugReportApplication _bugReportApplication;
|
||||
|
||||
public BugReportController(ICameraBugReportApplication bugReportApplication)
|
||||
{
|
||||
_bugReportApplication = bugReportApplication;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ثبت یک گزارش خرابی جدید
|
||||
/// </summary>
|
||||
[HttpPost("submit")]
|
||||
public IActionResult SubmitBugReport([FromBody] CreateCameraBugReportCommand command)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
var result = _bugReportApplication.Create(command);
|
||||
if (result.IsSuccedded)
|
||||
return Ok(new { success = true, message = result.Message });
|
||||
|
||||
return BadRequest(new { success = false, message = result.Message });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت تمام گزارشهای خرابی (برای Admin)
|
||||
/// </summary>
|
||||
[HttpGet("list")]
|
||||
public IActionResult GetBugReports(
|
||||
[FromQuery] int? type,
|
||||
[FromQuery] int? priority,
|
||||
[FromQuery] int? status,
|
||||
[FromQuery] string searchTerm = "",
|
||||
[FromQuery] int pageNumber = 1,
|
||||
[FromQuery] int pageSize = 10)
|
||||
{
|
||||
var searchModel = new CameraBugReportSearchModel
|
||||
{
|
||||
Type = type.HasValue ? (CameraBugReportType)type.Value : null,
|
||||
Priority = priority.HasValue ? (CameraBugPriority)priority.Value : null,
|
||||
Status = status.HasValue ? (CameraBugReportStatus)status.Value : null,
|
||||
SearchTerm = searchTerm,
|
||||
PageNumber = pageNumber,
|
||||
PageSize = pageSize
|
||||
};
|
||||
|
||||
var bugReports = _bugReportApplication.GetAll(searchModel);
|
||||
return Ok(new { success = true, data = bugReports });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// دریافت جزئیات یک گزارش خرابی
|
||||
/// </summary>
|
||||
[HttpGet("{id}")]
|
||||
public IActionResult GetBugReportDetails(long id)
|
||||
{
|
||||
var bugReport = _bugReportApplication.GetDetails(id);
|
||||
if (bugReport == null)
|
||||
return NotFound(new { success = false, message = "گزارش خرابی یافت نشد." });
|
||||
|
||||
return Ok(new { success = true, data = bugReport });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ویرایش یک گزارش خرابی
|
||||
/// </summary>
|
||||
[HttpPut("{id}")]
|
||||
public IActionResult EditBugReport(long id, [FromBody] EditCameraBugReportCommand command)
|
||||
{
|
||||
if (id != command.Id)
|
||||
return BadRequest(new { success = false, message = "ID مطابقت ندارد." });
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
var result = _bugReportApplication.Edit(command);
|
||||
if (result.IsSuccedded)
|
||||
return Ok(new { success = true, message = result.Message });
|
||||
|
||||
return BadRequest(new { success = false, message = result.Message });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// حذف یک گزارش خرابی
|
||||
/// </summary>
|
||||
[HttpDelete("{id}")]
|
||||
public IActionResult DeleteBugReport(long id)
|
||||
{
|
||||
var result = _bugReportApplication.Delete(id);
|
||||
if (result.IsSuccedded)
|
||||
return Ok(new { success = true, message = result.Message });
|
||||
|
||||
return BadRequest(new { success = false, message = result.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"sqlDebugging": true,
|
||||
"dotnetRunMessages": "true",
|
||||
"nativeDebugging": true,
|
||||
"applicationUrl": "https://localhost:5004;http://localhost:5003;",
|
||||
"applicationUrl": "https://localhost:5004;http://localhost:5003;https://192.168.0.117:5006",
|
||||
"jsWebView2Debugging": false,
|
||||
"hotReloadEnabled": true
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user