index.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. 'use client'
  2. import List from './list'
  3. import React, { useEffect, useRef, useState } from 'react'
  4. import Input from '@/app/components/base/input'
  5. import cn from '@/utils/classnames'
  6. import { RiAddLine, RiRefreshLine, RiSearchLine } from '@remixicon/react'
  7. import Button from '@/app/components/base/button'
  8. import { fetchCorpus, fetchIntent } from '@/service/common'
  9. import DetailModal from './detail-modal'
  10. import { Cascader as AntdCascader } from 'antd'
  11. const CorpusIndex = () => {
  12. const [intentCascader, setIntentCascader] = useState<any>([])
  13. useEffect(() => {
  14. fetchIntent({
  15. url: '/intentions',
  16. params: {
  17. page: 1,
  18. limit: 99999,
  19. },
  20. }).then((res: any) => {
  21. const map = new Map()
  22. res.data.forEach((v: any) => {
  23. if (map.has(v.type_id)) {
  24. const parent = map.get(v.type_id)
  25. parent.children.push(v)
  26. map.set(v.type_id, parent)
  27. }
  28. else {
  29. map.set(v.type_id, {
  30. id: v.type_id,
  31. name: v.type_name,
  32. children: [v],
  33. })
  34. }
  35. })
  36. setIntentCascader(Array.from(map.values()))
  37. })
  38. }, [])
  39. const [page, setPage] = useState<number>(0)
  40. const [limit, setLimit] = useState<number>(10)
  41. const [question, setQuestion] = useState<string>('')
  42. const [intentName, setIntentName] = useState<string>('')
  43. const [intentValue, setIntentValue] = useState<any>([])
  44. const query = useRef<any>({})
  45. const [list, setList] = useState<any>([])
  46. const [total, setTotal] = useState(0)
  47. const handlePage = () => {
  48. const params: any = {
  49. page: page + 1,
  50. limit,
  51. }
  52. if (query.current.question)
  53. params.question_search = query.current.question
  54. if (query.current.intentName)
  55. params.intention_id = query.current.intentName
  56. fetchCorpus({
  57. url: '/intentions/corpus',
  58. params,
  59. }).then((res: any) => {
  60. setList(res.data)
  61. setTotal(res.total)
  62. })
  63. }
  64. const [refresh, setRefresh] = useState<boolean>(false)
  65. const handleSearch = (reset = false) => {
  66. setRefresh(true)
  67. setPage(0)
  68. if (reset) {
  69. setQuestion('')
  70. setIntentName('')
  71. setIntentValue([])
  72. query.current = {}
  73. }
  74. else {
  75. query.current = {
  76. question, intentName,
  77. }
  78. }
  79. handlePage()
  80. setRefresh(false)
  81. }
  82. useEffect(() => {
  83. if (!refresh)
  84. handlePage()
  85. }, [page, limit])
  86. const [detailModalVisible, setDetailModalVisible] = useState(false)
  87. const [transfer, setTransfer] = useState<any>({
  88. mode: 'add',
  89. row: {},
  90. })
  91. return (
  92. <>
  93. <div className='flex h-full w-full flex-col bg-background-default-subtle p-6'>
  94. <div className="flex items-center gap-2">
  95. <div className="flex shrink-0 items-center text-gray-500">
  96. 标准问题
  97. <Input
  98. className="ml-2"
  99. showClearIcon
  100. wrapperClassName='!w-[200px]'
  101. value={question}
  102. onChange={e => setQuestion(e.target.value)}
  103. onClear={() => setQuestion('')}
  104. />
  105. </div>
  106. <div className="ml-2 flex shrink-0 items-center text-gray-500">
  107. 意图名称
  108. <div className="ml-2 flex h-[32px]">
  109. <AntdCascader
  110. value={intentValue}
  111. className="h-[32px] w-[200px]"
  112. options={intentCascader}
  113. onChange={(val: any) => {
  114. setIntentValue(val)
  115. setIntentName(val?.[val.length - 1] || '')
  116. }}
  117. placeholder="请选择"
  118. fieldNames={{ label: 'name', value: 'id' }}
  119. showSearch={true}
  120. />
  121. </div>
  122. </div>
  123. <Button variant='primary' className={cn('ml-auto shrink-0')} onClick={() => {
  124. handleSearch(false)
  125. }}>
  126. <RiSearchLine className='mr-1 h-4 w-4' />
  127. 搜索
  128. </Button>
  129. <Button variant='primary' className={cn('shrink-0')} onClick={() => {
  130. handleSearch(true)
  131. }}>
  132. <RiRefreshLine className='mr-1 h-4 w-4' />
  133. 重置
  134. </Button>
  135. </div>
  136. <div className="mt-2">
  137. <Button variant='primary' className={cn('shrink-0')}
  138. onClick={() => {
  139. setTransfer({ mode: 'add', row: null })
  140. setDetailModalVisible(true)
  141. }}>
  142. <RiAddLine className='mr-1 h-4 w-4' />
  143. 新增
  144. </Button>
  145. </div>
  146. <div className="flex-1">
  147. <List
  148. list={list || []}
  149. onUpdate={() => handleSearch(false)}
  150. pagination={{
  151. total,
  152. limit,
  153. onLimitChange: setLimit,
  154. current: page,
  155. onChange: setPage,
  156. }}
  157. />
  158. </div>
  159. </div>
  160. {
  161. detailModalVisible && (
  162. <DetailModal
  163. transfer={transfer}
  164. onCancel={() => {
  165. setDetailModalVisible(false)
  166. handleSearch()
  167. }}
  168. onSend={() => {
  169. setDetailModalVisible(false)
  170. handleSearch()
  171. }}
  172. onRefresh={(id: string) => {
  173. setTransfer({
  174. mode: 'edit',
  175. row: { id },
  176. })
  177. }}
  178. />
  179. )
  180. }
  181. </>
  182. )
  183. }
  184. export default CorpusIndex