index.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. <template>
  2. <div class="container">
  3. <Breadcrumb :items="['大模型', '知识库管理']" />
  4. <div class="main-container">
  5. <div class="lf-container">
  6. <div class="lf-container-top">
  7. <a-input-search
  8. :placeholder="$t('cardList.searchInput.placeholder')"
  9. style="width: 130px;"
  10. />
  11. <addKnow></addKnow>
  12. </div>
  13. <div class="lf-container-down">
  14. <div class="tabs">
  15. <div
  16. class="tab"
  17. v-for="(tab, index) in tabs"
  18. :key="index"
  19. @click="selectTab(index)"
  20. :class="{ 'active': selectedTab === index }"
  21. >
  22. {{ tab }}
  23. </div>
  24. </div>
  25. </div>
  26. </div>
  27. <div class="rt-container">
  28. <a-tabs default-active-key="1">
  29. <a-tab-pane key="1" title="数据集">
  30. <div class="rt-container-main">
  31. <a-card ref="account" class="general-card" :title="$t('')" style="padding-top: 20px">
  32. <a-row>
  33. <a-col :flex="1" :span="12">
  34. <a-form
  35. :model="formModel"
  36. :label-col-props="{ span: 6 }"
  37. :wrapper-col-props="{ span: 18 }"
  38. label-align="left"
  39. >
  40. <a-row :gutter="16">
  41. <a-col :span="24" style="margin-bottom: 10px;display: flex;justify-content: right">
  42. <a-input-search
  43. :placeholder="$t('cardList.searchInput.placeholder')"
  44. style="width: 200px;margin-right: 10px"
  45. />
  46. <!-- 新建-->
  47. <add />
  48. </a-col>
  49. <!-- <a-col :span="8">-->
  50. <!-- <a-form-item field="name" :label="$t('searchTable.form.name')">-->
  51. <!-- <a-input-->
  52. <!-- v-model="formModel.name"-->
  53. <!-- :placeholder="$t('searchTable.form.name.placeholder')"-->
  54. <!-- />-->
  55. <!-- </a-form-item>-->
  56. <!-- </a-col>-->
  57. <!-- <a-col :span="8">-->
  58. <!-- <a-form-item-->
  59. <!-- field="contentType"-->
  60. <!-- :label="$t('searchTable.form.contentType')"-->
  61. <!-- >-->
  62. <!-- <a-select-->
  63. <!-- v-model="formModel.contentType"-->
  64. <!-- :options="contentTypeOptions"-->
  65. <!-- :placeholder="$t('searchTable.form.selectDefault')"-->
  66. <!-- />-->
  67. <!-- </a-form-item>-->
  68. <!-- </a-col>-->
  69. <!-- <a-col :span="8">-->
  70. <!-- <a-form-item-->
  71. <!-- field="filterType"-->
  72. <!-- :label="$t('searchTable.form.filterType')"-->
  73. <!-- >-->
  74. <!-- <a-select-->
  75. <!-- v-model="formModel.filterType"-->
  76. <!-- :options="filterTypeOptions"-->
  77. <!-- :placeholder="$t('searchTable.form.selectDefault')"-->
  78. <!-- />-->
  79. <!-- </a-form-item>-->
  80. <!-- </a-col>-->
  81. <!-- <a-col :span="8">-->
  82. <!-- <a-form-item-->
  83. <!-- field="createdTime"-->
  84. <!-- :label="$t('searchTable.form.createdTime')"-->
  85. <!-- >-->
  86. <!-- <a-range-picker-->
  87. <!-- v-model="formModel.createdTime"-->
  88. <!-- style="width: 100%"-->
  89. <!-- />-->
  90. <!-- </a-form-item>-->
  91. <!-- </a-col>-->
  92. <!-- <a-col :span="8">-->
  93. <!-- <a-form-item-->
  94. <!-- field="status"-->
  95. <!-- :label="$t('searchTable.form.status')"-->
  96. <!-- >-->
  97. <!-- <a-select-->
  98. <!-- v-model="formModel.status"-->
  99. <!-- :options="statusOptions"-->
  100. <!-- :placeholder="$t('searchTable.form.selectDefault')"-->
  101. <!-- />-->
  102. <!-- </a-form-item>-->
  103. <!-- </a-col>-->
  104. </a-row>
  105. </a-form>
  106. </a-col>
  107. <!-- <a-divider style="height: 40px" direction="vertical" />-->
  108. <!-- <a-col :flex="'200px'" style="text-align: right">-->
  109. <!-- <a-button @click="reset" style="margin-right: 20px">-->
  110. <!-- <template #icon>-->
  111. <!-- <icon-refresh />-->
  112. <!-- </template>-->
  113. <!-- {{ $t('searchTable.form.reset') }}-->
  114. <!-- </a-button>-->
  115. <!-- <a-button type="primary" @click="search">-->
  116. <!-- <template #icon>-->
  117. <!-- <icon-search />-->
  118. <!-- </template>-->
  119. <!-- {{ $t('searchTable.form.search') }}-->
  120. <!-- </a-button>-->
  121. <!-- </a-col>-->
  122. </a-row>
  123. <a-divider style="margin-top: 0" />
  124. <a-row style="margin-bottom: 16px">
  125. <a-col :span="12">
  126. <a-space>
  127. <!-- <a-button type="primary" @click="handleClick">-->
  128. <!-- <template #icon>-->
  129. <!-- <icon-plus />-->
  130. <!-- </template>-->
  131. <!-- {{ $t('searchTable.operation.create') }}-->
  132. <!-- </a-button>-->
  133. <!-- <a-upload action="/">-->
  134. <!-- <template #upload-button>-->
  135. <!-- <a-button>-->
  136. <!-- {{ $t('searchTable.operation.import') }}-->
  137. <!-- </a-button>-->
  138. <!-- </template>-->
  139. <!-- </a-upload>-->
  140. </a-space>
  141. </a-col>
  142. <a-col
  143. :span="12"
  144. style="display: flex; align-items: center; justify-content: end"
  145. >
  146. <!-- <a-button>-->
  147. <!-- <template #icon>-->
  148. <!-- <icon-download />-->
  149. <!-- </template>-->
  150. <!-- {{ $t('searchTable.operation.download') }}-->
  151. <!-- </a-button>-->
  152. <a-tooltip :content="$t('searchTable.actions.refresh')">
  153. <div class="action-icon" @click="search"
  154. ><icon-refresh size="18"
  155. /></div>
  156. </a-tooltip>
  157. <a-dropdown @select="handleSelectDensity">
  158. <a-tooltip :content="$t('searchTable.actions.density')">
  159. <div class="action-icon"><icon-line-height size="18" /></div>
  160. </a-tooltip>
  161. <template #content>
  162. <a-doption
  163. v-for="item in densityList"
  164. :key="item.value"
  165. :value="item.value"
  166. :class="{ active: item.value === size }"
  167. >
  168. <span>{{ item.name }}</span>
  169. </a-doption>
  170. </template>
  171. </a-dropdown>
  172. <!-- <a-tooltip :content="$t('searchTable.actions.columnSetting')">-->
  173. <!-- <a-popover-->
  174. <!-- trigger="click"-->
  175. <!-- position="bl"-->
  176. <!-- @popup-visible-change="popupVisibleChange"-->
  177. <!-- >-->
  178. <!-- <div class="action-icon"><icon-settings size="18" /></div>-->
  179. <!-- <template #content>-->
  180. <!-- <div id="tableSetting">-->
  181. <!-- <div-->
  182. <!-- v-for="(item, index) in showColumns"-->
  183. <!-- :key="item.dataIndex"-->
  184. <!-- class="setting"-->
  185. <!-- >-->
  186. <!-- <div style="margin-right: 4px; cursor: move">-->
  187. <!-- <icon-drag-arrow />-->
  188. <!-- </div>-->
  189. <!-- <div>-->
  190. <!-- <a-checkbox-->
  191. <!-- v-model="item.checked"-->
  192. <!-- @change="-->
  193. <!-- handleChange($event, item as TableColumnData, index)-->
  194. <!-- "-->
  195. <!-- >-->
  196. <!-- </a-checkbox>-->
  197. <!-- </div>-->
  198. <!-- <div class="title">-->
  199. <!-- {{ item.title === '#' ? '序列号' : item.title }}-->
  200. <!-- </div>-->
  201. <!-- </div>-->
  202. <!-- </div>-->
  203. <!-- </template>-->
  204. <!-- </a-popover>-->
  205. <!-- </a-tooltip>-->
  206. </a-col>
  207. </a-row>
  208. <a-table
  209. row-key="id"
  210. :loading="loading"
  211. :pagination="pagination"
  212. :columns="cloneColumns"
  213. :data="renderData"
  214. :bordered="false"
  215. :size="size"
  216. @page-change="onPageChange"
  217. :scroll="{ y: 580 }"
  218. >
  219. <template #contentType="{ record }">
  220. <a-space>
  221. <a-avatar
  222. v-if="record.contentType === 'img'"
  223. :size="16"
  224. shape="square"
  225. >
  226. <img
  227. alt="avatar"
  228. src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/581b17753093199839f2e327e726b157.svg~tplv-49unhts6dw-image.image"
  229. />
  230. </a-avatar>
  231. <a-avatar
  232. v-else-if="record.contentType === 'horizontalVideo'"
  233. :size="16"
  234. shape="square"
  235. >
  236. <img
  237. alt="avatar"
  238. src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/77721e365eb2ab786c889682cbc721c1.svg~tplv-49unhts6dw-image.image"
  239. />
  240. </a-avatar>
  241. <a-avatar v-else :size="16" shape="square">
  242. <img
  243. alt="avatar"
  244. src="//p3-armor.byteimg.com/tos-cn-i-49unhts6dw/ea8b09190046da0ea7e070d83c5d1731.svg~tplv-49unhts6dw-image.image"
  245. />
  246. </a-avatar>
  247. {{ $t(`searchTable.form.contentType.${record.contentType}`) }}
  248. </a-space>
  249. </template>
  250. <template #filterType="{ record }">
  251. {{ $t(`searchTable.form.filterType.${record.filterType}`) }}
  252. </template>
  253. <template #status="{ record }">
  254. <span v-if="record.status === 'offline'" class="circle"></span>
  255. <span v-else class="circle pass"></span>
  256. {{ $t(`searchTable.form.status.${record.status}`) }}
  257. </template>
  258. <template #operations="{ record }">
  259. <a-popconfirm content="确定删除吗?" type="warning" @ok="deleteItem(record)">
  260. <a-button v-permission="['admin']" type="text" size="small">
  261. {{ $t('删除') }}
  262. </a-button>
  263. </a-popconfirm>
  264. </template>
  265. </a-table>
  266. </a-card>
  267. </div>
  268. </a-tab-pane>
  269. <a-tab-pane key="2" title="测试">
  270. <div class="rt-container-main">
  271. <test ></test>
  272. </div>
  273. </a-tab-pane>
  274. <a-tab-pane key="3" title="配置">
  275. <div class="rt-container-main">
  276. <config ></config>
  277. </div>
  278. </a-tab-pane>
  279. </a-tabs>
  280. </div>
  281. </div>
  282. </div>
  283. </template>
  284. <script lang="ts" setup>
  285. import { computed, ref, reactive, watch, nextTick } from 'vue';
  286. import { useI18n } from 'vue-i18n';
  287. import useLoading from '@/hooks/loading';
  288. import { queryPolicyList, PolicyRecord, PolicyParams } from '@/api/list';
  289. import { Pagination } from '@/types/global';
  290. import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
  291. import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
  292. import cloneDeep from 'lodash/cloneDeep';
  293. import Sortable from 'sortablejs';
  294. import add from '@/views/dmx/knowledgeLib/add.vue'
  295. import addKnow from '@/views/dmx/knowledgeLib/addKnow.vue'
  296. import config from '@/views/dmx/knowledgeLib/config.vue'
  297. import test from '@/views/dmx/knowledgeLib/test.vue'
  298. import { deleteAccount } from "@/api/account";
  299. type SizeProps = 'mini' | 'small' | 'medium' | 'large';
  300. type Column = TableColumnData & { checked?: true };
  301. const account = ref(null)
  302. const generateFormModel = () => {
  303. return {
  304. number: '',
  305. name: '',
  306. contentType: '',
  307. filterType: '',
  308. createdTime: [],
  309. status: '',
  310. };
  311. };
  312. const { loading, setLoading } = useLoading(true);
  313. const { t } = useI18n();
  314. const renderData = ref<PolicyRecord[]>([]);
  315. const formModel = ref(generateFormModel());
  316. const cloneColumns = ref<Column[]>([]);
  317. const showColumns = ref<Column[]>([]);
  318. const edit = ref('add');
  319. const size = ref<SizeProps>('medium');
  320. let visible = ref(false)
  321. let selectedTab = ref(0)
  322. let tabs = reactive(['法律知识库', '政务知识库', '医学知识库', '其他知识库'])
  323. const selectTab = (index) => {
  324. selectedTab.value= index;
  325. }
  326. const basePagination: Pagination = {
  327. current: 1,
  328. pageSize: 20,
  329. };
  330. const pagination = reactive({
  331. ...basePagination,
  332. });
  333. const densityList = computed(() => [
  334. {
  335. name: t('searchTable.size.mini'),
  336. value: 'mini',
  337. },
  338. {
  339. name: t('searchTable.size.small'),
  340. value: 'small',
  341. },
  342. {
  343. name: t('searchTable.size.medium'),
  344. value: 'medium',
  345. },
  346. {
  347. name: t('searchTable.size.large'),
  348. value: 'large',
  349. },
  350. ]);
  351. const columns = computed<TableColumnData[]>(() => [
  352. // {
  353. // title: t('序号'),
  354. // dataIndex: 'index',
  355. // slotName: 'index',
  356. // },
  357. {
  358. title: t('名称'),
  359. dataIndex: 'name',
  360. },
  361. {
  362. title: t('分快数'),
  363. dataIndex: 'contentType',
  364. slotName: 'contentType',
  365. },
  366. {
  367. title: t('上传时间'),
  368. dataIndex: 'filterType',
  369. },
  370. {
  371. title: t('创建人'),
  372. dataIndex: 'count',
  373. },
  374. {
  375. title: t('解析状态'),
  376. dataIndex: 'createdTime',
  377. },
  378. {
  379. title: t('操作'),
  380. dataIndex: 'operations',
  381. slotName: 'operations',
  382. },
  383. ]);
  384. const contentTypeOptions = computed<SelectOptionData[]>(() => [
  385. {
  386. label: t('searchTable.form.contentType.img'),
  387. value: 'img',
  388. },
  389. {
  390. label: t('searchTable.form.contentType.horizontalVideo'),
  391. value: 'horizontalVideo',
  392. },
  393. {
  394. label: t('searchTable.form.contentType.verticalVideo'),
  395. value: 'verticalVideo',
  396. },
  397. ]);
  398. const filterTypeOptions = computed<SelectOptionData[]>(() => [
  399. {
  400. label: t('searchTable.form.filterType.artificial'),
  401. value: 'artificial',
  402. },
  403. {
  404. label: t('searchTable.form.filterType.rules'),
  405. value: 'rules',
  406. },
  407. ]);
  408. const statusOptions = computed<SelectOptionData[]>(() => [
  409. {
  410. label: t('searchTable.form.status.online'),
  411. value: 'online',
  412. },
  413. {
  414. label: t('searchTable.form.status.offline'),
  415. value: 'offline',
  416. },
  417. ]);
  418. const fetchData = async (
  419. params: PolicyParams = { current: 1, pageSize: 20 }
  420. ) => {
  421. setLoading(true);
  422. try {
  423. const { data } = await queryPolicyList(params);
  424. renderData.value = data.list;
  425. console.log(renderData);
  426. pagination.current = params.current;
  427. pagination.total = data.total;
  428. } catch (err) {
  429. // you can report use errorHandler or other
  430. } finally {
  431. setLoading(false);
  432. }
  433. };
  434. const search = () => {
  435. fetchData({
  436. ...basePagination,
  437. ...formModel.value,
  438. } as unknown as PolicyParams);
  439. };
  440. const handleClick = ()=>{
  441. visible.value = true;
  442. }
  443. const onPageChange = (current: number) => {
  444. fetchData({ ...basePagination, current });
  445. };
  446. fetchData();
  447. const reset = () => {
  448. formModel.value = generateFormModel();
  449. };
  450. const handleSelectDensity = (
  451. val: string | number | Record<string, any> | undefined,
  452. e: Event
  453. ) => {
  454. size.value = val as SizeProps;
  455. };
  456. const handleChange = (
  457. checked: boolean | (string | boolean | number)[],
  458. column: Column,
  459. index: number
  460. ) => {
  461. if (!checked) {
  462. cloneColumns.value = showColumns.value.filter(
  463. (item) => item.dataIndex !== column.dataIndex
  464. );
  465. } else {
  466. cloneColumns.value.splice(index, 0, column);
  467. }
  468. };
  469. const exchangeArray = <T extends Array<any>>(
  470. array: T,
  471. beforeIdx: number,
  472. newIdx: number,
  473. isDeep = false
  474. ): T => {
  475. const newArray = isDeep ? cloneDeep(array) : array;
  476. if (beforeIdx > -1 && newIdx > -1) {
  477. // 先替换后面的,然后拿到替换的结果替换前面的
  478. newArray.splice(
  479. beforeIdx,
  480. 1,
  481. newArray.splice(newIdx, 1, newArray[beforeIdx]).pop()
  482. );
  483. }
  484. return newArray;
  485. };
  486. const popupVisibleChange = (val: boolean) => {
  487. if (val) {
  488. nextTick(() => {
  489. const el = document.getElementById('tableSetting') as HTMLElement;
  490. const sortable = new Sortable(el, {
  491. onEnd(e: any) {
  492. const { oldIndex, newIndex } = e;
  493. exchangeArray(cloneColumns.value, oldIndex, newIndex);
  494. exchangeArray(showColumns.value, oldIndex, newIndex);
  495. },
  496. });
  497. });
  498. }
  499. };
  500. const deleteItem = async (row)=>{
  501. console.log(row);
  502. // let data = await deleteAccount({id: row.number})
  503. account.value.$messageSuccess('删除成功')
  504. //
  505. // if(data.code == 200){
  506. // this.$messageSuccess('删除成功')
  507. // }
  508. }
  509. watch(
  510. () => columns.value,
  511. (val) => {
  512. // alert(columns.value)
  513. cloneColumns.value = cloneDeep(val);
  514. cloneColumns.value.forEach((item, index) => {
  515. item.checked = true;
  516. });
  517. showColumns.value = cloneDeep(cloneColumns.value);
  518. },
  519. { deep: true, immediate: true }
  520. );
  521. </script>
  522. <script lang="ts">
  523. export default {
  524. name: 'SearchTable',
  525. methods: {
  526. }
  527. };
  528. </script>
  529. <style scoped lang="less">
  530. .container {
  531. padding: 0 20px 20px 20px;
  532. .main-container{
  533. display: flex;
  534. .lf-container{
  535. display: flex;
  536. flex-direction: column;
  537. align-items: center;
  538. justify-content: space-evenly;
  539. background: #ffffff;
  540. width: 200px;
  541. .lf-container-top{
  542. display: flex;
  543. }
  544. .lf-container-down{
  545. display: flex;
  546. flex-direction: column;
  547. width: 90%;
  548. height: calc(100% - 5rem);
  549. border: 1px solid #eeeeee;
  550. overflow: auto;
  551. padding: 10px;
  552. .tabs .tab {
  553. cursor: pointer;
  554. box-sizing: border-box;
  555. margin: 10px 0;
  556. padding:0 10px;
  557. color: rgba(0, 0, 0, 0.88);
  558. font-size: 14px;
  559. height: 40px;
  560. line-height: 40px;
  561. list-style: none;
  562. position: relative;
  563. background: #ffffff;
  564. border: 1px solid #f0f0f0;
  565. border-radius: 8px;
  566. }
  567. .tabs .tab:hover {
  568. border: 1px solid #ffffff;
  569. background: #e8e8ea;
  570. box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09);
  571. }
  572. .tabs .tab.active {
  573. border: 1px solid #e8e8ea;
  574. background: #e8e8ea;
  575. cursor: pointer;
  576. }
  577. }
  578. }
  579. .rt-container{
  580. //background: #626aea;
  581. margin-left: 20px;
  582. width: calc(100% - 200px);
  583. height: calc(100% - 5rem);
  584. .rt-container-main{
  585. height: 76vh;
  586. }
  587. }
  588. }
  589. }
  590. :deep(.arco-table-th) {
  591. &:last-child {
  592. .arco-table-th-item-title {
  593. margin-left: 16px;
  594. }
  595. }
  596. }
  597. .action-icon {
  598. margin-left: 12px;
  599. cursor: pointer;
  600. }
  601. .active {
  602. color: #0960bd;
  603. background-color: #e3f4fc;
  604. }
  605. .setting {
  606. display: flex;
  607. align-items: center;
  608. width: 200px;
  609. .title {
  610. margin-left: 12px;
  611. cursor: pointer;
  612. }
  613. }
  614. </style>