2025-05-06 06:45:49 +00:00
|
|
|
|
import Container from '@/components/shared/Container'
|
|
|
|
|
|
import { DX_CLASSNAMES } from '@/constants/app.constant'
|
2025-08-12 08:39:06 +00:00
|
|
|
|
import { GridDto, ListFormCustomizationTypeEnum } from '@/proxy/form/models'
|
2025-05-06 06:45:49 +00:00
|
|
|
|
import {
|
|
|
|
|
|
getListFormCustomization,
|
|
|
|
|
|
postListFormCustomization,
|
2025-08-12 08:39:06 +00:00
|
|
|
|
} from '@/services/list-form-customization.service'
|
2025-05-06 06:45:49 +00:00
|
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
2025-11-28 13:31:53 +00:00
|
|
|
|
import Chart, {
|
|
|
|
|
|
ChartRef,
|
|
|
|
|
|
CommonSeriesSettings,
|
|
|
|
|
|
Size,
|
|
|
|
|
|
Tooltip,
|
|
|
|
|
|
} from 'devextreme-react/chart'
|
2025-05-06 06:45:49 +00:00
|
|
|
|
import PivotGrid, {
|
2026-02-01 18:53:14 +00:00
|
|
|
|
Export,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
FieldChooser,
|
|
|
|
|
|
FieldPanel,
|
|
|
|
|
|
HeaderFilter,
|
2026-02-01 18:53:14 +00:00
|
|
|
|
LoadPanel,
|
2025-11-28 13:31:53 +00:00
|
|
|
|
PivotGridRef,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
PivotGridTypes,
|
|
|
|
|
|
Scrolling,
|
|
|
|
|
|
Search,
|
2025-11-28 13:31:53 +00:00
|
|
|
|
StateStoring,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
} from 'devextreme-react/pivot-grid'
|
|
|
|
|
|
import CustomStore from 'devextreme/data/custom_store'
|
|
|
|
|
|
import PivotGridDataSource, { Field } from 'devextreme/ui/pivot_grid/data_source'
|
2026-02-01 18:53:14 +00:00
|
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
2025-05-06 06:45:49 +00:00
|
|
|
|
import { Helmet } from 'react-helmet'
|
|
|
|
|
|
import { GridColumnData } from './GridColumnData'
|
|
|
|
|
|
import {
|
|
|
|
|
|
addCss,
|
|
|
|
|
|
addJs,
|
|
|
|
|
|
controlStyleCondition,
|
|
|
|
|
|
pivotFieldConvertDataType,
|
|
|
|
|
|
setGridPanelColor,
|
|
|
|
|
|
} from './Utils'
|
|
|
|
|
|
import { useFilters } from './useFilters'
|
2025-09-25 14:40:16 +00:00
|
|
|
|
import WidgetGroup from '@/components/common/WidgetGroup'
|
2026-02-01 18:53:14 +00:00
|
|
|
|
import { Button, Notification, toast } from '@/components/ui'
|
2025-11-07 23:00:51 +00:00
|
|
|
|
import { FaCog, FaTimes, FaUndo } from 'react-icons/fa'
|
2025-09-27 20:25:21 +00:00
|
|
|
|
import { usePermission } from '@/utils/hooks/usePermission'
|
|
|
|
|
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
|
|
|
|
|
import { usePWA } from '@/utils/hooks/usePWA'
|
2025-11-08 20:22:50 +00:00
|
|
|
|
import { layoutTypes } from '../admin/listForm/edit/types'
|
2025-11-09 10:30:15 +00:00
|
|
|
|
import { useListFormCustomDataSource } from './useListFormCustomDataSource'
|
|
|
|
|
|
import { useListFormColumns } from './useListFormColumns'
|
2026-01-17 20:13:25 +00:00
|
|
|
|
import { useStoreState } from '@/store'
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
2025-09-27 20:25:21 +00:00
|
|
|
|
interface PivotProps {
|
2025-05-06 06:45:49 +00:00
|
|
|
|
listFormCode: string
|
|
|
|
|
|
searchParams?: URLSearchParams
|
|
|
|
|
|
isSubForm?: boolean
|
|
|
|
|
|
level?: number
|
|
|
|
|
|
refreshData?: () => Promise<void>
|
2025-09-22 14:08:42 +00:00
|
|
|
|
gridDto?: GridDto
|
2025-09-29 08:33:51 +00:00
|
|
|
|
refreshGridDto: () => Promise<void>
|
2025-05-06 06:45:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const statedGridPanelColor = 'rgba(50, 200, 200, 0.5)' // kullanici tanimli gridState ile islem gormus gridin paneline ait renk
|
|
|
|
|
|
|
2025-09-27 20:25:21 +00:00
|
|
|
|
const Pivot = (props: PivotProps) => {
|
2025-09-22 14:08:42 +00:00
|
|
|
|
const { listFormCode, searchParams, isSubForm, level, gridDto } = props
|
2025-05-06 06:45:49 +00:00
|
|
|
|
const { translate } = useLocalization()
|
2025-09-27 20:25:21 +00:00
|
|
|
|
const { checkPermission } = usePermission()
|
|
|
|
|
|
const isPwaMode = usePWA()
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
2025-11-28 13:31:53 +00:00
|
|
|
|
const gridRef = useRef<PivotGridRef>()
|
|
|
|
|
|
const chartRef = useRef<ChartRef>(null)
|
2025-05-06 06:45:49 +00:00
|
|
|
|
const refListFormCode = useRef('')
|
2026-01-17 20:13:25 +00:00
|
|
|
|
const config = useStoreState((state) => state.abpConfig.config)
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
|
|
|
|
|
const [gridDataSource, setGridDataSource] = useState<CustomStore<any, any>>()
|
|
|
|
|
|
const [columnData, setColumnData] = useState<GridColumnData[]>()
|
|
|
|
|
|
|
|
|
|
|
|
const { filterToolbarData, ...filterData } = useFilters({
|
|
|
|
|
|
gridDto,
|
|
|
|
|
|
gridRef,
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-07 23:00:51 +00:00
|
|
|
|
const { createSelectDataSource } = useListFormCustomDataSource({ gridRef })
|
2025-05-06 06:45:49 +00:00
|
|
|
|
const { getBandedColumns } = useListFormColumns({
|
|
|
|
|
|
gridDto,
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
isSubForm,
|
2025-10-16 22:15:34 +00:00
|
|
|
|
gridRef,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
})
|
|
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const onCellPrepared = useCallback((e: any) => {
|
2025-05-06 06:45:49 +00:00
|
|
|
|
const columnFormats = gridDto?.columnFormats
|
|
|
|
|
|
if (!columnFormats) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// satir, hucre yada header vb. kisimlara conditional style uygulamak icin
|
|
|
|
|
|
for (let indxCol = 0; indxCol < columnFormats.length; indxCol++) {
|
|
|
|
|
|
const colFormat = columnFormats[indxCol]
|
|
|
|
|
|
for (let indxStyl = 0; indxStyl < colFormat.columnStylingDto.length; indxStyl++) {
|
|
|
|
|
|
const colStyle = colFormat.columnStylingDto[indxStyl] // uygulanacak style
|
|
|
|
|
|
if (e.rowType == colStyle.rowType) {
|
|
|
|
|
|
// header, filter, data, group, summaries ..her birisine style uygulanabilir
|
|
|
|
|
|
// style bütün satıra uygulansın olarak seçili ise yada sadece ilgili field üzerinde ise
|
|
|
|
|
|
if (colStyle.useRow || e.column?.dataField == colFormat.fieldName) {
|
|
|
|
|
|
if (
|
|
|
|
|
|
!colStyle.conditionValue ||
|
|
|
|
|
|
controlStyleCondition(e.data, colFormat.fieldName, colStyle)
|
|
|
|
|
|
) {
|
|
|
|
|
|
// css sınıf ismi var ise uygula
|
|
|
|
|
|
if (colStyle.cssClassName) {
|
|
|
|
|
|
e.cellElement.addClass(colStyle.cssClassName)
|
|
|
|
|
|
}
|
|
|
|
|
|
// css inline style var ise uygula
|
|
|
|
|
|
if (colStyle.cssStyles) {
|
|
|
|
|
|
e.cellElement.attr('style', e.cellElement.attr('style') + ';' + colStyle.cssStyles)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, [gridDto])
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const clearPivotFilters = useCallback(() => {
|
2025-11-28 13:31:53 +00:00
|
|
|
|
const grid = gridRef.current?.instance()
|
2025-09-27 20:25:21 +00:00
|
|
|
|
if (!grid) return
|
|
|
|
|
|
|
|
|
|
|
|
const ds = grid.getDataSource()
|
|
|
|
|
|
if (ds) {
|
|
|
|
|
|
const fields = ds.fields()
|
|
|
|
|
|
fields.forEach((f: any) => {
|
|
|
|
|
|
f.filterValues = undefined
|
|
|
|
|
|
f.filterType = undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
ds.reload()
|
|
|
|
|
|
}
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, [])
|
2025-09-27 20:25:21 +00:00
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const moveAllFieldsToFilterArea = useCallback(() => {
|
2025-11-28 13:31:53 +00:00
|
|
|
|
const grid = gridRef.current?.instance()
|
2025-09-27 20:25:21 +00:00
|
|
|
|
if (!grid) return
|
|
|
|
|
|
|
|
|
|
|
|
const ds = grid.getDataSource()
|
|
|
|
|
|
if (!ds) return
|
|
|
|
|
|
|
|
|
|
|
|
const fields = ds.fields()
|
|
|
|
|
|
|
2025-11-28 13:31:53 +00:00
|
|
|
|
fields.forEach((field: any) => {
|
2025-09-27 20:25:21 +00:00
|
|
|
|
field.area = 'filter' // tüm alanları filtre alanına taşı
|
|
|
|
|
|
field.areaIndex = undefined
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
ds.fields(fields)
|
|
|
|
|
|
ds.reload() // PivotGrid’i yeniden yükle
|
|
|
|
|
|
grid.repaint() // UI güncelle
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, [])
|
2025-09-27 20:25:21 +00:00
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const resetPivotGridState = useCallback(async () => {
|
2025-11-28 13:31:53 +00:00
|
|
|
|
const grid = gridRef.current?.instance()
|
2025-09-27 20:25:21 +00:00
|
|
|
|
if (grid) {
|
|
|
|
|
|
// kullaniciya ait kayitli grid state i sil customizationData boşalt silinsin.
|
|
|
|
|
|
await postListFormCustomization({
|
|
|
|
|
|
listFormCode: listFormCode,
|
|
|
|
|
|
customizationType: ListFormCustomizationTypeEnum.GridState,
|
2025-11-28 13:31:53 +00:00
|
|
|
|
filterName: `pivot-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
|
2025-09-27 20:25:21 +00:00
|
|
|
|
customizationData: '',
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
await props.refreshGridDto()
|
|
|
|
|
|
clearPivotFilters()
|
|
|
|
|
|
moveAllFieldsToFilterArea()
|
|
|
|
|
|
}
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, [listFormCode, props, clearPivotFilters, moveAllFieldsToFilterArea])
|
|
|
|
|
|
|
|
|
|
|
|
const onExporting = useCallback(async (e: PivotGridTypes.ExportingEvent) => {
|
|
|
|
|
|
e.cancel = true
|
|
|
|
|
|
|
|
|
|
|
|
const pivot = gridRef?.current?.instance()
|
|
|
|
|
|
if (!pivot) return
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
// PivotGrid sadece Excel export destekliyor
|
|
|
|
|
|
const [{ Workbook }, { saveAs }, { exportPivotGrid }] = await Promise.all([
|
|
|
|
|
|
import('exceljs'),
|
|
|
|
|
|
import('file-saver'),
|
|
|
|
|
|
import('devextreme/excel_exporter'),
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
const workbook = new Workbook()
|
|
|
|
|
|
const worksheet = workbook.addWorksheet(`${listFormCode}_pivot`)
|
|
|
|
|
|
|
|
|
|
|
|
await exportPivotGrid({
|
|
|
|
|
|
component: pivot as any,
|
|
|
|
|
|
worksheet,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const buffer = await workbook.xlsx.writeBuffer()
|
|
|
|
|
|
saveAs(
|
|
|
|
|
|
new Blob([buffer], { type: 'application/octet-stream' }),
|
|
|
|
|
|
`${listFormCode}_pivot_export.xlsx`,
|
|
|
|
|
|
)
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('Pivot export error:', err)
|
|
|
|
|
|
toast.push(
|
|
|
|
|
|
<Notification type="danger" duration={2500}>
|
|
|
|
|
|
{translate('::App.Common.ExportError') ?? 'Dışa aktarma sırasında hata oluştu.'}
|
|
|
|
|
|
</Notification>,
|
|
|
|
|
|
{ placement: 'top-end' },
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [listFormCode, translate])
|
2025-09-27 20:25:21 +00:00
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
// StateStoring fonksiyonlarını ref'e kaydet
|
2025-05-06 06:45:49 +00:00
|
|
|
|
const customSaveState = useCallback(
|
2025-11-28 13:31:53 +00:00
|
|
|
|
(state: any) => {
|
|
|
|
|
|
return postListFormCustomization({
|
2025-05-06 06:45:49 +00:00
|
|
|
|
listFormCode: listFormCode,
|
|
|
|
|
|
customizationType: ListFormCustomizationTypeEnum.GridState,
|
2025-11-28 13:31:53 +00:00
|
|
|
|
filterName: `pivot-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
customizationData: JSON.stringify(state),
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
setGridPanelColor(statedGridPanelColor)
|
2025-11-28 13:31:53 +00:00
|
|
|
|
})
|
|
|
|
|
|
},
|
2025-05-06 06:45:49 +00:00
|
|
|
|
[listFormCode],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
const customLoadState = useCallback(
|
2025-11-28 13:31:53 +00:00
|
|
|
|
() => {
|
|
|
|
|
|
return getListFormCustomization(
|
2025-05-06 06:45:49 +00:00
|
|
|
|
listFormCode,
|
|
|
|
|
|
ListFormCustomizationTypeEnum.GridState,
|
2025-11-28 13:31:53 +00:00
|
|
|
|
`pivot-${gridRef.current?.instance()?.option('stateStoring')?.storageKey ?? ''}`,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
).then((response: any) => {
|
|
|
|
|
|
setGridPanelColor(statedGridPanelColor)
|
|
|
|
|
|
if (response.data?.length > 0) {
|
|
|
|
|
|
return JSON.parse(response.data[0].customizationData)
|
|
|
|
|
|
}
|
2025-11-28 13:31:53 +00:00
|
|
|
|
})
|
|
|
|
|
|
},
|
2025-05-06 06:45:49 +00:00
|
|
|
|
[listFormCode],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const customSaveStateRef = useRef(customSaveState)
|
|
|
|
|
|
const customLoadStateRef = useRef(customLoadState)
|
|
|
|
|
|
|
2025-05-06 06:45:49 +00:00
|
|
|
|
useEffect(() => {
|
2026-02-01 18:53:14 +00:00
|
|
|
|
customSaveStateRef.current = customSaveState
|
|
|
|
|
|
customLoadStateRef.current = customLoadState
|
|
|
|
|
|
}, [customSaveState, customLoadState])
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
refListFormCode.current = listFormCode
|
2025-05-06 06:45:49 +00:00
|
|
|
|
}, [listFormCode])
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!gridDto) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Set js and css
|
|
|
|
|
|
const grdOpt = gridDto.gridOptions
|
|
|
|
|
|
if (grdOpt.customJsSources.length) {
|
|
|
|
|
|
for (const js of grdOpt.customJsSources) {
|
|
|
|
|
|
addJs(js)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (grdOpt.customStyleSources.length) {
|
|
|
|
|
|
for (const css of grdOpt.customStyleSources) {
|
|
|
|
|
|
addCss(css)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [gridDto])
|
|
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
// Kolonları memoize et
|
|
|
|
|
|
const memoizedColumns = useMemo(() => {
|
|
|
|
|
|
if (!gridDto || !config) return undefined
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
|
|
|
|
|
const cols = getBandedColumns()
|
2026-02-01 18:53:14 +00:00
|
|
|
|
return cols?.filter((a) => a.colData?.pivotSettingsDto.isPivot)
|
|
|
|
|
|
}, [gridDto, config])
|
|
|
|
|
|
|
|
|
|
|
|
// DataSource'u memoize et
|
|
|
|
|
|
const memoizedDataSource = useMemo(() => {
|
|
|
|
|
|
if (!gridDto) return undefined
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const cols = getBandedColumns()
|
|
|
|
|
|
return createSelectDataSource(
|
2025-05-06 06:45:49 +00:00
|
|
|
|
gridDto.gridOptions,
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
searchParams,
|
2025-11-08 20:22:50 +00:00
|
|
|
|
layoutTypes.pivot,
|
2025-11-11 11:50:54 +00:00
|
|
|
|
cols,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
)
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, [gridDto, listFormCode, createSelectDataSource])
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (memoizedColumns) {
|
|
|
|
|
|
setColumnData(memoizedColumns)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [memoizedColumns])
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-02-01 18:53:14 +00:00
|
|
|
|
if (memoizedDataSource) {
|
|
|
|
|
|
setGridDataSource(memoizedDataSource)
|
|
|
|
|
|
}
|
|
|
|
|
|
}, [memoizedDataSource])
|
|
|
|
|
|
|
|
|
|
|
|
// Pivot dataSource ve fields'i set et + StateStoring ayarla
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!columnData || !gridDataSource || !gridRef?.current || !gridDto) {
|
2025-05-06 06:45:49 +00:00
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
const instance = gridRef?.current?.instance()
|
|
|
|
|
|
if (!instance) return
|
|
|
|
|
|
|
|
|
|
|
|
// 1. StateStoring'i ÖNCE ayarla
|
|
|
|
|
|
const stateStoring: any = {
|
|
|
|
|
|
enabled: gridDto?.gridOptions.stateStoringDto?.enabled,
|
|
|
|
|
|
type: gridDto?.gridOptions.stateStoringDto?.type,
|
|
|
|
|
|
savingTimeout: gridDto?.gridOptions.stateStoringDto?.savingTimeout,
|
|
|
|
|
|
storageKey: gridDto?.gridOptions.stateStoringDto?.storageKey,
|
|
|
|
|
|
}
|
|
|
|
|
|
if (
|
|
|
|
|
|
gridDto?.gridOptions.stateStoringDto?.enabled &&
|
|
|
|
|
|
gridDto?.gridOptions.stateStoringDto?.type === 'custom'
|
|
|
|
|
|
) {
|
|
|
|
|
|
stateStoring.customSave = (state: any) => customSaveStateRef.current(state)
|
|
|
|
|
|
stateStoring.customLoad = () => customLoadStateRef.current()
|
|
|
|
|
|
}
|
|
|
|
|
|
instance.option('stateStoring', stateStoring)
|
|
|
|
|
|
|
|
|
|
|
|
// 2. Default fields'i hazırla
|
|
|
|
|
|
const defaultFields: any = columnData?.map((b) => {
|
2025-05-06 06:45:49 +00:00
|
|
|
|
return {
|
|
|
|
|
|
dataField: b.dataField,
|
|
|
|
|
|
caption: b.caption,
|
|
|
|
|
|
dataType: pivotFieldConvertDataType(b.dataType),
|
|
|
|
|
|
area: b.colData?.pivotSettingsDto.area,
|
|
|
|
|
|
format: b.colData?.pivotSettingsDto.format,
|
|
|
|
|
|
summaryType: b.colData?.pivotSettingsDto.summaryType,
|
|
|
|
|
|
groupInterval: b.colData?.pivotSettingsDto.groupInterval,
|
|
|
|
|
|
sortOrder: b.colData?.pivotSettingsDto.sortOrder,
|
|
|
|
|
|
expanded: b.colData?.pivotSettingsDto.expanded,
|
|
|
|
|
|
wordWrapEnabled: b.colData?.pivotSettingsDto.wordWrapEnabled,
|
|
|
|
|
|
visible: true,
|
|
|
|
|
|
width: b.width,
|
|
|
|
|
|
} as Field
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
// 3. DataSource'u ayarla - fields olmadan
|
2025-05-06 06:45:49 +00:00
|
|
|
|
const dataSource: PivotGridTypes.Properties['dataSource'] = {
|
|
|
|
|
|
remoteOperations: true,
|
|
|
|
|
|
store: gridDataSource,
|
2026-02-01 18:53:14 +00:00
|
|
|
|
fields: defaultFields,
|
2025-05-06 06:45:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-01 18:53:14 +00:00
|
|
|
|
instance.option('dataSource', dataSource)
|
|
|
|
|
|
|
|
|
|
|
|
// 4. DataSource set edildikten SONRA state'i yükle - state fields'i override edecek
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
const ds = instance.getDataSource()
|
|
|
|
|
|
if (ds && typeof ds.state === 'function') {
|
|
|
|
|
|
ds.state(null) // Bu saved state'teki fields'i kullanacak
|
2025-11-28 13:31:53 +00:00
|
|
|
|
}
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, 50)
|
|
|
|
|
|
}, [columnData, gridDataSource, gridDto])
|
|
|
|
|
|
|
|
|
|
|
|
// Chart binding - sadece bir kez
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!gridRef?.current || !chartRef?.current) return
|
|
|
|
|
|
|
|
|
|
|
|
const pivotInstance = gridRef?.current?.instance()
|
|
|
|
|
|
const chartInstance = chartRef?.current?.instance()
|
|
|
|
|
|
if (pivotInstance && chartInstance) {
|
|
|
|
|
|
pivotInstance.bindChart(chartInstance, {
|
|
|
|
|
|
dataFieldsDisplayMode: 'splitPanes',
|
|
|
|
|
|
alternateDataFields: false,
|
|
|
|
|
|
})
|
2025-05-06 06:45:49 +00:00
|
|
|
|
}
|
2026-02-01 18:53:14 +00:00
|
|
|
|
}, [gridDto])
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
|
|
|
|
|
return (
|
2025-09-25 14:40:16 +00:00
|
|
|
|
<>
|
|
|
|
|
|
<WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
|
|
|
|
|
|
|
|
|
|
|
|
<Container className={DX_CLASSNAMES}>
|
|
|
|
|
|
{!isSubForm && (
|
|
|
|
|
|
<Helmet
|
2025-11-03 11:25:05 +00:00
|
|
|
|
titleTemplate="%s | Erp Platform"
|
2025-09-25 14:40:16 +00:00
|
|
|
|
title={translate('::' + gridDto?.gridOptions.title)}
|
2025-11-03 11:25:05 +00:00
|
|
|
|
defaultTitle="Erp Platform"
|
2025-09-25 14:40:16 +00:00
|
|
|
|
></Helmet>
|
|
|
|
|
|
)}
|
|
|
|
|
|
{gridDto && columnData && (
|
2025-09-27 20:25:21 +00:00
|
|
|
|
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
|
|
|
|
|
|
<div className="flex justify-end items-center">
|
|
|
|
|
|
<div className="relative pb-1 flex gap-1 border-b-1">
|
2025-12-02 21:07:31 +00:00
|
|
|
|
|
2025-09-27 20:25:21 +00:00
|
|
|
|
<Button
|
|
|
|
|
|
size="xs"
|
|
|
|
|
|
variant={'default'}
|
2025-12-02 21:07:31 +00:00
|
|
|
|
className="text-sm flex items-center gap-1"
|
2025-09-27 20:25:21 +00:00
|
|
|
|
onClick={clearPivotFilters}
|
2026-01-17 20:13:25 +00:00
|
|
|
|
title={translate('::ListForms.ListForm.RemoveFilter')}
|
2025-09-27 20:25:21 +00:00
|
|
|
|
>
|
2026-01-17 20:13:25 +00:00
|
|
|
|
<FaTimes className="w-3 h-3" /> {translate('::ListForms.ListForm.RemoveFilter')}
|
2025-09-27 20:25:21 +00:00
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="xs"
|
|
|
|
|
|
variant={'default'}
|
2025-12-02 21:07:31 +00:00
|
|
|
|
className="text-sm flex items-center gap-1"
|
2025-09-27 20:25:21 +00:00
|
|
|
|
onClick={resetPivotGridState}
|
2026-01-17 20:13:25 +00:00
|
|
|
|
title={translate('::ListForms.ListForm.ResetGridState')}
|
2025-09-27 20:25:21 +00:00
|
|
|
|
>
|
2026-01-17 20:13:25 +00:00
|
|
|
|
<FaUndo className="w-3 h-3" /> {translate('::ListForms.ListForm.ResetGridState')}
|
2025-09-27 20:25:21 +00:00
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
|
|
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="xs"
|
|
|
|
|
|
variant={'default'}
|
|
|
|
|
|
className="text-sm"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
window.open(
|
|
|
|
|
|
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
|
|
|
|
|
':listFormCode',
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
),
|
|
|
|
|
|
isPwaMode ? '_self' : '_blank',
|
|
|
|
|
|
)
|
|
|
|
|
|
}}
|
2026-01-17 20:13:25 +00:00
|
|
|
|
title={translate('::ListForms.ListForm.Manage')}
|
2025-09-27 20:25:21 +00:00
|
|
|
|
>
|
2025-09-29 08:33:51 +00:00
|
|
|
|
<FaCog className="w-3 h-3" />
|
2025-09-27 20:25:21 +00:00
|
|
|
|
</Button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-09-25 14:40:16 +00:00
|
|
|
|
{gridDto.gridOptions.pivotOptionDto.showChart && (
|
|
|
|
|
|
<Chart ref={chartRef as any}>
|
|
|
|
|
|
<Size height={gridDto.gridOptions.pivotOptionDto.chartHeight} />
|
|
|
|
|
|
<Tooltip enabled={true}></Tooltip>
|
|
|
|
|
|
<CommonSeriesSettings
|
|
|
|
|
|
type={gridDto.gridOptions.pivotOptionDto.chartCommonSeriesType}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</Chart>
|
|
|
|
|
|
)}
|
2025-05-06 06:45:49 +00:00
|
|
|
|
|
2025-09-27 20:25:21 +00:00
|
|
|
|
<div className="dx-datagrid-header-panel h-1"></div>
|
|
|
|
|
|
|
2025-09-25 14:40:16 +00:00
|
|
|
|
<PivotGrid
|
|
|
|
|
|
ref={gridRef as any}
|
|
|
|
|
|
id={'Pivot-' + listFormCode}
|
|
|
|
|
|
allowFiltering={gridDto.gridOptions.filterRowDto.visible}
|
|
|
|
|
|
allowSorting={gridDto.gridOptions.sortMode !== 'none'}
|
|
|
|
|
|
allowSortingBySummary={gridDto.gridOptions.sortMode !== 'none'}
|
|
|
|
|
|
height={gridDto.gridOptions.height || '100%'}
|
|
|
|
|
|
width={gridDto.gridOptions.width || '100%'}
|
|
|
|
|
|
showBorders={gridDto.gridOptions.columnOptionDto?.showBorders}
|
|
|
|
|
|
rtlEnabled={gridDto.gridOptions.columnOptionDto?.rtlEnabled}
|
|
|
|
|
|
hoverStateEnabled={gridDto.gridOptions.columnOptionDto?.hoverStateEnabled}
|
|
|
|
|
|
onCellPrepared={onCellPrepared}
|
2026-02-01 18:53:14 +00:00
|
|
|
|
onExporting={onExporting}
|
2025-05-06 06:45:49 +00:00
|
|
|
|
>
|
2026-02-01 18:53:14 +00:00
|
|
|
|
<Export enabled={gridDto.gridOptions.exportDto?.enabled} />
|
2025-09-25 14:40:16 +00:00
|
|
|
|
<HeaderFilter
|
|
|
|
|
|
allowSelectAll={gridDto.gridOptions.selectionDto.allowSelectAll}
|
|
|
|
|
|
width={gridDto.gridOptions.headerFilterDto.width}
|
|
|
|
|
|
height={gridDto.gridOptions.headerFilterDto.height}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Search
|
|
|
|
|
|
enabled={gridDto.gridOptions.headerFilterDto.allowSearch}
|
|
|
|
|
|
timeout={gridDto.gridOptions.headerFilterDto.searchTimeout}
|
|
|
|
|
|
></Search>
|
|
|
|
|
|
</HeaderFilter>
|
|
|
|
|
|
<FieldPanel
|
|
|
|
|
|
allowFieldDragging={gridDto.gridOptions.pivotOptionDto.allowFieldDragging}
|
|
|
|
|
|
visible={gridDto.gridOptions.pivotOptionDto.showFieldPanel}
|
|
|
|
|
|
showDataFields={gridDto.gridOptions.pivotOptionDto.showDataFields}
|
|
|
|
|
|
showColumnFields={gridDto.gridOptions.pivotOptionDto.showColumnFields}
|
|
|
|
|
|
showRowFields={gridDto.gridOptions.pivotOptionDto.showRowFields}
|
|
|
|
|
|
showFilterFields={gridDto.gridOptions.pivotOptionDto.showFilterFields}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<FieldChooser
|
2025-09-27 20:25:21 +00:00
|
|
|
|
enabled={gridDto.gridOptions.pivotOptionDto.columnChooserEnabled}
|
2025-09-25 14:40:16 +00:00
|
|
|
|
height={500}
|
|
|
|
|
|
/>
|
2026-02-01 18:53:14 +00:00
|
|
|
|
<LoadPanel
|
|
|
|
|
|
enabled={gridDto.gridOptions.pagerOptionDto?.loadPanelEnabled as boolean | undefined}
|
|
|
|
|
|
text={gridDto.gridOptions.pagerOptionDto?.loadPanelText}
|
2025-11-28 13:31:53 +00:00
|
|
|
|
/>
|
2025-09-25 14:40:16 +00:00
|
|
|
|
<Scrolling mode={gridDto.gridOptions.pagerOptionDto.scrollingMode} />
|
|
|
|
|
|
</PivotGrid>
|
2025-09-27 20:25:21 +00:00
|
|
|
|
</div>
|
2025-09-25 14:40:16 +00:00
|
|
|
|
)}
|
|
|
|
|
|
</Container>
|
|
|
|
|
|
</>
|
2025-05-06 06:45:49 +00:00
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default Pivot
|