Report App Service2

This commit is contained in:
Sedat ÖZTÜRK 2025-08-15 14:52:30 +03:00
parent cd51347f3b
commit 8d3f39a2e9
17 changed files with 217 additions and 377 deletions

View file

@ -16,12 +16,12 @@ namespace Kurs.Platform.Reports;
public class ReportAppService : PlatformAppService, IReportAppService
{
private readonly IRepository<ReportTemplate, Guid> _reportTemplateRepository;
private readonly IRepository<GeneratedReport, Guid> _generatedReportRepository;
private readonly IRepository<ReportGenerated, Guid> _generatedReportRepository;
private readonly IRepository<ReportParameter, Guid> _reportParameterRepository;
public ReportAppService(
IRepository<ReportTemplate, Guid> reportTemplateRepository,
IRepository<GeneratedReport, Guid> generatedReportRepository,
IRepository<ReportGenerated, Guid> generatedReportRepository,
IRepository<ReportParameter, Guid> reportParameterRepository)
{
_reportTemplateRepository = reportTemplateRepository;
@ -222,7 +222,7 @@ public class ReportAppService : PlatformAppService, IReportAppService
generatedContent = generatedContent.Replace(pattern, param.Value ?? "");
}
var generatedReport = new GeneratedReport(
var generatedReport = new ReportGenerated(
GuidGenerator.Create(),
template.Id,
template.Name,
@ -297,7 +297,7 @@ public class ReportAppService : PlatformAppService, IReportAppService
return dto;
}
private GeneratedReportDto MapToGeneratedReportDto(GeneratedReport report)
private GeneratedReportDto MapToGeneratedReportDto(ReportGenerated report)
{
var dto = new GeneratedReportDto
{

View file

@ -34,12 +34,12 @@ namespace Kurs.Platform.Reports
.ForMember(dest => dest.Type, opt => opt.MapFrom(src => (Entities.ReportParameterType)src.Type))
.ForMember(dest => dest.ReportTemplateId, opt => opt.Ignore());
CreateMap<GeneratedReport, GeneratedReportDto>()
CreateMap<ReportGenerated, GeneratedReportDto>()
.ForMember(dest => dest.Parameters, opt => opt.MapFrom(src =>
ConvertParametersFromJson(src.Parameters)))
.ForMember(dest => dest.Template, opt => opt.MapFrom(src => src.Template));
CreateMap<GenerateReportDto, GeneratedReport>()
CreateMap<GenerateReportDto, ReportGenerated>()
.ForMember(dest => dest.Parameters, opt => opt.MapFrom(src => ConvertParametersToJson(src.Parameters)))
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.TemplateId, opt => opt.MapFrom(src => src.TemplateId))

View file

@ -25660,7 +25660,7 @@
},
{
"key": "admin.reports.view",
"path": "/admin/reports/:id",
"path": "/admin/report/:id",
"componentPath": "@/views/report/ReportViewerPage",
"routeType": "protected",
"authority": ["App.Reports.Update"]

View file

@ -4,7 +4,7 @@ using Volo.Abp.Domain.Entities.Auditing;
namespace Kurs.Platform.Entities
{
public class GeneratedReport : FullAuditedAggregateRoot<Guid>
public class ReportGenerated : FullAuditedAggregateRoot<Guid>
{
public Guid? TemplateId { get; set; }
@ -22,12 +22,12 @@ namespace Kurs.Platform.Entities
// Navigation property
public virtual ReportTemplate Template { get; set; }
public GeneratedReport()
public ReportGenerated()
{
GeneratedAt = DateTime.UtcNow;
}
public GeneratedReport(
public ReportGenerated(
Guid id,
Guid? templateId,
string templateName,

View file

@ -6,9 +6,9 @@ using Volo.Abp.Domain.Repositories;
namespace Kurs.Platform.Repositories
{
public interface IGeneratedReportRepository : IRepository<GeneratedReport, Guid>
public interface IGeneratedReportRepository : IRepository<ReportGenerated, Guid>
{
Task<List<GeneratedReport>> GetListAsync(
Task<List<ReportGenerated>> GetListAsync(
int skipCount = 0,
int maxResultCount = int.MaxValue,
string sorting = null,
@ -18,8 +18,8 @@ namespace Kurs.Platform.Repositories
Task<long> GetCountAsync(string filter = null, Guid? templateId = null);
Task<List<GeneratedReport>> GetByTemplateIdAsync(Guid? templateId);
Task<List<ReportGenerated>> GetByTemplateIdAsync(Guid? templateId);
Task<GeneratedReport> GetByIdWithTemplateAsync(Guid id);
Task<ReportGenerated> GetByIdWithTemplateAsync(Guid id);
}
}

View file

@ -84,7 +84,7 @@ public class PlatformDbContext :
// Reports Entities
public DbSet<ReportTemplate> ReportTemplates { get; set; }
public DbSet<ReportParameter> ReportParameters { get; set; }
public DbSet<GeneratedReport> GeneratedReports { get; set; }
public DbSet<ReportGenerated> GeneratedReports { get; set; }
public DbSet<ListFormImport> ListFormImports { get; set; }
public DbSet<ListFormImportExecute> ListFormImportExecutes { get; set; }
@ -723,9 +723,9 @@ public class PlatformDbContext :
b.Property(x => x.Description).HasMaxLength(1000);
});
builder.Entity<GeneratedReport>(b =>
builder.Entity<ReportGenerated>(b =>
{
b.ToTable(PlatformConsts.DbTablePrefix + nameof(GeneratedReport), PlatformConsts.DbSchema);
b.ToTable(PlatformConsts.DbTablePrefix + nameof(ReportGenerated), PlatformConsts.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.TemplateId).IsRequired(false); // Nullable yapıyoruz

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Kurs.Platform.Migrations
{
[DbContext(typeof(PlatformDbContext))]
[Migration("20250815110914_Reports")]
[Migration("20250815115111_Reports")]
partial class Reports
{
/// <inheritdoc />
@ -2039,79 +2039,6 @@ namespace Kurs.Platform.Migrations
b.ToTable("PDataSource", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.GeneratedReport", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<DateTime>("GeneratedAt")
.HasColumnType("datetime2");
b.Property<string>("GeneratedContent")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Parameters")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<Guid?>("TemplateId")
.HasColumnType("uniqueidentifier");
b.Property<string>("TemplateName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("TemplateId");
b.ToTable("PGeneratedReport", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.GlobalSearch", b =>
{
b.Property<int>("Id")
@ -2959,6 +2886,79 @@ namespace Kurs.Platform.Migrations
b.ToTable("PProduct", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<DateTime>("GeneratedAt")
.HasColumnType("datetime2");
b.Property<string>("GeneratedContent")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Parameters")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<Guid?>("TemplateId")
.HasColumnType("uniqueidentifier");
b.Property<string>("TemplateName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("TemplateId");
b.ToTable("PReportGenerated", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b =>
{
b.Property<Guid>("Id")
@ -5959,16 +5959,6 @@ namespace Kurs.Platform.Migrations
b.Navigation("Entity");
});
modelBuilder.Entity("Kurs.Platform.Entities.GeneratedReport", b =>
{
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template")
.WithMany()
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Template");
});
modelBuilder.Entity("Kurs.Platform.Entities.ListFormCustomization", b =>
{
b.HasOne("Kurs.Platform.Entities.ListForm", null)
@ -5989,6 +5979,16 @@ namespace Kurs.Platform.Migrations
.IsRequired();
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b =>
{
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template")
.WithMany()
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Template");
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b =>
{
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate")

View file

@ -37,7 +37,7 @@ namespace Kurs.Platform.Migrations
});
migrationBuilder.CreateTable(
name: "PGeneratedReport",
name: "PReportGenerated",
columns: table => new
{
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
@ -58,9 +58,9 @@ namespace Kurs.Platform.Migrations
},
constraints: table =>
{
table.PrimaryKey("PK_PGeneratedReport", x => x.Id);
table.PrimaryKey("PK_PReportGenerated", x => x.Id);
table.ForeignKey(
name: "FK_PGeneratedReport_PReportTemplate_TemplateId",
name: "FK_PReportGenerated_PReportTemplate_TemplateId",
column: x => x.TemplateId,
principalTable: "PReportTemplate",
principalColumn: "Id",
@ -99,8 +99,8 @@ namespace Kurs.Platform.Migrations
});
migrationBuilder.CreateIndex(
name: "IX_PGeneratedReport_TemplateId",
table: "PGeneratedReport",
name: "IX_PReportGenerated_TemplateId",
table: "PReportGenerated",
column: "TemplateId");
migrationBuilder.CreateIndex(
@ -113,7 +113,7 @@ namespace Kurs.Platform.Migrations
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "PGeneratedReport");
name: "PReportGenerated");
migrationBuilder.DropTable(
name: "PReportParameter");

View file

@ -2036,79 +2036,6 @@ namespace Kurs.Platform.Migrations
b.ToTable("PDataSource", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.GeneratedReport", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<DateTime>("GeneratedAt")
.HasColumnType("datetime2");
b.Property<string>("GeneratedContent")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Parameters")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<Guid?>("TemplateId")
.HasColumnType("uniqueidentifier");
b.Property<string>("TemplateName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("TemplateId");
b.ToTable("PGeneratedReport", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.GlobalSearch", b =>
{
b.Property<int>("Id")
@ -2956,6 +2883,79 @@ namespace Kurs.Platform.Migrations
b.ToTable("PProduct", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b =>
{
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("nvarchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("uniqueidentifier")
.HasColumnName("CreatorId");
b.Property<Guid?>("DeleterId")
.HasColumnType("uniqueidentifier")
.HasColumnName("DeleterId");
b.Property<DateTime?>("DeletionTime")
.HasColumnType("datetime2")
.HasColumnName("DeletionTime");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("nvarchar(max)")
.HasColumnName("ExtraProperties");
b.Property<DateTime>("GeneratedAt")
.HasColumnType("datetime2");
b.Property<string>("GeneratedContent")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<bool>("IsDeleted")
.ValueGeneratedOnAdd()
.HasColumnType("bit")
.HasDefaultValue(false)
.HasColumnName("IsDeleted");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime2")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("uniqueidentifier")
.HasColumnName("LastModifierId");
b.Property<string>("Parameters")
.HasMaxLength(4000)
.HasColumnType("nvarchar(4000)");
b.Property<Guid?>("TemplateId")
.HasColumnType("uniqueidentifier");
b.Property<string>("TemplateName")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.HasKey("Id");
b.HasIndex("TemplateId");
b.ToTable("PReportGenerated", (string)null);
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b =>
{
b.Property<Guid>("Id")
@ -5956,16 +5956,6 @@ namespace Kurs.Platform.Migrations
b.Navigation("Entity");
});
modelBuilder.Entity("Kurs.Platform.Entities.GeneratedReport", b =>
{
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template")
.WithMany()
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Template");
});
modelBuilder.Entity("Kurs.Platform.Entities.ListFormCustomization", b =>
{
b.HasOne("Kurs.Platform.Entities.ListForm", null)
@ -5986,6 +5976,16 @@ namespace Kurs.Platform.Migrations
.IsRequired();
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportGenerated", b =>
{
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "Template")
.WithMany()
.HasForeignKey("TemplateId")
.OnDelete(DeleteBehavior.SetNull);
b.Navigation("Template");
});
modelBuilder.Entity("Kurs.Platform.Entities.ReportParameter", b =>
{
b.HasOne("Kurs.Platform.Entities.ReportTemplate", "ReportTemplate")

View file

@ -28,7 +28,7 @@ export const Dashboard: React.FC = () => {
return templates.filter((template) => {
const matchesSearch =
template.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
template.description.toLowerCase().includes(searchQuery.toLowerCase()) ||
template.description?.toLowerCase().includes(searchQuery.toLowerCase()) ||
template.tags.some((tag: any) => tag.toLowerCase().includes(searchQuery.toLowerCase()))
const matchesCategory = selectedCategory === 'Tümü' || template.category === selectedCategory

View file

@ -1,140 +0,0 @@
import React from 'react'
import { Plus, Trash2 } from 'lucide-react'
import { ReportParameterDto } from '@/proxy/reports/models'
import { Button, Input } from '../ui'
interface ParameterFormProps {
parameters: ReportParameterDto[]
onChange: (parameters: ReportParameterDto[]) => void
}
export const ParameterForm: React.FC<ParameterFormProps> = ({ parameters, onChange }) => {
const addParameter = () => {
const newParameter: ReportParameterDto = {
id: crypto.randomUUID(),
name: '',
placeholder: '',
type: 'text',
required: false,
description: '',
}
onChange([...parameters, newParameter])
}
const updateParameter = (id: string, updates: Partial<ReportParameterDto>) => {
onChange(parameters.map((param) => (param.id === id ? { ...param, ...updates } : param)))
}
const removeParameter = (id: string) => {
onChange(parameters.filter((param) => param.id !== id))
}
const generatePlaceholder = (name: string) => {
return `@@${name.toUpperCase()}`
}
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h3 className="text-lg font-medium text-gray-900">Parametre Tanımları</h3>
<Button onClick={addParameter} size="sm">
<Plus className="h-4 w-4 mr-2" />
Parametre Ekle
</Button>
</div>
{parameters.length === 0 ? (
<div className="py-8 text-gray-500">
<p>Henüz parametre eklenmemiş.</p>
<p className="text-sm">Dinamik içerik için parametreler ekleyin.</p>
</div>
) : (
<div className="space-y-4">
{parameters.map((param, index) => (
<div key={param.id} className="bg-gray-50 p-4 rounded-lg border border-gray-200">
<div className="flex items-start justify-between mb-4">
<h4 className="font-medium text-gray-900">Parametre #{index + 1}</h4>
<Button variant="solid" size="sm" onClick={() => removeParameter(param.id)}>
<Trash2 className="h-4 w-4" />
</Button>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Input
value={param.name}
onChange={(e) => {
const name = e.target.value
updateParameter(param.id, {
name,
placeholder: generatePlaceholder(name),
})
}}
placeholder="Parametre Adı Örn: SIRKETADI"
/>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Parametre Tipi
</label>
<select
value={param.type}
onChange={(e) =>
updateParameter(param.id, {
type: e.target.value as ReportParameterDto['type'],
})
}
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="text">Metin</option>
<option value="number">Sayı</option>
<option value="date">Tarih</option>
<option value="email">E-posta</option>
<option value="url">URL</option>
</select>
</div>
<Input
placeholder="Varsayılan Değer"
value={param.defaultValue || ''}
onChange={(e) => updateParameter(param.id, { defaultValue: e.target.value })}
/>
<div className="flex items-center">
<input
type="checkbox"
id={`required-${param.id}`}
checked={param.required}
onChange={(e) => updateParameter(param.id, { required: e.target.checked })}
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
<label htmlFor={`required-${param.id}`} className="ml-2 text-sm text-gray-700">
Zorunlu parametre
</label>
</div>
</div>
<div className="mt-4">
<Input
value={param.description || ''}
onChange={(e) => updateParameter(param.id, { description: e.target.value })}
placeholder="Açıklama"
rows={2}
textArea={true}
/>
</div>
{param.name && (
<div className="mt-3 p-2 bg-blue-50 rounded border-l-4 border-blue-400">
<p className="text-sm text-blue-700">
<strong>Kullanım:</strong>{' '}
<code className="bg-blue-100 px-1 rounded">{param.placeholder}</code>
</p>
</div>
)}
</div>
))}
</div>
)}
</div>
)
}

View file

@ -4,14 +4,14 @@ import { Button } from '../ui/Button'
import { ArrowLeft, Calendar, FileText, Download, ZoomIn, ZoomOut } from 'lucide-react'
import html2canvas from 'html2canvas'
import jsPDF from 'jspdf'
import { GeneratedReportDto, ReportTemplateDto } from '@/proxy/reports/models'
import { ReportGeneratedDto, ReportTemplateDto } from '@/proxy/reports/models'
import { useReports } from '@/utils/hooks/useReports'
export const ReportViewer: React.FC = () => {
const { id } = useParams<{ id: string }>()
const navigate = useNavigate()
const [zoomLevel, setZoomLevel] = useState(100)
const [report, setReport] = useState<GeneratedReportDto | null>(null)
const [report, setReport] = useState<ReportGeneratedDto | null>(null)
const [template, setTemplate] = useState<ReportTemplateDto | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)

View file

@ -16,10 +16,6 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
onDelete,
onGenerate,
}) => {
const formatDate = (date: Date) => {
return new Date(date).toLocaleDateString('tr-TR')
}
return (
<div className="bg-white rounded-xl shadow-md hover:shadow-lg transition-all duration-200 border border-gray-200">
<div className="p-6">
@ -54,7 +50,7 @@ export const TemplateCard: React.FC<TemplateCardProps> = ({
<div className="flex items-center justify-between">
<div className="text-xs text-gray-500">
<p>Güncellenme: {formatDate(template.lastModificationTime)}</p>
<p>Güncellenme: {template.lastModificationTime}</p>
</div>
<div className="flex items-center space-x-2">

View file

@ -34,9 +34,9 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
if (template) {
setFormData({
name: template.name,
description: template.description,
description: template.description || '',
htmlContent: template.htmlContent,
category: template.category,
category: template.category || 'Genel',
tags: template.tags,
parameters: template.parameters,
})
@ -70,6 +70,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
// Yeni parametre oluştur
return {
id: crypto.randomUUID(),
reportTemplateId: template?.id || '',
name: paramName,
placeholder: `@@${paramName}`,
type: 'text',
@ -96,7 +97,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
setIsSaving(true)
try {
await onSave(formData)
await onSave(formData as unknown as ReportTemplateDto)
onClose()
} catch (error) {
console.error('Error saving template:', error)
@ -166,6 +167,7 @@ export const TemplateEditor: React.FC<TemplateEditorProps> = ({
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 h-full">
<div className="space-y-4">
<Input
autoFocus
value={formData.name}
onChange={(e) =>
setFormData((prev) => ({

View file

@ -1,23 +1,11 @@
// reports.models.ts
/** Enum, backend ile birebir (0..4) */
export enum ReportParameterType {
Text = 0,
Number = 1,
Date = 2,
Email = 3,
Url = 4,
}
/** ---- API MODELLERİ (Raw JSON) ---- */
/** Not: Tarihler APIden ISO string olarak gelir (Date değil) */
export type ReportParameterType = 'text' | 'number' | 'date' | 'select' | 'checkbox'
export interface ReportParameterDto {
id: string
reportTemplateId: string
name: string
placeholder?: string
type: ReportParameterType // enum (0..4)
type: ReportParameterType
defaultValue?: string
required: boolean
description?: string
@ -39,7 +27,7 @@ export interface ReportTemplateDto {
lastModifierId?: string
}
export interface GeneratedReportDto {
export interface ReportGeneratedDto {
id: string
templateId?: string | null
templateName: string
@ -89,7 +77,7 @@ export interface UpdateReportTemplateDto {
}
/** Generate inputu */
export interface GenerateReportDto {
export interface ReportGenerateDto {
templateId: string
parameters: Record<string, string>
}
@ -103,16 +91,10 @@ export interface GetReportTemplatesInput {
category?: string
}
export interface GetGeneratedReportsInput {
export interface GetReportsGeneratedInput {
skipCount?: number
maxResultCount?: number
sorting?: string
filter?: string
templateId?: string
}
/** (Opsiyonel) Paged wrapper — projende zaten varsa bunu kullanmana gerek yok */
export interface PagedResultDto<T> {
items: T[]
totalCount: number
}

View file

@ -1,16 +1,16 @@
import {
ReportTemplateDto,
GeneratedReportDto,
ReportGeneratedDto,
CreateReportTemplateDto,
UpdateReportTemplateDto,
GenerateReportDto, // backend'deki GenerateReportDto (templateId + parameters)
ReportGenerateDto, // backend'deki GenerateReportDto (templateId + parameters)
} from '@/proxy/reports/models'
import apiService from './api.service'
import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy'
export interface ReportsData {
templates: ReportTemplateDto[]
generatedReports: GeneratedReportDto[]
generatedReports: ReportGeneratedDto[]
}
export class ReportsService {
@ -71,7 +71,7 @@ export class ReportsService {
// GENERATED REPORTS
getGeneratedReports = (input: PagedAndSortedResultRequestDto) =>
apiService.fetchData<PagedResultDto<GeneratedReportDto>, PagedAndSortedResultRequestDto>(
apiService.fetchData<PagedResultDto<ReportGeneratedDto>, PagedAndSortedResultRequestDto>(
{
method: 'GET',
url: '/api/app/report/generated-reports', // ✔ Swagger: GET /api/app/report/generated-reports
@ -85,7 +85,7 @@ export class ReportsService {
)
getGeneratedReportById = (id: string) =>
apiService.fetchData<GeneratedReportDto>(
apiService.fetchData<ReportGeneratedDto>(
{
method: 'GET',
url: `/api/app/report/${id}/generated-report`, // ✔ Swagger: GET /api/app/report/{id}/generated-report
@ -93,8 +93,8 @@ export class ReportsService {
{ apiName: this.apiName },
)
generateReport = (input: GenerateReportDto) =>
apiService.fetchData<GeneratedReportDto, GenerateReportDto>(
generateReport = (input: ReportGenerateDto) =>
apiService.fetchData<ReportGeneratedDto, ReportGenerateDto>(
{
method: 'POST',
url: '/api/app/report/generate-report', // ✔ Swagger: POST /api/app/report/generate-report

View file

@ -1,4 +1,4 @@
import { GeneratedReportDto, ReportTemplateDto } from '@/proxy/reports/models'
import { ReportGeneratedDto, ReportTemplateDto } from '@/proxy/reports/models'
import ReportsService from '@/services/reports.service'
import { useState, useCallback, useEffect } from 'react'
@ -6,7 +6,7 @@ const reportsService = new ReportsService()
interface ReportData {
templates: ReportTemplateDto[]
generatedReports: GeneratedReportDto[]
generatedReports: ReportGeneratedDto[]
}
export const useReports = () => {
@ -127,13 +127,13 @@ export const useReports = () => {
async (templateId: string, parameterValues: Record<string, string>) => {
setIsLoading(true)
try {
const reportData: GeneratedReportDto = {
const reportData: ReportGeneratedDto = {
templateId,
parameters: parameterValues,
} as GeneratedReportDto
} as ReportGeneratedDto
const response = await reportsService.generateReport(reportData)
const report = response.data as GeneratedReportDto
const report = response.data as ReportGeneratedDto
if (report) {
// Update local state
@ -158,7 +158,7 @@ export const useReports = () => {
async (reportId: string) => {
try {
const response = await reportsService.getGeneratedReportById(reportId)
return response.data as GeneratedReportDto
return response.data as ReportGeneratedDto
} catch (error) {
console.error('Error getting report by id:', error)
// Fallback to local data