user-modal.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. 'use client'
  2. import React, { useCallback, useEffect, useState } from 'react'
  3. import { RiAddLine, RiCloseLine, RiRefreshLine, RiSearchLine } from '@remixicon/react'
  4. import Modal from '@/app/components/base/modal'
  5. import Button from '@/app/components/base/button'
  6. import { delCorpus, fetchIntentType, fetchTypes } from '@/service/common'
  7. import 'react-multi-email/dist/style.css'
  8. import Input from '@/app/components/base/input'
  9. import useSWR from 'swr'
  10. import cn from '@/utils/classnames'
  11. import Confirm from '@/app/components/base/confirm'
  12. import Pagination from '@/app/components/base/pagination'
  13. import { SimpleSelect } from '@/app/components/base/select'
  14. const TypeModal = ({
  15. onCancel,
  16. onSend,
  17. }: any) => {
  18. const [page, setPage] = React.useState<number>(0)
  19. const [limit, setLimit] = useState<number>(10)
  20. const [name, setName] = useState('')
  21. const [query, setQuery] = useState<any>({})
  22. const { data, mutate }: any = useSWR(
  23. {
  24. url: '/xxx',
  25. params: {
  26. page: page + 1,
  27. limit,
  28. ...query,
  29. },
  30. },
  31. fetchIntentType,
  32. )
  33. const list: any = data?.data || []
  34. const total = data?.total || 0
  35. const handleSearch = (reset = false) => {
  36. if (reset)
  37. setIntentType('')
  38. const params: any = {}
  39. if (intentType)
  40. params.intentType = intentType
  41. setQuery(params)
  42. setPage(0)
  43. }
  44. useEffect(() => {
  45. mutate()
  46. }, [page, limit])
  47. const [showConfirmDelete, setShowConfirmDelete] = useState(false)
  48. const [row, setRow] = useState<any>({})
  49. const handleDel = async () => {
  50. try {
  51. await delCorpus({
  52. url: `/tags/${row.id}`,
  53. body: {},
  54. })
  55. setShowConfirmDelete(false)
  56. }
  57. catch (e) { }
  58. }
  59. const [showDetail, setShowDetail] = useState(false)
  60. const [mode, setMode] = useState<any>('add')
  61. const [editIntentType, setEditIntentType] = useState('')
  62. const [selectUser, setSelectUser] = useState<any>('')
  63. const [userOptions, setUserOptions] = useState<any>([])
  64. useEffect(() => {
  65. fetchTypes({
  66. url: '/tags/page',
  67. params: {
  68. page: 1,
  69. limit: 99999,
  70. tag_type: 'knowledge_category',
  71. },
  72. }).then((res: any) => {
  73. setUserOptions(res.data.map((v: any) => ({ name: v.name, value: v.id })) || [])
  74. })
  75. }, [])
  76. const handleSave = useCallback(async () => {
  77. // try {
  78. // let res
  79. // if (transfer.mode === 'add') {
  80. // res = await addCorpus({
  81. // url: '/xxx',
  82. // body: { name, type: 'knowledge_category' },
  83. // })
  84. // }
  85. // else {
  86. // res = await editCorpus({
  87. // url: '/xxx',
  88. // body: { name },
  89. // })
  90. // }
  91. // const { id }: any = res
  92. // if (id) {
  93. // onCancel()
  94. // onSend()
  95. // }
  96. // }
  97. // catch (e) { }
  98. }, [mode, editIntentType, onCancel, onSend])
  99. return (
  100. <div>
  101. <Modal overflowVisible isShow onClose={() => { }} className="p-[24px 32px] w-[800px] max-w-[800px]">
  102. <div className='mb-2 flex justify-between'>
  103. <div className='text-xl font-semibold text-text-primary'>关联用户</div>
  104. <RiCloseLine className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={onCancel} />
  105. </div>
  106. <div className='flex h-[600px] flex-col'>
  107. <div className="flex items-center gap-2">
  108. <div className="flex shrink-0 items-center text-gray-500">
  109. 用户名称
  110. <Input
  111. className="ml-2"
  112. showClearIcon
  113. wrapperClassName='!w-[200px]'
  114. value={name}
  115. onChange={e => setName(e.target.value)}
  116. onClear={() => setName('')}
  117. />
  118. </div>
  119. <Button variant='primary' className={cn('ml-auto shrink-0')} onClick={() => {
  120. handleSearch(false)
  121. }}>
  122. <RiSearchLine className='mr-1 h-4 w-4' />
  123. 搜索
  124. </Button>
  125. <Button variant='primary' className={cn('shrink-0')} onClick={() => {
  126. handleSearch(true)
  127. }}>
  128. <RiRefreshLine className='mr-1 h-4 w-4' />
  129. 重置
  130. </Button>
  131. </div>
  132. <div className="mt-2">
  133. <Button variant='primary' className={cn('shrink-0')}
  134. onClick={() => {
  135. setMode('add')
  136. setEditIntentType('')
  137. setShowDetail(true)
  138. }}>
  139. <RiAddLine className='mr-1 h-4 w-4' />
  140. 添加用户
  141. </Button>
  142. </div>
  143. <div className="flex-1">
  144. <div className='relative flex h-full w-full flex-col'>
  145. <div className='relative grow overflow-x-auto'>
  146. <table className={'mt-3 w-full min-w-[700px] max-w-full border-collapse border-0 text-sm'}>
  147. <thead className="h-8 border-b border-divider-subtle text-xs font-medium uppercase leading-8 text-text-tertiary">
  148. <tr>
  149. <td>用户名称</td>
  150. <td className="w-[120px] text-center">操作</td>
  151. </tr>
  152. </thead>
  153. <tbody className="text-text-secondary">
  154. {list.map((item: any) => (
  155. <tr
  156. key={item.id}
  157. className={'h-8 border-b border-divider-subtle hover:bg-background-default-hover'}
  158. >
  159. <td>{item.name}</td>
  160. <td className="flex justify-center gap-2">
  161. <Button variant='ghost' size='small' className={cn('shrink-0 text-red-600')} onClick={() => {
  162. setRow(item)
  163. setShowConfirmDelete(true)
  164. }}>
  165. 解除关联
  166. </Button>
  167. </td>
  168. </tr>
  169. ))}
  170. </tbody>
  171. </table>
  172. </div>
  173. {/* Show Pagination only if the total is more than the limit */}
  174. {total && (
  175. <Pagination
  176. total={total}
  177. limit={limit}
  178. onLimitChange={setLimit}
  179. current={page}
  180. onChange={setPage}
  181. className='w-full shrink-0 px-0 pb-0'
  182. />
  183. )}
  184. </div>
  185. </div>
  186. </div>
  187. </Modal>
  188. {showConfirmDelete && (
  189. <Confirm
  190. title="删除确认"
  191. content={`请确认是否删除${row.name}?`}
  192. isShow={showConfirmDelete}
  193. onConfirm={handleDel}
  194. onCancel={() => setShowConfirmDelete(false)}
  195. />
  196. )}
  197. {
  198. showDetail && (
  199. <Modal overflowVisible isShow onClose={() => { }} className="p-[24px 32px] w-[400px]">
  200. <div className='mb-2 flex justify-between'>
  201. <div className='text-xl font-semibold text-text-primary'>添加用户</div>
  202. <RiCloseLine className='h-4 w-4 cursor-pointer text-text-tertiary' onClick={() => setShowDetail(false)} />
  203. </div>
  204. <div>
  205. <div className={cn('flex flex-wrap items-center justify-between py-4')}>
  206. <div className='shrink-0 py-2 text-sm font-medium leading-[20px] text-text-primary'>
  207. 选择用户
  208. </div>
  209. <div className='w-full'>
  210. <SimpleSelect
  211. defaultValue={selectUser}
  212. onSelect={(i) => { setSelectUser(i.value) }}
  213. items={userOptions}
  214. allowSearch={false}
  215. />
  216. </div>
  217. </div>
  218. <Button
  219. tabIndex={0}
  220. className='w-full'
  221. onClick={handleSave}
  222. disabled={!editIntentType.length}
  223. variant='primary'
  224. >
  225. 保存
  226. </Button>
  227. </div>
  228. </Modal>
  229. )
  230. }
  231. </div>
  232. )
  233. }
  234. export default TypeModal