Transfer.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /**
  2. * Transfer
  3. * @author: oldj
  4. * @homepage: https://oldj.net
  5. */
  6. import { useModel } from '@@/plugin-model/useModel'
  7. import { ArrowBackIcon, ArrowForwardIcon } from '@chakra-ui/icons'
  8. import { Box, Center, Grid, IconButton, VStack } from '@chakra-ui/react'
  9. import React, { useState } from 'react'
  10. import clsx from 'clsx'
  11. import styles from './Transfer.less'
  12. type IdType = string
  13. interface ITransferSourceObject {
  14. id: IdType
  15. [key: string]: any
  16. }
  17. interface IListProps {
  18. data: ITransferSourceObject[]
  19. selected_keys: IdType[]
  20. setSelectedKeys: (ids: IdType[]) => void
  21. }
  22. interface Props {
  23. dataSource: ITransferSourceObject[]
  24. targetKeys: IdType[]
  25. render?: (obj: ITransferSourceObject) => React.ReactElement
  26. onChange?: (next_target_keys: IdType[]) => void
  27. }
  28. const Transfer = (props: Props) => {
  29. const { dataSource, targetKeys, render, onChange } = props
  30. const { lang } = useModel('useI18n')
  31. const [right_keys, setRightKeys] = useState<IdType[]>(targetKeys)
  32. const [left_selectd_keys, setLeftSelectedKeys] = useState<IdType[]>([])
  33. const [right_selectd_keys, setRightSelectedKeys] = useState<IdType[]>([])
  34. const List = (list_props: IListProps) => {
  35. const { data, selected_keys, setSelectedKeys } = list_props
  36. const toggleSelect = (id: IdType) => {
  37. setSelectedKeys(
  38. selected_keys.includes(id)
  39. ? selected_keys.filter((i) => i != id)
  40. : [...selected_keys, id],
  41. )
  42. }
  43. return (
  44. <div className={styles.list}>
  45. {data.map((item) => {
  46. if (!item || !item.id) return null
  47. const is_selected = selected_keys.includes(item.id)
  48. return (
  49. <Box
  50. key={item.id}
  51. className={clsx(styles.item, is_selected && styles.selected)}
  52. px={3}
  53. py={1}
  54. onClick={() => toggleSelect(item.id)}
  55. >
  56. {render ? render(item) : item.title || item.id}
  57. </Box>
  58. )
  59. })}
  60. </div>
  61. )
  62. }
  63. const moveLeftToRight = () => {
  64. let result = [...right_keys, ...left_selectd_keys]
  65. setRightKeys(result)
  66. setLeftSelectedKeys([])
  67. onChange && onChange(result)
  68. }
  69. const moveRightToLeft = () => {
  70. let result = right_keys.filter((i) => !right_selectd_keys.includes(i))
  71. setRightKeys(result)
  72. setRightSelectedKeys([])
  73. onChange && onChange(result)
  74. }
  75. return (
  76. <div className={styles.root}>
  77. <Grid templateColumns="minmax(0, 1fr) 40px minmax(0, 1fr)" gap={1}>
  78. <Box borderWidth="1px" borderRadius="md">
  79. <Box className={styles.title} borderBottomWidth={1} px={3} py={1}>
  80. {lang.all}{' '}
  81. <span>
  82. (
  83. {left_selectd_keys.length === 0
  84. ? dataSource.length
  85. : `${left_selectd_keys.length}/${dataSource.length}`}
  86. )
  87. </span>
  88. </Box>
  89. <List
  90. data={dataSource.filter((i) => !right_keys.includes(i.id))}
  91. selected_keys={left_selectd_keys}
  92. setSelectedKeys={setLeftSelectedKeys}
  93. />
  94. </Box>
  95. <Center h="100%">
  96. <VStack>
  97. <IconButton
  98. size="sm"
  99. variant="outline"
  100. aria-label="Move to right"
  101. icon={<ArrowForwardIcon />}
  102. isDisabled={left_selectd_keys.length === 0}
  103. onClick={moveLeftToRight}
  104. />
  105. <IconButton
  106. size="sm"
  107. variant="outline"
  108. aria-label="Move to left"
  109. icon={<ArrowBackIcon />}
  110. isDisabled={right_selectd_keys.length === 0}
  111. onClick={moveRightToLeft}
  112. />
  113. </VStack>
  114. </Center>
  115. <Box borderWidth="1px" borderRadius="md">
  116. <Box className={styles.title} borderBottomWidth={1} px={3} py={1}>
  117. {lang.selected}{' '}
  118. <span>
  119. (
  120. {right_selectd_keys.length === 0
  121. ? right_keys.length
  122. : `${right_selectd_keys.length}/${right_keys.length}`}
  123. )
  124. </span>
  125. </Box>
  126. <List
  127. data={
  128. right_keys.map((id) =>
  129. dataSource.find((i) => i.id === id),
  130. ) as ITransferSourceObject[]
  131. }
  132. selected_keys={right_selectd_keys}
  133. setSelectedKeys={setRightSelectedKeys}
  134. />
  135. </Box>
  136. </Grid>
  137. </div>
  138. )
  139. }
  140. export default Transfer