index.vue 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. <template>
  2. <LayoutContainer showCollapse resizable class="application-manage">
  3. <template #left>
  4. <h4 class="p-12-16 pb-0 mt-12">{{ $t('views.application.title') }}</h4>
  5. <folder-tree
  6. :source="SourceTypeEnum.APPLICATION"
  7. :data="folderList"
  8. :currentNodeKey="folder.currentFolder?.id"
  9. @handleNodeClick="folderClickHandle"
  10. @refreshTree="refreshFolder"
  11. :draggable="true"
  12. />
  13. </template>
  14. <ContentContainer>
  15. <template #header>
  16. <FolderBreadcrumb :folderList="folderList" @click="folderClickHandle" />
  17. </template>
  18. <template #search>
  19. <div class="flex">
  20. <div class="flex-between complex-search">
  21. <el-select
  22. class="complex-search__left"
  23. v-model="search_type"
  24. style="width: 100px"
  25. @change="search_type_change"
  26. >
  27. <el-option :label="$t('common.creator')" value="create_user" />
  28. <el-option :label="$t('common.name')" value="name" />
  29. <el-option :label="$t('views.application.publishStatus')" value="publish_status" />
  30. </el-select>
  31. <el-input
  32. v-if="search_type === 'name'"
  33. v-model="search_form.name"
  34. @change="searchHandle"
  35. :placeholder="$t('common.searchBar.placeholder')"
  36. style="width: 190px"
  37. clearable
  38. />
  39. <el-select
  40. v-else-if="search_type === 'create_user'"
  41. v-model="search_form.create_user"
  42. @change="searchHandle"
  43. filterable
  44. clearable
  45. style="width: 190px"
  46. >
  47. <el-option v-for="u in user_options" :key="u.id" :value="u.id" :label="u.nick_name" />
  48. </el-select>
  49. <el-select
  50. v-else-if="search_type === 'publish_status'"
  51. v-model="search_form.publish_status"
  52. @change="searchHandle"
  53. filterable
  54. clearable
  55. style="width: 190px"
  56. >
  57. <el-option :label="$t('common.status.published')" value="published" />
  58. <el-option :label="$t('common.status.unpublished')" value="unpublished" />
  59. </el-select>
  60. </div>
  61. <span
  62. class="ml-8"
  63. v-if="permissionPrecise.batchDelete() || permissionPrecise.batchMove()"
  64. >
  65. <el-button @click="batchSelectedHandle(true)" v-if="isBatch === false">
  66. <AppIcon iconName="app-batch-delete" class="mr-4" />
  67. {{ $t('views.paragraph.setting.batchSelected') }}
  68. </el-button>
  69. <el-button @click="batchSelectedHandle(false)" v-if="isBatch === true">
  70. <AppIcon iconName="app-batch-delete" class="mr-4" />
  71. {{ $t('views.paragraph.setting.cancelSelected') }}
  72. </el-button>
  73. </span>
  74. <div v-if="isBatch === false">
  75. <el-button
  76. class="ml-8"
  77. v-show="false"
  78. v-if="permissionPrecise.create()"
  79. @click="openTemplateStoreDialog()"
  80. >
  81. <AppIcon iconName="app-template-center" class="mr-4" />
  82. {{ $t('workflow.setting.templateCenter') }}
  83. </el-button>
  84. <el-dropdown trigger="click" v-if="permissionPrecise.create()">
  85. <el-button type="primary" class="ml-8">
  86. {{ $t('common.create') }}
  87. <el-icon class="el-icon--right">
  88. <arrow-down />
  89. </el-icon>
  90. </el-button>
  91. <template #dropdown>
  92. <el-dropdown-menu class="create-dropdown">
  93. <el-dropdown-item @click="openCreateDialog('SIMPLE')">
  94. <div class="flex">
  95. <el-avatar shape="square" class="avatar-blue mt-4" :size="32">
  96. <img
  97. src="@/assets/application/icon_simple_application.svg"
  98. style="width: 65%"
  99. alt=""
  100. />
  101. </el-avatar>
  102. <div class="pre-wrap ml-8">
  103. <div class="lighter">
  104. {{ $t('views.application.simpleAgent') }}
  105. </div>
  106. <el-text type="info" size="small" class="color-secondary"
  107. >{{ $t('views.application.simplePlaceholder') }}
  108. </el-text>
  109. </div>
  110. </div>
  111. </el-dropdown-item>
  112. <el-dropdown-item @click="openCreateDialog('WORK_FLOW')">
  113. <div class="flex">
  114. <el-avatar shape="square" class="avatar-purple mt-4" :size="32">
  115. <img
  116. src="@/assets/application/icon_workflow_application.svg"
  117. style="width: 65%"
  118. alt=""
  119. />
  120. </el-avatar>
  121. <div class="pre-wrap ml-8">
  122. <div class="lighter">{{ $t('views.application.AdvancedAgent') }}</div>
  123. <el-text type="info" size="small" class="color-secondary"
  124. >{{ $t('views.application.advancedPlaceholder') }}
  125. </el-text>
  126. </div>
  127. </div>
  128. </el-dropdown-item>
  129. <el-upload
  130. class="import-button"
  131. ref="elUploadRef"
  132. :file-list="[]"
  133. action="#"
  134. multiple
  135. :auto-upload="false"
  136. :show-file-list="false"
  137. :limit="1"
  138. :on-change="(file: any, fileList: any) => importApplication(file)"
  139. >
  140. <el-dropdown-item>
  141. <div class="flex align-center w-full">
  142. <el-avatar shape="square" class="mt-4" :size="32" style="background: none">
  143. <img src="@/assets/icon_import.svg" alt="" />
  144. </el-avatar>
  145. <div class="pre-wrap ml-8">
  146. <div class="lighter">{{ $t('views.application.importApplication') }}</div>
  147. </div>
  148. </div>
  149. </el-dropdown-item>
  150. </el-upload>
  151. <el-dropdown-item @click="openCreateFolder" divided>
  152. <div class="flex align-center">
  153. <AppIcon iconName="app-folder" style="font-size: 32px"></AppIcon>
  154. <div class="pre-wrap ml-4">
  155. <div class="lighter">
  156. {{ $t('components.folder.addFolder') }}
  157. </div>
  158. </div>
  159. </div>
  160. </el-dropdown-item>
  161. </el-dropdown-menu>
  162. </template>
  163. </el-dropdown>
  164. </div>
  165. </div>
  166. </template>
  167. <div
  168. v-loading.fullscreen.lock="paginationConfig.current_page === 1 && loading"
  169. style="max-height: calc(100vh - 120px)"
  170. >
  171. <InfiniteScroll
  172. :size="applicationList.length"
  173. :total="paginationConfig.total"
  174. :page_size="paginationConfig.page_size"
  175. v-model:current_page="paginationConfig.current_page"
  176. @load="getList"
  177. :loading="loading"
  178. >
  179. <el-checkbox-group v-model="multipleSelection" @change="handleCheckedChatChange">
  180. <el-row v-if="applicationList.length > 0" :gutter="15" class="w-full">
  181. <template v-for="(item, index) in applicationList" :key="index">
  182. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="6" class="mb-16">
  183. <CardBox
  184. :title="item.name"
  185. :description="item.desc"
  186. class="cursor"
  187. @click="goApp(item)"
  188. :disabled="isBatch"
  189. >
  190. <template #icon>
  191. <el-avatar shape="square" :size="32" style="background: none">
  192. <img :src="resetUrl(item?.icon, resetUrl('./favicon.ico'))" alt="" />
  193. </el-avatar>
  194. </template>
  195. <template #subTitle>
  196. <el-text class="color-secondary lighter flex align-center" size="small">
  197. <span
  198. :title="i18n_name(item.nick_name)"
  199. class="ellipsis"
  200. style="max-width: 90px"
  201. >
  202. {{ i18n_name(item.nick_name) }}
  203. </span>
  204. <span class="ml-4 mr-4"> {{ $t('common.createdIn') }}</span>
  205. <span> {{ dateFormat(item.create_time) }}</span>
  206. </el-text>
  207. </template>
  208. <template #tag>
  209. <el-checkbox :value="item.id" v-if="isBatch" @change="checkboxChange(item)" />
  210. <div v-else>
  211. <el-tag size="small" v-if="isWorkFlow(item.type)" class="warning-tag">
  212. {{ $t('views.application.senior') }}
  213. </el-tag>
  214. <el-tag size="small" class="blue-tag" v-else>
  215. {{ $t('views.application.simple') }}
  216. </el-tag>
  217. </div>
  218. </template>
  219. <template #footer>
  220. <div v-if="item.is_publish" class="flex align-center">
  221. <el-icon class="color-success mr-8" style="font-size: 16px">
  222. <SuccessFilled />
  223. </el-icon>
  224. <span class="color-secondary">
  225. {{ $t('common.status.published') }}
  226. </span>
  227. <el-divider direction="vertical" />
  228. <AppIcon iconName="app-clock" class="color-secondary mr-8"></AppIcon>
  229. <span class="color-secondary">{{ dateFormat(item.update_time) }}</span>
  230. </div>
  231. <div v-else class="flex align-center">
  232. <AppIcon iconName="app-disabled" class="color-secondary mr-8"></AppIcon>
  233. <span class="color-secondary">
  234. {{ $t('common.status.unpublished') }}
  235. </span>
  236. </div>
  237. </template>
  238. <template #mouseEnter>
  239. <div @click.stop>
  240. <el-tooltip
  241. effect="dark"
  242. :content="$t('views.application.operation.toChat')"
  243. placement="top"
  244. >
  245. <el-button text @click.stop="toChat(item)">
  246. <AppIcon iconName="app-create-chat" class="color-secondary"></AppIcon>
  247. </el-button>
  248. </el-tooltip>
  249. <el-divider direction="vertical" />
  250. <el-dropdown trigger="click">
  251. <el-button text @click.stop>
  252. <AppIcon iconName="app-more" class="color-secondary"></AppIcon>
  253. </el-button>
  254. <template #dropdown>
  255. <el-dropdown-menu>
  256. <el-dropdown-item
  257. @mousedown.stop="settingApplication($event, item)"
  258. v-if="permissionPrecise.edit(item.id)"
  259. @click.stop
  260. >
  261. <AppIcon iconName="app-setting" class="color-secondary"></AppIcon>
  262. {{ $t('common.setting') }}
  263. </el-dropdown-item>
  264. <el-dropdown-item
  265. @click.stop="openAuthorization(item)"
  266. v-if="permissionPrecise.auth(item.id)"
  267. >
  268. <AppIcon
  269. iconName="app-resource-authorization"
  270. class="color-secondary"
  271. ></AppIcon>
  272. {{ $t('views.system.resourceAuthorization.title') }}
  273. </el-dropdown-item>
  274. <el-dropdown-item
  275. @click.stop="openTriggerDrawer(item)"
  276. v-if="
  277. apiType === 'workspace' && permissionPrecise.trigger_read(item.id)
  278. "
  279. >
  280. <AppIcon iconName="app-trigger" class="color-secondary"></AppIcon>
  281. {{ $t('views.trigger.title') }}
  282. </el-dropdown-item>
  283. <el-dropdown-item
  284. @click.stop="openMoveToDialog(item)"
  285. v-if="permissionPrecise.edit(item.id) && apiType === 'workspace'"
  286. >
  287. <AppIcon iconName="app-migrate" class="color-secondary"></AppIcon>
  288. {{ $t('common.moveTo') }}
  289. </el-dropdown-item>
  290. <el-dropdown-item
  291. @click="copyApplication(item)"
  292. v-if="permissionPrecise.create()"
  293. >
  294. <AppIcon iconName="app-copy" class="color-secondary"></AppIcon>
  295. {{ $t('common.copy') }}
  296. </el-dropdown-item>
  297. <el-dropdown-item
  298. divided
  299. @click.stop="exportApplication(item)"
  300. v-if="permissionPrecise.export(item.id)"
  301. >
  302. <AppIcon iconName="app-export" class="color-secondary"></AppIcon>
  303. {{ $t('common.export') }}
  304. </el-dropdown-item>
  305. <el-dropdown-item
  306. divided
  307. @click.stop="deleteApplication(item)"
  308. v-if="permissionPrecise.delete(item.id)"
  309. >
  310. <AppIcon iconName="app-delete" class="color-secondary"></AppIcon>
  311. {{ $t('common.delete') }}
  312. </el-dropdown-item>
  313. </el-dropdown-menu>
  314. </template>
  315. </el-dropdown>
  316. </div>
  317. </template>
  318. </CardBox>
  319. </el-col>
  320. </template>
  321. </el-row>
  322. <el-empty :description="$t('common.noData')" v-else />
  323. </el-checkbox-group>
  324. </InfiniteScroll>
  325. </div>
  326. <!-- 批量操作拦 -->
  327. <div class="mul-operation border-t w-full flex align-center" v-if="isBatch">
  328. <el-checkbox
  329. v-model="checkAll"
  330. :indeterminate="isIndeterminate"
  331. @change="handleCheckAllChange"
  332. >
  333. {{ $t('common.allCheck') }}
  334. </el-checkbox>
  335. <el-button
  336. class="ml-16"
  337. :disabled="multipleSelection.length === 0"
  338. @click="openMoveToDialog()"
  339. v-if="permissionPrecise.batchMove()"
  340. >
  341. {{ $t('common.moveTo') }}
  342. </el-button>
  343. <el-button
  344. :disabled="multipleSelection.length === 0"
  345. @click="deleteMulApplication"
  346. v-if="permissionPrecise.batchDelete()"
  347. >
  348. {{ $t('common.delete') }}
  349. </el-button>
  350. <span class="color-secondary ml-24 mr-16">
  351. {{ $t('common.selected') }} {{ multipleSelection.length }} / {{ paginationConfig.total }}
  352. {{ $t('views.document.items') }}
  353. </span>
  354. <el-button link type="primary" @click="batchSelectedHandle(false)">
  355. {{ $t('views.paragraph.setting.cancelSelected') }}
  356. </el-button>
  357. </div>
  358. </ContentContainer>
  359. <CreateApplicationDialog ref="CreateApplicationDialogRef" />
  360. <CopyApplicationDialog ref="CopyApplicationDialogRef" />
  361. <CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" />
  362. <MoveToDialog
  363. ref="MoveToDialogRef"
  364. :source="SourceTypeEnum.APPLICATION"
  365. @refresh="refreshApplicationList"
  366. v-if="apiType === 'workspace'"
  367. />
  368. <ResourceAuthorizationDrawer
  369. :type="SourceTypeEnum.APPLICATION"
  370. ref="ResourceAuthorizationDrawerRef"
  371. />
  372. <TemplateStoreDialog ref="templateStoreDialogRef" :api-type="apiType" @refresh="getList" />
  373. <ResourceTriggerDrawer
  374. ref="resourceTriggerDrawerRef"
  375. :source="SourceTypeEnum.APPLICATION"
  376. ></ResourceTriggerDrawer>
  377. </LayoutContainer>
  378. </template>
  379. <script lang="ts" setup>
  380. import { onMounted, ref, reactive, computed } from 'vue'
  381. import { useRouter, useRoute } from 'vue-router'
  382. import type { CheckboxValueType } from 'element-plus'
  383. import CreateApplicationDialog from '@/views/application/component/CreateApplicationDialog.vue'
  384. import CreateFolderDialog from '@/components/folder-tree/CreateFolderDialog.vue'
  385. import CopyApplicationDialog from '@/views/application/component/CopyApplicationDialog.vue'
  386. import MoveToDialog from '@/components/folder-tree/MoveToDialog.vue'
  387. import ResourceAuthorizationDrawer from '@/components/resource-authorization-drawer/index.vue'
  388. import ResourceTriggerDrawer from '@/views/trigger/ResourceTriggerDrawer.vue'
  389. import TemplateStoreDialog from '@/views/application/template-store/TemplateStoreDialog.vue'
  390. import ApplicationApi from '@/api/application/application'
  391. import WorkspaceApi from '@/api/workspace/workspace'
  392. import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
  393. import { i18n_name, resetUrl } from '@/utils/common'
  394. import { isWorkFlow } from '@/utils/application'
  395. import { dateFormat } from '@/utils/time'
  396. import { SourceTypeEnum } from '@/enums/common'
  397. import permissionMap from '@/permission'
  398. import { hasPermission } from '@/utils/permission'
  399. import { ComplexPermission } from '@/utils/permission/type'
  400. import { EditionConst, PermissionConst, RoleConst } from '@/utils/permission/data'
  401. import useStore from '@/stores'
  402. import { t } from '@/locales'
  403. const router = useRouter()
  404. const apiType = computed<'workspace'>(() => {
  405. return 'workspace'
  406. })
  407. const permissionPrecise = computed(() => {
  408. return permissionMap['application'][apiType.value]
  409. })
  410. const { folder, application, user } = useStore()
  411. const loading = ref(false)
  412. const search_type = ref('name')
  413. const search_form = ref<any>({
  414. name: '',
  415. create_user: '',
  416. publish_status: undefined,
  417. })
  418. const user_options = ref<any[]>([])
  419. const paginationConfig = reactive({
  420. current_page: 1,
  421. page_size: 30,
  422. total: 0,
  423. })
  424. const folderList = ref<any[]>([])
  425. const applicationList = ref<any[]>([])
  426. const CopyApplicationDialogRef = ref()
  427. // 批量操作
  428. const isBatch = ref(false)
  429. const multipleSelection = ref<any[]>([])
  430. const checkAll = ref(false)
  431. const isIndeterminate = computed(() => {
  432. return (
  433. multipleSelection.value.length > 0 &&
  434. multipleSelection.value.length < applicationList.value.length
  435. )
  436. })
  437. function batchSelectedHandle(bool: boolean) {
  438. isBatch.value = bool
  439. multipleSelection.value = []
  440. checkAll.value = false
  441. }
  442. const handleCheckAllChange = (val: CheckboxValueType) => {
  443. let bool
  444. if (isIndeterminate.value) {
  445. bool = true
  446. } else {
  447. bool = val as boolean
  448. }
  449. multipleSelection.value = bool ? applicationList.value.map((v) => v.id) : []
  450. checkAll.value = bool as boolean
  451. }
  452. const handleCheckedChatChange = (value: CheckboxValueType[]) => {
  453. const checkedCount = value.length
  454. checkAll.value = checkedCount === applicationList.value.length
  455. }
  456. const checkboxChange = (data?: any) => {
  457. const index = multipleSelection.value.indexOf(data?.id)
  458. if (index === -1) {
  459. multipleSelection.value.push(data?.id)
  460. } else {
  461. multipleSelection.value.splice(index, 1)
  462. }
  463. checkAll.value = multipleSelection.value.length === applicationList.value.length
  464. }
  465. function deleteMulApplication() {
  466. MsgConfirm(
  467. `${t('views.document.delete.confirmTitle1')} ${multipleSelection.value.length} ${t('views.application.delete.confirmTitle2')}`,
  468. t('views.paragraph.delete.confirmMessage'),
  469. {
  470. confirmButtonText: t('common.confirm'),
  471. confirmButtonClass: 'danger',
  472. },
  473. )
  474. .then(() => {
  475. ApplicationApi.delMulApplication(multipleSelection.value, loading).then(() => {
  476. batchSelectedHandle(false)
  477. paginationConfig.current_page = 1
  478. applicationList.value = []
  479. getList()
  480. MsgSuccess(t('views.document.delete.successMessage'))
  481. })
  482. })
  483. .catch(() => {})
  484. }
  485. const resourceTriggerDrawerRef = ref<InstanceType<typeof ResourceTriggerDrawer>>()
  486. const openTriggerDrawer = (data: any) => {
  487. resourceTriggerDrawerRef.value?.open(data)
  488. }
  489. const ResourceAuthorizationDrawerRef = ref()
  490. function openAuthorization(item: any) {
  491. ResourceAuthorizationDrawerRef.value.open(item.id)
  492. }
  493. const MoveToDialogRef = ref()
  494. function openMoveToDialog(data?: any) {
  495. let obj
  496. if (isBatch.value) {
  497. obj = {
  498. id_list: multipleSelection.value,
  499. }
  500. } else {
  501. // 仅2个参数就行
  502. obj = {
  503. id: data.id,
  504. folder_id: data.folder,
  505. }
  506. }
  507. MoveToDialogRef.value?.open(obj)
  508. }
  509. function refreshApplicationList(row: any) {
  510. if (row) {
  511. // 不是根目录才会移除
  512. if (folder.currentFolder?.parent_id) {
  513. const index = applicationList.value.findIndex((v) => v.id === row.id)
  514. applicationList.value.splice(index, 1)
  515. }
  516. } else {
  517. batchSelectedHandle(false)
  518. paginationConfig.current_page = 1
  519. applicationList.value = []
  520. getList()
  521. }
  522. }
  523. const goApp = (item: any) => {
  524. if (isBatch.value) {
  525. const index = multipleSelection.value.indexOf(item?.id)
  526. if (index === -1) {
  527. multipleSelection.value.push(item?.id)
  528. } else {
  529. multipleSelection.value.splice(index, 1)
  530. }
  531. checkAll.value = multipleSelection.value.length === applicationList.value.length
  532. return
  533. }
  534. router.push({ path: get_route(item) })
  535. }
  536. const get_route = (item: any) => {
  537. if (
  538. hasPermission(
  539. [
  540. new ComplexPermission(
  541. [RoleConst.USER],
  542. [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
  543. [],
  544. 'AND',
  545. ),
  546. RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
  547. PermissionConst.APPLICATION_OVERVIEW_READ.getWorkspacePermissionWorkspaceManageRole,
  548. PermissionConst.APPLICATION_OVERVIEW_READ.getApplicationWorkspaceResourcePermission(
  549. item.id,
  550. ),
  551. ],
  552. 'OR',
  553. )
  554. ) {
  555. return `/application/workspace/${item.id}/${item.type}/overview`
  556. } else if (
  557. hasPermission(
  558. [
  559. new ComplexPermission(
  560. [RoleConst.USER],
  561. [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
  562. [],
  563. 'AND',
  564. ),
  565. RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
  566. PermissionConst.APPLICATION_EDIT.getWorkspacePermissionWorkspaceManageRole,
  567. PermissionConst.APPLICATION_EDIT.getApplicationWorkspaceResourcePermission(item.id),
  568. ],
  569. 'OR',
  570. )
  571. ) {
  572. if (item.type == 'WORK_FLOW') {
  573. return `/application/workspace/${item.id}/workflow`
  574. } else {
  575. return `/application/workspace/${item.id}/${item.type}/setting`
  576. }
  577. } else if (
  578. hasPermission(
  579. [
  580. new ComplexPermission(
  581. [RoleConst.USER],
  582. [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
  583. [EditionConst.IS_EE, EditionConst.IS_PE],
  584. 'AND',
  585. ),
  586. new ComplexPermission(
  587. [RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
  588. [PermissionConst.APPLICATION_ACCESS_READ.getWorkspacePermissionWorkspaceManageRole],
  589. [EditionConst.IS_EE, EditionConst.IS_PE],
  590. 'OR',
  591. ),
  592. new ComplexPermission(
  593. [],
  594. [
  595. PermissionConst.APPLICATION_ACCESS_READ.getApplicationWorkspaceResourcePermission(
  596. item.id,
  597. ),
  598. ],
  599. [EditionConst.IS_EE, EditionConst.IS_PE],
  600. 'OR',
  601. ),
  602. ],
  603. 'OR',
  604. )
  605. ) {
  606. return `/application/workspace/${item.id}/${item.type}/access`
  607. } else if (
  608. hasPermission(
  609. [
  610. new ComplexPermission(
  611. [RoleConst.USER],
  612. [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
  613. [EditionConst.IS_EE, EditionConst.IS_PE],
  614. 'AND',
  615. ),
  616. new ComplexPermission(
  617. [RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
  618. [PermissionConst.APPLICATION_CHAT_USER_READ.getWorkspacePermissionWorkspaceManageRole],
  619. [EditionConst.IS_EE, EditionConst.IS_PE],
  620. 'OR',
  621. ),
  622. new ComplexPermission(
  623. [],
  624. [
  625. PermissionConst.APPLICATION_CHAT_USER_READ.getApplicationWorkspaceResourcePermission(
  626. item.id,
  627. ),
  628. ],
  629. [EditionConst.IS_EE, EditionConst.IS_PE],
  630. 'OR',
  631. ),
  632. ],
  633. 'OR',
  634. )
  635. ) {
  636. return `/application/workspace/${item.id}/${item.type}/chat-user`
  637. } else if (
  638. hasPermission(
  639. [
  640. new ComplexPermission(
  641. [RoleConst.USER],
  642. [PermissionConst.APPLICATION.getApplicationWorkspaceResourcePermission(item.id)],
  643. [],
  644. 'AND',
  645. ),
  646. PermissionConst.APPLICATION_CHAT_LOG_READ.getWorkspacePermissionWorkspaceManageRole,
  647. PermissionConst.APPLICATION_CHAT_LOG_READ.getApplicationWorkspaceResourcePermission(
  648. item.id,
  649. ),
  650. ],
  651. 'OR',
  652. )
  653. ) {
  654. return `/application//workspace${item.id}/${item.type}/chat-log`
  655. } else return `/application/`
  656. }
  657. const CreateApplicationDialogRef = ref()
  658. function openCreateDialog(type?: string) {
  659. CreateApplicationDialogRef.value.open(folder.currentFolder?.id || 'default', type)
  660. }
  661. const search_type_change = () => {
  662. search_form.value = { name: '', create_user: '' }
  663. }
  664. function toChat(row: any) {
  665. const api =
  666. row.type == 'WORK_FLOW'
  667. ? (id: string) => ApplicationApi.getApplicationDetail(id)
  668. : (id: string) => Promise.resolve({ data: row })
  669. api(row.id).then((ok) => {
  670. let aips = ok.data?.work_flow?.nodes
  671. ?.filter((v: any) => v.id === 'base-node')
  672. .map((v: any) => {
  673. return v.properties.api_input_field_list
  674. ? v.properties.api_input_field_list.map((v: any) => {
  675. return {
  676. name: v.variable,
  677. value: v.default_value,
  678. }
  679. })
  680. : v.properties.input_field_list
  681. ? v.properties.input_field_list
  682. .filter((v: any) => v.assignment_method === 'api_input')
  683. .map((v: any) => {
  684. return {
  685. name: v.variable,
  686. value: v.default_value,
  687. }
  688. })
  689. : []
  690. })
  691. .reduce((x: Array<any>, y: Array<any>) => [...x, ...y])
  692. aips = aips ? aips : []
  693. const apiParams = mapToUrlParams(aips) ? '?' + mapToUrlParams(aips) : ''
  694. ApplicationApi.getAccessToken(row.id, loading).then((res: any) => {
  695. const newUrl = application.location + res?.data?.access_token + apiParams
  696. window.open(newUrl)
  697. })
  698. })
  699. }
  700. function mapToUrlParams(map: any[]) {
  701. const params = new URLSearchParams()
  702. map.forEach((item: any) => {
  703. params.append(encodeURIComponent(item.name), encodeURIComponent(item.value))
  704. })
  705. return params.toString() // 返回 URL 查询字符串
  706. }
  707. function copyApplication(row: any) {
  708. ApplicationApi.getApplicationDetail(row.id, loading).then((res: any) => {
  709. if (res?.data) {
  710. CopyApplicationDialogRef.value.open(
  711. { ...res.data, model_id: res.data.model },
  712. folder.currentFolder?.id || 'default',
  713. )
  714. }
  715. })
  716. }
  717. function settingApplication(event: any, row: any) {
  718. if (isWorkFlow(row.type)) {
  719. if (event?.ctrlKey) {
  720. event?.preventDefault()
  721. event.stopPropagation()
  722. const newUrl = router.resolve({
  723. path: `/application/workspace/${row.id}/workflow`,
  724. }).href
  725. window.open(newUrl)
  726. } else {
  727. router.push({ path: `/application/workspace/${row.id}/workflow` })
  728. }
  729. } else {
  730. router.push({ path: `/application/workspace/${row.id}/${row.type}/setting` })
  731. }
  732. }
  733. function deleteApplication(row: any) {
  734. MsgConfirm(
  735. `${t('views.application.delete.confirmTitle')}${row.name} ?`,
  736. row.resource_count > 0
  737. ? t('views.application.delete.resourceCountMessage', row.resource_count)
  738. : '',
  739. {
  740. confirmButtonText: t('common.confirm'),
  741. cancelButtonText: t('common.cancel'),
  742. confirmButtonClass: 'danger',
  743. },
  744. )
  745. .then(() => {
  746. ApplicationApi.delApplication(row.id, loading).then(() => {
  747. const index = applicationList.value.findIndex((v) => v.id === row.id)
  748. applicationList.value.splice(index, 1)
  749. MsgSuccess(t('common.deleteSuccess'))
  750. })
  751. })
  752. .catch(() => {})
  753. }
  754. const exportApplication = (application: any) => {
  755. ApplicationApi.exportApplication(application.id, application.name, loading).catch((e) => {
  756. if (e.response.status !== 403) {
  757. e.response.data.text().then((res: string) => {
  758. MsgError(`${t('views.application.tip.ExportError')}:${JSON.parse(res).message}`)
  759. })
  760. }
  761. })
  762. }
  763. const elUploadRef = ref()
  764. const importApplication = (file: any) => {
  765. const formData = new FormData()
  766. formData.append('file', file.raw, file.name)
  767. elUploadRef.value.clearFiles()
  768. ApplicationApi.importApplication(folder.currentFolder.id, formData, loading)
  769. .then(async (res: any) => {
  770. if (res?.data) {
  771. applicationList.value = []
  772. user.profile()
  773. }
  774. })
  775. .then(() => {
  776. getList()
  777. })
  778. .catch((e) => {
  779. if (e.code === 400) {
  780. MsgConfirm(t('common.tip'), t('views.application.tip.professionalMessage'), {
  781. cancelButtonText: t('common.confirm'),
  782. confirmButtonText: t('common.professional'),
  783. }).then(() => {
  784. window.open('https://maxkb.cn/pricing.html', '_blank')
  785. })
  786. }
  787. })
  788. }
  789. // 文件夹相关
  790. const CreateFolderDialogRef = ref()
  791. function openCreateFolder() {
  792. CreateFolderDialogRef.value.open(SourceTypeEnum.APPLICATION, folder.currentFolder.id)
  793. }
  794. function getFolder(bool?: boolean) {
  795. const params = {}
  796. folder
  797. .asyncGetFolder(SourceTypeEnum.APPLICATION, params, apiType.value, loading)
  798. .then((res: any) => {
  799. folderList.value = res.data
  800. if (bool) {
  801. // 初始化刷新
  802. folder.setCurrentFolder(res.data?.[0] || {})
  803. }
  804. getList()
  805. })
  806. }
  807. function folderClickHandle(row: any) {
  808. if (row.id === folder.currentFolder?.id) {
  809. return
  810. }
  811. batchSelectedHandle(false)
  812. folder.setCurrentFolder(row)
  813. paginationConfig.current_page = 1
  814. applicationList.value = []
  815. getList()
  816. }
  817. function refreshFolder() {
  818. paginationConfig.current_page = 1
  819. applicationList.value = []
  820. getFolder()
  821. }
  822. function searchHandle() {
  823. paginationConfig.current_page = 1
  824. applicationList.value = []
  825. getList()
  826. }
  827. const templateStoreDialogRef = ref()
  828. function openTemplateStoreDialog() {
  829. templateStoreDialogRef.value?.open(folder.currentFolder.id)
  830. }
  831. function getList() {
  832. const params: any = {
  833. folder_id: folder.currentFolder?.id || 'default',
  834. }
  835. if (search_form.value[search_type.value]) {
  836. params[search_type.value] = search_form.value[search_type.value]
  837. }
  838. ApplicationApi.getApplication(paginationConfig, params, loading).then((res) => {
  839. paginationConfig.total = res.data.total
  840. applicationList.value = [...applicationList.value, ...res.data.records]
  841. })
  842. }
  843. onMounted(() => {
  844. getFolder(folder.currentFolder?.id ? false : true)
  845. WorkspaceApi.getAllMemberList(user.getWorkspaceId(), loading).then((res) => {
  846. user_options.value = res.data
  847. })
  848. })
  849. </script>
  850. <style lang="scss" scoped></style>