李金
3 months ago
7 changed files with 158 additions and 4768 deletions
-
5package.json
-
4src/components/draggable-panel/FloatMode.tsx
-
2src/components/r-form/index.tsx
-
2src/components/r-form/utils/index.tsx
-
111src/pages/x-form/hooks/useApi.tsx
-
146src/pages/x-form/utils/index.tsx
-
4358yarn.lock
@ -1,111 +0,0 @@ |
|||||
import { useNavigate, useRouterState } from '@tanstack/react-router' |
|
||||
import { useAtom } from 'jotai/index' |
|
||||
import { apiAtom } from '@/store/x-form/model.ts' |
|
||||
import { useCallback, useEffect, useRef, useState } from 'react' |
|
||||
import { Input, message, Modal } from 'antd' |
|
||||
import { Route } from '@/pages/x-form' |
|
||||
import { useApiContext } from '@/context.ts' |
|
||||
|
|
||||
export const useApi = () => { |
|
||||
|
|
||||
const { location } = useRouterState() |
|
||||
const apiCtx = useApiContext() |
|
||||
const nav = useNavigate() |
|
||||
const [ api, setApi ] = useAtom(apiAtom) |
|
||||
const { api: apiParam } = Route.useSearch() |
|
||||
const [ isChange, setChange ] = useState(false) |
|
||||
const [ innerApi, setInnerApi ] = useState('') |
|
||||
const [ open, setOpen ] = useState(false) |
|
||||
const apiRef = useRef<string>(apiParam) |
|
||||
|
|
||||
|
|
||||
useEffect(() => { |
|
||||
|
|
||||
if (apiCtx.isApi && apiCtx.api) { |
|
||||
apiRef.current = apiCtx.api |
|
||||
setApi(apiCtx.api) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
if (!apiParam && api) { |
|
||||
apiRef.current = api |
|
||||
nav({ |
|
||||
to: location.pathname, |
|
||||
search: { |
|
||||
api |
|
||||
} |
|
||||
}) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
if (apiParam && !api) { |
|
||||
apiRef.current = apiParam |
|
||||
setApi(apiParam) |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
//延时弹出
|
|
||||
setTimeout(() => { |
|
||||
if (!apiRef.current) { |
|
||||
setOpen(true) |
|
||||
} |
|
||||
}, 2000) |
|
||||
|
|
||||
}, [ api, apiParam, apiCtx ]) |
|
||||
|
|
||||
const onOK = useCallback(() => { |
|
||||
if (!innerApi) { |
|
||||
message.destroy() |
|
||||
message.error('请填写 api 参数') |
|
||||
return |
|
||||
} |
|
||||
setChange(false) |
|
||||
setOpen(false) |
|
||||
setApi(innerApi) |
|
||||
setChange(true) |
|
||||
|
|
||||
nav({ |
|
||||
to: location.pathname, |
|
||||
search: { |
|
||||
api: innerApi |
|
||||
} |
|
||||
}) |
|
||||
}, [ innerApi ]) |
|
||||
|
|
||||
const holderElement = ( |
|
||||
<> |
|
||||
<Modal |
|
||||
title={'请指定 api 参数'} |
|
||||
closable={false} |
|
||||
open={open} |
|
||||
maskClosable={false} |
|
||||
afterOpenChange={setOpen} |
|
||||
onCancel={() => { |
|
||||
setOpen(false) |
|
||||
}} |
|
||||
onOk={() => { |
|
||||
onOK() |
|
||||
}} |
|
||||
> |
|
||||
<Input value={innerApi} |
|
||||
onKeyDown={e => { |
|
||||
if (e.key === 'Enter') { |
|
||||
onOK() |
|
||||
} |
|
||||
}} |
|
||||
onChange={e => { |
|
||||
setInnerApi(e.target.value) |
|
||||
}}/> |
|
||||
</Modal> |
|
||||
</> |
|
||||
) |
|
||||
return { |
|
||||
holderElement, |
|
||||
updateApi: setOpen, |
|
||||
setApi, |
|
||||
apiChange: isChange, |
|
||||
api, |
|
||||
apiCtx, |
|
||||
} as const |
|
||||
|
|
||||
} |
|
@ -1,146 +0,0 @@ |
|||||
import { XFormTypes } from '@/types/x-form/model' |
|
||||
import { ProColumns } from '@ant-design/pro-components' |
|
||||
import Switch from '@/components/switch' |
|
||||
import { Checkbox, DatePicker, Input, Radio, Select, TreeSelect } from 'antd' |
|
||||
import request from '@/request' |
|
||||
import { convertToBool, genProTableColumnWidthProps } from '@/utils' |
|
||||
import { ReactNode } from 'react' |
|
||||
|
|
||||
const getValueType = (column: XFormTypes.IColumn) => { |
|
||||
switch (column.type) { |
|
||||
case 'input': |
|
||||
return 'text' |
|
||||
case 'select': |
|
||||
return 'select' |
|
||||
case 'date': |
|
||||
return 'date' |
|
||||
case 'switch': |
|
||||
return 'switch' |
|
||||
case 'radio': |
|
||||
return 'radio' |
|
||||
case 'checkbox': |
|
||||
return 'checkbox' |
|
||||
case 'textarea': |
|
||||
return 'textarea' |
|
||||
case 'tree': |
|
||||
return 'treeSelect' |
|
||||
default: |
|
||||
return 'text' |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//根据type返回对应的组件
|
|
||||
const getComponent = (column: XFormTypes.IColumn) => { |
|
||||
const type = getValueType(column) as any |
|
||||
switch (type) { |
|
||||
case 'input': |
|
||||
return Input |
|
||||
case 'select': |
|
||||
return Select |
|
||||
case 'date': |
|
||||
return DatePicker |
|
||||
case 'switch': |
|
||||
return Switch |
|
||||
case 'radio': |
|
||||
return Radio |
|
||||
case 'checkbox': |
|
||||
return Checkbox |
|
||||
case 'textarea': |
|
||||
return Input.TextArea |
|
||||
case 'tree': |
|
||||
case 'treeSelect': |
|
||||
return TreeSelect |
|
||||
default: |
|
||||
return Input |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
export const transformAntdTableProColumns = (columns: XFormTypes.IColumn[]) => { |
|
||||
|
|
||||
return (columns || []).map(item => { |
|
||||
const { value, props, multiple, checkStrictly } = item |
|
||||
|
|
||||
const { width, fieldProps: _fieldProps } = genProTableColumnWidthProps(item.width) |
|
||||
const fieldProps: ProColumns['fieldProps'] = { |
|
||||
dataFiledNames: props, |
|
||||
...(multiple ? { multiple: true } : {}), |
|
||||
...(checkStrictly ? { treeCheckStrictly: true } : {}), |
|
||||
..._fieldProps, |
|
||||
} |
|
||||
|
|
||||
const formItemProps: ProColumns['formItemProps'] = (form, config) => { |
|
||||
|
|
||||
return { |
|
||||
rules: item.rules?.map(i => { |
|
||||
return { |
|
||||
required: i.required, |
|
||||
message: i.message |
|
||||
} |
|
||||
}), |
|
||||
...(value ? { valuePropName: value } : {}) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const rowProps = item.gutter ? { gutter: item.gutter } : { gutter: [ 16, 0 ], } |
|
||||
const colProps = item.span ? { span: item.span } : {} |
|
||||
|
|
||||
const type = getValueType(item) |
|
||||
return { |
|
||||
title: item.label, |
|
||||
dataIndex: item.prop, |
|
||||
key: item.prop, |
|
||||
width, |
|
||||
valueType: type, |
|
||||
hideInSearch: !item.search, |
|
||||
hideInTable: item.hide, |
|
||||
fieldProps, |
|
||||
formItemProps, |
|
||||
colProps, |
|
||||
rowProps, |
|
||||
request: item.dicUrl ? async (params, props) => { |
|
||||
const { fieldProps: { dataFiledNames } } = props |
|
||||
const { value, res: resKey, label } = dataFiledNames || {} |
|
||||
const url = `/${item.dicUrl.replace(/^:/, '/')}` |
|
||||
return request[item.dicMethod || 'get'](url, params).then(res => { |
|
||||
return (res.data?.[resKey] || res.data || []).map((i: any) => { |
|
||||
// console.log(i)
|
|
||||
const disabled = 'disabled' in i ? i.disabled : |
|
||||
('status' in i ? !convertToBool(i.status) : false) |
|
||||
return { |
|
||||
title: i[label || 'label'], |
|
||||
label: i[label || 'label'], |
|
||||
value: i[value || 'id'], |
|
||||
disabled, |
|
||||
data: i |
|
||||
} |
|
||||
}) |
|
||||
}) |
|
||||
} : undefined, |
|
||||
renderFormItem: (_scheam, config) => { |
|
||||
const Component = getComponent(item) as any |
|
||||
const { options, ...props } = config as any |
|
||||
|
|
||||
if ([ 'tree', 'treeSelect' ].includes(_scheam.valueType as string)) { |
|
||||
return <Component {...props} treeData={options}/> |
|
||||
} |
|
||||
if (_scheam.valueType as string === 'select') { |
|
||||
return <Select {...props} options={options}/> |
|
||||
} |
|
||||
|
|
||||
return <Component {...config} /> |
|
||||
}, |
|
||||
render: (text: any, record: any) => { |
|
||||
if (type === 'switch' || type === 'checkbox' || type === 'radio') { |
|
||||
return <Switch size={'small'} value={record[item.prop]}/> |
|
||||
} |
|
||||
if (item.colorFormat) { |
|
||||
return <span style={{ color: item.colorFormat }}>{text}</span> |
|
||||
} |
|
||||
return text |
|
||||
|
|
||||
} |
|
||||
} as ProColumns |
|
||||
}) |
|
||||
|
|
||||
} |
|
4358
yarn.lock
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue