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",
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(DbType.String),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(DbType.String, "Name"),
});
#region Report Categories Fields
@ -1586,7 +1586,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
AuthName = listFormName,
Url=$"/admin/reports/TemplateReport/view?id=@Id",
IsVisible = true,
VisibleExpression = "((e)=> e.row.data.Description !== 'Liste Raporları')"
VisibleExpression = "((e)=> e.row.data.CategoryId !== 'Listeler')"
},
new() {
Hint = "App.Platform.Design",
@ -1595,7 +1595,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
AuthName = listFormName + ".Update",
Url=$"/admin/reports/TemplateReport/design?id=@Id",
IsVisible = true,
VisibleExpression = "((e)=> e.row.data.Description !== 'Liste Raporları')"
VisibleExpression = "((e)=> e.row.data.CategoryId !== 'Listeler')"
},
new() {
Hint = "App.Platform.View",
@ -1604,7 +1604,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
AuthName = listFormName,
Url=$"/admin/reports/DynamicListFormReport/view?listFormCode=@Name",
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
{
public class ReportCategory : FullAuditedEntity<Guid>, IMultiTenant
public class ReportCategory : FullAuditedEntity<string>, IMultiTenant
{
public Guid? TenantId { get; set; }
@ -14,6 +14,11 @@ namespace Sozsoft.Platform.Entities
public string Icon { 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 Description { 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 ReportCategory ReportCategory { get; set; }
public ReportTemplate(
Guid id,
string name,
string description,
string htmlContent,
Guid categoryId,
string categoryId,
string status
) : base(id)
{

View file

@ -648,17 +648,12 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.ReportCategory)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(256);
b.Property(x => x.Name).IsRequired().HasMaxLength(256);
b.Property(x => x.Description).HasMaxLength(4096); // JSON string
b.Property(x => x.Icon).HasMaxLength(64);
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 =>
@ -667,11 +662,18 @@ public class PlatformDbContext :
b.ConfigureByConvention();
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.HtmlContent).IsRequired();
b.Property(x => x.Status).HasMaxLength(20);
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

View file

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

View file

@ -651,7 +651,7 @@ namespace Sozsoft.Platform.Migrations
name: "Adm_T_ReportCategory",
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),
Name = table.Column<string>(type: "nvarchar(256)", maxLength: 256, nullable: false),
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),
Description = table.Column<string>(type: "nvarchar(1024)", maxLength: 1024, nullable: true),
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),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -2262,7 +2262,7 @@ namespace Sozsoft.Platform.Migrations
column: x => x.CategoryId,
principalTable: "Adm_T_ReportCategory",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(

View file

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

View file

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

View file

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

View file

@ -224,7 +224,7 @@ public class DynamicListFormReport : XtraReport
var topMargin = new TopMarginBand { HeightF = Margins.Top };
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 detail = new DetailBand { HeightF = 24 };
var reportFooter = new ReportFooterBand { HeightF = HasAnySummary(fields) ? 28 : 0 };
@ -244,11 +244,11 @@ public class DynamicListFormReport : XtraReport
{
PageInfo = PageInfo.DateTime,
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),
TextAlignment = TextAlignment.MiddleLeft
};
reportHeader.Controls.Add(generatedAt);
bottomMargin.Controls.Add(generatedAt);
var pageInfo = new XRPageInfo
{

View file

@ -8,12 +8,29 @@ import ReportViewer, {
} from 'devexpress-reporting-react/dx-report-viewer'
import { ajaxSetup } from '@devexpress/analytics-core/analytics-utils-native'
import { APP_NAME } from '@/constants/app.constant'
import { MODE_DARK } from '@/constants/theme.constant'
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 = [
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,
]
@ -24,6 +41,45 @@ const loadViewerCss = () => {
link.href = href
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 = () => {
@ -31,11 +87,13 @@ const DevexpressReportViewer: React.FC = () => {
const { id } = useParams<{ id: string }>()
const location = useLocation()
const token = useStoreState((state) => state.auth.session.token)
const themeMode = useStoreState((state) => state.theme.mode)
const [isRequestAuthReady, setIsRequestAuthReady] = useState(false)
const isDarkMode = themeMode === MODE_DARK
useEffect(() => {
loadViewerCss()
}, [])
loadViewerCss(isDarkMode)
}, [isDarkMode])
useEffect(() => {
setIsRequestAuthReady(false)
@ -65,7 +123,7 @@ const DevexpressReportViewer: React.FC = () => {
if (!id) return null
return (
<Container>
<Container className={getViewerClassName(isDarkMode)}>
<Helmet
titleTemplate={`%s | ${APP_NAME}`}
title={translate('::App.Reports')}