|
|
import { Button, Input, Modal, ModalProps, Select, SelectProps, Spin, Tag } from 'antd' import { memo, ReactNode, useEffect, useRef, useState } from 'react' import { Flexbox } from 'react-layout-kit' import { useStyle } from './style.ts' import { List, ListViewItem } from './List.tsx' import { useTranslation } from '@/i18n.ts' import DepartmentTree from '@/components/department-tree/DepartmentTree.tsx' import { DraggablePanel } from '@/components/draggable-panel' import { useAtom, useAtomValue } from 'jotai' import { userListAtom, userSearchAtom, } from '@/store/user.ts' import { IUser } from '@/types' import EmptyWrap from '@/components/empty/EmptyWrap.tsx'
export interface UserSelectProps extends SelectProps { value?: any[] onChange?: (value: any[]) => void //多选
multiple?: boolean, renderValue?: (value: any[], def: ReactNode) => ReactNode
}
export interface UserModelProps extends Pick<ModalProps, 'open'> { value?: any[] onChange?: (value?: any[]) => void children?: ReactNode //多选
multiple?: boolean
renderValue?: (value: any[], def: ReactNode) => ReactNode
}
export type UserPickerProps = | { type?: 'modal'; /** Props for the modal component */ } & UserModelProps | { type: 'select'; /** Props for the select component */ } & UserSelectProps
const UserSelect = memo((props: UserSelectProps) => {
return ( <Select {...props}>
</Select> ) })
const UserModel = memo(({ multiple, children, value, onChange, ...props }: UserModelProps) => { const { styles, cx } = useStyle() const { t } = useTranslation() const [ innerValue, setValue ] = useState(() => {
if (!multiple && !Array.isArray(value)) { return [ value ] } }) const [ , setSearch ] = useAtom(userSearchAtom) const { data: users, isPending } = useAtomValue(userListAtom) const [ open, setOpen ] = useState(false) const selectUserRef = useRef<IUser[]>([]) const [ , update ] = useState({})
useEffect(() => { if (value === undefined) return
setValue(Array.isArray(value) ? value : [ value ]) }, [ value ])
useEffect(() => {
selectUserRef.current = [] innerValue?.forEach(id => { const item = users?.rows?.find(user => user.id === id) if (item) { selectUserRef.current = [ ...selectUserRef.current, item ] } }) update({})
}, [ innerValue ])
useEffect(() => { return () => { selectUserRef.current = [] }
}, [])
const renderTarget = () => { return <span onClick={() => setOpen(true)}> {children ?? <Button type={'primary'} >{t('component.UserPicker.targetText', '选择成员')}</Button>} </span> }
const renderValue = () => { const dom = selectUserRef.current?.map(user => { return <Tag key={user.id} color={'blue'} closable onClose={() => { const newVal = innerValue?.filter(val => val !== user.id) setValue(newVal) onChange?.(newVal) }}>{user.name}</Tag> }) if (props.renderValue) { return props.renderValue(selectUserRef.current, dom) } return dom }
return ( <> <div> {renderTarget()} </div> <div className={styles.values}> {renderValue()} </div>
<Modal className={styles.modal} title={t('component.UserPicker.title', '成员选择')} width={800} {...props} open={open} onOk={() => { onChange?.(multiple ? innerValue : innerValue?.[0]) setOpen(false) }} onCancel={() => { setOpen(false) }} > <Flexbox horizontal={true} className={styles.container} gap={8} height={400}> <Flexbox flex={5} gap={10}> <Input.Search allowClear={true} onSearch={value => { setSearch({ key: value, }) }} placeholder={t('component.UserPicker.placeholder', '输入成员姓名,回车查询')}/> <Flexbox flex={1} horizontal={true} className={styles.bordered}> <Flexbox flex={1} padding={4}> <DepartmentTree root={true} fieldNames={{ title: 'name', key: 'id' }} autoExpandParent={true} onSelect={(keys) => { setSearch({ dept_id: keys?.[0] }) }} /> </Flexbox> <Flexbox flex={1} className={styles.usersPanel}> <Spin spinning={isPending} delay={200}> <EmptyWrap isEmpty={!users?.rows || users?.rows.length === 0}> <List rowKey={'id'} multiple={multiple} value={innerValue} onChange={(val) => { setValue(val) }} dataSource={users?.rows ?? []} /> </EmptyWrap> </Spin> </Flexbox> </Flexbox> </Flexbox> <DraggablePanel expandable={false} placement="right" maxWidth={300} minWidth={280} className={cx(styles.bordered, styles.draggablePanel)} > <Flexbox flex={6 / 2}> <div className={styles.selected}>{t('component.UserPicker.selected', '已选({{count}})', { count: selectUserRef.current?.length ?? 0 })}</div> <div> { selectUserRef.current?.map(user => { return (<ListViewItem onDel={user => { setValue(innerValue?.filter(id => id !== user.id)) }} key={user.id} user={user!}/>) }) } </div> </Flexbox> </DraggablePanel>
</Flexbox> </Modal> </>
) })
const UserPicker = memo(({ type = 'modal', ...props }: UserPickerProps) => { return type === 'modal' ? <UserModel {...props as UserModelProps} /> : <UserSelect {...props as UserSelectProps} /> })
export default UserPicker
|