index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. <template>
  2. <div class="bm-main-box">
  3. <div class="flex items-center">
  4. <div class="bm-main-box-title">{{ $route.meta.title }}</div>
  5. <div class="ml-auto flex items-center gap-[var(--czr-gap)]">
  6. <div
  7. class="__hover flex items-center gap-[0.3rem] text-[0.88rem] text-[#576275]"
  8. @click="
  9. () => (state.query.form.isCreate = !state.query.form.isCreate)
  10. "
  11. >
  12. <SvgIcon
  13. name="czr_add1"
  14. size="14"
  15. :active="state.query.form.isCreate"
  16. />我的创建
  17. </div>
  18. <div
  19. class="__hover flex items-center gap-[0.3rem] text-[0.88rem] text-[#576275]"
  20. @click="() => (state.query.form.isStar = !state.query.form.isStar)"
  21. >
  22. <SvgIcon
  23. name="star"
  24. size="15"
  25. class="mb-[2px]"
  26. :active="state.query.form.isStar"
  27. />我的收藏
  28. </div>
  29. <CzrForm class="bm-filter" label-width="0px" @handleEnter="onSearch">
  30. <CzrFormColumn
  31. width="6.68rem"
  32. class="__czr-table-form-column"
  33. :span="24"
  34. label-width="0px"
  35. v-model:param="state.query.form.groupId"
  36. link="select"
  37. :options="DictionaryStore.knowledgeGroups.list"
  38. placeholder="全部分组"
  39. />
  40. <CzrFormColumn
  41. width="6.68rem"
  42. class="__czr-table-form-column"
  43. :span="24"
  44. label-width="0px"
  45. v-model:param="state.query.form.tagIds"
  46. link="select"
  47. :options="DictionaryStore.knowledgeTags.list"
  48. placeholder="全部标签"
  49. />
  50. <CzrFormColumn
  51. width="15.63rem"
  52. class="__czr-table-form-column"
  53. :span="24"
  54. label-width="0px"
  55. v-model:param="state.text"
  56. placeholder="按名称搜索"
  57. :prefix-icon="Search"
  58. />
  59. </CzrForm>
  60. </div>
  61. </div>
  62. <div
  63. class="mt-[1rem] flex-1 overflow-hidden"
  64. v-loading="state.query.loading"
  65. >
  66. <CzrTableCard
  67. class="table-card"
  68. :page="state.query.page.pageNum"
  69. :pageSize="state.query.page.pageSize"
  70. :total="state.query.result.total"
  71. :data="state.query.result.data"
  72. @handlePage="onPage"
  73. :col="4"
  74. >
  75. <template #model="{ row, index }">
  76. <template v-if="row.empty">
  77. <div
  78. class="knowledge __hover flex items-center justify-center"
  79. @click="onAdd"
  80. >
  81. <img src="@/assets/images/knowledge-item-add.png" />
  82. <span
  83. class="ml-[var(--czr-gap)] text-[1.25rem] text-[var(--czr-main-color)]"
  84. >创建知识库</span
  85. >
  86. </div>
  87. </template>
  88. <template v-else>
  89. <div
  90. class="__hover knowledge flex flex-col"
  91. @click="
  92. $router.push({
  93. name: '78430247-a531-4c8f-8a08-c88e93a836e2',
  94. params: {
  95. id: index,
  96. },
  97. })
  98. "
  99. >
  100. <div class="flex">
  101. <img
  102. src="@/assets/images/knowledge-item-icon.png"
  103. class="mr-[var(--czr-gap)] h-[3.25rem] w-[3.25rem]"
  104. />
  105. <div
  106. class="flex flex-1 flex-col justify-around overflow-hidden"
  107. >
  108. <div class="flex items-center">
  109. <div
  110. class="flex-1 text-[1.25rem] font-bold text-[#2E3238]"
  111. v-title
  112. >
  113. {{ row.name }}
  114. </div>
  115. <div class="ml-auto">
  116. <tagsSelect
  117. :value="row.datasetTags"
  118. @onChange="(tags) => onChangeTag(row, tags)"
  119. />
  120. </div>
  121. </div>
  122. <div class="text-[0.75rem] text-[#6F7889]">
  123. 创建者:{{ row.userName }}
  124. </div>
  125. </div>
  126. </div>
  127. <div
  128. class="mt-[var(--czr-gap)] mb-auto text-[0.88rem] text-[#606266]"
  129. style="line-height: 1.4rem"
  130. v-title="{ lines: 3 }"
  131. >
  132. {{ row.description }}
  133. </div>
  134. <div
  135. class="flex items-center gap-[var(--czr-gap)] text-[0.75rem] text-[#6F7889]"
  136. >
  137. <div>文档数:{{ row.docCount }}</div>
  138. <div>|</div>
  139. <div>字符:{{ row.wordCounts }}</div>
  140. <div>|</div>
  141. <div>关联应用:{{ row.p6 }}</div>
  142. <el-tooltip content="编辑" effect="light" placement="top">
  143. <SvgIcon
  144. name="czr_edit"
  145. size="14"
  146. class="__hover ml-auto"
  147. @click.stop="onEdit(row)"
  148. />
  149. </el-tooltip>
  150. <el-tooltip content="删除" effect="light" placement="top">
  151. <SvgIcon
  152. name="czr_del"
  153. size="16"
  154. class="__hover"
  155. @click.stop="onDel(row)"
  156. />
  157. </el-tooltip>
  158. <el-tooltip
  159. :content="row.datasetCollection ? '取消收藏' : '收藏'"
  160. effect="light"
  161. placement="top"
  162. >
  163. <SvgIcon
  164. name="star"
  165. size="15"
  166. class="__hover"
  167. :active="!!row.datasetCollection"
  168. @click.stop="onStart(row)"
  169. />
  170. </el-tooltip>
  171. </div>
  172. </div>
  173. </template>
  174. </template>
  175. </CzrTableCard>
  176. </div>
  177. <detailCom
  178. v-model:show="state.detail.show"
  179. :transfer="state.detail.transfer"
  180. @refresh="onSearch"
  181. />
  182. </div>
  183. </template>
  184. <script setup lang="ts">
  185. import { getCurrentInstance, onMounted, reactive, ref, watch } from 'vue'
  186. import { Search } from '@element-plus/icons-vue'
  187. import { debounce } from 'lodash'
  188. import { useAppStore, useDialogStore, useDictionaryStore } from '@/stores'
  189. import { ElMessage } from 'element-plus'
  190. import tagsSelect from './tags-select.vue'
  191. import detailCom from './detail.vue'
  192. import {
  193. datasetsCancelCollect,
  194. datasetsGetAllByPage,
  195. datasetsTagsBinding,
  196. } from '@/api/modules/knowledge'
  197. import { datasetCollections } from '@/api/modules/knowledge/collect'
  198. const AppStore = useAppStore()
  199. const DialogStore = useDialogStore()
  200. const DictionaryStore = useDictionaryStore()
  201. const emit = defineEmits([])
  202. const props = defineProps({})
  203. const { proxy }: any = getCurrentInstance()
  204. const state: any = reactive({
  205. text: '',
  206. query: {
  207. init: false,
  208. loading: false,
  209. page: {
  210. pageNum: 1,
  211. pageSize: 20,
  212. },
  213. form: {},
  214. formReal: {},
  215. result: {
  216. total: 0,
  217. data: [],
  218. },
  219. },
  220. detail: {
  221. show: false,
  222. transfer: {},
  223. },
  224. })
  225. const setText = debounce((v) => {
  226. state.query.form.name = v
  227. }, 1000)
  228. watch(
  229. () => state.text,
  230. (n) => {
  231. setText(n)
  232. },
  233. )
  234. watch(
  235. () => state.query.form,
  236. (n) => {
  237. if (state.query.init) {
  238. onSearch()
  239. }
  240. },
  241. { deep: true },
  242. )
  243. const onPage = (pageNum, pageSize) => {
  244. setTimeout(() => {
  245. state.query.init = true
  246. }, 100)
  247. state.query.page = {
  248. pageNum: pageNum,
  249. pageSize: pageSize,
  250. }
  251. const params = {
  252. // tenantId: AppStore.tenantInfo?.id,
  253. page: state.query.page.pageNum,
  254. size: state.query.page.pageSize,
  255. }
  256. // 添加表单参数
  257. for (const [k, v] of Object.entries(state.query.formReal)) {
  258. if (proxy.$czrUtil.isValue(v)) {
  259. if (k === 'isCreate') {
  260. if (v) {
  261. params['creator'] = AppStore.userInfo?.id
  262. }
  263. }
  264. if (k === 'isStar') {
  265. if (v) {
  266. params['collectId'] = AppStore.userInfo?.id
  267. }
  268. }
  269. if (k === 'tagIds') {
  270. params['tagIds'] = [v]
  271. } else {
  272. params[k] = v
  273. }
  274. }
  275. }
  276. state.query.loading = true
  277. datasetsGetAllByPage(params)
  278. .then(({ data }: any) => {
  279. state.query.result.total = data.totalElements
  280. state.query.result.data = [{ empty: true }, ...data.content]
  281. })
  282. .catch(({ message }: any) => {
  283. ElMessage.error(message)
  284. })
  285. .finally(() => {
  286. state.query.loading = false
  287. })
  288. }
  289. const onSearch = () => {
  290. state.query.formReal = JSON.parse(JSON.stringify(state.query.form))
  291. onPage(1, state.query.page.pageSize)
  292. }
  293. const onReset = () => {
  294. state.query.page = {
  295. pageNum: 1,
  296. pageSize: 20,
  297. }
  298. state.query.form = {}
  299. onSearch()
  300. }
  301. const onAdd = () => {
  302. state.detail.transfer = {
  303. mode: 'add',
  304. }
  305. state.detail.show = true
  306. }
  307. const onEdit = (row) => {
  308. state.detail.transfer = {
  309. mode: 'edit',
  310. id: row.id,
  311. }
  312. state.detail.show = true
  313. }
  314. const onDel = (row: any) => {
  315. DialogStore.confirm({
  316. title: '删除确认',
  317. content: `${row.p6}个应用正在使用该大模型,请确认是否删除`,
  318. onSubmit: () => {
  319. ElMessage.success('删除成功!')
  320. onSearch()
  321. },
  322. })
  323. }
  324. const onChangeTag = (row, tags) => {
  325. datasetsTagsBinding({
  326. datasetId: row.id,
  327. tag_ids: tags,
  328. })
  329. .then(() => {
  330. ElMessage.success('标签绑定成功!')
  331. })
  332. .catch(({ message }: any) => {
  333. ElMessage.error(message)
  334. })
  335. .finally(() => {
  336. onSearch()
  337. })
  338. }
  339. const onStart = (row) => {
  340. if (row.datasetCollection) {
  341. datasetsCancelCollect(row.id)
  342. .then(() => {
  343. ElMessage.success('取消收藏成功!')
  344. })
  345. .catch(({ message }: any) => {
  346. ElMessage.error(message)
  347. })
  348. .finally(() => {
  349. onSearch()
  350. })
  351. } else {
  352. datasetCollections({
  353. tenantId: AppStore.tenantInfo?.id,
  354. targetId: row.id,
  355. })
  356. .then(() => {
  357. ElMessage.success('收藏成功!')
  358. })
  359. .catch(({ message }: any) => {
  360. ElMessage.error(message)
  361. })
  362. .finally(() => {
  363. onSearch()
  364. })
  365. }
  366. }
  367. const initDictionary = () => {
  368. DictionaryStore.initKnowledgeGroups(AppStore.tenantInfo?.id)
  369. }
  370. onMounted(() => {
  371. initDictionary()
  372. onReset()
  373. })
  374. </script>
  375. <style lang="scss" scoped>
  376. .knowledge {
  377. width: 100%;
  378. height: 11.81rem;
  379. background-image: url('@/assets/images/knowledge-item-bg.png');
  380. background-repeat: no-repeat;
  381. background-size: 100% 100%;
  382. padding: 1rem 1.5rem;
  383. }
  384. </style>