agilebuilder-ui 1.1.46 → 1.1.48-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/lib/{401-1bde8dc9.js → 401-a94cd05b.js} +1 -1
  2. package/lib/{404-48d76996.js → 404-eb21244b.js} +1 -1
  3. package/lib/{iframe-page-77e184a0.js → iframe-page-7add4333.js} +1 -1
  4. package/lib/index-7a601895.js +92839 -0
  5. package/lib/super-ui.css +1 -1
  6. package/lib/super-ui.js +33 -32
  7. package/lib/super-ui.umd.cjs +172 -133
  8. package/lib/{tab-content-iframe-index-39745d49.js → tab-content-iframe-index-483b398c.js} +1 -1
  9. package/lib/{tab-content-index-65696e56.js → tab-content-index-0862686f.js} +1 -1
  10. package/lib/{tache-subprocess-history-ef943f95.js → tache-subprocess-history-c80e8ed2.js} +1 -1
  11. package/package.json +7 -2
  12. package/packages/chat-embed/index.ts +6 -0
  13. package/packages/chat-embed/src/chat-embed-message.ts +79 -0
  14. package/packages/chat-embed/src/chat-embed.css +117 -0
  15. package/packages/chat-embed/src/chat-sender.vue +240 -0
  16. package/packages/chat-embed/src/header.vue +50 -0
  17. package/packages/chat-embed/src/index.vue +425 -0
  18. package/packages/chat-embed/src/recommendation-message.vue +37 -0
  19. package/packages/chat-embed/src/util.ts +33 -0
  20. package/packages/department-tree-inline/src/department-multi-tree-inline.vue +42 -34
  21. package/packages/department-tree-inline/src/department-single-tree-inline.vue +53 -42
  22. package/packages/department-tree-inline/src/department-tree-service.js +17 -11
  23. package/packages/department-tree-inline/src/search-result.vue +187 -219
  24. package/packages/department-tree-mobile/src/department-tree-inline-app.vue +17 -4
  25. package/packages/department-user-tree-inline/src/department-user-multiple-tree-inline.vue +52 -43
  26. package/packages/department-user-tree-inline/src/department-user-single-tree-inline.vue +52 -42
  27. package/packages/department-user-tree-inline/src/department-user-tree-multi-service.js +23 -13
  28. package/packages/department-user-tree-inline/src/department-user-tree-single-service.js +9 -5
  29. package/packages/department-user-tree-inline/src/group-user-tree-service.js +17 -11
  30. package/packages/department-user-tree-inline/src/search-result.vue +207 -220
  31. package/packages/department-user-tree-mobile/src/department-user-tree-inline-app.vue +14 -3
  32. package/packages/dynamic-source-select/src/dynamic-source-select-service.js +7 -2
  33. package/packages/empty-state/index.vue +28 -0
  34. package/packages/fs-preview/src/fs-preview.vue +12 -3
  35. package/packages/fs-upload/src/fs-upload-multi.vue +6 -4
  36. package/packages/fs-upload/src/fs-upload-single.vue +7 -6
  37. package/packages/fs-upload/src/fs-upload.vue +3 -1
  38. package/packages/fs-upload/src/see-big-picture.vue +3 -0
  39. package/packages/fs-upload-list/src/fs-upload-list.vue +8 -2
  40. package/packages/fs-upload-new/src/fs-button-upload.vue +11 -4
  41. package/packages/fs-upload-new/src/fs-drag-upload.vue +11 -4
  42. package/packages/fs-upload-new/src/fs-preview-new.vue +8 -5
  43. package/packages/fs-upload-new/src/fs-upload-new.vue +17 -0
  44. package/packages/index.js +16 -13
  45. package/packages/json-view/index.ts +3 -0
  46. package/packages/json-view/json-view-dialog.vue +53 -0
  47. package/packages/json-view/json-view.vue +126 -0
  48. package/packages/plugins/export-data-new.js +2 -0
  49. package/packages/super-grid/src/apis.js +11 -0
  50. package/packages/super-grid/src/components/grid-icon.vue +6 -3
  51. package/packages/super-grid/src/custom-formatter.js +15 -2
  52. package/packages/super-grid/src/dynamic-input.vue +46 -4
  53. package/packages/super-grid/src/formatter.js +5 -1
  54. package/packages/super-grid/src/normal-column-content.vue +30 -38
  55. package/packages/super-grid/src/normal-column.vue +8 -1
  56. package/packages/super-grid/src/super-grid.vue +23 -10
  57. package/packages/utils/utils.js +27 -9
  58. package/packages/workgroup-tree-inline/src/search-result.vue +2 -1
  59. package/packages/workgroup-tree-inline/src/workgroup-tree-inline.vue +50 -41
  60. package/packages/workgroup-tree-mobile/src/workgroup-tree-inline-app.vue +16 -5
  61. package/packages/workgroup-user-tree-inline/src/search-result.vue +2 -1
  62. package/packages/workgroup-user-tree-inline/src/workgroup-tree-inline-service.js +30 -24
  63. package/packages/workgroup-user-tree-inline/src/workgroup-user-tree-inline.vue +49 -37
  64. package/packages/workgroup-user-tree-mobile/src/workgroup-user-tree-inline-app.vue +281 -222
  65. package/src/assets/chat-embed/avatar.png +0 -0
  66. package/src/i18n/langs/cn.js +20 -6
  67. package/src/i18n/langs/en.js +19 -5
  68. package/src/store/modules/chat-ai-store.ts +78 -0
  69. package/src/store/modules/tab-content.js +9 -3
  70. package/src/styles/index.scss +45 -0
  71. package/src/utils/auth.js +10 -7
  72. package/src/utils/chat-ai-util.ts +31 -0
  73. package/src/utils/common-util.js +78 -8
  74. package/src/utils/global-prop.js +17 -0
  75. package/src/utils/insert_css.js +14 -1
  76. package/src/utils/jump-page-utils.js +8 -4
  77. package/src/views/dsc-component/Sidebar/SidebarItem.vue +6 -0
  78. package/src/views/dsc-component/tabs/tab-content.vue +6 -0
  79. package/lib/index-465b0d69.js +0 -73558
@@ -0,0 +1,425 @@
1
+ <template>
2
+ <!-- <div v-permission="'mc.ragFlow.converseWithChat'"> -->
3
+ <div v-if="enableAiChat">
4
+ <div ref="chatIcon" :style="style" style="position: fixed; cursor: pointer; z-index: 100">
5
+ <img src="https://maxkb.fit2cloud.com/ui/MaxKB.gif" @click="showChatDialog" />
6
+ </div>
7
+ <transition name="slide-up">
8
+ <div v-show="showChatVisable" ref="chatContainerRef" class="chat-container">
9
+ <!-- 头部 -->
10
+ <Header
11
+ :aiAvatar="aiAvatar"
12
+ :dialogFullScreen="dialogFullScreen"
13
+ @expandDialog="expandDialog"
14
+ @showChatDialog="showChatDialog"
15
+ />
16
+ <!-- 聊天内容展示 -->
17
+ <!-- <div ref="talkMainRef" :key="talkMainRefKey" class="chat-embed__main"> -->
18
+ <div ref="talkMainRef" class="chat-embed__main" :key="talkMainRefKey">
19
+ <div class="chat-embed__main_content">
20
+ <BubbleList :list="messageList" :max-height="bubbleMaxHeight" :is-fog="true">
21
+ <template #content="{ item }">
22
+ <template v-if="!item.isRecommend && item.thinkingContent !== null">
23
+ <!-- ai消息正在回复中 -->
24
+ <Thinking
25
+ style="margin-bottom: 5px"
26
+ v-model="item.showThinkingContent"
27
+ :status="item.thinkingStatus"
28
+ auto-collapse
29
+ :content="item.thinkingContent"
30
+ max-width="100%"
31
+ :typing="{ interval: 20 }"
32
+ duration=".3s"
33
+ class="thinking-chain-warp"
34
+ >
35
+ </Thinking>
36
+ </template>
37
+ <template v-if="item.content">
38
+ <!-- ai消息和用户消息 -->
39
+ <div
40
+ :class="item.role === 'ai' ? 'content-container' : 'content-borderless-container'"
41
+ :style="{ maxWidth: bubbleMaxWidth }"
42
+ >
43
+ <Typewriter
44
+ v-if="item.role === 'ai' && !item.isRecommend"
45
+ :content="item.content"
46
+ :typing="{ interval: 10 }"
47
+ :is-markdown="true"
48
+ />
49
+ <template v-else-if="item.role === 'user'">
50
+ {{ item.content }}
51
+ <template v-if="item.additionalData?.length > 0">
52
+ <el-divider border-style="dashed" />
53
+ <el-tag type="primary">
54
+ <template #default>
55
+ <div
56
+ style="
57
+ display: flex;
58
+ align-items: center;
59
+ flex-shrink: 0;
60
+ min-width: max-content;
61
+ margin-left: auto;
62
+ gap: 10px;
63
+ "
64
+ >
65
+ <el-icon><Paperclip /></el-icon>
66
+ {{ item.additionalDataLabel }}
67
+ </div>
68
+ </template>
69
+ </el-tag>
70
+ <div
71
+ style="
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ margin-top: 10px;
76
+ gap: 10px;
77
+ "
78
+ >
79
+ <el-button plain round size="small" @click="viewJson(item.additionalData)">
80
+ <el-icon><View /></el-icon> <span>预览数据</span>
81
+ </el-button>
82
+ <el-button
83
+ plain
84
+ round
85
+ size="small"
86
+ @click="downloadJsonData(item.additionalData, item.menuName)"
87
+ >
88
+ <el-icon><Download /></el-icon> 下载数据
89
+ </el-button>
90
+ </div>
91
+ </template>
92
+ </template>
93
+ <template v-else> {{ item.content }} </template>
94
+ </div>
95
+ <template v-if="item.recommendations && item.recommendations.length > 0">
96
+ <!-- 推荐内容的消息 -->
97
+ <RecommendationMessage :item="item" @clickRecommendation="clickRecommendation" />
98
+ </template>
99
+ </template>
100
+ </template>
101
+ <template #footer="{ item }">
102
+ <div
103
+ v-if="item.role === 'ai' && !item.isRecommend && item.thinkingStatus !== 'thinking'"
104
+ class="footer-container"
105
+ >
106
+ <el-tooltip class="box-item" effect="dark" :content="$t('chatEmbed.regenerate')">
107
+ <el-button type="info" :icon="Refresh" size="small" circle @click="regenerateQuestion(item)" />
108
+ </el-tooltip>
109
+ <el-tooltip class="box-item" effect="dark" :content="$t('chatEmbed.copy')">
110
+ <el-button
111
+ type="info"
112
+ color="#626aef"
113
+ :icon="DocumentCopy"
114
+ size="small"
115
+ circle
116
+ @click="cpoyContent(item)"
117
+ />
118
+ </el-tooltip>
119
+ </div>
120
+ </template>
121
+ </BubbleList>
122
+ </div>
123
+ <!-- 对话输入框 -->
124
+ <div ref="talkInputRef" class="chat-embed__input_container">
125
+ <ChatSender
126
+ :loading="loading"
127
+ @submit-question="sendQuestion"
128
+ @new-chat-session="newChatSession"
129
+ @handle-cancel="handleCancel"
130
+ @view-json="viewJson"
131
+ />
132
+ </div>
133
+ </div>
134
+ </div>
135
+ </transition>
136
+ <json-view-dialog v-model="jsonDialogVisible" :json-object="jsonObject" :append-to-body="true" title="预览数据" />
137
+ </div>
138
+ </template>
139
+ <script setup lang="ts">
140
+ import { ref, onMounted, onUnmounted, nextTick } from 'vue'
141
+ import { Refresh, DocumentCopy } from '@element-plus/icons-vue'
142
+ import { BubbleList, Thinking, useXStream, Typewriter } from 'vue-element-plus-x'
143
+ import { useDraggable } from '@vueuse/core'
144
+ import { ElMessage } from 'element-plus'
145
+ import { getMessageTemplate, defaultMessage } from './chat-embed-message'
146
+ import RecommendationMessage from './recommendation-message.vue'
147
+ import { BubbleProps } from 'vue-element-plus-x/types/Bubble'
148
+ import { useI18n } from 'vue-i18n'
149
+ import Header from './header.vue'
150
+ import ChatSender from './chat-sender.vue'
151
+ import { JsonViewDialog } from '../../json-view'
152
+ import { generateFileName, downloadJsonFile } from './util.ts'
153
+
154
+ const enableAiChat = ref(false)
155
+ if (window.$vueApp.config.globalProperties.enableAiChat) {
156
+ enableAiChat.value = true
157
+ }
158
+
159
+ const { t } = useI18n()
160
+ const chatIcon = ref()
161
+ let isActualClick = ref(true)
162
+ const isActualClickTimer = ref(null)
163
+
164
+ const jsonDialogVisible = ref(false)
165
+ const jsonObject = ref({})
166
+
167
+ const initialX = document.documentElement.clientWidth - 100
168
+ const initialY = document.documentElement.clientHeight - 100
169
+ const { x, y, style } = useDraggable(chatIcon, {
170
+ // 聊天图标的初始位置
171
+ initialValue: { x: initialX, y: initialY },
172
+ preventDefault: true,
173
+ onStart() {
174
+ // 拖拽开始时重置状态
175
+ isActualClick.value = true
176
+ },
177
+ onMove(position) {
178
+ isActualClick.value = false
179
+ // 限制拖拽范围 防止拖出屏幕外
180
+ const maxX = window.innerWidth - chatIcon.value.offsetWidth
181
+ const maxY = window.innerHeight - chatIcon.value.offsetHeight
182
+ position.x = Math.max(0, Math.min(position.x, maxX))
183
+ position.y = Math.max(0, Math.min(position.y, maxY))
184
+ },
185
+ onEnd() {
186
+ adjustChatIconPosition()
187
+ // 延迟重置确保 click 事件先处理
188
+ setTimeout(() => (isActualClick.value = true), 50)
189
+ }
190
+ })
191
+
192
+ function adjustChatIconPosition() {
193
+ if (!chatIcon.value) return
194
+ const maxX = window.innerWidth - chatIcon.value.offsetWidth
195
+ const maxY = window.innerHeight - chatIcon.value.offsetHeight
196
+ if (x.value > maxX) x.value = maxX
197
+ if (y.value > maxY) y.value = maxY
198
+ }
199
+
200
+ const talkInputRef = ref()
201
+ // 显示聊天窗口的状态
202
+ const showChatVisable = ref(false)
203
+ // 聊天窗口的引用
204
+ const chatContainerRef = ref()
205
+ // 聊天窗口主区域的引用
206
+ const talkMainRef = ref()
207
+ // 聊天输入框状态
208
+ const loading = ref(false)
209
+ // 聊天窗口是否全屏
210
+ const dialogFullScreen = ref(false)
211
+
212
+ const talkMainRefKey = ref(0)
213
+
214
+ const bubbleMaxWidth = ref('')
215
+ const bubbleMaxHeight = ref('500px')
216
+
217
+ const aiAvatar = ref('https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png')
218
+
219
+ // 聊天内容
220
+ const messageList: any = ref([])
221
+ // 默认ai提示消息
222
+ messageList.value.push(defaultMessage)
223
+ // messageList.value.push(getMessageTemplate('user', '11111111111', true))
224
+ // 正在生成的ai消息
225
+ const answerContent: any = ref({})
226
+ // 后端会话session_id
227
+ const session_id = ref(null)
228
+
229
+ onMounted(() => {
230
+ window.addEventListener('resize', adjustChatIconPosition)
231
+ })
232
+
233
+ onUnmounted(() => {
234
+ window.removeEventListener('resize', adjustChatIconPosition)
235
+ // 清除定时器
236
+ if (isActualClickTimer.value) {
237
+ clearTimeout(isActualClickTimer.value)
238
+ }
239
+ })
240
+
241
+ // 处理聊天窗口的显示和隐藏
242
+ function showChatDialog() {
243
+ if (isActualClick.value) {
244
+ showChatVisable.value = !showChatVisable.value
245
+ talkMainRefKey.value++
246
+ nextTick(() => {
247
+ setHeightAndWidth()
248
+ })
249
+ }
250
+ }
251
+
252
+ const { cancel, data } = useXStream()
253
+
254
+ // 发送聊天内容
255
+ function sendQuestion(submitData: any) {
256
+ const question = submitData.question
257
+ if (!question) {
258
+ return
259
+ }
260
+ data.value = []
261
+ const message = getMessageTemplate('user', question, true)
262
+ if (submitData.additionalData && submitData.additionalData.length > 0) {
263
+ message.additionalData = submitData.additionalData
264
+ message.additionalDataLabel = submitData.additionalDataLabel
265
+ message.menuName = submitData.menuName
266
+ message.menuCode = submitData.menuCode
267
+ }
268
+ messageList.value.push(message)
269
+ // console.log('submit', question)
270
+ loading.value = true
271
+ if (!session_id.value) {
272
+ session_id.value = new Date().getTime().toString()
273
+ }
274
+ // 创建一个新的消息对象
275
+ answerContent.value = getMessageTemplate('ai', '', false)
276
+ // 设置消息的状态为正在思考 并存下历史的 question信息
277
+ answerContent.value.thinkingStatus = 'thinking'
278
+ answerContent.value.question = question
279
+ answerContent.value.menuName = submitData.menuName
280
+ answerContent.value.menuCode = submitData.menuCode
281
+ answerContent.value.askAdditionalData = submitData.additionalData
282
+ messageList.value.push(answerContent.value)
283
+ try {
284
+ window.$vueApp.config.globalProperties.$http
285
+ .post(window.$vueApp.config.globalProperties.baseAPI + '/component/ai/multiple-fuck', {
286
+ question: question,
287
+ messageId: session_id.value,
288
+ data: JSON.stringify(submitData.additionalData)
289
+ })
290
+ .then((res) => {
291
+ // 创建一个新的消息对象
292
+ answerContent.value.thinkingStatus = 'end'
293
+ answerContent.value.content = res
294
+ answerContent.value = {}
295
+ loading.value = false
296
+ })
297
+ } catch (err) {
298
+ console.error('Fetch error:', err)
299
+ messageList.push(getMessageTemplate('ai', t('chatEmbed.requestFailed'), false))
300
+ loading.value = false
301
+ }
302
+ }
303
+
304
+ // 处理聊天内容的取消
305
+ function handleCancel() {
306
+ loading.value = false
307
+ messageList.value[messageList.value.length - 1].thinkingStatus = 'end'
308
+ cancel()
309
+ }
310
+
311
+ // 处理聊天窗口的全屏和缩小
312
+ function expandDialog() {
313
+ dialogFullScreen.value = !dialogFullScreen.value
314
+ setHeightAndWidth()
315
+ }
316
+
317
+ function setHeightAndWidth() {
318
+ let heightVh = 100
319
+ let widthVw = 40
320
+ if (dialogFullScreen.value) {
321
+ heightVh = 100
322
+ widthVw = 100
323
+ }
324
+ chatContainerRef.value.style.height = `calc(${heightVh}vh - var(--chat-padding) * 2)`
325
+ chatContainerRef.value.style.width = `calc(${widthVw}vw - var(--chat-padding) * 2)`
326
+ // talkMainRef.value.style.height = `calc(${heightVh}vh - var(--header-height) - var(--chat-padding) * 2)`
327
+ const talkHeight = talkInputRef.value.offsetHeight
328
+ // alert(`talkHeight: ${talkHeight}`)
329
+ // bubbleMaxHeight.value = `calc(${heightVh}vh - var(--header-height) - var(--chat-padding) * 5 - 144px)`
330
+ nextTick(() => {
331
+ const talkHeight = talkInputRef.value?.offsetHeight || 80
332
+ // 定义具体的像素值
333
+ const headerHeight = 56
334
+ const chatPadding = 12
335
+ // 更清晰的计算:总高度 - 头部 - 输入框 - 各种padding和间距
336
+ bubbleMaxHeight.value = `calc(${heightVh}vh - ${headerHeight}px - ${talkHeight}px - ${chatPadding * 4}px)`
337
+ talkMainRefKey.value++
338
+ })
339
+ }
340
+
341
+ // 点击推荐内容的处理函数
342
+ // 这里可以根据需要进行处理,比如发送请求、更新状态等
343
+ function clickRecommendation(item: BubbleProps) {
344
+ console.log('clickRecommendation', item)
345
+ sendQuestion(item.content)
346
+ }
347
+
348
+ function regenerateQuestion(answerData) {
349
+ sendQuestion({
350
+ question: answerData.question,
351
+ additionalData: answerData.additionalData,
352
+ additionalDataLabel: answerData.additionalDataLabel,
353
+ menuName: answerData.menuName,
354
+ menuCode: answerData.menuCode
355
+ })
356
+ }
357
+
358
+ function cpoyContent(item: BubbleProps) {
359
+ // 复制内容到剪贴板
360
+ if (!item.content) {
361
+ return
362
+ }
363
+ navigator.clipboard.writeText(item.content).then(() => {
364
+ ElMessage({
365
+ message: t('chatEmbed.copySuccess'),
366
+ type: 'success'
367
+ })
368
+ })
369
+ }
370
+
371
+ function newChatSession() {
372
+ // 清空聊天记录
373
+ messageList.value = []
374
+ if (session_id.value) {
375
+ try {
376
+ window.$vueApp.config.globalProperties.$http
377
+ .post(window.$vueApp.config.globalProperties.baseAPI + '/component/ai/multiple-fuck/clear/' + session_id.value)
378
+ .then((res) => {
379
+ //
380
+ })
381
+ } catch (err) {
382
+ console.error('Fetch error:', err)
383
+ messageList.push(getMessageTemplate('ai', t('chatEmbed.requestFailed'), false))
384
+ loading.value = false
385
+ }
386
+ }
387
+ session_id.value = null
388
+ // 重置加载状态
389
+ loading.value = false
390
+ messageList.value.push(defaultMessage)
391
+ }
392
+
393
+ function viewJson(viewData: any) {
394
+ jsonObject.value = viewData
395
+ jsonDialogVisible.value = true
396
+ }
397
+
398
+ // 下载 JSON 数据功能
399
+ function downloadJsonData(data: any, fileName: string) {
400
+ try {
401
+ downloadJsonFile(data, generateFileName(fileName || 'data'))
402
+ } catch (error) {
403
+ console.error('下载失败:', error)
404
+ }
405
+ }
406
+ </script>
407
+ <style lang="scss" rel="stylesheet/scss" scoped>
408
+ @import url('./chat-embed.css');
409
+ :root {
410
+ --header-height: 56px;
411
+ --chat-padding: 12px;
412
+ }
413
+
414
+ h4 {
415
+ font-size: 16px;
416
+ margin-top: 0px;
417
+ margin-bottom: 0px;
418
+ }
419
+ :deep(.el-bubble-content-wrapper .el-bubble-content) {
420
+ padding: 0 !important;
421
+ }
422
+ :deep(.el-divider--horizontal) {
423
+ margin: 5px 0;
424
+ }
425
+ </style>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <Bubble
3
+ v-for="(recommendation, index) in item.recommendations"
4
+ class="chat-embed__recommendation"
5
+ :no-style="true"
6
+ variant="borderless"
7
+ >
8
+ <template v-if="index === 0" #header>
9
+ <div class="content-container-header">推荐内容</div>
10
+ </template>
11
+ <template #content>
12
+ <div class="content-borderless-container" @click="clickRecommendation(recommendation)">
13
+ {{ recommendation.content }}
14
+ </div>
15
+ </template>
16
+ </Bubble>
17
+ </template>
18
+ <script lang="ts" setup>
19
+ import { Bubble } from 'vue-element-plus-x'
20
+ import { defineProps, defineEmits } from 'vue'
21
+ const props = defineProps({
22
+ item: {
23
+ type: Object,
24
+ required: true
25
+ }
26
+ })
27
+
28
+ const emit = defineEmits(['clickRecommendation'])
29
+
30
+ const clickRecommendation = (recommendation: any) => {
31
+ emit('clickRecommendation', recommendation)
32
+ }
33
+ </script>
34
+
35
+ <style scoped>
36
+ @import url('./chat-embed.css');
37
+ </style>
@@ -0,0 +1,33 @@
1
+ // 生成文件名
2
+ function generateFileName(fileName: string): string {
3
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)
4
+ const safeName = fileName.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_')
5
+ return `${safeName}_${timestamp}.json`
6
+ }
7
+
8
+ // 核心下载方法
9
+ function downloadJsonFile(data: any, fileName: string) {
10
+ // 将数据转换为格式化的 JSON 字符串
11
+ const jsonString = JSON.stringify(data, null, 2)
12
+
13
+ // 创建 Blob 对象
14
+ const blob = new Blob([jsonString], {
15
+ type: 'application/json;charset=utf-8'
16
+ })
17
+
18
+ // 创建下载链接
19
+ const url = URL.createObjectURL(blob)
20
+ const link = document.createElement('a')
21
+ link.href = url
22
+ link.download = fileName
23
+
24
+ // 触发下载
25
+ document.body.appendChild(link)
26
+ link.click()
27
+
28
+ // 清理
29
+ document.body.removeChild(link)
30
+ URL.revokeObjectURL(url)
31
+ }
32
+
33
+ export { generateFileName, downloadJsonFile }
@@ -19,39 +19,42 @@
19
19
  </el-autocomplete>
20
20
  </el-header>
21
21
  <el-main style="padding: 10px">
22
- <div
23
- v-if="!searchValue"
24
- style="padding-top: 5px; overflow: auto; width: 100%; display: inline-block !important"
25
- >
26
- <el-tree
27
- ref="deparmentTree"
28
- :filter-node-method="filterNode"
29
- :load="loadNode"
30
- :props="defaultProps"
31
- :show-checkbox="true"
32
- check-strictly
33
- lazy
34
- node-key="id"
35
- @check="handleCheckNode"
36
- @check-change="handleCheckChange"
37
- @node-expand="handleNodeExpand"
38
- @node-click="handleNodeClick"
22
+ <template v-if="!searchValue">
23
+ <div
24
+ v-if="canShowOrgTree"
25
+ style="padding-top: 5px; overflow: auto; width: 100%; display: inline-block !important"
39
26
  >
40
- <template #default="{ node, data }">
41
- <span>
42
- <el-icon>
43
- <Menu v-if="node.data.id === -1 || node.data.branch" />
44
- <Tickets v-else-if="node.data.id === -2 || node.data.id === -3" />
45
- <Calendar v-else />
46
- </el-icon>
47
- <span :title="node.label">
48
- {{ node.label }}
27
+ <el-tree
28
+ ref="deparmentTree"
29
+ :filter-node-method="filterNode"
30
+ :load="loadNode"
31
+ :props="defaultProps"
32
+ :show-checkbox="true"
33
+ check-strictly
34
+ lazy
35
+ node-key="id"
36
+ @check="handleCheckNode"
37
+ @check-change="handleCheckChange"
38
+ @node-expand="handleNodeExpand"
39
+ @node-click="handleNodeClick"
40
+ >
41
+ <template #default="{ node, data }">
42
+ <span>
43
+ <el-icon>
44
+ <Menu v-if="node.data.id === -1 || node.data.branch" />
45
+ <Tickets v-else-if="node.data.id === -2 || node.data.id === -3" />
46
+ <Calendar v-else />
47
+ </el-icon>
48
+ <span :title="node.label">
49
+ {{ node.label }}
50
+ </span>
49
51
  </span>
50
- </span>
51
- </template>
52
- </el-tree>
53
- </div>
54
-
52
+ </template>
53
+ </el-tree>
54
+ </div>
55
+ <!-- 暂无信息 -->
56
+ <EmptyState v-else style="width: 100%; height: 100%" />
57
+ </template>
55
58
  <div v-if="searchValue && searchValue.length > 0" style="height: 100%; overflow: hidden">
56
59
  <user-result
57
60
  :grid-data="searchResult"
@@ -96,7 +99,7 @@ import utils from '../../utils/utils'
96
99
  import departmentTreeService from './department-tree-service'
97
100
  import UserResult from './search-result.vue'
98
101
  import memoryCacheUtils from '../../utils/memory-cache-utils'
99
-
102
+ import EmptyState from '../../empty-state/index.vue'
100
103
  export default {
101
104
  data() {
102
105
  return {
@@ -139,12 +142,14 @@ export default {
139
142
  memoryCacheKey: 'DEPARTMENT_MEMORY_KEY',
140
143
  // 记忆选择数据, 搜索框获得焦点后,下拉显示最近选中的10个人,倒序排列,最后选中的在最上面显示。
141
144
  memoryCacheData: [],
142
- ElIconSearch
145
+ ElIconSearch,
146
+ canShowOrgTree: false
143
147
  }
144
148
  },
145
149
  name: 'InlineDepartmentMultiTree',
146
150
  components: {
147
- UserResult
151
+ UserResult,
152
+ EmptyState
148
153
  },
149
154
  props: {
150
155
  checkStrictly: {
@@ -199,6 +204,9 @@ export default {
199
204
  }
200
205
  },
201
206
  created() {
207
+ utils.canShowOrgTree().then((showOrgTree) => {
208
+ this.canShowOrgTree = showOrgTree
209
+ })
202
210
  this.initSelectDepts(this.searchField, this.selectDepartmentInfo, this.separator).then((selectUsers) => {
203
211
  if (selectUsers) {
204
212
  this.selectResult = selectUsers