ReportCategory ve ReportTemplate arasındaki bağlantı

This commit is contained in:
Sedat ÖZTÜRK 2026-06-16 15:54:01 +03:00
parent 08b83cc42d
commit ec438afab5
11 changed files with 121 additions and 47 deletions

View file

@ -1443,8 +1443,8 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
]} ]}
}), }),
DeleteCommand = $"UPDATE \"{FullNameTable(TableNameEnum.ReportCategory)}\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id", DeleteCommand = $"UPDATE \"{FullNameTable(TableNameEnum.ReportCategory)}\" SET \"DeleterId\"=@DeleterId, \"DeletionTime\"=CURRENT_TIMESTAMP, \"IsDeleted\"='true' WHERE \"Id\"=@Id",
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(), DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(DbType.String),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(), InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(DbType.String, "Name"),
}); });
#region Report Categories Fields #region Report Categories Fields
@ -1586,7 +1586,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
AuthName = listFormName, AuthName = listFormName,
Url=$"/admin/reports/TemplateReport/view?id=@Id", Url=$"/admin/reports/TemplateReport/view?id=@Id",
IsVisible = true, IsVisible = true,
VisibleExpression = "((e)=> e.row.data.Description !== 'Liste Raporları')" VisibleExpression = "((e)=> e.row.data.CategoryId !== 'Listeler')"
}, },
new() { new() {
Hint = "App.Platform.Design", Hint = "App.Platform.Design",
@ -1595,7 +1595,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
AuthName = listFormName + ".Update", AuthName = listFormName + ".Update",
Url=$"/admin/reports/TemplateReport/design?id=@Id", Url=$"/admin/reports/TemplateReport/design?id=@Id",
IsVisible = true, IsVisible = true,
VisibleExpression = "((e)=> e.row.data.Description !== 'Liste Raporları')" VisibleExpression = "((e)=> e.row.data.CategoryId !== 'Listeler')"
}, },
new() { new() {
Hint = "App.Platform.View", Hint = "App.Platform.View",
@ -1604,7 +1604,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
AuthName = listFormName, AuthName = listFormName,
Url=$"/admin/reports/DynamicListFormReport/view?listFormCode=@Name", Url=$"/admin/reports/DynamicListFormReport/view?listFormCode=@Name",
IsVisible = true, IsVisible = true,
VisibleExpression = "((e)=> e.row.data.Description !== 'Liste Raporları')" VisibleExpression = "((e)=> e.row.data.CategoryId === 'Listeler')"
}, },
}), }),
} }

View file

@ -5,7 +5,7 @@ using Volo.Abp.MultiTenancy;
namespace Sozsoft.Platform.Entities namespace Sozsoft.Platform.Entities
{ {
public class ReportCategory : FullAuditedEntity<Guid>, IMultiTenant public class ReportCategory : FullAuditedEntity<string>, IMultiTenant
{ {
public Guid? TenantId { get; set; } public Guid? TenantId { get; set; }
@ -14,6 +14,11 @@ namespace Sozsoft.Platform.Entities
public string Icon { get; set; } public string Icon { get; set; }
public ICollection<ReportTemplate> ReportTemplates { get; set; } public ICollection<ReportTemplate> ReportTemplates { get; set; }
public ReportCategory(string id)
{
Id = id;
}
} }
} }

View file

@ -11,17 +11,19 @@ namespace Sozsoft.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 Guid CategoryId { get; set; }
public string CategoryId { get; set; }
public ReportCategory ReportCategory { get; set; }
public string Status { get; set; } public string Status { get; set; }
public ReportCategory ReportCategory { get; set; }
public ReportTemplate( public ReportTemplate(
Guid id, Guid id,
string name, string name,
string description, string description,
string htmlContent, string htmlContent,
Guid categoryId, string categoryId,
string status string status
) : base(id) ) : base(id)
{ {

View file

@ -648,17 +648,12 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ReportCategory)), Prefix.DbSchema); b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ReportCategory)), Prefix.DbSchema);
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(256);
b.Property(x => x.Name).IsRequired().HasMaxLength(256); b.Property(x => x.Name).IsRequired().HasMaxLength(256);
b.Property(x => x.Description).HasMaxLength(4096); // JSON string b.Property(x => x.Description).HasMaxLength(4096); // JSON string
b.Property(x => x.Icon).HasMaxLength(64); b.Property(x => x.Icon).HasMaxLength(64);
b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0"); b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasMany(x => x.ReportTemplates)
.WithOne(x => x.ReportCategory)
.HasForeignKey(x => x.CategoryId)
.HasPrincipalKey(c => c.Id)
.OnDelete(DeleteBehavior.Cascade);
}); });
builder.Entity<ReportTemplate>(b => builder.Entity<ReportTemplate>(b =>
@ -667,11 +662,18 @@ public class PlatformDbContext :
b.ConfigureByConvention(); b.ConfigureByConvention();
b.Property(x => x.Name).IsRequired().HasMaxLength(256); b.Property(x => x.Name).IsRequired().HasMaxLength(256);
b.Property(x => x.CategoryId).HasMaxLength(256);
b.Property(x => x.Description).HasMaxLength(1024); b.Property(x => x.Description).HasMaxLength(1024);
b.Property(x => x.HtmlContent).IsRequired(); b.Property(x => x.HtmlContent).IsRequired();
b.Property(x => x.Status).HasMaxLength(20); b.Property(x => x.Status).HasMaxLength(20);
b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0"); b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasOne(x => x.ReportCategory)
.WithMany(x => x.ReportTemplates)
.HasPrincipalKey(x => x.Id)
.HasForeignKey(x => x.CategoryId)
.OnDelete(DeleteBehavior.Restrict);
}); });
//Administration //Administration

View file

@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
namespace Sozsoft.Platform.Migrations namespace Sozsoft.Platform.Migrations
{ {
[DbContext(typeof(PlatformDbContext))] [DbContext(typeof(PlatformDbContext))]
[Migration("20260615110840_Initial")] [Migration("20260616123136_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@ -4289,8 +4289,9 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b => modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b =>
{ {
b.Property<Guid>("Id") b.Property<string>("Id")
.HasColumnType("uniqueidentifier"); .HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -4353,8 +4354,9 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<Guid>("CategoryId") b.Property<string>("CategoryId")
.HasColumnType("uniqueidentifier"); .HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -8586,8 +8588,7 @@ namespace Sozsoft.Platform.Migrations
b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory") b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory")
.WithMany("ReportTemplates") .WithMany("ReportTemplates")
.HasForeignKey("CategoryId") .HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Restrict);
.IsRequired();
b.Navigation("ReportCategory"); b.Navigation("ReportCategory");
}); });

View file

@ -651,7 +651,7 @@ namespace Sozsoft.Platform.Migrations
name: "Adm_T_ReportCategory", name: "Adm_T_ReportCategory",
columns: table => new columns: table => new
{ {
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false), Id = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true), TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
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(max)", maxLength: 4096, nullable: true), Description = table.Column<string>(type: "nvarchar(max)", maxLength: 4096, nullable: true),
@ -2244,7 +2244,7 @@ namespace Sozsoft.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(1024)", maxLength: 1024, nullable: true), Description = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false), HtmlContent = table.Column<string>(type: "nvarchar(max)", nullable: false),
CategoryId = table.Column<Guid>(type: "uniqueidentifier", nullable: false), CategoryId = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: true),
Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true), Status = table.Column<string>(type: "nvarchar(20)", maxLength: 20, 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),
@ -2262,7 +2262,7 @@ namespace Sozsoft.Platform.Migrations
column: x => x.CategoryId, column: x => x.CategoryId,
principalTable: "Adm_T_ReportCategory", principalTable: "Adm_T_ReportCategory",
principalColumn: "Id", principalColumn: "Id",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Restrict);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(

View file

@ -4286,8 +4286,9 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b => modelBuilder.Entity("Sozsoft.Platform.Entities.ReportCategory", b =>
{ {
b.Property<Guid>("Id") b.Property<string>("Id")
.HasColumnType("uniqueidentifier"); .HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -4350,8 +4351,9 @@ namespace Sozsoft.Platform.Migrations
b.Property<Guid>("Id") b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier"); .HasColumnType("uniqueidentifier");
b.Property<Guid>("CategoryId") b.Property<string>("CategoryId")
.HasColumnType("uniqueidentifier"); .HasMaxLength(256)
.HasColumnType("nvarchar(256)");
b.Property<DateTime>("CreationTime") b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2") .HasColumnType("datetime2")
@ -8583,8 +8585,7 @@ namespace Sozsoft.Platform.Migrations
b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory") b.HasOne("Sozsoft.Platform.Entities.ReportCategory", "ReportCategory")
.WithMany("ReportTemplates") .WithMany("ReportTemplates")
.HasForeignKey("CategoryId") .HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Restrict);
.IsRequired();
b.Navigation("ReportCategory"); b.Navigation("ReportCategory");
}); });

View file

@ -1362,20 +1362,25 @@
} }
], ],
"ReportCategories": [ "ReportCategories": [
{
"name": "Genel Raporlar",
"description": "Şirket içi genel tüm raporlar",
"icon": "📊"
},
{ {
"name": "Taahhütnameler", "name": "Taahhütnameler",
"description": "Kursiyeler ile ilgili taahhütname raporları", "description": "Kursiyeler ile ilgili taahhütname raporları",
"icon": "✍️" "icon": "✍️"
}, },
{
"name": "Raporlar",
"description": "Şirket içi genel tüm raporlar",
"icon": "📊"
},
{ {
"name": "Listeler", "name": "Listeler",
"description": "Tüm listelerin raporları", "description": "Tüm listelerin raporları",
"icon": "📜" "icon": "📜"
},
{
"name": "Formlar",
"description": "Tüm single formların raporları",
"icon": "📜"
} }
], ],
"ReportTemplates": [ "ReportTemplates": [

View file

@ -490,7 +490,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
private readonly IRepository<GlobalSearch, int> _globalSearch; private readonly IRepository<GlobalSearch, int> _globalSearch;
private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository; private readonly IRepository<CustomEndpoint, Guid> _customEndpointRepository;
private readonly IRepository<CustomComponent, Guid> _customComponentRepository; private readonly IRepository<CustomComponent, Guid> _customComponentRepository;
private readonly IRepository<ReportCategory, Guid> _reportCategoriesRepository; private readonly IRepository<ReportCategory, string> _reportCategoriesRepository;
private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository; private readonly IRepository<ReportTemplate, Guid> _reportTemplatesRepository;
private readonly IRepository<Home, Guid> _homeRepository; private readonly IRepository<Home, Guid> _homeRepository;
private readonly IRepository<About, Guid> _aboutRepository; private readonly IRepository<About, Guid> _aboutRepository;
@ -547,7 +547,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
IRepository<SkillLevel, string> skillLevelRepository, IRepository<SkillLevel, string> skillLevelRepository,
IRepository<CustomEndpoint, Guid> customEndpointRepository, IRepository<CustomEndpoint, Guid> customEndpointRepository,
IRepository<CustomComponent, Guid> customComponentRepository, IRepository<CustomComponent, Guid> customComponentRepository,
IRepository<ReportCategory, Guid> reportCategoriesRepository, IRepository<ReportCategory, string> reportCategoriesRepository,
IRepository<ReportTemplate, Guid> reportTemplatesRepository, IRepository<ReportTemplate, Guid> reportTemplatesRepository,
IRepository<Home, Guid> homeRepository, IRepository<Home, Guid> homeRepository,
IRepository<About, Guid> aboutRepository, IRepository<About, Guid> aboutRepository,
@ -865,7 +865,7 @@ public class TenantDataSeeder : IDataSeedContributor, ITransientDependency
if (!exists) if (!exists)
{ {
await _reportCategoriesRepository.InsertAsync(new ReportCategory await _reportCategoriesRepository.InsertAsync(new ReportCategory(item.Name)
{ {
Name = item.Name, Name = item.Name,
Description = item.Description, Description = item.Description,

View file

@ -224,7 +224,7 @@ public class DynamicListFormReport : XtraReport
var topMargin = new TopMarginBand { HeightF = Margins.Top }; var topMargin = new TopMarginBand { HeightF = Margins.Top };
var bottomMargin = new BottomMarginBand { HeightF = 32 }; var bottomMargin = new BottomMarginBand { HeightF = 32 };
var reportHeader = new ReportHeaderBand { HeightF = 42 }; var reportHeader = new ReportHeaderBand { HeightF = 32 };
var pageHeader = new PageHeaderBand { HeightF = 28 }; var pageHeader = new PageHeaderBand { HeightF = 28 };
var detail = new DetailBand { HeightF = 24 }; var detail = new DetailBand { HeightF = 24 };
var reportFooter = new ReportFooterBand { HeightF = HasAnySummary(fields) ? 28 : 0 }; var reportFooter = new ReportFooterBand { HeightF = HasAnySummary(fields) ? 28 : 0 };
@ -244,11 +244,11 @@ public class DynamicListFormReport : XtraReport
{ {
PageInfo = PageInfo.DateTime, PageInfo = PageInfo.DateTime,
TextFormatString = "{0:dd.MM.yyyy HH:mm}", TextFormatString = "{0:dd.MM.yyyy HH:mm}",
BoundsF = new System.Drawing.RectangleF(0, 30, pageWidth / 2, 12), BoundsF = new System.Drawing.RectangleF(0, 0, pageWidth / 2, 18),
Font = new DXFont("Arial", 7.5F), Font = new DXFont("Arial", 7.5F),
TextAlignment = TextAlignment.MiddleLeft TextAlignment = TextAlignment.MiddleLeft
}; };
reportHeader.Controls.Add(generatedAt); bottomMargin.Controls.Add(generatedAt);
var pageInfo = new XRPageInfo var pageInfo = new XRPageInfo
{ {

View file

@ -8,12 +8,29 @@ import ReportViewer, {
} from 'devexpress-reporting-react/dx-report-viewer' } from 'devexpress-reporting-react/dx-report-viewer'
import { ajaxSetup } from '@devexpress/analytics-core/analytics-utils-native' import { ajaxSetup } from '@devexpress/analytics-core/analytics-utils-native'
import { APP_NAME } from '@/constants/app.constant' import { APP_NAME } from '@/constants/app.constant'
import { MODE_DARK } from '@/constants/theme.constant'
import { useStoreState } from '@/store' import { useStoreState } from '@/store'
const loadViewerCss = () => { const VIEWER_THEME_LINK_ID = 'devexpress-report-viewer-theme'
const VIEWER_DARK_OVERRIDES_ID = 'devexpress-report-viewer-dark-overrides'
const getViewerClassName = (isDarkMode: boolean) =>
[
'dx-viewport',
'dx-device-desktop',
'dx-device-generic',
'dx-theme-generic',
'dx-theme-generic-typography',
isDarkMode ? 'dx-color-scheme-dark' : 'dx-color-scheme-light',
'report-viewer-shell',
isDarkMode ? 'report-viewer-shell-dark' : '',
]
.filter(Boolean)
.join(' ')
const loadViewerCss = (isDarkMode: boolean) => {
const styles = [ const styles = [
new URL('@devexpress/analytics-core/dist/css/dx-analytics.common.css', import.meta.url).href, new URL('@devexpress/analytics-core/dist/css/dx-analytics.common.css', import.meta.url).href,
new URL('@devexpress/analytics-core/dist/css/dx-analytics.light.css', import.meta.url).href,
new URL('devexpress-reporting/dist/css/dx-webdocumentviewer.css', import.meta.url).href, new URL('devexpress-reporting/dist/css/dx-webdocumentviewer.css', import.meta.url).href,
] ]
@ -24,6 +41,45 @@ const loadViewerCss = () => {
link.href = href link.href = href
document.head.appendChild(link) document.head.appendChild(link)
}) })
const themeHref = isDarkMode
? new URL('@devexpress/analytics-core/dist/css/dx-analytics.dark.css', import.meta.url).href
: new URL('@devexpress/analytics-core/dist/css/dx-analytics.light.css', import.meta.url).href
let themeLink = document.getElementById(VIEWER_THEME_LINK_ID) as HTMLLinkElement | null
if (!themeLink) {
themeLink = document.createElement('link')
themeLink.id = VIEWER_THEME_LINK_ID
themeLink.rel = 'stylesheet'
document.head.appendChild(themeLink)
}
if (themeLink.href !== themeHref) {
themeLink.href = themeHref
}
if (!document.getElementById(VIEWER_DARK_OVERRIDES_ID)) {
const style = document.createElement('style')
style.id = VIEWER_DARK_OVERRIDES_ID
style.textContent = `
.report-viewer-shell {
min-height: calc(100vh - 4rem);
}
.report-viewer-shell-dark {
background: #111827;
color: #e5e7eb;
}
.report-viewer-shell-dark .dxrd-preview,
.report-viewer-shell-dark .dxrd-preview-wrapper,
.report-viewer-shell-dark .dxrd-toolbar-wrapper,
.report-viewer-shell-dark .dxrd-right-panel,
.report-viewer-shell-dark .dxrd-search-wrapper {
background-color: #111827;
}
`
document.head.appendChild(style)
}
} }
const DevexpressReportViewer: React.FC = () => { const DevexpressReportViewer: React.FC = () => {
@ -31,11 +87,13 @@ const DevexpressReportViewer: React.FC = () => {
const { id } = useParams<{ id: string }>() const { id } = useParams<{ id: string }>()
const location = useLocation() const location = useLocation()
const token = useStoreState((state) => state.auth.session.token) const token = useStoreState((state) => state.auth.session.token)
const themeMode = useStoreState((state) => state.theme.mode)
const [isRequestAuthReady, setIsRequestAuthReady] = useState(false) const [isRequestAuthReady, setIsRequestAuthReady] = useState(false)
const isDarkMode = themeMode === MODE_DARK
useEffect(() => { useEffect(() => {
loadViewerCss() loadViewerCss(isDarkMode)
}, []) }, [isDarkMode])
useEffect(() => { useEffect(() => {
setIsRequestAuthReady(false) setIsRequestAuthReady(false)
@ -65,7 +123,7 @@ const DevexpressReportViewer: React.FC = () => {
if (!id) return null if (!id) return null
return ( return (
<Container> <Container className={getViewerClassName(isDarkMode)}>
<Helmet <Helmet
titleTemplate={`%s | ${APP_NAME}`} titleTemplate={`%s | ${APP_NAME}`}
title={translate('::App.Reports')} title={translate('::App.Reports')}