ReportViewer ve ReportDesigner bundle çıkarıldı
This commit is contained in:
parent
ff3344b3ae
commit
b070702378
8 changed files with 1474 additions and 1271 deletions
|
|
@ -4667,12 +4667,12 @@ public class ListFormSeeder_SupplyChain : IDataSeedContributor, ITransientDepend
|
|||
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.PurchaseOrder)),
|
||||
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
|
||||
PagerOptionJson = DefaultPagerOptionJson,
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 500, true, true, true, true, false, true),
|
||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 800, 400, true, true, true, true, false, true),
|
||||
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
|
||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>()
|
||||
{
|
||||
new() {
|
||||
Order=1, ColCount=1, ColSpan=1, ItemType="group", Items =[
|
||||
Order=1, ColCount=2, ColSpan=1, ItemType="group", Items =[
|
||||
new EditingFormItemDto { Order = 1, DataField="OrderNumber", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxTextBox, EditorOptions = EditorOptionValues.Disabled },
|
||||
new EditingFormItemDto { Order = 2, DataField="SupplierId", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxSelectBox, EditorOptions=EditorOptionValues.ShowClearButton },
|
||||
new EditingFormItemDto { Order = 3, DataField="OrderDate", ColSpan = 1, IsRequired = true, EditorType2 = EditorTypes.dxDateBox, EditorOptions = EditorOptionValues.DateFormat },
|
||||
|
|
|
|||
2224
ui/package-lock.json
generated
2224
ui/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -37,10 +37,9 @@
|
|||
"axios": "^1.7.9",
|
||||
"classnames": "^2.5.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"devexpress-reporting-react": "^25.1.7",
|
||||
"devextreme": "^25.1.7",
|
||||
"devextreme-dist": "^25.1.7",
|
||||
"devextreme-react": "^25.1.7",
|
||||
"devexpress-reporting-react": "^25.2.3",
|
||||
"devextreme": "^25.2.3",
|
||||
"devextreme-react": "^25.2.3",
|
||||
"easy-peasy": "^6.0.5",
|
||||
"emoji-picker-react": "^4.14.1",
|
||||
"exceljs": "^4.4.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,19 @@
|
|||
{
|
||||
"commit": "16dca4a0",
|
||||
"commit": "270e50e0",
|
||||
"releases": [
|
||||
{
|
||||
"version": "1.0.40",
|
||||
"buildDate": "2026-01-17",
|
||||
"commit": "52c93ccbaf1be1c8365097e97276f48988864de4",
|
||||
"changeLog": [
|
||||
"- Grid üzerinden Dil desteği güncellemeleri yapıldı.",
|
||||
"- Nodejs 24 versiyonuna geçildi.",
|
||||
"- Grid ve Popup içerisinde Numeric formatlar geliştirildi.",
|
||||
"- File Management geliştirildi.",
|
||||
"- XtraReport viewer ve desing komponentleri geliştirildi.",
|
||||
"- Devexpress Licenceı artırıldı."
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "1.0.37",
|
||||
"buildDate": "2025-12-07",
|
||||
|
|
@ -192,7 +205,7 @@
|
|||
{
|
||||
"version": "1.0.14",
|
||||
"buildDate": "2025-09-22",
|
||||
"commit": "51208b86937484d68b699120d74872067b1c7ef6",
|
||||
"commit": "1c4ab4f8232b4cd2a39fa66f8101664840113ce5",
|
||||
"changeLog": [
|
||||
"Yeni versiyon çıktı uyarı gelecek şekilde düzenlendi.",
|
||||
"Sağ alt kısımda mesaj çıkacak ve yenile butonu ile uygulama yeni versiyona geçecektir."
|
||||
|
|
|
|||
|
|
@ -1,98 +1,134 @@
|
|||
import React, { Suspense, startTransition, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { useEffect, useState } from 'react'
|
||||
import Container from '@/components/shared/Container'
|
||||
import Grid from './Grid'
|
||||
import { FaChartArea, FaList, FaSitemap, FaTable, FaTh, FaCalendarAlt, FaIdCard, FaProjectDiagram } from 'react-icons/fa'
|
||||
import { useStoreActions, useStoreState } from '@/store/store'
|
||||
import classNames from 'classnames'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
|
||||
import Container from '@/components/shared/Container'
|
||||
import { Badge, Button } from '@/components/ui'
|
||||
import Pivot from './Pivot'
|
||||
import Tree from './Tree'
|
||||
import { getList } from '@/services/form.service'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
||||
|
||||
import { useStoreActions, useStoreState } from '@/store/store'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { getList } from '@/services/form.service'
|
||||
import { ListViewLayoutType } from '../admin/listForm/edit/types'
|
||||
import Chart from './Chart'
|
||||
import GanttView from './GanttView'
|
||||
import SchedulerView from './SchedulerView'
|
||||
|
||||
const List = () => {
|
||||
const params = useParams()
|
||||
const { translate } = useLocalization()
|
||||
import {
|
||||
FaChartArea,
|
||||
FaList,
|
||||
FaSitemap,
|
||||
FaTable,
|
||||
FaCalendarAlt,
|
||||
FaProjectDiagram,
|
||||
} from 'react-icons/fa'
|
||||
|
||||
/* =======================
|
||||
🔥 LAZY VIEW IMPORTS
|
||||
======================= */
|
||||
const Grid = React.lazy(() => import('./Grid'))
|
||||
const Pivot = React.lazy(() => import('./Pivot'))
|
||||
const Tree = React.lazy(() => import('./Tree'))
|
||||
const Chart = React.lazy(() => import('./Chart'))
|
||||
const GanttView = React.lazy(() => import('./GanttView'))
|
||||
const SchedulerView = React.lazy(() => import('./SchedulerView'))
|
||||
|
||||
const List: React.FC = () => {
|
||||
const { listFormCode = '' } = useParams()
|
||||
const [searchParams] = useSearchParams()
|
||||
const listFormCode = params?.listFormCode ?? ''
|
||||
const mode = useStoreState((state) => state.theme.mode)
|
||||
const [viewMode, setViewMode] = useState<ListViewLayoutType>()
|
||||
|
||||
const [gridDto, setGridDto] = useState<GridDto>()
|
||||
const { translate } = useLocalization()
|
||||
const mode = useStoreState((state) => state.theme.mode)
|
||||
const MenuIcon = useCurrentMenuIcon('w-5 h-5')
|
||||
|
||||
const { states } = useStoreState((state) => state.admin.lists)
|
||||
const { setStates } = useStoreActions((a) => a.admin.lists)
|
||||
|
||||
// 🔹 Tekrar çağırılabilir metod
|
||||
const refreshGridDto = async () => {
|
||||
const [gridDto, setGridDto] = useState<GridDto | null>(null)
|
||||
const [viewMode, setViewMode] = useState<ListViewLayoutType | undefined>()
|
||||
|
||||
/* =======================
|
||||
🔹 GRID DTO FETCH
|
||||
======================= */
|
||||
const refreshGridDto = useCallback(async () => {
|
||||
if (!listFormCode) return
|
||||
try {
|
||||
const response = await getList({ listFormCode })
|
||||
setGridDto(response.data)
|
||||
} catch (error) {
|
||||
console.error('GridDto refresh error:', error)
|
||||
} catch (err) {
|
||||
console.error('GridDto load error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refreshGridDto()
|
||||
}, [listFormCode])
|
||||
|
||||
useEffect(() => {
|
||||
const listFormStates = states.find((a) => a.listFormCode === listFormCode)
|
||||
refreshGridDto()
|
||||
}, [refreshGridDto])
|
||||
|
||||
if (listFormStates) {
|
||||
setViewMode(listFormStates.layout)
|
||||
return
|
||||
}
|
||||
/* =======================
|
||||
🔹 INITIAL VIEW MODE
|
||||
======================= */
|
||||
useEffect(() => {
|
||||
if (!gridDto) return
|
||||
|
||||
if (gridDto) {
|
||||
setViewMode(gridDto?.gridOptions?.layoutDto.defaultLayout)
|
||||
return
|
||||
}
|
||||
}, [gridDto])
|
||||
const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout
|
||||
|
||||
if (!listFormCode) {
|
||||
return null
|
||||
}
|
||||
const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout
|
||||
|
||||
if (!gridDto) {
|
||||
setViewMode(savedLayout ?? defaultLayout)
|
||||
}, [gridDto, states, listFormCode])
|
||||
|
||||
/* =======================
|
||||
🔹 VIEW SWITCH HANDLER
|
||||
======================= */
|
||||
const setLayout = useCallback(
|
||||
(layout: ListViewLayoutType) => {
|
||||
startTransition(() => {
|
||||
setViewMode(layout)
|
||||
})
|
||||
setStates({ listFormCode, layout })
|
||||
},
|
||||
[listFormCode, setStates],
|
||||
)
|
||||
|
||||
/* =======================
|
||||
🔹 PRELOAD MAP (HOVER)
|
||||
======================= */
|
||||
const preload = useMemo(
|
||||
() => ({
|
||||
grid: () => import('./Grid'),
|
||||
pivot: () => import('./Pivot'),
|
||||
tree: () => import('./Tree'),
|
||||
chart: () => import('./Chart'),
|
||||
gantt: () => import('./GanttView'),
|
||||
scheduler: () => import('./SchedulerView'),
|
||||
}),
|
||||
[],
|
||||
)
|
||||
|
||||
if (!listFormCode || !gridDto || !viewMode) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{/* =======================
|
||||
HEADER
|
||||
======================= */}
|
||||
<div
|
||||
className={classNames('flex items-center border-solid gap-1 pb-1', {
|
||||
'border-gray-100': mode === 'light',
|
||||
'border-neutral-700': mode === 'dark',
|
||||
})}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{MenuIcon}
|
||||
<h4 className="text-slate-700 text-sm font-medium leading-none">
|
||||
{translate('::' + gridDto?.gridOptions?.title) || ''}
|
||||
</h4>
|
||||
●
|
||||
<Badge content={viewMode} />
|
||||
</div>
|
||||
|
||||
{gridDto?.gridOptions?.description === gridDto?.gridOptions?.title ? (
|
||||
<p className="mr-auto"></p>
|
||||
) : (
|
||||
<p className="text-slate-500 text-xs mr-auto ml-2 leading-none">
|
||||
{translate('::' + gridDto?.gridOptions?.description)}
|
||||
</p>
|
||||
className={classNames(
|
||||
'flex items-center gap-2 pb-1 border-b',
|
||||
mode === 'light' ? 'border-gray-200' : 'border-neutral-700',
|
||||
)}
|
||||
>
|
||||
{MenuIcon}
|
||||
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
||||
<Badge content={viewMode} />
|
||||
|
||||
<p className="ml-2 text-xs text-slate-500 mr-auto">
|
||||
{translate('::' + gridDto.gridOptions.description)}
|
||||
</p>
|
||||
|
||||
{/* =======================
|
||||
VIEW BUTTONS
|
||||
======================= */}
|
||||
<div className="flex gap-1">
|
||||
{gridDto?.gridOptions?.layoutDto.scheduler &&
|
||||
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
||||
|
|
@ -100,13 +136,10 @@ const List = () => {
|
|||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'scheduler' ? 'solid' : 'default'}
|
||||
onClick={() => {
|
||||
setViewMode('scheduler')
|
||||
setStates({ listFormCode, layout: 'scheduler' })
|
||||
}}
|
||||
title="Scheduler Görünümü"
|
||||
onClick={() => setLayout('scheduler')}
|
||||
onMouseEnter={() => preload.scheduler()}
|
||||
>
|
||||
<FaCalendarAlt className="w-4 h-4" />
|
||||
<FaCalendarAlt />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
|
|
@ -116,13 +149,10 @@ const List = () => {
|
|||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'gantt' ? 'solid' : 'default'}
|
||||
onClick={() => {
|
||||
setViewMode('gantt')
|
||||
setStates({ listFormCode, layout: 'gantt' })
|
||||
}}
|
||||
title="Gantt Görünümü"
|
||||
onClick={() => setLayout('gantt')}
|
||||
onMouseEnter={() => preload.gantt()}
|
||||
>
|
||||
<FaProjectDiagram className="w-4 h-4" />
|
||||
<FaProjectDiagram />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
|
|
@ -131,106 +161,107 @@ const List = () => {
|
|||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'tree' ? 'solid' : 'default'}
|
||||
onClick={() => {
|
||||
setViewMode('tree')
|
||||
setStates({ listFormCode, layout: 'tree' })
|
||||
}}
|
||||
title="TreeList Görünümü"
|
||||
onClick={() => setLayout('tree')}
|
||||
onMouseEnter={() => preload.tree()}
|
||||
>
|
||||
<FaSitemap className="w-4 h-4" />
|
||||
<FaSitemap />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{gridDto?.gridOptions?.layoutDto.grid && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
||||
onClick={() => {
|
||||
setViewMode('grid')
|
||||
setStates({ listFormCode, layout: 'grid' })
|
||||
}}
|
||||
title="Grid Görünümü"
|
||||
>
|
||||
<FaList className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
||||
onClick={() => setLayout('grid')}
|
||||
onMouseEnter={() => preload.grid()}
|
||||
>
|
||||
<FaList />
|
||||
</Button>
|
||||
|
||||
{gridDto?.gridOptions?.layoutDto.pivot && (
|
||||
{gridDto.gridOptions.layoutDto.pivot && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'pivot' ? 'solid' : 'default'}
|
||||
onClick={() => {
|
||||
setViewMode('pivot')
|
||||
setStates({ listFormCode, layout: 'pivot' })
|
||||
}}
|
||||
title="Pivot Görünümü"
|
||||
onClick={() => setLayout('pivot')}
|
||||
onMouseEnter={() => preload.pivot()}
|
||||
>
|
||||
<FaTable className="w-4 h-4" />
|
||||
<FaTable />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{gridDto?.gridOptions?.layoutDto.chart && (
|
||||
{gridDto.gridOptions.layoutDto.chart && (
|
||||
<Button
|
||||
size="xs"
|
||||
variant={viewMode === 'chart' ? 'solid' : 'default'}
|
||||
onClick={() => {
|
||||
setViewMode('chart')
|
||||
setStates({ listFormCode, layout: 'chart' })
|
||||
}}
|
||||
title="Grafik Görünümü"
|
||||
onClick={() => setLayout('chart')}
|
||||
onMouseEnter={() => preload.chart()}
|
||||
>
|
||||
<FaChartArea className="w-4 h-4" />
|
||||
<FaChartArea />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{viewMode === 'pivot' ? (
|
||||
<Pivot
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
refreshGridDto={refreshGridDto}
|
||||
/>
|
||||
) : viewMode === 'scheduler' ? (
|
||||
<SchedulerView
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
) : viewMode === 'gantt' ? (
|
||||
<GanttView
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
) : viewMode === 'tree' ? (
|
||||
<Tree
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
) : viewMode === 'grid' ? (
|
||||
<Grid
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
) : viewMode === 'chart' ? (
|
||||
<Chart
|
||||
id={gridDto?.gridOptions.id!}
|
||||
listFormCode={listFormCode}
|
||||
filter={searchParams.toString()}
|
||||
isSubForm={true}
|
||||
gridDto={gridDto}
|
||||
refreshGridDto={refreshGridDto}
|
||||
/>
|
||||
) : null}
|
||||
{/* =======================
|
||||
VIEW RENDER
|
||||
======================= */}
|
||||
<Suspense fallback={<div className="p-4 text-sm">Yükleniyor...</div>}>
|
||||
{viewMode === 'grid' && (
|
||||
<Grid
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'pivot' && (
|
||||
<Pivot
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
refreshGridDto={refreshGridDto}
|
||||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'tree' && (
|
||||
<Tree
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'scheduler' && (
|
||||
<SchedulerView
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'gantt' && (
|
||||
<GanttView
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'chart' && (
|
||||
<Chart
|
||||
id={gridDto?.gridOptions.id!}
|
||||
listFormCode={listFormCode}
|
||||
filter={searchParams.toString()}
|
||||
isSubForm={true}
|
||||
gridDto={gridDto}
|
||||
refreshGridDto={refreshGridDto}
|
||||
/>
|
||||
)}
|
||||
</Suspense>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,58 @@
|
|||
import React from 'react'
|
||||
import React, { lazy, Suspense, useEffect } from 'react'
|
||||
import { Container } from '@/components/shared'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import ReportDesigner, { RequestOptions } from 'devexpress-reporting-react/dx-report-designer'
|
||||
import '@devexpress/analytics-core/dist/css/dx-analytics.common.css'
|
||||
import '@devexpress/analytics-core/dist/css/dx-analytics.light.css'
|
||||
import '@devexpress/analytics-core/dist/css/dx-querybuilder.css'
|
||||
import 'devexpress-reporting/dist/css/dx-webdocumentviewer.css'
|
||||
import 'devexpress-reporting/dist/css/dx-reportdesigner.css'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { RequestOptions } from 'devexpress-reporting-react/dx-report-designer'
|
||||
|
||||
const ReportDesigner = lazy(() =>
|
||||
import('devexpress-reporting-react/dx-report-designer')
|
||||
)
|
||||
|
||||
const loadDesignerCss = () => {
|
||||
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/analytics-core/dist/css/dx-querybuilder.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-reportdesigner.css', import.meta.url).href,
|
||||
]
|
||||
|
||||
styles.forEach((href) => {
|
||||
if (document.querySelector(`link[href="${href}"]`)) return
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = href
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
}
|
||||
|
||||
const DevexpressReportDesigner: React.FC = () => {
|
||||
const { translate } = useLocalization()
|
||||
const { id } = useParams<{ id: string }>()
|
||||
|
||||
if (!id) {
|
||||
return null
|
||||
}
|
||||
useEffect(() => {
|
||||
loadDesignerCss()
|
||||
}, [])
|
||||
|
||||
if (!id) return null
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Helmet
|
||||
titleTemplate="%s | Erp Platform"
|
||||
title={translate('::' + 'App.Reports')}
|
||||
title={translate('::App.Reports')}
|
||||
defaultTitle="Erp Platform"
|
||||
></Helmet>
|
||||
/>
|
||||
|
||||
<ReportDesigner reportUrl={id}>
|
||||
<RequestOptions
|
||||
host={`${import.meta.env.VITE_API_URL}/`}
|
||||
getDesignerModelAction="DXXRD/GetDesignerModel"
|
||||
/>
|
||||
</ReportDesigner>
|
||||
<Suspense fallback={<div>Rapor tasarımcısı yükleniyor...</div>}>
|
||||
<ReportDesigner reportUrl={id}>
|
||||
<RequestOptions
|
||||
host={`${import.meta.env.VITE_API_URL}/`}
|
||||
getDesignerModelAction="DXXRD/GetDesignerModel"
|
||||
/>
|
||||
</ReportDesigner>
|
||||
</Suspense>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,63 @@
|
|||
import React, { useMemo } from 'react'
|
||||
import React, { useMemo, lazy, Suspense, useEffect } from 'react'
|
||||
import { Container } from '@/components/shared'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import ReportViewer, { RequestOptions } from 'devexpress-reporting-react/dx-report-viewer'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import 'devextreme/dist/css/dx.light.css'
|
||||
import '@devexpress/analytics-core/dist/css/dx-analytics.common.css'
|
||||
import '@devexpress/analytics-core/dist/css/dx-analytics.light.css'
|
||||
import 'devexpress-reporting/dist/css/dx-webdocumentviewer.css'
|
||||
import { useParams, useLocation } from 'react-router-dom'
|
||||
import { RequestOptions } from 'devexpress-reporting-react/dx-report-viewer'
|
||||
|
||||
// Lazy load
|
||||
const ReportViewer = lazy(() =>
|
||||
import('devexpress-reporting-react/dx-report-viewer')
|
||||
)
|
||||
|
||||
const loadViewerCss = () => {
|
||||
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,
|
||||
]
|
||||
|
||||
styles.forEach((href) => {
|
||||
if (document.querySelector(`link[href="${href}"]`)) return
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = href
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
}
|
||||
|
||||
const DevexpressReportViewer: React.FC = () => {
|
||||
const { translate } = useLocalization()
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const location = useLocation()
|
||||
|
||||
// Query string parametrelerini reportUrl'e ekle
|
||||
useEffect(() => {
|
||||
loadViewerCss()
|
||||
}, [])
|
||||
|
||||
const reportUrlWithParams = useMemo(() => {
|
||||
if (location.search) {
|
||||
return `${id}${location.search}`
|
||||
}
|
||||
return id
|
||||
if (!id) return ''
|
||||
return location.search ? `${id}${location.search}` : id
|
||||
}, [id, location.search])
|
||||
|
||||
if (!id) {
|
||||
return null
|
||||
}
|
||||
if (!id) return null
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Helmet
|
||||
titleTemplate="%s | Erp Platform"
|
||||
title={translate('::' + 'App.Reports')}
|
||||
title={translate('::App.Reports')}
|
||||
defaultTitle="Erp Platform"
|
||||
></Helmet>
|
||||
/>
|
||||
|
||||
<ReportViewer reportUrl={reportUrlWithParams}>
|
||||
<RequestOptions host={`${import.meta.env.VITE_API_URL}/`} invokeAction="DXXRDV" />
|
||||
</ReportViewer>
|
||||
<Suspense fallback={<div>Rapor yükleniyor...</div>}>
|
||||
<ReportViewer reportUrl={reportUrlWithParams}>
|
||||
<RequestOptions
|
||||
host={`${import.meta.env.VITE_API_URL}/`}
|
||||
invokeAction="DXXRDV"
|
||||
/>
|
||||
</ReportViewer>
|
||||
</Suspense>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export default defineConfig(async ({ mode }) => {
|
|||
globPatterns: ['**/*.{js,css,html,wasm}'],
|
||||
|
||||
// Büyük asset'leri de cache'leyebil
|
||||
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024,
|
||||
maximumFileSizeToCacheInBytes: 15 * 1024 * 1024,
|
||||
|
||||
// EN KRİTİK: yeni SW beklemeden kontrolü alsın
|
||||
clientsClaim: true,
|
||||
|
|
@ -139,6 +139,7 @@ export default defineConfig(async ({ mode }) => {
|
|||
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
chunkSizeWarningLimit: 2000,
|
||||
sourcemap: false,
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
|
|
@ -154,6 +155,41 @@ export default defineConfig(async ({ mode }) => {
|
|||
}
|
||||
return 'assets/[name]-[hash][extname]'
|
||||
},
|
||||
manualChunks(id) {
|
||||
// 🔴 DEVEXTREME (esm + non-esm + react wrapper)
|
||||
if (
|
||||
id.includes('node_modules/devextreme') ||
|
||||
id.includes('node_modules/devextreme-react')
|
||||
) {
|
||||
return 'dx-framework'
|
||||
}
|
||||
|
||||
// 🔴 REPORTING
|
||||
if (id.includes('devexpress-reporting') || id.includes('@devexpress')) {
|
||||
return 'dx-reporting'
|
||||
}
|
||||
|
||||
// 🟣 EXPORT TOOLS
|
||||
if (
|
||||
id.includes('exceljs') ||
|
||||
id.includes('xlsx') ||
|
||||
id.includes('jspdf') ||
|
||||
id.includes('html2canvas') ||
|
||||
id.includes('file-saver')
|
||||
) {
|
||||
return 'export-tools'
|
||||
}
|
||||
|
||||
// 🟡 EDITOR
|
||||
if (id.includes('monaco-editor') || id.includes('codemirror')) {
|
||||
return 'editor'
|
||||
}
|
||||
|
||||
// ⚪ KALAN VENDOR
|
||||
if (id.includes('node_modules')) {
|
||||
return 'vendor'
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue