index.vue 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589
  1. <template>
  2. <div class="document p-16-24">
  3. <h2 class="mb-16">{{ $t('common.fileUpload.document') }}</h2>
  4. <el-card style="--el-card-padding: 0">
  5. <div class="main-calc-height">
  6. <div class="p-24">
  7. <div class="flex-between">
  8. <div>
  9. <template v-if="!isShared">
  10. <el-button
  11. v-if="knowledgeDetail?.type === 0 && permissionPrecise.doc_create(id)"
  12. type="primary"
  13. @click="
  14. router.push({
  15. path: `/knowledge/document/upload/${folderId}/${type}`,
  16. query: { id: id },
  17. })
  18. "
  19. >{{ $t('views.document.uploadDocument') }}
  20. </el-button>
  21. <el-button
  22. v-if="knowledgeDetail?.type === 1 && permissionPrecise.doc_create(id)"
  23. type="primary"
  24. @click="importDoc"
  25. >{{ $t('views.document.importDocument') }}
  26. </el-button>
  27. <el-button
  28. v-if="knowledgeDetail?.type === 2 && permissionPrecise.doc_create(id)"
  29. type="primary"
  30. @click="
  31. router.push({
  32. path: `/knowledge/import/lark/${folderId}`,
  33. query: {
  34. id: id,
  35. folder_token: knowledgeDetail?.meta.folder_token,
  36. },
  37. })
  38. "
  39. >{{ $t('views.document.importDocument') }}
  40. </el-button>
  41. <el-button
  42. v-if="knowledgeDetail?.type === 4 && permissionPrecise.doc_create(id)"
  43. type="primary"
  44. @click="toImportWorkflow"
  45. >{{ $t('views.document.importDocument') }}
  46. </el-button>
  47. <el-button
  48. v-if="knowledgeDetail?.type === 5 && permissionPrecise.doc_create(id)"
  49. type="primary"
  50. @click="
  51. router.push({
  52. path: `/knowledge/document/upload/${folderId}/${type}`,
  53. query: { id: id },
  54. })
  55. "
  56. >{{ $t('views.document.uploadDocument') }}
  57. </el-button>
  58. <el-button
  59. v-if="knowledgeDetail?.type === 5"
  60. @click="openSyncToSampleCenter"
  61. :disabled="multipleSelection.length === 0"
  62. >推送到样本中心
  63. </el-button>
  64. <el-button
  65. @click="batchRefresh"
  66. :disabled="multipleSelection.length === 0"
  67. v-if="permissionPrecise.doc_vector(id)"
  68. >{{ $t('views.knowledge.setting.vectorization') }}
  69. </el-button>
  70. <el-button
  71. @click="openGenerateDialog()"
  72. :disabled="multipleSelection.length === 0"
  73. v-if="permissionPrecise.doc_generate(id)"
  74. >{{ $t('views.document.generateQuestion.title') }}
  75. </el-button>
  76. <el-button
  77. @click="openBatchEditDocument"
  78. :disabled="multipleSelection.length === 0"
  79. v-if="permissionPrecise.doc_edit(id)"
  80. >
  81. {{ $t('common.setting') }}
  82. </el-button>
  83. <el-dropdown v-if="MoreFilledPermission0(id)">
  84. <el-button class="ml-12 mr-12">
  85. <AppIcon iconName="app-more"></AppIcon>
  86. </el-button>
  87. <template #dropdown>
  88. <el-dropdown-menu>
  89. <el-dropdown-item
  90. @click="openknowledgeDialog()"
  91. :disabled="multipleSelection.length === 0"
  92. v-if="permissionPrecise.doc_migrate(id)"
  93. >
  94. {{ $t('views.document.setting.migration') }}
  95. </el-dropdown-item>
  96. <el-dropdown-item
  97. @click="openAddTagDialog()"
  98. :disabled="multipleSelection.length === 0"
  99. v-if="permissionPrecise.doc_tag(id)"
  100. >{{ $t('views.document.tag.addTag') }}
  101. </el-dropdown-item>
  102. <el-dropdown-item
  103. divided
  104. @click="syncMulDocument"
  105. :disabled="multipleSelection.length === 0"
  106. v-if="knowledgeDetail?.type === 1 && permissionPrecise.doc_sync(id)"
  107. >{{ $t('views.document.syncDocument') }}
  108. </el-dropdown-item>
  109. <el-dropdown-item
  110. divided
  111. @click="syncLarkMulDocument"
  112. :disabled="multipleSelection.length === 0"
  113. v-if="knowledgeDetail?.type === 2 && permissionPrecise.doc_sync(id)"
  114. >{{ $t('views.document.syncDocument') }}
  115. </el-dropdown-item>
  116. <el-dropdown-item
  117. @click="exportMulDocument"
  118. :disabled="multipleSelection.length === 0"
  119. v-if="permissionPrecise.doc_export(id)"
  120. >
  121. {{ $t('views.document.setting.export') }} Excel
  122. </el-dropdown-item>
  123. <el-dropdown-item
  124. @click="exportMulDocumentZip"
  125. :disabled="multipleSelection.length === 0"
  126. v-if="permissionPrecise.doc_export(id)"
  127. >
  128. {{ $t('views.document.setting.export') }} Zip
  129. </el-dropdown-item>
  130. <el-dropdown-item
  131. divided
  132. @click="deleteMulDocument"
  133. :disabled="multipleSelection.length === 0"
  134. v-if="permissionPrecise.doc_delete(id)"
  135. >{{ $t('common.delete') }}
  136. </el-dropdown-item>
  137. </el-dropdown-menu>
  138. </template>
  139. </el-dropdown>
  140. </template>
  141. </div>
  142. <div class="flex">
  143. <div class="flex-between complex-search">
  144. <el-select
  145. class="complex-search__left"
  146. v-model="search_type"
  147. style="width: 120px"
  148. @change="search_type_change"
  149. >
  150. <el-option :label="$t('common.name')" value="name" />
  151. </el-select>
  152. <el-input
  153. v-if="search_type === 'name'"
  154. v-model="search_form.name"
  155. @change="refresh"
  156. :placeholder="$t('common.searchBar.placeholder')"
  157. style="width: 220px"
  158. clearable
  159. />
  160. </div>
  161. <el-tooltip
  162. effect="dark"
  163. :content="$t('common.ExecutionRecord.title')"
  164. placement="top"
  165. v-if="knowledgeDetail?.type === 4 && permissionPrecise.doc_create(id)"
  166. >
  167. <el-button @click="openListAction" class="ml-12">
  168. <AppIcon iconName="app-execution-record" class="color-secondary"></AppIcon>
  169. </el-button>
  170. </el-tooltip>
  171. <el-button @click="openTagDrawer" class="ml-12" v-if="permissionPrecise.tag_read(id)">
  172. {{ $t('views.document.tag.label') }}
  173. </el-button>
  174. </div>
  175. </div>
  176. <app-table
  177. ref="multipleTableRef"
  178. class="mt-16 document-table"
  179. :data="documentData"
  180. :pagination-config="paginationConfig"
  181. :quick-create="
  182. knowledgeDetail?.type === 0 && permissionPrecise.doc_create(id) && !isShared
  183. "
  184. @sizeChange="handleSizeChange"
  185. @changePage="getList"
  186. @cell-mouse-enter="cellMouseEnter"
  187. @cell-mouse-leave="cellMouseLeave"
  188. @creatQuick="creatQuickHandle"
  189. @row-click="rowClickHandle"
  190. @selection-change="handleSelectionChange"
  191. @sort-change="handleSortChange"
  192. v-loading="loading"
  193. :row-key="(row: any) => row.id"
  194. :storeKey="storeKey"
  195. @cell-click="cellClickHandle"
  196. >
  197. <el-table-column
  198. type="selection"
  199. width="55"
  200. :reserve-selection="true"
  201. v-if="!isShared"
  202. />
  203. <el-table-column prop="name" :label="$t('views.document.table.name')" min-width="280">
  204. <template #default="{ row }">
  205. <ReadWrite
  206. v-if="!isShared"
  207. @change="editName($event, row.id)"
  208. :data="row.name"
  209. :showEditIcon="row.id === currentMouseId"
  210. />
  211. <span v-else>{{ row.name }}</span>
  212. </template>
  213. </el-table-column>
  214. <el-table-column
  215. prop="status"
  216. :label="$t('views.document.fileStatus.label')"
  217. width="120"
  218. >
  219. <template #header>
  220. <div>
  221. <span>{{ $t('views.document.fileStatus.label') }}</span>
  222. <el-dropdown trigger="click" @command="dropdownHandle">
  223. <el-button
  224. style="margin-top: 1px"
  225. link
  226. :type="filterMethod['status'] ? 'primary' : ''"
  227. >
  228. <el-icon>
  229. <Filter />
  230. </el-icon>
  231. </el-button>
  232. <template #dropdown>
  233. <el-dropdown-menu style="width: 100px">
  234. <el-dropdown-item
  235. :class="filterMethod['status'] ? '' : 'is-active'"
  236. :command="beforeCommand('status', '')"
  237. class="justify-center"
  238. >{{ $t('common.status.all') }}
  239. </el-dropdown-item>
  240. <el-dropdown-item
  241. :class="filterMethod['status'] === State.SUCCESS ? 'is-active' : ''"
  242. class="justify-center"
  243. :command="beforeCommand('status', State.SUCCESS)"
  244. >{{ $t('common.status.success') }}
  245. </el-dropdown-item>
  246. <el-dropdown-item
  247. :class="filterMethod['status'] === State.FAILURE ? 'is-active' : ''"
  248. class="justify-center"
  249. :command="beforeCommand('status', State.FAILURE)"
  250. >{{ $t('common.status.fail') }}
  251. </el-dropdown-item>
  252. <el-dropdown-item
  253. :class="
  254. filterMethod['status'] === State.STARTED &&
  255. filterMethod['task_type'] == TaskType.EMBEDDING
  256. ? 'is-active'
  257. : ''
  258. "
  259. class="justify-center"
  260. :command="beforeCommand('status', State.STARTED, TaskType.EMBEDDING)"
  261. >{{ $t('views.document.fileStatus.EMBEDDING') }}
  262. </el-dropdown-item>
  263. <el-dropdown-item
  264. :class="filterMethod['status'] === State.PENDING ? 'is-active' : ''"
  265. class="justify-center"
  266. :command="beforeCommand('status', State.PENDING)"
  267. >{{ $t('views.document.fileStatus.PENDING') }}
  268. </el-dropdown-item>
  269. <el-dropdown-item
  270. :class="
  271. filterMethod['status'] === State.STARTED &&
  272. filterMethod['task_type'] === TaskType.GENERATE_PROBLEM
  273. ? 'is-active'
  274. : ''
  275. "
  276. class="justify-center"
  277. :command="
  278. beforeCommand('status', State.STARTED, TaskType.GENERATE_PROBLEM)
  279. "
  280. >{{ $t('views.document.fileStatus.GENERATE') }}
  281. </el-dropdown-item>
  282. </el-dropdown-menu>
  283. </template>
  284. </el-dropdown>
  285. </div>
  286. </template>
  287. <template #default="{ row }">
  288. <StatusValue :status="row.status" :status-meta="row.status_meta"></StatusValue>
  289. </template>
  290. </el-table-column>
  291. <el-table-column
  292. prop="char_length"
  293. :label="$t('views.document.table.char_length')"
  294. align="right"
  295. min-width="120"
  296. sortable
  297. >
  298. <template #default="{ row }">
  299. {{ numberFormat(row.char_length) }}
  300. </template>
  301. </el-table-column>
  302. <el-table-column
  303. prop="paragraph_count"
  304. :label="$t('views.document.table.paragraph')"
  305. align="right"
  306. min-width="120"
  307. sortable
  308. />
  309. <el-table-column width="110">
  310. <template #header>
  311. <div>
  312. <span>{{ $t('views.document.enableStatus.label') }}</span>
  313. <el-dropdown trigger="click" @command="dropdownHandle">
  314. <el-button
  315. style="margin-top: 1px"
  316. link
  317. :type="filterMethod['is_active'] ? 'primary' : ''"
  318. >
  319. <el-icon>
  320. <Filter />
  321. </el-icon>
  322. </el-button>
  323. <template #dropdown>
  324. <el-dropdown-menu style="width: 100px">
  325. <el-dropdown-item
  326. :class="filterMethod['is_active'] === '' ? 'is-active' : ''"
  327. :command="beforeCommand('is_active', '')"
  328. class="justify-center"
  329. >{{ $t('common.status.all') }}
  330. </el-dropdown-item>
  331. <el-dropdown-item
  332. :class="filterMethod['is_active'] === true ? 'is-active' : ''"
  333. class="justify-center"
  334. :command="beforeCommand('is_active', true)"
  335. >{{ $t('common.status.enabled') }}
  336. </el-dropdown-item>
  337. <el-dropdown-item
  338. :class="filterMethod['is_active'] === false ? 'is-active' : ''"
  339. class="justify-center"
  340. :command="beforeCommand('is_active', false)"
  341. >{{ $t('common.status.disabled') }}
  342. </el-dropdown-item>
  343. </el-dropdown-menu>
  344. </template>
  345. </el-dropdown>
  346. </div>
  347. </template>
  348. <template #default="{ row }">
  349. <div v-if="row.is_active" class="flex align-center">
  350. <el-icon class="color-success mr-8" style="font-size: 16px">
  351. <SuccessFilled />
  352. </el-icon>
  353. <span class="color-text-primary">
  354. {{ $t('common.status.enabled') }}
  355. </span>
  356. </div>
  357. <div v-else class="flex align-center">
  358. <AppIcon iconName="app-disabled" class="color-secondary mr-8"></AppIcon>
  359. <span class="color-text-primary">
  360. {{ $t('common.status.disabled') }}
  361. </span>
  362. </div>
  363. </template>
  364. </el-table-column>
  365. <el-table-column width="150" prop="tag">
  366. <template #header>
  367. <div>
  368. <span>{{ $t('dynamicsForm.tag.label') }}</span>
  369. <el-dropdown trigger="click" @visible-change="handleTagVisibleChange">
  370. <el-button
  371. style="margin-top: 1px"
  372. link
  373. :type="filterMethod['tags']?.length > 0 ? 'primary' : ''"
  374. >
  375. <el-icon>
  376. <Filter />
  377. </el-icon>
  378. </el-button>
  379. <template #dropdown>
  380. <div>
  381. <el-cascader-panel
  382. v-model="tagFilterValue"
  383. :options="tagFilterOptions"
  384. :props="{
  385. multiple: true,
  386. checkStrictly: true,
  387. emitPath: false,
  388. showPrefix: false,
  389. }"
  390. @change="(val: any) => dropdownHandle({ attr: 'tags', command: val })"
  391. />
  392. </div>
  393. </template>
  394. </el-dropdown>
  395. </div>
  396. </template>
  397. <template #default="{ row }">
  398. <el-popover
  399. trigger="hover"
  400. placement="bottom-start"
  401. :disabled="!row.tag_count"
  402. :popper-style="{ width: 'auto', maxWidth: '300px' }"
  403. >
  404. <div
  405. v-for="tag in row.tags"
  406. :key="tag.id"
  407. class="flex align-center lighter color-text-primary mt-4 mb-4"
  408. >
  409. <span class="color-secondary ellipsis-1" style="width: 40%" :title="tag.key">{{
  410. tag.key
  411. }}</span>
  412. <span class="ml-4 ellipsis-1" :title="tag.value"> {{ tag.value }}</span>
  413. </div>
  414. <template #reference>
  415. <el-tag v-if="row.tag_count" type="info" effect="plain" class="never mr-4">
  416. <div class="flex align-center color-text-primary">
  417. <AppIcon iconName="app-tag"></AppIcon>
  418. <span class="ml-4">{{ row.tag_count }}</span>
  419. </div>
  420. </el-tag>
  421. </template>
  422. </el-popover>
  423. <el-button
  424. class="button-new-tag"
  425. size="small"
  426. :disabled="!permissionPrecise.doc_tag(id)"
  427. @click.stop="openAddTagDialog(row.id)"
  428. >
  429. <AppIcon iconName="app-add-outlined" class="mr-4"></AppIcon>
  430. {{ $t('views.document.tag.key') }}
  431. </el-button>
  432. </template>
  433. </el-table-column>
  434. <el-table-column width="165">
  435. <template #header>
  436. <div>
  437. <span>{{ $t('views.document.form.hit_handling_method.label') }}</span>
  438. <el-dropdown trigger="click" @command="dropdownHandle">
  439. <el-button
  440. style="margin-top: 1px"
  441. link
  442. :type="filterMethod['hit_handling_method'] ? 'primary' : ''"
  443. >
  444. <el-icon>
  445. <Filter />
  446. </el-icon>
  447. </el-button>
  448. <template #dropdown>
  449. <el-dropdown-menu style="width: 150px">
  450. <el-dropdown-item
  451. :class="filterMethod['hit_handling_method'] ? '' : 'is-active'"
  452. :command="beforeCommand('hit_handling_method', '')"
  453. class="justify-center"
  454. >{{ $t('common.status.all') }}
  455. </el-dropdown-item>
  456. <template v-for="(value, key) of hitHandlingMethod" :key="key">
  457. <el-dropdown-item
  458. :class="filterMethod['hit_handling_method'] === key ? 'is-active' : ''"
  459. class="justify-center"
  460. :command="beforeCommand('hit_handling_method', key)"
  461. >{{ $t(value) }}
  462. </el-dropdown-item>
  463. </template>
  464. </el-dropdown-menu>
  465. </template>
  466. </el-dropdown>
  467. </div>
  468. </template>
  469. <template #default="{ row }">
  470. {{
  471. $t(hitHandlingMethod[row.hit_handling_method as keyof typeof hitHandlingMethod])
  472. }}
  473. </template>
  474. </el-table-column>
  475. <el-table-column
  476. prop="create_time"
  477. :label="$t('common.createTime')"
  478. width="175"
  479. sortable
  480. >
  481. <template #default="{ row }">
  482. {{ datetimeFormat(row.create_time) }}
  483. </template>
  484. </el-table-column>
  485. <el-table-column
  486. prop="update_time"
  487. :label="$t('views.document.table.updateTime')"
  488. width="175"
  489. sortable
  490. >
  491. <template #default="{ row }">
  492. {{ datetimeFormat(row.update_time) }}
  493. </template>
  494. </el-table-column>
  495. <el-table-column
  496. :label="$t('common.operation')"
  497. align="left"
  498. width="160"
  499. fixed="right"
  500. v-if="!isShared"
  501. >
  502. <template #default="{ row }">
  503. <span @click.stop>
  504. <el-switch
  505. :loading="loading"
  506. size="small"
  507. v-model="row.is_active"
  508. :before-change="() => changeState(row)"
  509. v-if="permissionPrecise.doc_edit(id)"
  510. />
  511. </span>
  512. <el-divider direction="vertical" />
  513. <template v-if="knowledgeDetail?.type === 0 || knowledgeDetail?.type === 4">
  514. <el-tooltip
  515. effect="dark"
  516. :content="$t('views.document.setting.cancelVectorization')"
  517. placement="top"
  518. v-if="
  519. ([State.STARTED, State.PENDING] as Array<string>).includes(
  520. getTaskState(row.status, TaskType.EMBEDDING),
  521. )
  522. "
  523. >
  524. <span class="mr-4">
  525. <el-button
  526. type="primary"
  527. text
  528. @click.stop="cancelTask(row, TaskType.EMBEDDING)"
  529. v-if="permissionPrecise.doc_vector(id)"
  530. >
  531. <el-icon><Close /></el-icon>
  532. </el-button>
  533. </span>
  534. </el-tooltip>
  535. <el-tooltip
  536. effect="dark"
  537. :content="$t('views.knowledge.setting.vectorization')"
  538. placement="top"
  539. v-else
  540. >
  541. <span class="mr-4" v-if="permissionPrecise.doc_vector(id)">
  542. <el-button type="primary" text @click.stop="refreshDocument(row)">
  543. <AppIcon iconName="app-document-refresh" style="font-size: 16px"></AppIcon>
  544. </el-button>
  545. </span>
  546. </el-tooltip>
  547. <el-tooltip
  548. effect="dark"
  549. :content="$t('common.setting')"
  550. placement="top"
  551. v-if="permissionPrecise.doc_edit(id)"
  552. >
  553. <span class="mr-4">
  554. <el-button type="primary" text @click.stop="settingDoc(row)">
  555. <AppIcon iconName="app-setting"></AppIcon>
  556. </el-button>
  557. </span>
  558. </el-tooltip>
  559. <span @click.stop>
  560. <el-dropdown trigger="click" v-if="MoreFilledPermission1(id)">
  561. <el-button text type="primary">
  562. <AppIcon iconName="app-more"></AppIcon>
  563. </el-button>
  564. <template #dropdown>
  565. <el-dropdown-menu>
  566. <el-dropdown-item
  567. v-if="
  568. ([State.STARTED, State.PENDING] as Array<string>).includes(
  569. getTaskState(row.status, TaskType.GENERATE_PROBLEM),
  570. ) && permissionPrecise.doc_generate(id)
  571. "
  572. @click="cancelTask(row, TaskType.GENERATE_PROBLEM)"
  573. >
  574. <el-icon class="color-secondary"><Close /></el-icon>
  575. {{ $t('views.document.setting.cancelGenerateQuestion') }}
  576. </el-dropdown-item>
  577. <el-dropdown-item
  578. @click="openGenerateDialog(row)"
  579. v-else-if="permissionPrecise.doc_generate(id)"
  580. >
  581. <AppIcon
  582. iconName="app-generate-question"
  583. class="color-secondary"
  584. ></AppIcon>
  585. {{ $t('views.document.generateQuestion.title') }}
  586. </el-dropdown-item>
  587. <el-dropdown-item
  588. @click="openTagSettingDrawer(row)"
  589. v-if="permissionPrecise.doc_tag(id)"
  590. >
  591. <AppIcon iconName="app-tag" class="color-secondary"></AppIcon>
  592. {{ $t('views.document.tag.setting') }}
  593. </el-dropdown-item>
  594. <el-dropdown-item
  595. @click="openknowledgeDialog(row)"
  596. v-if="permissionPrecise.doc_migrate(id)"
  597. >
  598. <AppIcon iconName="app-migrate" class="color-secondary"></AppIcon>
  599. {{ $t('views.document.setting.migration') }}
  600. </el-dropdown-item>
  601. <el-dropdown-item
  602. @click="exportDocument(row)"
  603. v-if="permissionPrecise.doc_export(id)"
  604. >
  605. <AppIcon iconName="app-export" class="color-secondary"></AppIcon>
  606. {{ $t('views.document.setting.export') }} Excel
  607. </el-dropdown-item>
  608. <el-dropdown-item
  609. @click="exportDocumentZip(row)"
  610. v-if="permissionPrecise.doc_export(id)"
  611. >
  612. <AppIcon iconName="app-export" class="color-secondary"></AppIcon>
  613. {{ $t('views.document.setting.export') }} Zip
  614. </el-dropdown-item>
  615. <el-dropdown-item
  616. @click.stop="downloadDocument(row)"
  617. v-if="permissionPrecise.doc_download(id)"
  618. >
  619. <AppIcon iconName="app-download" class="color-secondary" />
  620. {{ $t('views.document.setting.download') }}
  621. </el-dropdown-item>
  622. <el-upload
  623. v-if="permissionPrecise.doc_replace(id)"
  624. ref="elUploadRef"
  625. :file-list="[]"
  626. action="#"
  627. :auto-upload="false"
  628. :show-file-list="false"
  629. :on-change="(file: any, fileList: any) => replaceDocument(file, row)"
  630. >
  631. <el-dropdown-item>
  632. <AppIcon iconName="app-upload" class="color-secondary" />
  633. {{ $t('views.document.setting.replace') }}
  634. </el-dropdown-item>
  635. </el-upload>
  636. <el-dropdown-item
  637. @click.stop="deleteDocument(row)"
  638. v-if="permissionPrecise.doc_delete(id)"
  639. >
  640. <AppIcon iconName="app-delete" class="color-secondary"></AppIcon>
  641. {{ $t('common.delete') }}</el-dropdown-item
  642. >
  643. </el-dropdown-menu>
  644. </template>
  645. </el-dropdown>
  646. </span>
  647. </template>
  648. <template v-if="knowledgeDetail?.type === 1 || knowledgeDetail?.type === 2">
  649. <el-tooltip
  650. effect="dark"
  651. :content="$t('views.document.setting.cancelVectorization')"
  652. placement="top"
  653. v-if="
  654. ([State.STARTED, State.PENDING] as Array<string>).includes(
  655. getTaskState(row.status, TaskType.EMBEDDING),
  656. ) && permissionPrecise.doc_vector(id)
  657. "
  658. >
  659. <span class="mr-4">
  660. <el-button
  661. type="primary"
  662. text
  663. @click.stop="cancelTask(row, TaskType.EMBEDDING)"
  664. >
  665. <el-icon><Close /></el-icon>
  666. </el-button>
  667. </span>
  668. </el-tooltip>
  669. <el-tooltip
  670. effect="dark"
  671. :content="$t('views.knowledge.setting.vectorization')"
  672. placement="top"
  673. v-if="permissionPrecise.vector(id)"
  674. >
  675. <span class="mr-4">
  676. <el-button type="primary" text @click.stop="refreshDocument(row)">
  677. <AppIcon iconName="app-document-refresh" style="font-size: 16px"></AppIcon>
  678. </el-button>
  679. </span>
  680. </el-tooltip>
  681. <el-tooltip
  682. effect="dark"
  683. :content="$t('common.setting')"
  684. placement="top"
  685. v-if="permissionPrecise.doc_edit(id)"
  686. >
  687. <span class="mr-4">
  688. <el-button type="primary" text @click.stop="settingDoc(row)">
  689. <AppIcon iconName="app-setting"></AppIcon>
  690. </el-button>
  691. </span>
  692. </el-tooltip>
  693. <span @click.stop>
  694. <el-dropdown trigger="click" v-if="MoreFilledPermission2(id)">
  695. <el-button text type="primary">
  696. <AppIcon iconName="app-more"></AppIcon>
  697. </el-button>
  698. <template #dropdown>
  699. <el-dropdown-menu>
  700. <el-dropdown-item
  701. @click="syncDocument(row)"
  702. v-if="permissionPrecise.sync(id)"
  703. >
  704. <AppIcon iconName="app-sync" class="color-secondary"></AppIcon>
  705. {{ $t('views.knowledge.setting.sync') }}</el-dropdown-item
  706. >
  707. <el-dropdown-item
  708. @click="openTagSettingDrawer(row)"
  709. v-if="permissionPrecise.doc_tag(id)"
  710. >
  711. <AppIcon iconName="app-tag" class="color-secondary"></AppIcon>
  712. {{ $t('views.document.tag.setting') }}
  713. </el-dropdown-item>
  714. <el-dropdown-item
  715. v-if="
  716. permissionPrecise.doc_generate(id) &&
  717. ([State.STARTED, State.PENDING] as Array<string>).includes(
  718. getTaskState(row.status, TaskType.GENERATE_PROBLEM),
  719. )
  720. "
  721. @click="cancelTask(row, TaskType.GENERATE_PROBLEM)"
  722. >
  723. <el-icon class="color-secondary"><Close /></el-icon>
  724. {{ $t('views.document.setting.cancelGenerateQuestion') }}
  725. </el-dropdown-item>
  726. <el-dropdown-item
  727. @click="openGenerateDialog(row)"
  728. v-else-if="permissionPrecise.doc_generate(id)"
  729. >
  730. <AppIcon
  731. iconName="app-generate-question"
  732. class="color-secondary"
  733. ></AppIcon>
  734. {{ $t('views.document.generateQuestion.title') }}
  735. </el-dropdown-item>
  736. <el-dropdown-item
  737. @click="openknowledgeDialog(row)"
  738. v-if="permissionPrecise.doc_migrate(id)"
  739. >
  740. <AppIcon iconName="app-migrate" class="color-secondary"></AppIcon>
  741. {{ $t('views.document.setting.migration') }}
  742. </el-dropdown-item>
  743. <el-dropdown-item
  744. @click="exportDocument(row)"
  745. v-if="permissionPrecise.doc_export(id)"
  746. >
  747. <AppIcon iconName="app-export" class="color-secondary"></AppIcon>
  748. {{ $t('views.document.setting.export') }} Excel
  749. </el-dropdown-item>
  750. <el-dropdown-item
  751. @click="exportDocumentZip(row)"
  752. v-if="permissionPrecise.doc_export(id)"
  753. >
  754. <AppIcon iconName="app-export" class="color-secondary"></AppIcon>
  755. {{ $t('views.document.setting.export') }} Zip
  756. </el-dropdown-item>
  757. <el-dropdown-item
  758. @click.stop="deleteDocument(row)"
  759. v-if="permissionPrecise.doc_delete(id)"
  760. >
  761. <AppIcon iconName="app-delete" class="color-secondary"></AppIcon>
  762. {{ $t('common.delete') }}
  763. </el-dropdown-item>
  764. </el-dropdown-menu>
  765. </template>
  766. </el-dropdown>
  767. </span>
  768. </template>
  769. </template>
  770. </el-table-column>
  771. </app-table>
  772. </div>
  773. </div>
  774. </el-card>
  775. <div class="mul-operation w-full flex" v-if="multipleSelection.length !== 0">
  776. <el-button
  777. :disabled="multipleSelection.length === 0"
  778. @click="cancelTaskHandle(1)"
  779. v-if="permissionPrecise.doc_vector(id)"
  780. >
  781. {{ $t('views.document.setting.cancelVectorization') }}
  782. </el-button>
  783. <el-button
  784. :disabled="multipleSelection.length === 0"
  785. @click="cancelTaskHandle(2)"
  786. v-if="permissionPrecise.doc_generate(id)"
  787. >
  788. {{ $t('views.document.setting.cancelGenerate') }}
  789. </el-button>
  790. <el-text type="info" class="secondary ml-24">
  791. {{ $t('common.selected') }} {{ multipleSelection.length }}
  792. {{ $t('views.document.items') }}
  793. </el-text>
  794. <el-button class="ml-16" type="primary" link @click="clearSelection">
  795. {{ $t('common.clear') }}
  796. </el-button>
  797. </div>
  798. <EmbeddingContentDialog ref="embeddingContentDialogRef"></EmbeddingContentDialog>
  799. <ImportDocumentDialog ref="ImportDocumentDialogRef" :title="title" @refresh="refresh" />
  800. <!-- 选择知识库 -->
  801. <SelectKnowledgeDialog
  802. ref="selectKnowledgeDialogRef"
  803. @refresh="refreshMigrate"
  804. :workspaceId="knowledgeDetail?.workspace_id"
  805. />
  806. <GenerateRelatedDialog ref="GenerateRelatedDialogRef" @refresh="getList" :apiType="apiType" />
  807. <TagDrawer ref="tagDrawerRef" @tag-changed="onTagChanged" />
  808. <TagSettingDrawer
  809. ref="tagSettingDrawerRef"
  810. @refresh="
  811. () => {
  812. onTagChanged()
  813. getList()
  814. }
  815. "
  816. />
  817. <AddTagDialog ref="addTagDialogRef" @addTags="addTags" :apiType="apiType" />
  818. <!-- 执行详情 -->
  819. <ExecutionRecord ref="ListActionRef"></ExecutionRecord>
  820. <!-- 推送到样本中心 -->
  821. <SyncToSampleCenterDialog ref="syncToSampleCenterDialogRef" />
  822. </div>
  823. </template>
  824. <script setup lang="ts">
  825. import { ref, onMounted, onBeforeUnmount, computed, reactive } from 'vue'
  826. import { useRouter, useRoute, onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
  827. import type { ElTable } from 'element-plus'
  828. import ImportDocumentDialog from './component/ImportDocumentDialog.vue'
  829. import SelectKnowledgeDialog from './component/SelectKnowledgeDialog.vue'
  830. import { numberFormat } from '@/utils/common'
  831. import { datetimeFormat } from '@/utils/time'
  832. import { hitHandlingMethod } from '@/enums/document'
  833. import { MsgSuccess, MsgConfirm, MsgError, MsgAlert } from '@/utils/message'
  834. import useStore from '@/stores'
  835. import StatusValue from '@/views/document/component/Status.vue'
  836. import GenerateRelatedDialog from '@/components/generate-related-dialog/index.vue'
  837. import EmbeddingContentDialog from '@/views/document/component/EmbeddingContentDialog.vue'
  838. import { TaskType, State } from '@/utils/status'
  839. import { t } from '@/locales'
  840. import permissionMap from '@/permission'
  841. import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
  842. import TagDrawer from './tag/TagDrawer.vue'
  843. import TagSettingDrawer from './tag/TagSettingDrawer.vue'
  844. import AddTagDialog from '@/views/document/tag/MulAddTagDialog.vue'
  845. import ExecutionRecord from '@/views/knowledge-workflow/component/execution-record/ExecutionRecordDrawer.vue'
  846. import SyncToSampleCenterDialog from '@/views/document/component/SyncToSampleCenterDialog.vue'
  847. const route = useRoute()
  848. const router = useRouter()
  849. const {
  850. params: { id, folderId, type }, // id为knowledgeID
  851. } = route as any
  852. const { common } = useStore()
  853. const storeKey = 'documents'
  854. onBeforeRouteUpdate(() => {
  855. common.savePage(storeKey, null)
  856. common.saveCondition(storeKey, null)
  857. })
  858. onBeforeRouteLeave((to: any) => {
  859. if (to.name !== 'ParagraphIndex') {
  860. common.savePage(storeKey, null)
  861. common.saveCondition(storeKey, null)
  862. } else {
  863. common.saveCondition(storeKey, {
  864. search_type: search_type.value,
  865. search_form: search_form.value,
  866. filterMethod: filterMethod.value,
  867. })
  868. }
  869. })
  870. const isShared = computed(() => {
  871. return folderId === 'share'
  872. })
  873. const apiType = computed(() => {
  874. if (route.path.includes('shared')) {
  875. return 'systemShare'
  876. } else if (route.path.includes('resource-management')) {
  877. return 'systemManage'
  878. } else if (route.path.includes('share/')) {
  879. return 'workspaceShare'
  880. } else {
  881. return 'workspace'
  882. }
  883. })
  884. const permissionPrecise = computed(() => {
  885. return permissionMap['knowledge'][apiType.value]
  886. })
  887. const MoreFilledPermission0 = (id: string) => {
  888. return (
  889. permissionPrecise.value.doc_migrate(id) ||
  890. (knowledgeDetail?.value.type === 1 && permissionPrecise.value.doc_sync(id)) ||
  891. (knowledgeDetail?.value.type === 2 && permissionPrecise.value.doc_sync(id)) ||
  892. permissionPrecise.value.doc_delete(id) ||
  893. permissionPrecise.value.doc_tag(id)
  894. )
  895. }
  896. const MoreFilledPermission1 = (id: string) => {
  897. return (
  898. permissionPrecise.value.doc_generate(id) ||
  899. permissionPrecise.value.doc_migrate(id) ||
  900. permissionPrecise.value.doc_export(id) ||
  901. permissionPrecise.value.doc_download(id) ||
  902. permissionPrecise.value.doc_delete(id) ||
  903. permissionPrecise.value.doc_tag(id) ||
  904. permissionPrecise.value.doc_replace(id)
  905. )
  906. }
  907. const MoreFilledPermission2 = (id: string) => {
  908. return (
  909. permissionPrecise.value.sync(id) ||
  910. permissionPrecise.value.doc_generate(id) ||
  911. permissionPrecise.value.doc_migrate(id) ||
  912. permissionPrecise.value.doc_export(id) ||
  913. permissionPrecise.value.doc_delete(id)
  914. )
  915. }
  916. const getTaskState = (status: string, taskType: number) => {
  917. const statusList = status.split('').reverse()
  918. return taskType - 1 > statusList.length + 1 ? 'n' : statusList[taskType - 1]
  919. }
  920. const search_type = ref('name')
  921. const search_form = ref<any>({
  922. name: '',
  923. tag: '',
  924. })
  925. const beforePagination = computed(() => common.paginationConfig[storeKey])
  926. const beforeSearch = computed(() => common.search[storeKey])
  927. const embeddingContentDialogRef = ref<InstanceType<typeof EmbeddingContentDialog>>()
  928. const ListActionRef = ref<InstanceType<typeof ExecutionRecord>>()
  929. const loading = ref(false)
  930. let interval: any
  931. const filterMethod = ref<any>({})
  932. const orderBy = ref<string>('')
  933. const documentData = ref<any[]>([])
  934. const currentMouseId = ref(null)
  935. const knowledgeDetail = ref<any>({})
  936. const paginationConfig = ref({
  937. current_page: 1,
  938. page_size: 10,
  939. total: 0,
  940. })
  941. const ImportDocumentDialogRef = ref()
  942. const multipleTableRef = ref<InstanceType<typeof ElTable>>()
  943. const multipleSelection = ref<any[]>([])
  944. const title = ref('')
  945. const selectKnowledgeDialogRef = ref()
  946. const openListAction = () => {
  947. ListActionRef.value?.open(id)
  948. }
  949. const toImportWorkflow = () => {
  950. if (knowledgeDetail.value.is_publish) {
  951. router.push({
  952. path: `/knowledge/import/workflow/${folderId}`,
  953. query: {
  954. id: id,
  955. },
  956. })
  957. } else {
  958. MsgConfirm(t('common.tip'), t('views.document.tip.toImportDocConfirm'), {
  959. cancelButtonText: t('common.close'),
  960. showConfirmButton: false,
  961. type: 'warning',
  962. })
  963. .then(() => {})
  964. .catch(() => {})
  965. }
  966. }
  967. const exportDocument = (document: any) => {
  968. loadSharedApi({ type: 'document', systemType: apiType.value })
  969. .exportDocument(document.name, document.knowledge_id, document.id, loading)
  970. .then(() => {
  971. MsgSuccess(t('common.exportSuccess'))
  972. })
  973. }
  974. const exportDocumentZip = (document: any) => {
  975. loadSharedApi({ type: 'document', systemType: apiType.value })
  976. .exportDocumentZip(document.name, document.knowledge_id, document.id, loading)
  977. .then(() => {
  978. MsgSuccess(t('common.exportSuccess'))
  979. })
  980. }
  981. function cancelTaskHandle(val: any) {
  982. const arr: string[] = []
  983. multipleSelection.value.map((v) => {
  984. if (v) {
  985. arr.push(v.id)
  986. }
  987. })
  988. const obj = {
  989. id_list: arr,
  990. type: val,
  991. }
  992. loadSharedApi({ type: 'document', systemType: apiType.value })
  993. .putBatchCancelTask(id, obj, loading)
  994. .then(() => {
  995. MsgSuccess(t('views.document.tip.cancelSuccess'))
  996. multipleTableRef.value?.clearSelection()
  997. })
  998. }
  999. function clearSelection() {
  1000. multipleTableRef.value?.clearSelection()
  1001. }
  1002. function openknowledgeDialog(row?: any) {
  1003. const arr: string[] = []
  1004. if (row) {
  1005. arr.push(row.id)
  1006. } else {
  1007. multipleSelection.value.map((v) => {
  1008. if (v) {
  1009. arr.push(v.id)
  1010. }
  1011. })
  1012. }
  1013. selectKnowledgeDialogRef.value.open(arr)
  1014. }
  1015. function dropdownHandle(obj: any) {
  1016. filterMethod.value[obj.attr] = obj.command
  1017. if (obj.attr == 'status') {
  1018. filterMethod.value['task_type'] = obj.task_type
  1019. }
  1020. getList()
  1021. }
  1022. function beforeCommand(attr: string, val: any, task_type?: number) {
  1023. return {
  1024. attr: attr,
  1025. command: val,
  1026. task_type,
  1027. }
  1028. }
  1029. const cancelTask = (row: any, task_type: number) => {
  1030. loadSharedApi({ type: 'document', systemType: apiType.value })
  1031. .putCancelTask(id, row.id, { type: task_type })
  1032. .then(() => {
  1033. MsgSuccess(t('views.document.tip.sendMessage'))
  1034. })
  1035. }
  1036. function importDoc() {
  1037. title.value = t('views.document.importDocument')
  1038. ImportDocumentDialogRef.value.open()
  1039. }
  1040. function settingDoc(row: any) {
  1041. title.value = t('common.setting')
  1042. ImportDocumentDialogRef.value.open(row)
  1043. }
  1044. const handleSelectionChange = (val: any[]) => {
  1045. multipleSelection.value = val
  1046. }
  1047. function openBatchEditDocument() {
  1048. title.value = t('common.setting')
  1049. const arr: string[] = multipleSelection.value.map((v) => v.id)
  1050. ImportDocumentDialogRef.value.open(null, arr)
  1051. }
  1052. /**
  1053. * 初始化轮询
  1054. */
  1055. const initInterval = () => {
  1056. interval = setInterval(() => {
  1057. getList(true)
  1058. }, 6000)
  1059. }
  1060. /**
  1061. * 关闭轮询
  1062. */
  1063. const closeInterval = () => {
  1064. if (interval) {
  1065. clearInterval(interval)
  1066. }
  1067. }
  1068. function syncDocument(row: any) {
  1069. if (+row.type === 1) {
  1070. syncWebDocument(row)
  1071. } else {
  1072. syncLarkDocument(row)
  1073. }
  1074. }
  1075. function syncLarkDocument(row: any) {
  1076. MsgConfirm(t('views.document.sync.confirmTitle'), t('views.document.sync.confirmMessage1'), {
  1077. confirmButtonText: t('views.document.sync.label'),
  1078. confirmButtonClass: 'danger',
  1079. })
  1080. .then(() => {
  1081. loadSharedApi({ type: 'document', systemType: apiType.value })
  1082. .putLarkDocumentSync(id, row.id)
  1083. .then(() => {
  1084. getList()
  1085. })
  1086. })
  1087. .catch(() => {})
  1088. }
  1089. function syncWebDocument(row: any) {
  1090. if (row.meta?.source_url) {
  1091. MsgConfirm(t('views.document.sync.confirmTitle'), t('views.document.sync.confirmMessage1'), {
  1092. confirmButtonText: t('views.document.sync.label'),
  1093. confirmButtonClass: 'danger',
  1094. })
  1095. .then(() => {
  1096. loadSharedApi({ type: 'document', systemType: apiType.value })
  1097. .putDocumentSync(row.knowledge_id, row.id)
  1098. .then(() => {
  1099. getList()
  1100. })
  1101. })
  1102. .catch(() => {})
  1103. } else {
  1104. MsgConfirm(t('common.tip'), t('views.document.sync.confirmMessage2'), {
  1105. confirmButtonText: t('common.confirm'),
  1106. type: 'warning',
  1107. })
  1108. .then(() => {})
  1109. .catch(() => {})
  1110. }
  1111. }
  1112. function refreshDocument(row: any) {
  1113. const embeddingDocument = (stateList: Array<string>) => {
  1114. return loadSharedApi({ type: 'document', systemType: apiType.value })
  1115. .putDocumentRefresh(row.knowledge_id, row.id, stateList)
  1116. .then(() => {
  1117. getList()
  1118. })
  1119. }
  1120. embeddingContentDialogRef.value?.open(embeddingDocument)
  1121. }
  1122. function rowClickHandle(row: any, column: any) {
  1123. console.log(column)
  1124. if (column && (column.type === 'selection' || column.property === 'tag')) {
  1125. return
  1126. }
  1127. router.push({
  1128. path: `/paragraph/${id}/${row.id}`,
  1129. query: { from: apiType.value, isShared: isShared.value ? 'true' : 'false' },
  1130. })
  1131. }
  1132. /*
  1133. 快速创建空白文档
  1134. */
  1135. function creatQuickHandle(val: string) {
  1136. loading.value = true
  1137. const obj = [{ name: val }]
  1138. loadSharedApi({ type: 'document', systemType: apiType.value })
  1139. .putMulDocument(id, obj)
  1140. .then(() => {
  1141. getList()
  1142. MsgSuccess(t('common.createSuccess'))
  1143. })
  1144. .catch(() => {
  1145. loading.value = false
  1146. })
  1147. }
  1148. function syncMulDocument() {
  1149. const arr: string[] = []
  1150. multipleSelection.value.map((v) => {
  1151. if (v) {
  1152. arr.push(v.id)
  1153. }
  1154. })
  1155. MsgConfirm(t('views.document.sync.confirmTitle'), t('views.document.sync.confirmMessage1'), {
  1156. confirmButtonText: t('views.document.sync.label'),
  1157. confirmButtonClass: 'danger',
  1158. })
  1159. .then(() => {
  1160. loadSharedApi({ type: 'document', systemType: apiType.value })
  1161. .putMulSyncDocument(id, arr, loading)
  1162. .then(() => {
  1163. MsgSuccess(t('views.document.sync.successMessage'))
  1164. getList()
  1165. })
  1166. })
  1167. .catch(() => {})
  1168. }
  1169. function syncLarkMulDocument() {
  1170. const arr: string[] = []
  1171. multipleSelection.value.map((v) => {
  1172. if (v) {
  1173. arr.push(v.id)
  1174. }
  1175. })
  1176. loadSharedApi({ type: 'document', systemType: apiType.value })
  1177. .putMulLarkSyncDocument(id, arr, loading)
  1178. .then(() => {
  1179. MsgSuccess(t('views.document.sync.successMessage'))
  1180. getList()
  1181. })
  1182. }
  1183. function exportMulDocument() {
  1184. const arr: string[] = []
  1185. multipleSelection.value.map((v) => {
  1186. if (v) {
  1187. arr.push(v.id)
  1188. }
  1189. })
  1190. loadSharedApi({ type: 'document', systemType: apiType.value })
  1191. .exportMulDocument(knowledgeDetail.value.name, id, arr, loading)
  1192. .then(() => {
  1193. MsgSuccess(t('common.exportSuccess'))
  1194. })
  1195. }
  1196. function exportMulDocumentZip() {
  1197. const arr: string[] = []
  1198. multipleSelection.value.map((v) => {
  1199. if (v) {
  1200. arr.push(v.id)
  1201. }
  1202. })
  1203. loadSharedApi({ type: 'document', systemType: apiType.value })
  1204. .exportMulDocumentZip(knowledgeDetail.value.name, id, arr, loading)
  1205. .then(() => {
  1206. MsgSuccess(t('common.exportSuccess'))
  1207. })
  1208. }
  1209. function deleteMulDocument() {
  1210. MsgConfirm(
  1211. `${t('views.document.delete.confirmTitle1')} ${multipleSelection.value.length} ${t('views.document.delete.confirmTitle2')}`,
  1212. t('views.document.delete.confirmMessage'),
  1213. {
  1214. confirmButtonText: t('common.confirm'),
  1215. confirmButtonClass: 'danger',
  1216. },
  1217. )
  1218. .then(() => {
  1219. const arr: string[] = []
  1220. multipleSelection.value.map((v) => {
  1221. if (v) {
  1222. arr.push(v.id)
  1223. }
  1224. })
  1225. loadSharedApi({ type: 'document', systemType: apiType.value })
  1226. .delMulDocument(id, arr, loading)
  1227. .then(() => {
  1228. MsgSuccess(t('views.document.delete.successMessage'))
  1229. multipleTableRef.value?.clearSelection()
  1230. getList()
  1231. })
  1232. })
  1233. .catch(() => {})
  1234. }
  1235. // 推送到样本中心
  1236. const syncToSampleCenterDialogRef = ref()
  1237. function openSyncToSampleCenter() {
  1238. syncToSampleCenterDialogRef.value?.open(knowledgeDetail.value, multipleSelection.value)
  1239. }
  1240. function batchRefresh() {
  1241. const arr: string[] = multipleSelection.value.map((v) => v.id)
  1242. const embeddingBatchDocument = (stateList: Array<string>) => {
  1243. loadSharedApi({ type: 'document', systemType: apiType.value })
  1244. .putBatchRefresh(id, arr, stateList, loading)
  1245. .then(() => {
  1246. MsgSuccess(t('views.document.tip.vectorizationSuccess'))
  1247. multipleTableRef.value?.clearSelection()
  1248. })
  1249. }
  1250. embeddingContentDialogRef.value?.open(embeddingBatchDocument)
  1251. }
  1252. function downloadDocument(row: any) {
  1253. loadSharedApi({ type: 'document', systemType: apiType.value })
  1254. .getDownloadSourceFile(id, row.id, row.name)
  1255. .then(() => {
  1256. getList()
  1257. })
  1258. }
  1259. const elUploadRef = ref()
  1260. function replaceDocument(file: any, row: any) {
  1261. const formData = new FormData()
  1262. formData.append('file', file.raw, file.name)
  1263. elUploadRef.value.clearFiles()
  1264. loadSharedApi({ type: 'document', systemType: apiType.value })
  1265. .postReplaceSourceFile(id, row.id, formData, loading)
  1266. .then(() => {
  1267. MsgSuccess(t('views.document.tip.replaceSuccess'))
  1268. getList()
  1269. })
  1270. .catch((e: any) => {})
  1271. }
  1272. function deleteDocument(row: any) {
  1273. MsgConfirm(
  1274. `${t('views.document.delete.confirmTitle3')} ${row.name} ?`,
  1275. `${t('views.document.delete.confirmMessage1')} ${row.paragraph_count} ${t('views.document.delete.confirmMessage2')}`,
  1276. {
  1277. confirmButtonText: t('common.confirm'),
  1278. confirmButtonClass: 'danger',
  1279. },
  1280. )
  1281. .then(() => {
  1282. loadSharedApi({ type: 'document', systemType: apiType.value })
  1283. .delDocument(id, row.id, loading)
  1284. .then(() => {
  1285. MsgSuccess(t('common.deleteSuccess'))
  1286. getList()
  1287. })
  1288. })
  1289. .catch(() => {})
  1290. }
  1291. /*
  1292. 更新名称或状态
  1293. */
  1294. function updateData(documentId: string, data: any, msg: string) {
  1295. loadSharedApi({ type: 'document', systemType: apiType.value })
  1296. .putDocument(id, documentId, data, loading)
  1297. .then((res: any) => {
  1298. const index = documentData.value.findIndex((v) => v.id === documentId)
  1299. documentData.value.splice(index, 1, res.data)
  1300. MsgSuccess(msg)
  1301. return true
  1302. })
  1303. .catch(() => {
  1304. return false
  1305. })
  1306. }
  1307. async function changeState(row: any) {
  1308. const obj = {
  1309. is_active: !row.is_active,
  1310. }
  1311. const str = !row.is_active ? t('common.status.enableSuccess') : t('common.status.disableSuccess')
  1312. await updateData(row.id, obj, str)
  1313. }
  1314. function editName(val: string, id: string) {
  1315. if (val) {
  1316. const obj = {
  1317. name: val,
  1318. }
  1319. updateData(id, obj, t('common.modifySuccess'))
  1320. } else {
  1321. MsgError(t('views.document.tip.nameMessage'))
  1322. }
  1323. }
  1324. function cellMouseEnter(row: any, column: any) {
  1325. if (column && column.property === 'name') {
  1326. currentMouseId.value = row.id
  1327. }
  1328. }
  1329. function cellMouseLeave() {
  1330. currentMouseId.value = null
  1331. }
  1332. function handleSizeChange() {
  1333. paginationConfig.value.current_page = 1
  1334. getList()
  1335. }
  1336. function handleSortChange({ prop, order }: { prop: string; order: string }) {
  1337. orderBy.value = order === 'ascending' ? prop : `-${prop}`
  1338. getList()
  1339. }
  1340. function getList(bool?: boolean) {
  1341. const param = {
  1342. ...filterMethod.value,
  1343. order_by: orderBy.value,
  1344. folder_id: folderId,
  1345. }
  1346. if (search_form.value[search_type.value]) {
  1347. param[search_type.value] = search_form.value[search_type.value]
  1348. }
  1349. loadSharedApi({ type: 'document', isShared: isShared.value, systemType: apiType.value })
  1350. .getDocumentPage(id as string, paginationConfig.value, param, bool ? undefined : loading)
  1351. .then((res: any) => {
  1352. documentData.value = res.data.records
  1353. paginationConfig.value.total = res.data.total
  1354. })
  1355. }
  1356. const search_type_change = () => {
  1357. search_form.value = { name: '', tag: '' }
  1358. }
  1359. function getDetail() {
  1360. loadSharedApi({ type: 'knowledge', isShared: isShared.value, systemType: apiType.value })
  1361. .getKnowledgeDetail(id, loading)
  1362. .then((res: any) => {
  1363. knowledgeDetail.value = res.data
  1364. })
  1365. }
  1366. function refreshMigrate() {
  1367. multipleTableRef.value?.clearSelection()
  1368. getList()
  1369. }
  1370. function refresh() {
  1371. paginationConfig.value.current_page = 1
  1372. getList()
  1373. }
  1374. const GenerateRelatedDialogRef = ref()
  1375. function openGenerateDialog(row?: any) {
  1376. const arr: string[] = []
  1377. if (row) {
  1378. arr.push(row.id)
  1379. } else {
  1380. multipleSelection.value.map((v) => {
  1381. if (v) {
  1382. arr.push(v.id)
  1383. }
  1384. })
  1385. }
  1386. GenerateRelatedDialogRef.value.open(arr, 'document')
  1387. }
  1388. function cellClickHandle(row: any, column: any, cell: any, event: any) {
  1389. if (column.property === 'tag' && permissionPrecise.value.doc_tag(id)) {
  1390. event.stopPropagation()
  1391. openTagSettingDrawer(row)
  1392. }
  1393. }
  1394. const tagFilterValue = ref<string[]>([])
  1395. const tagFilterDirty = ref(false)
  1396. const tagFilterOptions = ref<any[]>([])
  1397. const tagFilterLoaded = ref(false)
  1398. const tagFilterLoading = ref(false)
  1399. function buildTagCascaderOptions(tags: any[]) {
  1400. const options = tags.map((group: any) => ({
  1401. label: group.key,
  1402. value: group.key,
  1403. children: (group.values || []).map((item: any) => ({
  1404. label: item.value,
  1405. value: item.id, // 叶子节点 tag.id
  1406. })),
  1407. }))
  1408. options.push({
  1409. label: t('views.document.tag.noTag'),
  1410. value: 'NO_TAG',
  1411. children: [],
  1412. })
  1413. return options
  1414. }
  1415. async function ensureTagFilterOptions(needRefresh = false) {
  1416. // 非刷新 && 已加载 && 非脏数据
  1417. if (!needRefresh && tagFilterLoaded.value && !tagFilterDirty.value) return
  1418. try {
  1419. tagFilterLoading.value = true
  1420. const params = {}
  1421. const res: any = await loadSharedApi({
  1422. type: 'knowledge',
  1423. systemType: apiType.value,
  1424. isShared: isShared.value,
  1425. }).getTags(id, params, tagFilterLoading)
  1426. tagFilterOptions.value = buildTagCascaderOptions(res?.data || [])
  1427. tagFilterLoaded.value = true
  1428. tagFilterDirty.value = false
  1429. } finally {
  1430. tagFilterLoading.value = false
  1431. }
  1432. }
  1433. async function handleTagVisibleChange(visible: boolean) {
  1434. if (!visible) return
  1435. await ensureTagFilterOptions()
  1436. }
  1437. function onTagChanged() {
  1438. tagFilterDirty.value = true
  1439. }
  1440. const tagDrawerRef = ref()
  1441. function openTagDrawer() {
  1442. tagDrawerRef.value.open()
  1443. }
  1444. const tagSettingDrawerRef = ref()
  1445. function openTagSettingDrawer(doc: any) {
  1446. tagSettingDrawerRef.value.open(doc)
  1447. }
  1448. const addTagDialogRef = ref()
  1449. function openAddTagDialog(rowId?: string) {
  1450. addTagDialogRef.value?.open(rowId)
  1451. }
  1452. function addTags(tags: any, rowId?: string) {
  1453. const arr: string[] = multipleSelection.value.length
  1454. ? multipleSelection.value.map((v) => v.id)
  1455. : [rowId]
  1456. loadSharedApi({ type: 'document', systemType: apiType.value })
  1457. .postMulDocumentTags(id, { tag_ids: tags, document_ids: arr }, loading)
  1458. .then(() => {
  1459. addTagDialogRef.value?.close()
  1460. getList()
  1461. clearSelection()
  1462. })
  1463. }
  1464. onMounted(() => {
  1465. getDetail()
  1466. if (beforePagination.value) {
  1467. paginationConfig.value = beforePagination.value
  1468. }
  1469. if (beforeSearch.value) {
  1470. filterMethod.value = beforeSearch.value['filterMethod']
  1471. search_type.value = beforeSearch.value['search_type']
  1472. search_form.value = beforeSearch.value['search_form']
  1473. }
  1474. getList()
  1475. // 初始化定时任务
  1476. initInterval()
  1477. if (route.query.imported === 'true') {
  1478. MsgAlert(t('common.tip'), t('common.knowledgeImportTip')).then(() => {
  1479. router.replace({ query: {} })
  1480. })
  1481. }
  1482. })
  1483. onBeforeUnmount(() => {
  1484. // 清除定时任务
  1485. closeInterval()
  1486. })
  1487. </script>
  1488. <style lang="scss" scoped>
  1489. .document {
  1490. .mul-operation {
  1491. right: 24px;
  1492. width: calc(100% - var(--sidebar-width) - 48px);
  1493. }
  1494. .document-table {
  1495. :deep(.el-table__row) {
  1496. cursor: pointer;
  1497. }
  1498. }
  1499. }
  1500. </style>