Form komponenti SelectBox Lookup
This commit is contained in:
parent
a913220999
commit
e14d6930c2
11 changed files with 267 additions and 48 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"commit": "3f69cc5",
|
||||
"commit": "a913220",
|
||||
"releases": [
|
||||
{
|
||||
"version": "1.0.8",
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@ import { GridBoxEditorComponent } from './editors/GridBoxEditorComponent'
|
|||
import { TagBoxEditorComponent } from './editors/TagBoxEditorComponent'
|
||||
import { RowMode, SimpleItemWithColData } from './types'
|
||||
import { PlatformEditorTypes } from '@/proxy/form/models'
|
||||
import { useLookupDataSource } from './useLookupDataSource'
|
||||
|
||||
const FormDevExpress = (props: {
|
||||
listFormCode: string
|
||||
isSubForm?: boolean
|
||||
mode: RowMode
|
||||
refForm: RefObject<FormDx>
|
||||
|
|
@ -20,7 +22,8 @@ const FormDevExpress = (props: {
|
|||
formItems: GroupItem[]
|
||||
setFormData: Dispatch<any>
|
||||
}) => {
|
||||
const { isSubForm, mode, refForm, formData, formItems, setFormData } = props
|
||||
const { listFormCode, isSubForm, mode, refForm, formData, formItems, setFormData } = props
|
||||
const { getLookupDataSource } = useLookupDataSource({ listFormCode, isSubForm })
|
||||
|
||||
return (
|
||||
<form className={`${DX_CLASSNAMES} p-2`}>
|
||||
|
|
@ -66,6 +69,10 @@ const FormDevExpress = (props: {
|
|||
...formItem.editorOptions,
|
||||
...(mode === 'view' ? { readOnly: true } : {}),
|
||||
}}
|
||||
dataSource={getLookupDataSource(
|
||||
formItem.colData?.editorOptions,
|
||||
formItem.colData,
|
||||
)}
|
||||
></TagBoxEditorComponent>
|
||||
)}
|
||||
>
|
||||
|
|
@ -88,6 +95,10 @@ const FormDevExpress = (props: {
|
|||
...formItem.editorOptions,
|
||||
...(mode === 'view' ? { readOnly: true } : {}),
|
||||
}}
|
||||
dataSource={getLookupDataSource(
|
||||
formItem.colData?.editorOptions,
|
||||
formItem.colData,
|
||||
)}
|
||||
></GridBoxEditorComponent>
|
||||
)}
|
||||
>
|
||||
|
|
@ -99,6 +110,16 @@ const FormDevExpress = (props: {
|
|||
{...formItem}
|
||||
editorOptions={{
|
||||
...formItem.editorOptions,
|
||||
...(formItem.colData?.lookupDto?.dataSourceType
|
||||
? {
|
||||
dataSource: getLookupDataSource(
|
||||
formItem.colData?.editorOptions,
|
||||
formItem.colData,
|
||||
),
|
||||
valueExpr: formItem.colData?.lookupDto?.valueExpr,
|
||||
displayExpr: formItem.colData?.lookupDto?.displayExpr,
|
||||
}
|
||||
: {}),
|
||||
...(mode === 'view' ? { readOnly: true } : { autoFocus: i === 1 }),
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ const FormEdit = (
|
|||
formData={formData}
|
||||
formItems={formItems}
|
||||
setFormData={setFormData}
|
||||
listFormCode={listFormCode}
|
||||
/>
|
||||
<SubForms gridDto={gridDto!} formData={formData} level={level ?? 0} />
|
||||
</Container>
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ const FormNew = (
|
|||
formData={formData}
|
||||
formItems={formItems}
|
||||
setFormData={setFormData}
|
||||
listFormCode={listFormCode}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ const FormView = (
|
|||
formData={formData}
|
||||
formItems={formItems}
|
||||
setFormData={() => {}}
|
||||
listFormCode={listFormCode}
|
||||
/>
|
||||
<SubForms gridDto={gridDto!} formData={formData} level={level ?? 0} refreshData={fetchData} />
|
||||
</Container>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { GridBoxOptionsDto } from '@/proxy/form/models'
|
||||
import { GridColumnData } from '@/views/list/GridColumnData'
|
||||
import { ColumnFormatDto, GridBoxOptionsDto } from '@/proxy/form/models'
|
||||
import { Button } from 'devextreme-react/button'
|
||||
import DataGrid from 'devextreme-react/data-grid'
|
||||
import DropDownBox from 'devextreme-react/drop-down-box'
|
||||
|
|
@ -12,29 +11,32 @@ const GridBoxEditorComponent = ({
|
|||
onValueChanged,
|
||||
col,
|
||||
editorOptions,
|
||||
dataSource
|
||||
}: {
|
||||
value: any
|
||||
options?: GridBoxOptionsDto
|
||||
values: any // all row data
|
||||
onValueChanged: (e: any) => void
|
||||
col?: GridColumnData
|
||||
col?: ColumnFormatDto
|
||||
editorOptions: any
|
||||
dataSource: any
|
||||
}): ReactElement => {
|
||||
const gridRef = useRef<DataGrid>(null)
|
||||
const val = Array.isArray(value) ? value : [value]
|
||||
const lookup = col?.lookup
|
||||
const dataSource: any =
|
||||
typeof lookup?.dataSource === 'function'
|
||||
? lookup.dataSource(values)
|
||||
: (lookup?.dataSource ?? [])
|
||||
const lookupDto = col?.lookupDto
|
||||
|
||||
// const dataSource: any =
|
||||
// typeof lookupDto?.dataSource === 'function'
|
||||
// ? lookupDto.dataSource(values)
|
||||
// : (lookupDto?.dataSource ?? [])
|
||||
|
||||
return (
|
||||
<DropDownBox
|
||||
{...editorOptions}
|
||||
value={val}
|
||||
dataSource={dataSource}
|
||||
valueExpr={lookup?.valueExpr}
|
||||
displayExpr={lookup?.displayExpr}
|
||||
valueExpr={lookupDto?.valueExpr}
|
||||
displayExpr={lookupDto?.displayExpr}
|
||||
showClearButton={options?.showClearButton}
|
||||
acceptCustomValue={options?.acceptCustomValue}
|
||||
onValueChanged={(e) => {
|
||||
|
|
@ -51,7 +53,7 @@ const GridBoxEditorComponent = ({
|
|||
<DataGrid
|
||||
ref={gridRef}
|
||||
dataSource={dataSource}
|
||||
key={lookup?.valueExpr}
|
||||
key={lookupDto?.valueExpr}
|
||||
filterRow={{
|
||||
visible: options?.filterRowVisible,
|
||||
applyFilter: 'auto',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { TagBoxOptionsDto } from '@/proxy/form/models'
|
||||
import { GridColumnData } from '@/views/list/GridColumnData'
|
||||
import { ColumnFormatDto, TagBoxOptionsDto } from '@/proxy/form/models'
|
||||
import TagBox from 'devextreme-react/tag-box'
|
||||
import { ApplyValueMode } from 'devextreme/common'
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
const TagBoxEditorComponent = ({
|
||||
|
|
@ -12,29 +10,32 @@ const TagBoxEditorComponent = ({
|
|||
onValueChanged,
|
||||
col,
|
||||
editorOptions,
|
||||
dataSource
|
||||
}: {
|
||||
value: any
|
||||
setDefaultValue: boolean
|
||||
options?: TagBoxOptionsDto
|
||||
values: any // all row data
|
||||
onValueChanged: (e: any) => void
|
||||
col?: GridColumnData
|
||||
col?: ColumnFormatDto
|
||||
editorOptions: any
|
||||
dataSource: any
|
||||
}): ReactElement => {
|
||||
const val = Array.isArray(value) ? value : [value]
|
||||
const lookup = col?.lookup
|
||||
const dataSource =
|
||||
typeof lookup?.dataSource === 'function'
|
||||
? lookup.dataSource(values)
|
||||
: (lookup?.dataSource ?? [])
|
||||
const lookupDto = col?.lookupDto
|
||||
|
||||
// const dataSource =
|
||||
// typeof lookup?.dataSource === 'function'
|
||||
// ? lookup.dataSource(values)
|
||||
// : (lookup?.dataSource ?? [])
|
||||
|
||||
return (
|
||||
<TagBox
|
||||
{...editorOptions}
|
||||
{...(setDefaultValue ? { defaultValue: val } : { value: val })}
|
||||
dataSource={dataSource}
|
||||
valueExpr={lookup?.valueExpr}
|
||||
displayExpr={lookup?.displayExpr}
|
||||
valueExpr={lookupDto?.valueExpr}
|
||||
displayExpr={lookupDto?.displayExpr}
|
||||
showClearButton={options?.showClearButton}
|
||||
showSelectionControls={options?.showSelectionControls ?? true}
|
||||
maxDisplayedTags={options?.maxDisplayedTags}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
import { FormItemComponent, SimpleItem } from 'devextreme/ui/form'
|
||||
import { GridColumnData } from '../list/GridColumnData'
|
||||
import { Overwrite } from '../../utils/types'
|
||||
import { GridBoxOptionsDto, PlatformEditorTypes, TagBoxOptionsDto } from '../../proxy/form/models'
|
||||
import { ColumnFormatDto, GridBoxOptionsDto, PlatformEditorTypes, TagBoxOptionsDto } from '../../proxy/form/models'
|
||||
import { Meta } from '@/@types/routes'
|
||||
|
||||
export type EditorType2 = FormItemComponent | PlatformEditorTypes.dxGridBox
|
||||
export type SimpleItemWithColData = Overwrite<
|
||||
SimpleItem,
|
||||
{
|
||||
colData?: GridColumnData
|
||||
colData?: ColumnFormatDto
|
||||
tagBoxOptions?: TagBoxOptionsDto
|
||||
gridBoxOptions?: GridBoxOptionsDto
|
||||
canRead: boolean
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ const useGridData = (props: {
|
|||
colSpan: i.colSpan,
|
||||
isRequired: i.isRequired,
|
||||
editorOptions,
|
||||
colData: cols?.find((x) => x.dataField === i.dataField),
|
||||
colData: gridDto?.columnFormats.find((x) => x.fieldName === i.dataField),
|
||||
tagBoxOptions: i.tagBoxOptions,
|
||||
gridBoxOptions: i.gridBoxOptions,
|
||||
}
|
||||
|
|
|
|||
153
ui/src/views/form/useLookupDataSource.ts
Normal file
153
ui/src/views/form/useLookupDataSource.ts
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import { dynamicFetch } from '@/services/form.service'
|
||||
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
|
||||
import CustomStore from 'devextreme/data/custom_store'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
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[],
|
||||
isSubForm?: boolean,
|
||||
) => {
|
||||
return new CustomStore({
|
||||
loadMode: 'raw',
|
||||
load: async () => {
|
||||
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) {
|
||||
return null
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const createLookupApiDataSource = (
|
||||
listFormCode?: string,
|
||||
lookupQuery?: string,
|
||||
filters?: any[],
|
||||
keyName?: string,
|
||||
isSubForm?: boolean,
|
||||
) => {
|
||||
return new CustomStore({
|
||||
key: keyName,
|
||||
loadMode: 'raw',
|
||||
load: async () => {
|
||||
if (!isSubForm && listFormCode && !window.location.pathname.includes(listFormCode)) {
|
||||
return
|
||||
}
|
||||
if (!lookupQuery) {
|
||||
return
|
||||
}
|
||||
|
||||
const [method, url, body, keySelector, nameSelector, groupSelector] = lookupQuery.split(';')
|
||||
|
||||
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) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!Array.isArray(data)) {
|
||||
data = [data]
|
||||
}
|
||||
|
||||
return data.map((a: any) => ({
|
||||
key: eval(keySelector),
|
||||
name: eval(nameSelector),
|
||||
group: eval(groupSelector),
|
||||
}))
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useLookupDataSource = ({
|
||||
listFormCode,
|
||||
isSubForm,
|
||||
}: {
|
||||
listFormCode: string
|
||||
isSubForm?: boolean
|
||||
}) => {
|
||||
const getLookupDataSource = useCallback(
|
||||
(options: any, colData: any) => {
|
||||
const { lookupDto } = colData
|
||||
const filters = []
|
||||
if (lookupDto.cascadeParentFields) {
|
||||
if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.StaticData) {
|
||||
filters.push([
|
||||
lookupDto?.cascadeRelationField,
|
||||
lookupDto?.cascadeFilterOperator,
|
||||
options?.data[lookupDto?.cascadeParentField],
|
||||
])
|
||||
} else {
|
||||
const data = options?.data ?? options
|
||||
for (const cascadeParentField of lookupDto.cascadeParentFields.split(',')) {
|
||||
filters.push(data[cascadeParentField])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, isSubForm)
|
||||
} else if (lookupDto.dataSourceType == UiLookupDataSourceTypeEnum.WebService) {
|
||||
return createLookupApiDataSource(
|
||||
listFormCode,
|
||||
lookupDto?.lookupQuery,
|
||||
filters,
|
||||
colData.lookupDto?.valueExpr?.toLowerCase(),
|
||||
isSubForm,
|
||||
)
|
||||
} else {
|
||||
return {
|
||||
store: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
[listFormCode, isSubForm],
|
||||
)
|
||||
|
||||
return { getLookupDataSource }
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { EditingFormItemDto, GridDto, PlatformEditorTypes } from '@/proxy/form/models'
|
||||
import { captionize } from 'devextreme/core/utils/inflector'
|
||||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||
import { Pagination, Select } from '@/components/ui'
|
||||
|
|
@ -7,13 +7,13 @@ import classNames from 'classnames'
|
|||
import { getList } from '@/services/form.service'
|
||||
import { FaInbox } from 'react-icons/fa'
|
||||
import FormDevExpress from '../form/FormDevExpress'
|
||||
import { GroupItem, SimpleItem } from 'devextreme/ui/form'
|
||||
import { GroupItem } from 'devextreme/ui/form'
|
||||
import { Form as FormDx } from 'devextreme-react/form'
|
||||
import FormButtons from '../form/FormButtons'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import CustomStore from 'devextreme/data/custom_store'
|
||||
import { PermissionResults } from '../form/types'
|
||||
import { PermissionResults, SimpleItemWithColData } from '../form/types'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
||||
|
|
@ -54,22 +54,61 @@ const CardItem = ({
|
|||
const formItems: GroupItem[] = useMemo(() => {
|
||||
if (!gridDto) return []
|
||||
|
||||
const items: SimpleItem[] = gridDto.columnFormats
|
||||
.filter((col) => col.visible && col.listOrderNo > 0)
|
||||
.sort((a, b) => a.listOrderNo - b.listOrderNo)
|
||||
.slice(0, 10)
|
||||
.map((col) => ({
|
||||
dataField: col.fieldName,
|
||||
label: { text: captionize(col.captionName || col.fieldName!) },
|
||||
}))
|
||||
|
||||
return [
|
||||
{
|
||||
itemType: 'group',
|
||||
colCount: 1,
|
||||
items: items,
|
||||
},
|
||||
]
|
||||
return gridDto?.gridOptions.editingFormDto
|
||||
?.sort((a: any, b: any) => {
|
||||
return a.order >= b.order ? 1 : -1
|
||||
})
|
||||
.map((e: any) => {
|
||||
return {
|
||||
itemType: e.itemType,
|
||||
colCount: e.colCount,
|
||||
colSpan: e.colSpan,
|
||||
caption: e.caption,
|
||||
items: e.items
|
||||
?.sort((a: any, b: any) => {
|
||||
return a.order >= b.order ? 1 : -1
|
||||
})
|
||||
.map((i: EditingFormItemDto) => {
|
||||
let editorOptions = {}
|
||||
try {
|
||||
editorOptions = i.editorOptions && JSON.parse(i.editorOptions)
|
||||
} catch {}
|
||||
const item: SimpleItemWithColData = {
|
||||
canRead:
|
||||
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canRead ??
|
||||
false,
|
||||
canUpdate:
|
||||
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canUpdate ??
|
||||
false,
|
||||
canCreate:
|
||||
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canCreate ??
|
||||
false,
|
||||
canExport:
|
||||
gridDto.columnFormats.find((x: any) => x.fieldName === i.dataField)?.canExport ??
|
||||
false,
|
||||
dataField: i.dataField,
|
||||
name: i.dataField,
|
||||
editorType2: i.editorType2,
|
||||
editorType:
|
||||
i.editorType2 == PlatformEditorTypes.dxGridBox ? 'dxDropDownBox' : i.editorType2,
|
||||
colSpan: i.colSpan,
|
||||
isRequired: i.isRequired,
|
||||
editorOptions,
|
||||
colData: gridDto.columnFormats.find((x) => x.fieldName === i.dataField),
|
||||
tagBoxOptions: i.tagBoxOptions,
|
||||
gridBoxOptions: i.gridBoxOptions,
|
||||
}
|
||||
if (i.dataField.indexOf(':') >= 0) {
|
||||
item.label = { text: captionize(i.dataField.split(':')[1]) }
|
||||
}
|
||||
item.editorOptions = {
|
||||
...item.editorOptions,
|
||||
readOnly: true,
|
||||
}
|
||||
return item
|
||||
}),
|
||||
} as GroupItem
|
||||
})
|
||||
}, [gridDto])
|
||||
|
||||
const permissionResults: PermissionResults = {
|
||||
|
|
@ -130,6 +169,7 @@ const CardItem = ({
|
|||
formData={formData}
|
||||
formItems={formItems}
|
||||
setFormData={setFormData}
|
||||
listFormCode={listFormCode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -194,7 +234,7 @@ const Card = ({ listFormCode, searchParams }: CardProps) => {
|
|||
const allowedSizes = pagerOptions?.allowedPageSizes
|
||||
?.split(',')
|
||||
.map((s) => Number(s.trim()))
|
||||
.filter((n) => !isNaN(n) && n > 0) || [20, 50, 100]
|
||||
.filter((n) => !isNaN(n) && n > 0) || [10, 20, 50, 100]
|
||||
|
||||
setPageSizeOptions(allowedSizes.map((size) => ({ value: size, label: `${size} page` })))
|
||||
}, [gridDto, listFormCode, searchParams])
|
||||
|
|
|
|||
Loading…
Reference in a new issue