125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
|
|
/**
|
|||
|
|
* Lookup cascade (bağımlı açılır liste) davranışı.
|
|||
|
|
* Grid ve Tree aynı kuralları paylaşır.
|
|||
|
|
*/
|
|||
|
|
import type { GridDto } from '@/proxy/form/models'
|
|||
|
|
|
|||
|
|
export type CascadeInfo = {
|
|||
|
|
parentFields: string[]
|
|||
|
|
childFields?: string[]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export type CascadeMaps = {
|
|||
|
|
/** fieldName -> cascade bilgisi */
|
|||
|
|
cascadeFieldsMap: Map<string, CascadeInfo>
|
|||
|
|
/** parentField -> etkilediği child alan adları */
|
|||
|
|
parentToChildrenMap: Map<string, Set<string>>
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const splitFields = (value?: string | null) =>
|
|||
|
|
(value ?? '')
|
|||
|
|
.split(',')
|
|||
|
|
.map((field) => field.trim())
|
|||
|
|
.filter(Boolean)
|
|||
|
|
|
|||
|
|
export const createCascadeMaps = (gridDto?: GridDto): CascadeMaps => {
|
|||
|
|
const cascadeFieldsMap = new Map<string, CascadeInfo>()
|
|||
|
|
const parentToChildrenMap = new Map<string, Set<string>>()
|
|||
|
|
|
|||
|
|
gridDto?.columnFormats.forEach((col) => {
|
|||
|
|
if (!col.fieldName || !col.lookupDto?.cascadeParentFields) return
|
|||
|
|
|
|||
|
|
const parentFields = splitFields(col.lookupDto.cascadeParentFields)
|
|||
|
|
const childFields = col.lookupDto.cascadeEmptyFields
|
|||
|
|
? splitFields(col.lookupDto.cascadeEmptyFields)
|
|||
|
|
: undefined
|
|||
|
|
|
|||
|
|
cascadeFieldsMap.set(col.fieldName, { parentFields, childFields })
|
|||
|
|
|
|||
|
|
parentFields.forEach((parentField) => {
|
|||
|
|
const children = parentToChildrenMap.get(parentField) ?? new Set<string>()
|
|||
|
|
children.add(col.fieldName!)
|
|||
|
|
parentToChildrenMap.set(parentField, children)
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
return { cascadeFieldsMap, parentToChildrenMap }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type AttachCascadeParams = {
|
|||
|
|
editor: any
|
|||
|
|
gridDto: GridDto
|
|||
|
|
cascadeInfo: CascadeInfo
|
|||
|
|
maps: CascadeMaps
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* `onEditorPreparing` içinde cascade davranışını editöre bağlar:
|
|||
|
|
* - parent değiştiğinde child alanları temizler,
|
|||
|
|
* - etkilenen child editörlerin `disabled` durumunu günceller,
|
|||
|
|
* - form ilk açıldığında parent'ı boş olan alanı devre dışı bırakır.
|
|||
|
|
*/
|
|||
|
|
export const attachCascadeBehavior = ({
|
|||
|
|
editor,
|
|||
|
|
gridDto,
|
|||
|
|
cascadeInfo,
|
|||
|
|
maps,
|
|||
|
|
}: AttachCascadeParams) => {
|
|||
|
|
const { cascadeFieldsMap, parentToChildrenMap } = maps
|
|||
|
|
const affectedChildren = parentToChildrenMap.get(editor.dataField)
|
|||
|
|
const previousHandler = editor.editorOptions.onValueChanged
|
|||
|
|
|
|||
|
|
editor.editorOptions.onValueChanged = (e: any) => {
|
|||
|
|
previousHandler?.(e)
|
|||
|
|
|
|||
|
|
const grid = editor.component
|
|||
|
|
const rowKey = grid.option('editing.editRowKey')
|
|||
|
|
const rowIndex = grid.getRowIndexByKey(rowKey)
|
|||
|
|
|
|||
|
|
// Parent değiştiğinde bağımlı alanları temizle.
|
|||
|
|
if (cascadeInfo.childFields && rowIndex >= 0) {
|
|||
|
|
cascadeInfo.childFields.forEach((childField) => grid.cellValue(rowIndex, childField, null))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!affectedChildren?.size) return
|
|||
|
|
|
|||
|
|
const formInstance = grid.option('editing.form') as any
|
|||
|
|
if (!formInstance?.getEditor) return
|
|||
|
|
|
|||
|
|
const rowData = grid.getVisibleRows().find((row: any) => row.key === rowKey)?.data
|
|||
|
|
if (!rowData) return
|
|||
|
|
|
|||
|
|
affectedChildren.forEach((childFieldName) => {
|
|||
|
|
const childInfo = cascadeFieldsMap.get(childFieldName)
|
|||
|
|
if (!childInfo) return
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
const childColumn = gridDto.columnFormats.find(
|
|||
|
|
(column) => column.fieldName === childFieldName,
|
|||
|
|
)
|
|||
|
|
const childEditorOptions = childColumn?.editorOptions
|
|||
|
|
? JSON.parse(childColumn.editorOptions)
|
|||
|
|
: {}
|
|||
|
|
const childEditor = formInstance.getEditor(childFieldName)
|
|||
|
|
|
|||
|
|
childEditor?.option(
|
|||
|
|
'disabled',
|
|||
|
|
childEditorOptions?.disabled === true ||
|
|||
|
|
childInfo.parentFields.some((parentField) => !rowData[parentField]),
|
|||
|
|
)
|
|||
|
|
} catch (err) {
|
|||
|
|
console.error(`Cascade child editor güncellenemedi: "${childFieldName}"`, err)
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// İlk açılışta parent'ı dolu değilse editörü kilitle.
|
|||
|
|
const grid = editor.component
|
|||
|
|
const rowKey = grid.option('editing.editRowKey')
|
|||
|
|
const rowData = grid.getVisibleRows().find((row: any) => row.key === rowKey)?.data
|
|||
|
|
|
|||
|
|
if (rowData && cascadeInfo.parentFields.some((parentField) => !rowData[parentField])) {
|
|||
|
|
editor.editorOptions.disabled = true
|
|||
|
|
}
|
|||
|
|
}
|