Report Manager kısmı değiştirildi.

This commit is contained in:
Sedat ÖZTÜRK 2025-10-08 14:31:29 +03:00
parent 8633f0a3f8
commit ffd04bb901
28 changed files with 230 additions and 208 deletions

View file

@ -12,7 +12,7 @@ namespace Kurs.Platform.Reports
[Required] [Required]
public string HtmlContent { get; set; } public string HtmlContent { get; set; }
public string CategoryName { get; set; } public Guid CategoryId { get; set; }
public List<string> Tags { get; set; } public List<string> Tags { get; set; }
public List<CreateReportParameterDto> Parameters { get; set; } public List<CreateReportParameterDto> Parameters { get; set; }

View file

@ -6,7 +6,7 @@ namespace Kurs.Platform.Reports
public class GetReportTemplatesInput : PagedAndSortedResultRequestDto public class GetReportTemplatesInput : PagedAndSortedResultRequestDto
{ {
public string Filter { get; set; } public string Filter { get; set; }
public string CategoryName { get; set; } public Guid CategoryId { get; set; }
} }
public class GetGeneratedReportsInput : PagedAndSortedResultRequestDto public class GetGeneratedReportsInput : PagedAndSortedResultRequestDto

View file

@ -15,9 +15,9 @@ namespace Kurs.Platform.Reports
Task DeleteTemplateAsync(Guid id); Task DeleteTemplateAsync(Guid id);
// Generated Report operations // Generated Report operations
Task<PagedResultDto<GeneratedReportDto>> GetGeneratedReportsAsync(GetGeneratedReportsInput input); Task<PagedResultDto<ReportGeneratedDto>> GetGeneratedReportsAsync(GetGeneratedReportsInput input);
Task<GeneratedReportDto> GetGeneratedReportAsync(Guid id); Task<ReportGeneratedDto> GetGeneratedReportAsync(Guid id);
Task<GeneratedReportDto> GenerateReportAsync(GenerateReportDto input); Task<ReportGeneratedDto> GenerateReportAsync(ReportGenerateDto input);
Task DeleteGeneratedReportAsync(Guid id); Task DeleteGeneratedReportAsync(Guid id);
// Bulk operations // Bulk operations
@ -27,6 +27,6 @@ namespace Kurs.Platform.Reports
public class ReportsDataDto public class ReportsDataDto
{ {
public PagedResultDto<ReportTemplateDto> Templates { get; set; } public PagedResultDto<ReportTemplateDto> Templates { get; set; }
public PagedResultDto<GeneratedReportDto> GeneratedReports { get; set; } public PagedResultDto<ReportGeneratedDto> GeneratedReports { get; set; }
} }
} }

View file

@ -4,14 +4,14 @@ using System.ComponentModel.DataAnnotations;
namespace Kurs.Platform.Reports namespace Kurs.Platform.Reports
{ {
public class GenerateReportDto public class ReportGenerateDto
{ {
[Required] [Required]
public Guid TemplateId { get; set; } public Guid TemplateId { get; set; }
public Dictionary<string, string> Parameters { get; set; } public Dictionary<string, string> Parameters { get; set; }
public GenerateReportDto() public ReportGenerateDto()
{ {
Parameters = []; Parameters = [];
} }

View file

@ -5,7 +5,7 @@ using Volo.Abp.Application.Dtos;
namespace Kurs.Platform.Reports namespace Kurs.Platform.Reports
{ {
public class GeneratedReportDto : FullAuditedEntityDto<Guid> public class ReportGeneratedDto : FullAuditedEntityDto<Guid>
{ {
public Guid? TemplateId { get; set; } public Guid? TemplateId { get; set; }
@ -15,13 +15,12 @@ namespace Kurs.Platform.Reports
[Required] [Required]
public string GeneratedContent { get; set; } public string GeneratedContent { get; set; }
public Dictionary<string, string> Parameters { get; set; } public Dictionary<string, string> Parameters { get; set; }
public DateTime GeneratedAt { get; set; }
public ReportTemplateDto Template { get; set; }
public GeneratedReportDto() public ReportTemplateDto ReportTemplate { get; set; }
public ReportGeneratedDto()
{ {
Parameters = []; Parameters = [];
GeneratedAt = DateTime.UtcNow;
} }
} }
} }

View file

@ -6,7 +6,7 @@ namespace Kurs.Platform.Reports
public class ReportParameterDto public class ReportParameterDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid ReportTemplateId { get; set; } public Guid? TemplateId { get; set; }
[Required] [Required]
public string Name { get; set; } public string Name { get; set; }
public string Placeholder { get; set; } public string Placeholder { get; set; }

View file

@ -13,8 +13,9 @@ namespace Kurs.Platform.Reports
[Required] [Required]
public string HtmlContent { get; set; } public string HtmlContent { get; set; }
public string CategoryName { get; set; } public Guid CategoryId { get; set; }
public List<string> Tags { get; set; } public List<string> Tags { get; set; }
public List<ReportParameterDto> Parameters { get; set; } public List<ReportParameterDto> Parameters { get; set; }
public ReportTemplateDto() public ReportTemplateDto()

View file

@ -2,37 +2,36 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
namespace Kurs.Platform.Reports namespace Kurs.Platform.Reports;
public class UpdateReportTemplateDto
{ {
public class UpdateReportTemplateDto [Required]
public string Name { get; set; }
public string Description { get; set; }
[Required]
public string HtmlContent { get; set; }
public Guid CategoryId { get; set; }
public List<string> Tags { get; set; }
public List<UpdateReportParameterDto> Parameters { get; set; }
public UpdateReportTemplateDto()
{ {
[Required] Tags = [];
public string Name { get; set; } Parameters = [];
public string Description { get; set; }
[Required]
public string HtmlContent { get; set; }
public string CategoryName { get; set; }
public List<string> Tags { get; set; }
public List<UpdateReportParameterDto> Parameters { get; set; }
public UpdateReportTemplateDto()
{
Tags = [];
Parameters = [];
}
}
public class UpdateReportParameterDto
{
public Guid? Id { get; set; }
[Required]
public string Name { get; set; }
public string Placeholder { get; set; }
public string Type { get; set; }
public string DefaultValue { get; set; }
public bool Required { get; set; }
public string Description { get; set; }
} }
} }
public class UpdateReportParameterDto
{
public Guid? Id { get; set; }
[Required]
public string Name { get; set; }
public string Placeholder { get; set; }
public string Type { get; set; }
public string DefaultValue { get; set; }
public bool Required { get; set; }
public string Description { get; set; }
}

View file

@ -51,14 +51,13 @@ public class ReportAppService : PlatformAppService, IReportAppService
{ {
query = query.Where(x => query = query.Where(x =>
x.Name.Contains(input.Filter) || x.Name.Contains(input.Filter) ||
x.Description.Contains(input.Filter) || x.Description.Contains(input.Filter)
x.CategoryName.Contains(input.Filter)
); );
} }
if (!string.IsNullOrWhiteSpace(input.CategoryName)) if (input.CategoryId != Guid.Empty)
{ {
query = query.Where(x => x.CategoryName == input.CategoryName); query = query.Where(x => x.CategoryId == input.CategoryId);
} }
// Toplam kayıt sayısı // Toplam kayıt sayısı
@ -105,7 +104,7 @@ public class ReportAppService : PlatformAppService, IReportAppService
input.Name, input.Name,
input.Description, input.Description,
input.HtmlContent, input.HtmlContent,
input.CategoryName) input.CategoryId)
{ {
Tags = JsonSerializer.Serialize(input.Tags) Tags = JsonSerializer.Serialize(input.Tags)
}; };
@ -141,14 +140,14 @@ public class ReportAppService : PlatformAppService, IReportAppService
template.Name = input.Name; template.Name = input.Name;
template.Description = input.Description; template.Description = input.Description;
template.HtmlContent = input.HtmlContent; template.HtmlContent = input.HtmlContent;
template.CategoryName = input.CategoryName; template.CategoryId = input.CategoryId;
template.Tags = JsonSerializer.Serialize(input.Tags ?? []); template.Tags = JsonSerializer.Serialize(input.Tags ?? []);
// Şablonu hemen persist et (audit alanları için de iyi olur) // Şablonu hemen persist et (audit alanları için de iyi olur)
await _reportTemplateRepository.UpdateAsync(template, autoSave: true); await _reportTemplateRepository.UpdateAsync(template, autoSave: true);
// 2) Parametrelerde upsert + artıklarını sil // 2) Parametrelerde upsert + artıklarını sil
var existingParams = await _reportParameterRepository.GetListAsync(p => p.ReportTemplateId == id); var existingParams = await _reportParameterRepository.GetListAsync(p => p.TemplateId == id);
var existingById = existingParams.ToDictionary(p => p.Id, p => p); var existingById = existingParams.ToDictionary(p => p.Id, p => p);
var inputParams = input.Parameters ?? new List<UpdateReportParameterDto>(); var inputParams = input.Parameters ?? new List<UpdateReportParameterDto>();
@ -231,13 +230,13 @@ public class ReportAppService : PlatformAppService, IReportAppService
await _reportTemplateRepository.DeleteAsync(id); await _reportTemplateRepository.DeleteAsync(id);
} }
public async Task<PagedResultDto<GeneratedReportDto>> GetGeneratedReportsAsync(GetGeneratedReportsInput input) public async Task<PagedResultDto<ReportGeneratedDto>> GetGeneratedReportsAsync(GetGeneratedReportsInput input)
{ {
var query = await _generatedReportRepository.GetQueryableAsync(); var query = await _generatedReportRepository.GetQueryableAsync();
// Okuma senaryosu: tracking gerekmiyor + Template'ı eager load edelim // Okuma senaryosu: tracking gerekmiyor + Template'ı eager load edelim
query = query.AsNoTracking() query = query.AsNoTracking()
.Include(x => x.Template); .Include(x => x.ReportTemplate);
// Filtre // Filtre
if (!string.IsNullOrWhiteSpace(input.Filter)) if (!string.IsNullOrWhiteSpace(input.Filter))
@ -260,7 +259,7 @@ public class ReportAppService : PlatformAppService, IReportAppService
if (!string.IsNullOrWhiteSpace(input.Sorting)) if (!string.IsNullOrWhiteSpace(input.Sorting))
query = query.OrderBy(input.Sorting); // ör. "generatedAt DESC" veya "templateName" query = query.OrderBy(input.Sorting); // ör. "generatedAt DESC" veya "templateName"
else else
query = query.OrderByDescending(x => x.GeneratedAt); query = query.OrderByDescending(x => x.CreationTime);
// Sayfalama // Sayfalama
var reports = await AsyncExecuter.ToListAsync( var reports = await AsyncExecuter.ToListAsync(
@ -270,17 +269,17 @@ public class ReportAppService : PlatformAppService, IReportAppService
// DTO map // DTO map
var reportDtos = reports.Select(MapToGeneratedReportDto).ToList(); var reportDtos = reports.Select(MapToGeneratedReportDto).ToList();
return new PagedResultDto<GeneratedReportDto>(totalCount, reportDtos); return new PagedResultDto<ReportGeneratedDto>(totalCount, reportDtos);
} }
public async Task<GeneratedReportDto> GetGeneratedReportAsync(Guid id) public async Task<ReportGeneratedDto> GetGeneratedReportAsync(Guid id)
{ {
var report = await _generatedReportRepository.GetAsync(id); var report = await _generatedReportRepository.GetAsync(id);
return MapToGeneratedReportDto(report); return MapToGeneratedReportDto(report);
} }
public async Task<GeneratedReportDto> GenerateReportAsync(GenerateReportDto input) public async Task<ReportGeneratedDto> GenerateReportAsync(ReportGenerateDto input)
{ {
var template = await _reportTemplateRepository.GetAsync(input.TemplateId); var template = await _reportTemplateRepository.GetAsync(input.TemplateId);
if (template == null) if (template == null)
@ -336,7 +335,7 @@ public class ReportAppService : PlatformAppService, IReportAppService
Name = template.Name, Name = template.Name,
Description = template.Description, Description = template.Description,
HtmlContent = template.HtmlContent, HtmlContent = template.HtmlContent,
CategoryName = template.CategoryName, CategoryId = template.CategoryId,
CreationTime = template.CreationTime, CreationTime = template.CreationTime,
LastModificationTime = template.LastModificationTime, LastModificationTime = template.LastModificationTime,
CreatorId = template.CreatorId, CreatorId = template.CreatorId,
@ -359,7 +358,7 @@ public class ReportAppService : PlatformAppService, IReportAppService
dto.Parameters = template.Parameters?.Select(p => new ReportParameterDto dto.Parameters = template.Parameters?.Select(p => new ReportParameterDto
{ {
Id = p.Id, Id = p.Id,
ReportTemplateId = p.ReportTemplateId, TemplateId = p.TemplateId,
Name = p.Name, Name = p.Name,
Placeholder = p.Placeholder, Placeholder = p.Placeholder,
Type = p.Type, Type = p.Type,
@ -371,15 +370,14 @@ public class ReportAppService : PlatformAppService, IReportAppService
return dto; return dto;
} }
private GeneratedReportDto MapToGeneratedReportDto(ReportGenerated report) private ReportGeneratedDto MapToGeneratedReportDto(ReportGenerated report)
{ {
var dto = new GeneratedReportDto var dto = new ReportGeneratedDto
{ {
Id = report.Id, Id = report.Id,
TemplateId = report.TemplateId, TemplateId = report.TemplateId,
TemplateName = report.TemplateName, TemplateName = report.TemplateName,
GeneratedContent = report.GeneratedContent, GeneratedContent = report.GeneratedContent,
GeneratedAt = report.GeneratedAt,
CreationTime = report.CreationTime, CreationTime = report.CreationTime,
LastModificationTime = report.LastModificationTime, LastModificationTime = report.LastModificationTime,
CreatorId = report.CreatorId, CreatorId = report.CreatorId,
@ -399,9 +397,9 @@ public class ReportAppService : PlatformAppService, IReportAppService
} }
// Template mapping // Template mapping
if (report.Template != null) if (report.ReportTemplate != null)
{ {
dto.Template = MapToReportTemplateDto(report.Template); dto.ReportTemplate = MapToReportTemplateDto(report.ReportTemplate);
} }
return dto; return dto;

View file

@ -26,23 +26,22 @@ namespace Kurs.Platform.Reports
CreateMap<CreateReportParameterDto, ReportParameter>() CreateMap<CreateReportParameterDto, ReportParameter>()
.ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.ReportTemplateId, opt => opt.Ignore()); .ForMember(dest => dest.TemplateId, opt => opt.Ignore());
CreateMap<UpdateReportParameterDto, ReportParameter>() CreateMap<UpdateReportParameterDto, ReportParameter>()
.ForMember(dest => dest.ReportTemplateId, opt => opt.Ignore()); .ForMember(dest => dest.TemplateId, opt => opt.Ignore());
CreateMap<ReportGenerated, GeneratedReportDto>() CreateMap<ReportGenerated, ReportGeneratedDto>()
.ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => .ForMember(dest => dest.Parameters, opt => opt.MapFrom(src =>
ConvertParametersFromJson(src.Parameters))) ConvertParametersFromJson(src.Parameters)))
.ForMember(dest => dest.Template, opt => opt.MapFrom(src => src.Template)); .ForMember(dest => dest.ReportTemplate, opt => opt.MapFrom(src => src.ReportTemplate));
CreateMap<GenerateReportDto, ReportGenerated>() CreateMap<ReportGenerateDto, ReportGenerated>()
.ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => ConvertParametersToJson(src.Parameters))) .ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => ConvertParametersToJson(src.Parameters)))
.ForMember(dest => dest.Id, opt => opt.Ignore()) .ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.TemplateId, opt => opt.MapFrom(src => src.TemplateId)) .ForMember(dest => dest.TemplateId, opt => opt.MapFrom(src => src.TemplateId))
.ForMember(dest => dest.TemplateName, opt => opt.Ignore()) .ForMember(dest => dest.TemplateName, opt => opt.Ignore())
.ForMember(dest => dest.GeneratedContent, opt => opt.Ignore()) .ForMember(dest => dest.GeneratedContent, opt => opt.Ignore());
.ForMember(dest => dest.GeneratedAt, opt => opt.Ignore());
CreateMap<ReportCategory, ReportCategoryDto>(); CreateMap<ReportCategory, ReportCategoryDto>();

View file

@ -24348,7 +24348,7 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc
new() new()
{ {
Order = 1, Order = 1,
ColCount = 2, ColCount = 1,
ColSpan = 2, ColSpan = 2,
ItemType = "group", ItemType = "group",
Items = Items =
@ -24641,7 +24641,7 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc
new EditingFormItemDto { Order = 2, DataField = "BranchId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=showClearButton }, new EditingFormItemDto { Order = 2, DataField = "BranchId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=showClearButton },
new EditingFormItemDto { Order = 3, DataField = "ClassTypeId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=showClearButton }, new EditingFormItemDto { Order = 3, DataField = "ClassTypeId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=showClearButton },
new EditingFormItemDto { Order = 4, DataField = "Name", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox }, new EditingFormItemDto { Order = 4, DataField = "Name", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 5, DataField = "LevelType", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox }, new EditingFormItemDto { Order = 5, DataField = "LevelType", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox },
new EditingFormItemDto { Order = 6, DataField = "LessonCount", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxNumberBox }, new EditingFormItemDto { Order = 6, DataField = "LessonCount", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxNumberBox },
new EditingFormItemDto { Order = 7, DataField = "LessonDuration", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxNumberBox }, new EditingFormItemDto { Order = 7, DataField = "LessonDuration", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxNumberBox },
new EditingFormItemDto { Order = 8, DataField = "MonthlyPaymentRate", ColSpan = 1, EditorType2 = EditorTypes.dxNumberBox }, new EditingFormItemDto { Order = 8, DataField = "MonthlyPaymentRate", ColSpan = 1, EditorType2 = EditorTypes.dxNumberBox },
@ -24805,6 +24805,19 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc
Visible = true, Visible = true,
IsActive = true, IsActive = true,
IsDeleted = false, IsDeleted = false,
ValidationRuleJson = JsonSerializer.Serialize(new ValidationRuleDto[]
{
new ValidationRuleDto() { Type = Enum.GetName(UiColumnValidationRuleTypeEnum.required) }
}),
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.StaticData,
DisplayExpr = "name",
ValueExpr = "key",
LookupQuery = JsonSerializer.Serialize(new LookupDataDto[] {
new () { Key="Seviye",Name="Seviye" },
new () { Key="Sınav Eğitimi",Name="Sınav Eğitimi" },
}),
}),
PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto PermissionJson = JsonSerializer.Serialize(new ListFormFieldPermissionDto
{ {
C = AppCodes.Definitions.Level + ".Create", C = AppCodes.Definitions.Level + ".Create",
@ -25014,7 +25027,7 @@ public class PlatformListFormsSeeder : IDataSeedContributor, ITransientDependenc
new() new()
{ {
Order = 1, Order = 1,
ColCount = 2, ColCount = 1,
ColSpan = 2, ColSpan = 2,
ItemType = "group", ItemType = "group",
Items = Items =

View file

@ -2639,6 +2639,12 @@
"en": "Category", "en": "Category",
"tr": "Kategori" "tr": "Kategori"
}, },
{
"resourceName": "Platform",
"key": "App.Reports.TemplateEditor.Placeholder.SelectCategory",
"en": "Select Category",
"tr": "Kategori Seç"
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.Reports.TemplateEditor.Label.Tags", "key": "App.Reports.TemplateEditor.Label.Tags",

View file

@ -12,18 +12,17 @@ namespace Kurs.Platform.Entities
public string TemplateName { get; set; } public string TemplateName { get; set; }
public string GeneratedContent { get; set; } public string GeneratedContent { get; set; }
public string Parameters { get; set; } public string Parameters { get; set; }
public DateTime GeneratedAt { get; set; }
public virtual ReportTemplate Template { get; set; } public virtual ReportTemplate ReportTemplate { get; set; }
public ReportGenerated() public ReportGenerated()
{ {
GeneratedAt = DateTime.UtcNow;
} }
public ReportGenerated( public ReportGenerated(
Guid id, Guid id,
Guid? templateId, Guid templateId,
string templateName, string templateName,
string generatedContent, string generatedContent,
string parameters string parameters
@ -33,7 +32,6 @@ namespace Kurs.Platform.Entities
TemplateName = templateName; TemplateName = templateName;
GeneratedContent = generatedContent; GeneratedContent = generatedContent;
Parameters = parameters; Parameters = parameters;
GeneratedAt = DateTime.UtcNow;
} }
} }
} }

View file

@ -8,7 +8,7 @@ namespace Kurs.Platform.Entities
{ {
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
public Guid ReportTemplateId { get; set; } public Guid? TemplateId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Placeholder { get; set; } public string Placeholder { get; set; }
public string Type { get; set; } public string Type { get; set; }
@ -24,14 +24,14 @@ namespace Kurs.Platform.Entities
public ReportParameter( public ReportParameter(
Guid id, Guid id,
Guid reportTemplateId, Guid templateId,
string name, string name,
string placeholder, string placeholder,
string type, string type,
bool required = false bool required = false
) : base(id) ) : base(id)
{ {
ReportTemplateId = reportTemplateId; TemplateId = templateId;
Name = name; Name = name;
Placeholder = placeholder; Placeholder = placeholder;
Type = type; Type = type;

View file

@ -12,15 +12,18 @@ namespace Kurs.Platform.Entities
public string Name { get; set; } public string Name { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string HtmlContent { get; set; } public string HtmlContent { get; set; }
public string CategoryName { get; set; } public Guid CategoryId { get; set; }
public string Tags { get; set; } public string Tags { get; set; }
public ReportCategory ReportCategory { get; set; } public ReportCategory ReportCategory { get; set; }
public ICollection<ReportParameter> Parameters { get; set; } public ICollection<ReportParameter> Parameters { get; set; }
public ICollection<ReportGenerated> Generated { get; set; }
public ReportTemplate() public ReportTemplate()
{ {
Parameters = []; Parameters = [];
Generated = [];
} }
public ReportTemplate( public ReportTemplate(
@ -28,14 +31,15 @@ namespace Kurs.Platform.Entities
string name, string name,
string description, string description,
string htmlContent, string htmlContent,
string categoryName = "Genel" Guid categoryId
) : base(id) ) : base(id)
{ {
Name = name; Name = name;
Description = description; Description = description;
HtmlContent = htmlContent; HtmlContent = htmlContent;
CategoryName = categoryName; CategoryId = categoryId;
Parameters = new List<ReportParameter>(); Parameters = [];
Generated = [];
} }
} }
} }

View file

@ -667,13 +667,11 @@ public class PlatformDbContext :
b.Property(x => x.Description).HasMaxLength(4000); // JSON string b.Property(x => x.Description).HasMaxLength(4000); // JSON string
b.Property(x => x.Icon).HasMaxLength(64); b.Property(x => x.Icon).HasMaxLength(64);
b.HasIndex(x => x.Name).IsUnique();
b.HasMany(x => x.ReportTemplates) b.HasMany(x => x.ReportTemplates)
.WithOne(x => x.ReportCategory) .WithOne(x => x.ReportCategory)
.HasForeignKey(x => x.CategoryName) .HasForeignKey(x => x.CategoryId)
.HasPrincipalKey(c => c.Name) .HasPrincipalKey(c => c.Id)
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.Cascade);
}); });
builder.Entity<ReportTemplate>(b => builder.Entity<ReportTemplate>(b =>
@ -684,12 +682,16 @@ public class PlatformDbContext :
b.Property(x => x.Name).IsRequired().HasMaxLength(256); b.Property(x => x.Name).IsRequired().HasMaxLength(256);
b.Property(x => x.Description).HasMaxLength(1000); b.Property(x => x.Description).HasMaxLength(1000);
b.Property(x => x.HtmlContent).IsRequired(); b.Property(x => x.HtmlContent).IsRequired();
b.Property(x => x.CategoryName).HasMaxLength(256);
b.Property(x => x.Tags).HasMaxLength(2000); b.Property(x => x.Tags).HasMaxLength(2000);
b.HasMany(t => t.Parameters) b.HasMany(t => t.Parameters)
.WithOne(p => p.ReportTemplate) .WithOne(p => p.ReportTemplate)
.HasForeignKey(p => p.ReportTemplateId) .HasForeignKey(p => p.TemplateId)
.OnDelete(DeleteBehavior.Cascade);
b.HasMany(t => t.Generated)
.WithOne(p => p.ReportTemplate)
.HasForeignKey(p => p.TemplateId)
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
}); });
@ -698,7 +700,7 @@ public class PlatformDbContext :
b.ToTable(Prefix.DbTableDefault + nameof(ReportParameter), Prefix.DbSchema); b.ToTable(Prefix.DbTableDefault + nameof(ReportParameter), Prefix.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.ReportTemplateId).IsRequired(); b.Property(x => x.TemplateId).IsRequired();
b.Property(x => x.Name).IsRequired().HasMaxLength(100); b.Property(x => x.Name).IsRequired().HasMaxLength(100);
b.Property(x => x.Placeholder).HasMaxLength(200); b.Property(x => x.Placeholder).HasMaxLength(200);
b.Property(x => x.Type).IsRequired(); b.Property(x => x.Type).IsRequired();
@ -716,13 +718,6 @@ public class PlatformDbContext :
b.Property(x => x.TemplateName).IsRequired().HasMaxLength(256); b.Property(x => x.TemplateName).IsRequired().HasMaxLength(256);
b.Property(x => x.GeneratedContent).IsRequired(); b.Property(x => x.GeneratedContent).IsRequired();
b.Property(x => x.Parameters).HasMaxLength(4000); // JSON string b.Property(x => x.Parameters).HasMaxLength(4000); // JSON string
b.Property(x => x.GeneratedAt).IsRequired();
b.HasOne(x => x.Template)
.WithMany()
.HasForeignKey(x => x.TemplateId)
.OnDelete(DeleteBehavior.SetNull)
.IsRequired(false);
}); });
//Administration //Administration

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Migrations namespace Kurs.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20251008085215_Initial")] [Migration("20251008104142_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -5183,9 +5183,6 @@ namespace Kurs.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("PReportCategory", (string)null); b.ToTable("PReportCategory", (string)null);
}); });
@ -5210,9 +5207,6 @@ namespace Kurs.Platform.Migrations
.HasColumnType("datetime2") .HasColumnType("datetime2")
.HasColumnName("DeletionTime"); .HasColumnName("DeletionTime");
b.Property<DateTime>("GeneratedAt")
.HasColumnType("datetime2");
b.Property<string>("GeneratedContent") b.Property<string>("GeneratedContent")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -5306,12 +5300,12 @@ namespace Kurs.Platform.Migrations
.HasMaxLength(200) .HasMaxLength(200)
.HasColumnType("nvarchar(200)"); .HasColumnType("nvarchar(200)");
b.Property<Guid>("ReportTemplateId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("Required") b.Property<bool>("Required")
.HasColumnType("bit"); .HasColumnType("bit");
b.Property<Guid>("TemplateId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("TenantId"); .HasColumnName("TenantId");
@ -5322,7 +5316,7 @@ namespace Kurs.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("ReportTemplateId"); b.HasIndex("TemplateId");
b.ToTable("PReportParameter", (string)null); b.ToTable("PReportParameter", (string)null);
}); });
@ -5332,9 +5326,8 @@ namespace Kurs.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("CategoryName") b.Property<Guid>("CategoryId")
.HasMaxLength(256) .HasColumnType("uniqueidentifier");
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -5389,7 +5382,7 @@ namespace Kurs.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CategoryName"); b.HasIndex("CategoryId");
b.ToTable("PReportTemplate", (string)null); b.ToTable("PReportTemplate", (string)null);
}); });
@ -8832,19 +8825,19 @@ namespace Kurs.Platform.Migrations
modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b => modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b =>
{ {
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template") b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate")
.WithMany() .WithMany("Generated")
.HasForeignKey("TemplateId") .HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.Cascade);
b.Navigation("Template"); b.Navigation("ReportTemplate");
}); });
modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b => modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b =>
{ {
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate") b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate")
.WithMany("Parameters") .WithMany("Parameters")
.HasForeignKey("ReportTemplateId") .HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
@ -8855,9 +8848,9 @@ namespace Kurs.Platform.Migrations
{ {
b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory") b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory")
.WithMany("ReportTemplates") .WithMany("ReportTemplates")
.HasForeignKey("CategoryName") .HasForeignKey("CategoryId")
.HasPrincipalKey("Name") .OnDelete(DeleteBehavior.Cascade)
.OnDelete(DeleteBehavior.SetNull); .IsRequired();
b.Navigation("ReportCategory"); b.Navigation("ReportCategory");
}); });
@ -9167,6 +9160,8 @@ namespace Kurs.Platform.Migrations
modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b =>
{ {
b.Navigation("Generated");
b.Navigation("Parameters"); b.Navigation("Parameters");
}); });

View file

@ -1727,7 +1727,6 @@ namespace Kurs.Platform.Migrations
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_PReportCategory", x => x.Id); table.PrimaryKey("PK_PReportCategory", x => x.Id);
table.UniqueConstraint("AK_PReportCategory_Name", x => x.Name);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
@ -3052,7 +3051,7 @@ namespace Kurs.Platform.Migrations
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true), Description = table.Column<string>(type: "nvarchar(1000)", maxLength: 1000, nullable: true),
HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false), HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false),
CategoryName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true), CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Tags = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true), Tags = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -3066,11 +3065,11 @@ namespace Kurs.Platform.Migrations
{ {
table.PrimaryKey("PK_PReportTemplate", x => x.Id); table.PrimaryKey("PK_PReportTemplate", x => x.Id);
table.ForeignKey( table.ForeignKey(
name: "FK_PReportTemplate_PReportCategory_CategoryName", name: "FK_PReportTemplate_PReportCategory_CategoryId",
column: x => x.CategoryName, column: x => x.CategoryId,
principalTable: "PReportCategory", principalTable: "PReportCategory",
principalColumn: "Name", principalColumn: "Id",
onDelete: ReferentialAction.SetNull); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
@ -3398,7 +3397,6 @@ namespace Kurs.Platform.Migrations
TemplateName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false), TemplateName = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
GeneratedContent = table.Column<string>(type: "nvarchar(max)", nullable: false), GeneratedContent = table.Column<string>(type: "nvarchar(max)", nullable: false),
Parameters = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true), Parameters = table.Column<string>(type: "nvarchar(4000)", maxLength: 4000, nullable: true),
GeneratedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false), CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true), LastModificationTime = table.Column<DateTime>(type: "datetime2", nullable: true),
@ -3415,7 +3413,7 @@ namespace Kurs.Platform.Migrations
column: x => x.TemplateId, column: x => x.TemplateId,
principalTable: "PReportTemplate", principalTable: "PReportTemplate",
principalColumn: "Id", principalColumn: "Id",
onDelete: ReferentialAction.SetNull); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
@ -3424,7 +3422,7 @@ namespace Kurs.Platform.Migrations
{ {
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
ReportTemplateId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), TemplateId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false), Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Placeholder = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true), Placeholder = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
Type = table.Column<string>(type: "nvarchar(max)", nullable: false), Type = table.Column<string>(type: "nvarchar(max)", nullable: false),
@ -3443,8 +3441,8 @@ namespace Kurs.Platform.Migrations
{ {
table.PrimaryKey("PK_PReportParameter", x => x.Id); table.PrimaryKey("PK_PReportParameter", x => x.Id);
table.ForeignKey( table.ForeignKey(
name: "FK_PReportParameter_PReportTemplate_ReportTemplateId", name: "FK_PReportParameter_PReportTemplate_TemplateId",
column: x => x.ReportTemplateId, column: x => x.TemplateId,
principalTable: "PReportTemplate", principalTable: "PReportTemplate",
principalColumn: "Id", principalColumn: "Id",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
@ -3993,26 +3991,20 @@ namespace Kurs.Platform.Migrations
table: "PNotification", table: "PNotification",
column: "NotificationRuleId"); column: "NotificationRuleId");
migrationBuilder.CreateIndex(
name: "IX_PReportCategory_Name",
table: "PReportCategory",
column: "Name",
unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PReportGenerated_TemplateId", name: "IX_PReportGenerated_TemplateId",
table: "PReportGenerated", table: "PReportGenerated",
column: "TemplateId"); column: "TemplateId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PReportParameter_ReportTemplateId", name: "IX_PReportParameter_TemplateId",
table: "PReportParameter", table: "PReportParameter",
column: "ReportTemplateId"); column: "TemplateId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PReportTemplate_CategoryName", name: "IX_PReportTemplate_CategoryId",
table: "PReportTemplate", table: "PReportTemplate",
column: "CategoryName"); column: "CategoryId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PRoute_Key", name: "IX_PRoute_Key",

View file

@ -5180,9 +5180,6 @@ namespace Kurs.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("PReportCategory", (string)null); b.ToTable("PReportCategory", (string)null);
}); });
@ -5207,9 +5204,6 @@ namespace Kurs.Platform.Migrations
.HasColumnType("datetime2") .HasColumnType("datetime2")
.HasColumnName("DeletionTime"); .HasColumnName("DeletionTime");
b.Property<DateTime>("GeneratedAt")
.HasColumnType("datetime2");
b.Property<string>("GeneratedContent") b.Property<string>("GeneratedContent")
.IsRequired() .IsRequired()
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
@ -5303,12 +5297,12 @@ namespace Kurs.Platform.Migrations
.HasMaxLength(200) .HasMaxLength(200)
.HasColumnType("nvarchar(200)"); .HasColumnType("nvarchar(200)");
b.Property<Guid>("ReportTemplateId")
.HasColumnType("uniqueidentifier");
b.Property<bool>("Required") b.Property<bool>("Required")
.HasColumnType("bit"); .HasColumnType("bit");
b.Property<Guid>("TemplateId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId") b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier") .HasColumnType("uniqueidentifier")
.HasColumnName("TenantId"); .HasColumnName("TenantId");
@ -5319,7 +5313,7 @@ namespace Kurs.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("ReportTemplateId"); b.HasIndex("TemplateId");
b.ToTable("PReportParameter", (string)null); b.ToTable("PReportParameter", (string)null);
}); });
@ -5329,9 +5323,8 @@ namespace Kurs.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<string>("CategoryName") b.Property<Guid>("CategoryId")
.HasMaxLength(256) .HasColumnType("uniqueidentifier");
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -5386,7 +5379,7 @@ namespace Kurs.Platform.Migrations
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("CategoryName"); b.HasIndex("CategoryId");
b.ToTable("PReportTemplate", (string)null); b.ToTable("PReportTemplate", (string)null);
}); });
@ -8829,19 +8822,19 @@ namespace Kurs.Platform.Migrations
modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b => modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b =>
{ {
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template") b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate")
.WithMany() .WithMany("Generated")
.HasForeignKey("TemplateId") .HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.Cascade);
b.Navigation("Template"); b.Navigation("ReportTemplate");
}); });
modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b => modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b =>
{ {
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate") b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate")
.WithMany("Parameters") .WithMany("Parameters")
.HasForeignKey("ReportTemplateId") .HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
@ -8852,9 +8845,9 @@ namespace Kurs.Platform.Migrations
{ {
b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory") b.HasOne("Kurs.Platform.Entities.ReportCategory", "ReportCategory")
.WithMany("ReportTemplates") .WithMany("ReportTemplates")
.HasForeignKey("CategoryName") .HasForeignKey("CategoryId")
.HasPrincipalKey("Name") .OnDelete(DeleteBehavior.Cascade)
.OnDelete(DeleteBehavior.SetNull); .IsRequired();
b.Navigation("ReportCategory"); b.Navigation("ReportCategory");
}); });
@ -9164,6 +9157,8 @@ namespace Kurs.Platform.Migrations
modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b => modelBuilder.Entity("Kurs.Platform.Entities.ReportTemplate", b =>
{ {
b.Navigation("Generated");
b.Navigation("Parameters"); b.Navigation("Parameters");
}); });

View file

@ -57,7 +57,7 @@ export const Dashboard: React.FC = () => {
// Filter by category (if not "tumu-category") // Filter by category (if not "tumu-category")
if (selectedCategory && selectedCategory.id !== 'tumu-category') { if (selectedCategory && selectedCategory.id !== 'tumu-category') {
filtered = filtered.filter((template) => template.categoryName === selectedCategory.name) filtered = filtered.filter((template) => template.categoryId === selectedCategory.id)
} }
// Filter by search query // Filter by search query
@ -167,7 +167,7 @@ export const Dashboard: React.FC = () => {
</div> </div>
{category.id !== 'tumu-category' && ( {category.id !== 'tumu-category' && (
<span className="text-sm text-gray-500 ml-2"> <span className="text-sm text-gray-500 ml-2">
({templates.filter((t) => t.categoryName === category.name).length}) ({templates.filter((t) => t.categoryId === category.id).length})
</span> </span>
)} )}
{category.id === 'tumu-category' && ( {category.id === 'tumu-category' && (
@ -283,6 +283,7 @@ export const Dashboard: React.FC = () => {
<TemplateCard <TemplateCard
key={template.id} key={template.id}
template={template} template={template}
categories={categories}
onEdit={handleEditTemplate} onEdit={handleEditTemplate}
onDelete={handleDeleteTemplate} onDelete={handleDeleteTemplate}
onGenerate={handleGenerateReport} onGenerate={handleGenerateReport}
@ -313,6 +314,7 @@ export const Dashboard: React.FC = () => {
setGeneratingTemplate(null) setGeneratingTemplate(null)
}} }}
template={generatingTemplate} template={generatingTemplate}
categories={categories}
onGenerate={handleReportGeneration} onGenerate={handleReportGeneration}
/> />
</> </>

View file

@ -1,7 +1,7 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import { Button, Input, Dialog } from '../ui' import { Button, Input, Dialog } from '../ui'
import { FaFileAlt } from 'react-icons/fa' import { FaFileAlt } from 'react-icons/fa'
import { ReportTemplateDto } from '@/proxy/reports/models' import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import { ROUTES_ENUM } from '@/routes/route.constant' import { ROUTES_ENUM } from '@/routes/route.constant'
@ -9,6 +9,7 @@ interface ReportGeneratorProps {
isOpen: boolean isOpen: boolean
onClose: () => void onClose: () => void
template: ReportTemplateDto | null template: ReportTemplateDto | null
categories: ReportCategoryDto[]
onGenerate: (templateId: string, parameters: Record<string, string>) => Promise<string | null> // Rapor ID'si döndürmek için (async) onGenerate: (templateId: string, parameters: Record<string, string>) => Promise<string | null> // Rapor ID'si döndürmek için (async)
} }
@ -16,6 +17,7 @@ export const ReportGenerator: React.FC<ReportGeneratorProps> = ({
isOpen, isOpen,
onClose, onClose,
template, template,
categories,
onGenerate, onGenerate,
}) => { }) => {
const [parameterValues, setParameterValues] = useState<Record<string, string>>({}) const [parameterValues, setParameterValues] = useState<Record<string, string>>({})
@ -80,7 +82,7 @@ export const ReportGenerator: React.FC<ReportGeneratorProps> = ({
<p className="text-gray-600 text-sm">{template.description}</p> <p className="text-gray-600 text-sm">{template.description}</p>
<div className="flex items-center mt-2 space-x-2"> <div className="flex items-center mt-2 space-x-2">
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded"> <span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded">
{template.categoryName} {categories.find((c) => c.id === template.categoryId)?.name}
</span> </span>
{template.tags.map((tag) => ( {template.tags.map((tag) => (
<span key={tag} className="text-xs bg-gray-100 text-gray-800 px-2 py-1 rounded"> <span key={tag} className="text-xs bg-gray-100 text-gray-800 px-2 py-1 rounded">

View file

@ -23,7 +23,7 @@ export const ReportViewer: React.FC = () => {
const [isLoading, setIsLoading] = useState(true) const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
const { translate } = useLocalization() const { translate } = useLocalization()
const { getReportById, getTemplateById } = useReports() const { getReportById, getTemplateById, categories } = useReports()
// İçeriği sayfalara bölen fonksiyon // İçeriği sayfalara bölen fonksiyon
const splitContentIntoPages = (content: string) => { const splitContentIntoPages = (content: string) => {
@ -254,7 +254,7 @@ export const ReportViewer: React.FC = () => {
} }
pdf.save( pdf.save(
`${report!.templateName}_${new Date(report!.generatedAt).toLocaleDateString('tr-TR')}.pdf`, `${report!.templateName}_${new Date(report!.creationTime).toLocaleDateString('tr-TR')}.pdf`,
) )
} catch (error) { } catch (error) {
console.error('PDF oluşturma hatası:', error) console.error('PDF oluşturma hatası:', error)
@ -274,7 +274,7 @@ export const ReportViewer: React.FC = () => {
<div className="flex items-center space-x-4 text-sm text-gray-500"> <div className="flex items-center space-x-4 text-sm text-gray-500">
<span className="flex items-center"> <span className="flex items-center">
<FaCalendarAlt className="h-4 w-4 mr-1" /> <FaCalendarAlt className="h-4 w-4 mr-1" />
{new Date(report.generatedAt).toLocaleDateString('tr-TR', { {new Date(report.creationTime).toLocaleDateString('tr-TR', {
year: 'numeric', year: 'numeric',
month: 'long', month: 'long',
day: 'numeric', day: 'numeric',
@ -285,7 +285,7 @@ export const ReportViewer: React.FC = () => {
{template && ( {template && (
<span className="flex items-center"> <span className="flex items-center">
<FaFileAlt className="h-4 w-4 mr-1" /> <FaFileAlt className="h-4 w-4 mr-1" />
{template.categoryName} {categories.find((c) => c.id === template.categoryId)?.name}
</span> </span>
)} )}
</div> </div>

View file

@ -1,11 +1,12 @@
import React from 'react' import React from 'react'
import { Button } from '../ui/Button' import { Button } from '../ui/Button'
import { FaFileAlt, FaEdit, FaTrash, FaPlay } from 'react-icons/fa'; import { FaFileAlt, FaEdit, FaTrash, FaPlay } from 'react-icons/fa'
import { ReportTemplateDto } from '@/proxy/reports/models' import { ReportCategoryDto, ReportTemplateDto } from '@/proxy/reports/models'
import { useLocalization } from '@/utils/hooks/useLocalization'; import { useLocalization } from '@/utils/hooks/useLocalization'
interface TemplateCardProps { interface TemplateCardProps {
template: ReportTemplateDto template: ReportTemplateDto
categories: ReportCategoryDto[]
onEdit: (template: ReportTemplateDto) => void onEdit: (template: ReportTemplateDto) => void
onDelete: (id: string) => void onDelete: (id: string) => void
onGenerate: (template: ReportTemplateDto) => void onGenerate: (template: ReportTemplateDto) => void
@ -13,6 +14,7 @@ interface TemplateCardProps {
export const TemplateCard: React.FC<TemplateCardProps> = ({ export const TemplateCard: React.FC<TemplateCardProps> = ({
template, template,
categories,
onEdit, onEdit,
onDelete, onDelete,
onGenerate, onGenerate,
@ -31,14 +33,16 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
<div className="flex items-center gap-1 flex-shrink-0 bg-gray-50 px-2 py-1 rounded-lg"> <div className="flex items-center gap-1 flex-shrink-0 bg-gray-50 px-2 py-1 rounded-lg">
<FaFileAlt className="h-4 w-4 text-blue-500" /> <FaFileAlt className="h-4 w-4 text-blue-500" />
<span className="text-xs text-gray-500 whitespace-nowrap">{template.parameters.length}</span> <span className="text-xs text-gray-500 whitespace-nowrap">
{template.parameters.length}
</span>
</div> </div>
</div> </div>
{/* Tags section with proper wrapping */} {/* Tags section with proper wrapping */}
<div className="flex items-center gap-1 mb-4 flex-wrap min-h-0"> <div className="flex items-center gap-1 mb-4 flex-wrap min-h-0">
<span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full font-medium flex-shrink-0"> <span className="text-xs bg-blue-100 text-blue-800 px-2 py-1 rounded-full font-medium flex-shrink-0">
{template.categoryName} {categories.find((c) => c.id === template.categoryId)?.name}
</span> </span>
{template.tags.slice(0, 2).map((tag) => ( {template.tags.slice(0, 2).map((tag) => (
<span <span
@ -56,13 +60,18 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
{/* Footer with date and actions */} {/* Footer with date and actions */}
<div className="flex flex-col gap-3 mt-auto pt-3 border-t border-gray-100"> <div className="flex flex-col gap-3 mt-auto pt-3 border-t border-gray-100">
<div className="text-xs text-gray-500"> <div className="text-xs text-gray-500">
<p className="truncate">{new Date(template.lastModificationTime || template.creationTime).toLocaleString('tr-TR', { <p className="truncate">
day: '2-digit', {new Date(template.lastModificationTime || template.creationTime).toLocaleString(
month: '2-digit', 'tr-TR',
year: 'numeric', {
hour: '2-digit', day: '2-digit',
minute: '2-digit' month: '2-digit',
})}</p> year: 'numeric',
hour: '2-digit',
minute: '2-digit',
},
)}
</p>
</div> </div>
<div className="flex items-center justify-center gap-2 w-full"> <div className="flex items-center justify-center gap-2 w-full">

View file

@ -25,7 +25,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
name: '', name: '',
description: '', description: '',
htmlContent: '', htmlContent: '',
categoryName: 'Genel Raporlar', categoryId: '',
tags: [] as string[], tags: [] as string[],
parameters: [] as ReportParameterDto[], parameters: [] as ReportParameterDto[],
}) })
@ -34,13 +34,23 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
const [tagInput, setTagInput] = useState('') const [tagInput, setTagInput] = useState('')
const [isSaving, setIsSaving] = useState(false) const [isSaving, setIsSaving] = useState(false)
// Debug kategorileri
useEffect(() => {
console.log('Categories received:', categories)
}, [categories])
// Debug form data değişimini takip et
useEffect(() => {
console.log('FormData changed:', formData)
}, [formData])
useEffect(() => { useEffect(() => {
if (template) { if (template) {
setFormData({ setFormData({
name: template.name, name: template.name,
description: template.description || '', description: template.description || '',
htmlContent: template.htmlContent, htmlContent: template.htmlContent,
categoryName: template.categoryName!, categoryId: template.categoryId!,
tags: template.tags, tags: template.tags,
parameters: template.parameters, parameters: template.parameters,
}) })
@ -49,7 +59,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
name: '', name: '',
description: '', description: '',
htmlContent: '', htmlContent: '',
categoryName: 'Genel Raporlar', categoryId: '',
tags: [], tags: [],
parameters: [], parameters: [],
}) })
@ -74,7 +84,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
// Yeni parametre oluştur // Yeni parametre oluştur
return { return {
id: crypto.randomUUID(), id: crypto.randomUUID(),
reportTemplateId: template?.id || '', templateId: template?.id || '',
name: paramName, name: paramName,
placeholder: `@@${paramName}`, placeholder: `@@${paramName}`,
type: 'text', type: 'text',
@ -99,6 +109,9 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
return return
} }
console.log('FormData before save:', formData)
console.log('Categories available:', categories)
setIsSaving(true) setIsSaving(true)
try { try {
await onSave(formData as unknown as ReportTemplateDto) await onSave(formData as unknown as ReportTemplateDto)
@ -213,17 +226,21 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
{translate('::App.Reports.TemplateEditor.Label.Category')} {translate('::App.Reports.TemplateEditor.Label.Category')}
</label> </label>
<select <select
value={formData.categoryName} value={formData.categoryId}
onChange={(e) => onChange={(e) => {
console.log('Category selected:', e.target.value)
setFormData((prev) => ({ setFormData((prev) => ({
...prev, ...prev,
categoryName: e.target.value, categoryId: e.target.value,
})) }))
} }}
className="block w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500" className="block w-full px-3 py-2 border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
> >
<option value="">
{translate('::App.Reports.TemplateEditor.Placeholder.SelectCategory')}
</option>
{categories.map((category) => ( {categories.map((category) => (
<option key={category.id} value={category.name}> <option key={category.id} value={category.id}>
{category.name} {category.name}
</option> </option>
))} ))}

View file

@ -9,7 +9,7 @@ export interface ReportCategoryDto {
export interface ReportParameterDto { export interface ReportParameterDto {
id: string id: string
reportTemplateId: string templateId: string
name: string name: string
placeholder?: string placeholder?: string
type: ReportParameterType type: ReportParameterType
@ -23,7 +23,7 @@ export interface ReportTemplateDto {
name: string name: string
description?: string description?: string
htmlContent: string htmlContent: string
categoryName?: string categoryId?: string
tags: string[] tags: string[]
parameters: ReportParameterDto[] parameters: ReportParameterDto[]
@ -40,7 +40,6 @@ export interface ReportGeneratedDto {
templateName: string templateName: string
generatedContent: string generatedContent: string
parameters: Record<string, string> parameters: Record<string, string>
generatedAt: string // ISO
// FullAuditedEntityDto alanları // FullAuditedEntityDto alanları
creationTime: string // ISO creationTime: string // ISO
@ -69,7 +68,7 @@ export interface CreateReportTemplateDto {
name: string name: string
description?: string description?: string
htmlContent: string htmlContent: string
categoryName?: string categoryId?: string
tags?: string[] tags?: string[]
parameters: CreateReportParameterDto[] parameters: CreateReportParameterDto[]
} }
@ -78,7 +77,7 @@ export interface UpdateReportTemplateDto {
name: string name: string
description?: string description?: string
htmlContent: string htmlContent: string
categoryName?: string categoryId?: string
tags?: string[] tags?: string[]
parameters: UpdateReportParameterDto[] parameters: UpdateReportParameterDto[]
} }
@ -95,7 +94,7 @@ export interface GetReportTemplatesInput {
maxResultCount?: number maxResultCount?: number
sorting?: string sorting?: string
filter?: string filter?: string
categoryName?: string categoryId?: string
} }
export interface GetReportsGeneratedInput { export interface GetReportsGeneratedInput {

View file

@ -38,7 +38,7 @@ export class ReportsService {
skipCount: input.skipCount, skipCount: input.skipCount,
maxResultCount: input.maxResultCount, maxResultCount: input.maxResultCount,
filter: input.filter, filter: input.filter,
categoryName: input.categoryName, categoryId: input.categoryId,
}, },
}, },
{ apiName: this.apiName }, { apiName: this.apiName },

View file

@ -191,14 +191,14 @@ export const useReports = () => {
[data.templates], [data.templates],
) )
const loadTemplatesByCategory = useCallback(async (categoryName?: string) => { const loadTemplatesByCategory = useCallback(async (categoryId?: string) => {
setIsLoading(true) setIsLoading(true)
try { try {
const templatesResponse = await reportsService.getTemplates({ const templatesResponse = await reportsService.getTemplates({
sorting: '', sorting: '',
skipCount: 0, skipCount: 0,
maxResultCount: 1000, maxResultCount: 1000,
categoryName: categoryName && categoryName !== 'Tümü' ? categoryName : undefined, categoryId: categoryId && categoryId !== 'Tümü' ? categoryId : undefined,
}) })
setData((prevData) => ({ setData((prevData) => ({

View file

@ -1,4 +1,4 @@
import { FaFolder, FaCommentDots, FaFileAlt, FaChartLine } from 'react-icons/fa'; import { FaFolder, FaCommentDots, FaFileAlt, FaChartLine } from 'react-icons/fa'
import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum' import { ForumCategory, ForumPost, ForumTopic } from '@/proxy/forum/forum'
import { useLocalization } from '@/utils/hooks/useLocalization' import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -62,7 +62,6 @@ export function AdminStats({ categories, topics, posts }: AdminStatsProps) {
dayjs.extend(relativeTime) dayjs.extend(relativeTime)
dayjs.locale('tr') dayjs.locale('tr')
// Topics -> "New topic created in {categoryName}"
topics.forEach((topic) => { topics.forEach((topic) => {
const category = categories.find((c) => c.id === topic.categoryId) const category = categories.find((c) => c.id === topic.categoryId)
if (topic.creationTime) { if (topic.creationTime) {