import { DataGridTypes, IFormatProps } from 'devextreme-react/data-grid' import { DataType, HorizontalEdge, SortOrder, ValidationRule } from 'devextreme/common' import CustomStore from 'devextreme/data/custom_store' import { SelectedFilterOperation } from 'devextreme/ui/data_grid' import { dynamicFetch } from '../services/form.service' import { useLocalization } from '../utils/hooks/useLocalization' import { addCss } from '../views/list/Utils' import { useDialogContext } from '../views/shared/DialogContext' import { usePWA } from '../utils/hooks/usePWA' import { usePermission } from '../utils/hooks/usePermission' import { GridColumnData } from '../views/list/GridColumnData' import { ColumnFormatDto, EditingFormItemDto, GridDto, PlatformEditorTypes, UiCommandButtonPositionTypeEnum, UiLookupDataSourceTypeEnum, } from '../proxy/form/models' const cellTemplateMultiValue = ( cellElement: HTMLElement, cellInfo: DataGridTypes.ColumnCellTemplateData, ) => { if (cellInfo?.value) { const text = Array.isArray(cellInfo.value) ? cellInfo.value .map((a: any) => { const { lookup } = cellInfo.column if (lookup && lookup.calculateCellValue) { return lookup.calculateCellValue(a) } return '' }) .join(', ') : cellInfo.value cellElement.textContent = text cellElement.title = text } } function calculateFilterExpressionMultiValue( this: DataGridTypes.Column, filterValue: any, selectedFilterOperation: string | null, ): string | Array { if (filterValue) { if (selectedFilterOperation == '=' || selectedFilterOperation === null) { return [this.dataField, 'contains', filterValue] } else if (selectedFilterOperation == '<>') { return [this.dataField, 'notcontains', filterValue] } else { return [this.dataField, selectedFilterOperation, filterValue] } } else { // filterValue null ise isblank veya isnotblank secilmistir if (selectedFilterOperation === '=') { return [ this.dataField, selectedFilterOperation, filterValue, 'or', this.dataField, selectedFilterOperation, ' ', ] } else if (selectedFilterOperation === '<>') { return [ this.dataField, selectedFilterOperation, filterValue, 'and', this.dataField, selectedFilterOperation, ' ', ] } else { return [this.dataField, selectedFilterOperation, filterValue] } } } const useListFormColumns = ({ gridDto, listFormCode, isSubForm, }: { gridDto?: GridDto listFormCode: string isSubForm?: boolean }) => { const dialog: any = useDialogContext() const { translate } = useLocalization() const { checkPermission } = usePermission() const isPwaMode = usePWA() const lookupDataSource = (options: any, colData: any, listFormCode: string) => { const { lookupDto } = colData const filters = [] if (lookupDto.cascadeParentFields) { if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) { filters.push([ lookupDto?.cascadeRelationField, lookupDto?.cascadeFilterOperator, options?.data[lookupDto?.cascadeParentField], ]) //TODO: Statik data test edilecek } else { const data = options?.data ?? options for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) { filters.push(data[cascadeParentField]) } } } //UiLookupDataSourceTypeEnum : // Data = 1 (Statik Data), // Query = 2 (API'den geliyor fakat API query çalıştırıyor) // WebService = 3 (API servisten geliyor) if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) { return createLookupStaticDataSource( () => JSON.parse(lookupDto?.lookupQuery), filters.length ? filters : null, ) } else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.Query) { return createLookupQueryDataSource(listFormCode, colData.fieldName, filters) } else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.WebService) { return createLookupApiDataSource( listFormCode, lookupDto?.lookupQuery, filters, colData.lookupDto?.valueExpr?.toLowerCase(), ) } else { return { store: [], } } } const createLookupStaticDataSource = ( load: () => any, filter: any = null, key: any = 'key', sort: any = 'name', ) => ({ store: new CustomStore({ key, loadMode: 'raw', load, }), sort, filter, }) const createLookupQueryDataSource = ( listFormCode?: string, listFormFieldName?: string, filters?: any[], ) => { return new CustomStore({ loadMode: 'raw', load: async (loadOptions) => { if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) { return } try { const response = await dynamicFetch('list-form-select/lookup', 'POST', null, { listFormCode, listFormFieldName, filters, }) return response.data.map((a: any) => ({ key: a.Key, name: a.Name, group: a.Group, })) } catch (error: any) { // toast.push( // // Select error // {error.toString()} // , // { // placement: 'top-end', // }, // ) return null } }, }) } const createLookupApiDataSource = ( listFormCode?: string, lookupQuery?: string, filters?: any[], keyName?: string, ) => { return new CustomStore({ key: keyName, loadMode: 'raw', load: async (loadOptions) => { //Sayfa degismisse istek yapma if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) { return } if (!lookupQuery) { return } const [method, url, body, keySelector, nameSelector, groupSelector] = lookupQuery.split(';') //POST;https://tcmb.gov.tr/api/doviz;{"dovizType":@param0};a=>a.DovizId;a=>a.DovizName;a=>a.Ulke //TODO: Body dinamik params test edilecek if (filters?.length) { for (let i = 0; i < filters.length; i++) { body.replace(`@param${i}`, filters[i]) } } try { const response = await dynamicFetch(url, method, null, body) let { data } = response if (!data) { // toast.push( // // {'Lookup Datası boş geldi.'} // , // { // placement: 'top-end', // }, // ) return } if (!Array.isArray(data)) { data = [data] } return data.map((a: any) => ({ key: eval(keySelector), name: eval(nameSelector), group: eval(groupSelector), })) } catch { // toast.push( // // {'Network error'} // , // { // placement: 'top-end', // }, // ) return } }, }) } const getCommandColumn = (): GridColumnData | undefined => { if (!gridDto) { return } const hasUpdate = gridDto.gridOptions.editingOptionDto.allowUpdating && checkPermission(gridDto.gridOptions.permissionDto.u) const hasDelete = gridDto.gridOptions.editingOptionDto.allowDeleting && checkPermission(gridDto.gridOptions.permissionDto.d) const hasCommandButtons = gridDto.gridOptions.commandColumnDto.length > 0 // Eğer hiçbir buton eklenecek durumda değilse: çık if (!hasUpdate && !hasDelete && !hasCommandButtons) { return } const column = { type: 'buttons', width: 'auto', buttons: [] as any, } if (hasUpdate) { column.buttons.push('edit') } if (hasDelete) { column.buttons.push('delete') } gridDto.gridOptions.commandColumnDto.forEach((action) => { if (action.buttonPosition !== UiCommandButtonPositionTypeEnum.CommandColumn) return if (!checkPermission(action.authName)) return const item = { visible: true, hint: action.hint, icon: action.icon, text: translate('::' + action.text), onClick: (e: any) => { if (typeof e.event?.preventDefault === 'function') { e.event.preventDefault() } if (action.url) { let url = action.url?.replace('@LISTFORMCODE', listFormCode) gridDto.columnFormats.forEach((field) => { if (field.fieldName) { url = url.replace(`@${field.fieldName}`, e.row.data[field.fieldName]) } }) window.open(url, isPwaMode ? '_self' : action.urlTarget) } else if (action.dialogName) { if (action.dialogParameters) { const dynamicMap = JSON.parse(action.dialogParameters) for (const [key, value] of Object.entries(dynamicMap)) { dynamicMap[key] = value.startsWith('@') ? e.row.data[value.replace('@', '')] : value } dialog.setConfig({ component: action.dialogName, props: dynamicMap, }) } } else if (action.onClick) { eval(action.onClick) } }, } column.buttons.push(item) }) return column as GridColumnData } const getColumns = (columnFormats: ColumnFormatDto[]) => { const columns: GridColumnData[] = [] if (!gridDto || !columnFormats) { return columns } columnFormats.forEach((colData) => { if (!colData.canRead || !colData.isActive) { return } const column: GridColumnData = {} column.colData = colData // Onemli: Baska event-callback lerde kullanmak icin eklendi, colData.lookupDto?.editorTemplateType //column.showEditorAlways = true column.dataField = colData.fieldName if (colData.dataType) column.dataType = colData.dataType as DataType if (colData.captionName) column.caption = translate('::' + colData.captionName) if (colData.width > 0) column.width = colData.width column.visible = colData.visible column.alignment = colData.alignment column.format = colData.format column.editorOptions = { ...(colData.editorOptions as IFormatProps) } // columnCustomizationDto column.fixed = colData.columnCustomizationDto?.fixed column.fixedPosition = colData.columnCustomizationDto?.fixedPosition as HorizontalEdge column.allowReordering = colData.columnCustomizationDto?.allowReordering // sort if (colData.sortIndex >= 0) { column.sortIndex = colData.sortIndex column.sortOrder = colData.sortDirection as SortOrder } // filterRow column.allowFiltering = colData.columnFilterDto?.allowFiltering column.selectedFilterOperation = colData.columnFilterDto ?.selectedFilterOperation as SelectedFilterOperation column.filterValue = colData.columnFilterDto?.filterValue // headerFilter column.allowHeaderFiltering = colData.columnHeaderDto?.allowHeaderFiltering if (column.allowHeaderFiltering == true) { column.headerFilter = {} column.headerFilter.allowSearch = colData.columnHeaderDto?.allowSearch column.headerFilter.dataSource = colData.columnHeaderDto?.dataSource } // search column.allowSearch = colData.allowSearch //export column.allowExporting = colData.canExport // grouping column.allowGrouping = colData.columnGroupingDto?.allowGrouping //if (colData.columnGroupingDto?.groupIndex > 0) // column.groupIndex = colData.columnGroupingDto?.groupIndex; //column.autoExpandGroup = colData.columnGroupingDto?.autoExpandGroup; // constsa dinamik olarak css verilerini ekle if (colData.columnCssClass) { column.cssClass = colData.columnCssClass if (colData.columnCssValue) { addCss(colData.columnCssValue) } } column.allowEditing = colData.columnEditingDto?.allowEditing // #region lookup ayarlari if (colData.lookupDto?.dataSourceType) { // UiColumnEditorTemplateTypeEnum : None:0, Table:1, TagBox:2 const allItems = gridDto.gridOptions.editingFormDto.flatMap((group) => group.items) const formItem = allItems.find((a) => a?.dataField === colData.fieldName) if (formItem?.editorType2 === PlatformEditorTypes.dxTagBox) { column.extras = { multiValue: true, editorOptions: formItem.editorOptions, tagBoxOptions: formItem.tagBoxOptions, } column.editCellTemplate = 'cellEditTagBox' column.calculateFilterExpression = calculateFilterExpressionMultiValue column.cellTemplate = cellTemplateMultiValue } else if (formItem?.editorType2 === PlatformEditorTypes.dxGridBox) { column.extras = { multiValue: false, editorOptions: formItem.editorOptions, gridBoxOptions: formItem.gridBoxOptions, } column.editCellTemplate = 'cellEditGridBox' column.cellTemplate = cellTemplateMultiValue if (formItem.gridBoxOptions?.selectionMode === 'multiple') { column.calculateFilterExpression = calculateFilterExpressionMultiValue column.extras.multiValue = true } } column.lookup = { valueExpr: colData.lookupDto?.valueExpr?.toLowerCase(), displayExpr: colData.lookupDto?.displayExpr?.toLowerCase(), dataSource: (o) => lookupDataSource(o, colData, listFormCode), } //column.lookup.dataSource = lookupDataSource(null, colData) //cascadeEmptyFields verisi dolu ise bu kolon/field bir parent field dir if (colData.lookupDto.cascadeEmptyFields) { // parent field guncellendigi zaman bu fonksiyon cagrilir column.setCellValue = function (rowData: any, value: any) { if (!colData.fieldName) return //console.log({ rowData, value, colData }) rowData[colData.fieldName] = Array.isArray(value) ? value[0] : value // cascadeEmptyFields alani aralarinda virgul olacak sekilde bosaltilmak istenen alanlari saklar colData?.lookupDto?.cascadeEmptyFields?.split(',').forEach((emptyField: any) => { rowData[emptyField] = null }) } } } // #endregion if (colData.validationRuleDto) { // for server side validation : https://js.devexpress.com/Demos/WidgetsGallery/Demo/DataGrid/DataValidation/jQuery/Light/ column.validationRules = colData.validationRuleDto as ValidationRule[] } columns.push(column) }) return columns } const getBandedColumns = () => { if (!gridDto) { return } const columns: GridColumnData[] = [] const insertedColumns: (string | undefined)[] = [] const commandColumn = getCommandColumn() if (commandColumn) { columns.push(commandColumn) } for (const col of gridDto.columnFormats) { if (!col.fieldName) { return } if (insertedColumns.some((a) => a === col.fieldName)) { // kolon zaten eklenmis ise islem yapma return } if (col.bandName) { // banded kolon ise; en fazla iki kirilima kadar eklenir const bands = col.bandName.split(':') // ic ice banded kolon const ise aralarinda : kullanilir if (bands.length > 1) { // band + band + column seklinde ise : let topBand = columns.find((e) => e.caption == bands[0] && e.isBand == true) if (!topBand) { // en ustteki band ilk defa ekleniyor ise topBand = { caption: bands[0], columns: [] as GridColumnData[], isBand: true } columns.push(topBand) } topBand.columns ??= [] as GridColumnData[] const band2 = { caption: bands[1], columns: [] as GridColumnData[], isBand: true } topBand.columns.push(band2) const rData = gridDto.columnFormats.filter((e) => e.bandName == col.bandName) const cols = getColumns(rData) as GridColumnData[] band2.columns.push(...cols) insertedColumns.push(...cols.map((e) => e.dataField)) } else { // band + column const band = { caption: bands[0], columns: [] as GridColumnData[], isBand: true } const rData = gridDto.columnFormats.filter((e) => e.bandName == bands[0]) const cols = getColumns(rData) as GridColumnData[] band.columns.push(...cols) columns.push(band) insertedColumns.push(...cols.map((e) => e.dataField)) } } else { // band a bagli olmayan kolonlar const cols = getColumns([col]) //console.log({ col, cols: JSON.stringify(cols) }) columns.push(...cols) insertedColumns.push(...cols.map((e) => e.dataField)) } } // FormEditingExtraItem // Devexpress Gridde kaydete basılınca // formda gözükecek olan EditingFormDto.Items elemanları gelmiyor // Sadece grid'de tanımlanmış columnları getiriyor. // Bu elemanları da getirmesi için aşağıdaki şekilde, // columns'da olmayan alanları da gizli olarak ekliyoruz if (columns?.length) { gridDto.gridOptions.editingFormDto.forEach((group) => { group.items?.forEach((item: EditingFormItemDto) => { if (!columns.some((a) => a.dataField === item.dataField)) { columns.push({ dataField: item.dataField, visible: false, showInColumnChooser: false, }) insertedColumns.push(item.dataField) } }) }) } return columns } return { getBandedColumns, } } export { useListFormColumns }