@jari-ace/element-plus-component 0.4.4 → 0.5.1

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 (54) hide show
  1. package/dist/components/autoComplete/JaAutoComplete.vue.d.ts +24 -24
  2. package/dist/components/avatar/JaAvatar.vue.d.ts.map +1 -1
  3. package/dist/components/avatar/JaAvatar.vue.js +4 -2
  4. package/dist/components/avatar/JaAvatar.vue.js.map +1 -1
  5. package/dist/components/flowShell/FlowFormShell.vue.d.ts +400 -0
  6. package/dist/components/flowShell/FlowFormShell.vue.d.ts.map +1 -0
  7. package/dist/components/flowShell/FlowFormShell.vue.js +671 -0
  8. package/dist/components/flowShell/FlowFormShell.vue.js.map +1 -0
  9. package/dist/components/flowShell/index.d.ts +4 -0
  10. package/dist/components/flowShell/index.d.ts.map +1 -0
  11. package/dist/components/flowShell/index.js +4 -0
  12. package/dist/components/flowShell/index.js.map +1 -0
  13. package/dist/components/formItem/JaFormItem.vue.d.ts +2 -2
  14. package/dist/components/index.d.ts +1 -0
  15. package/dist/components/index.d.ts.map +1 -1
  16. package/dist/components/index.js +1 -0
  17. package/dist/components/index.js.map +1 -1
  18. package/dist/components/input/JaInput.vue.d.ts +14 -14
  19. package/dist/components/inputI18n/InputI18n.vue.d.ts.map +1 -1
  20. package/dist/components/inputI18n/InputI18n.vue.js +2 -0
  21. package/dist/components/inputI18n/InputI18n.vue.js.map +1 -1
  22. package/dist/components/inputI18n/JaInputI18n.vue.d.ts +70 -70
  23. package/dist/components/inputNumber/JaInputNumber.vue.d.ts +18 -18
  24. package/dist/components/scrollbar/Scrollbar.vue.d.ts +10 -10
  25. package/dist/components/select/JaSelect.vue.d.ts +70 -70
  26. package/dist/components/switch/JaSwitch.vue.d.ts +2 -2
  27. package/dist/components/upload/JaUploader.vue.d.ts +16 -4
  28. package/dist/components/upload/JaUploader.vue.d.ts.map +1 -1
  29. package/dist/components/upload/index.d.ts +21 -5
  30. package/dist/components/upload/index.d.ts.map +1 -1
  31. package/dist/components/upload/uploader.vue.d.ts +7 -1
  32. package/dist/components/upload/uploader.vue.d.ts.map +1 -1
  33. package/dist/components/upload/uploader.vue.js +428 -202
  34. package/dist/components/upload/uploader.vue.js.map +1 -1
  35. package/dist/components/userGroupTree/src/userGroupTree.vue.d.ts +4 -4
  36. package/dist/components/userPicker/src/JaUserList.vue.d.ts.map +1 -1
  37. package/dist/components/userPicker/src/JaUserList.vue.js +0 -2
  38. package/dist/components/userPicker/src/JaUserList.vue.js.map +1 -1
  39. package/dist/components/userTag/UserInfoTag.vue.d.ts +7 -1
  40. package/dist/components/userTag/UserInfoTag.vue.d.ts.map +1 -1
  41. package/dist/components/userTag/UserInfoTag.vue.js +67 -50
  42. package/dist/components/userTag/UserInfoTag.vue.js.map +1 -1
  43. package/lib/index.css +2 -2
  44. package/lib/index.js +12307 -11479
  45. package/lib/index.umd.cjs +36 -36
  46. package/package.json +4 -2
  47. package/packages/components/avatar/JaAvatar.vue +4 -2
  48. package/packages/components/flowShell/FlowFormShell.vue +628 -0
  49. package/packages/components/flowShell/index.ts +5 -0
  50. package/packages/components/index.ts +1 -0
  51. package/packages/components/inputI18n/InputI18n.vue +3 -5
  52. package/packages/components/upload/uploader.vue +258 -39
  53. package/packages/components/userPicker/src/JaUserList.vue +0 -1
  54. package/packages/components/userTag/UserInfoTag.vue +28 -6
@@ -10,13 +10,12 @@ import {
10
10
  useLoginUser
11
11
  } from "@jari-ace/app-bolts";
12
12
  import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
13
- import { ArrowDown, Download, Upload, WarningFilled } from "@element-plus/icons-vue";
13
+ import { ArrowDown, Document, Download, Upload, WarningFilled, Picture, VideoPlay, Headset } from "@element-plus/icons-vue";
14
14
  import {
15
15
  useSystemClassificationLevelMap,
16
16
  useSystemClassificationLevels
17
17
  } from "../../hooks/useClassificationLevels";
18
18
  import Ace = Jari.Ace;
19
- import { ElMessageBox } from "element-plus";
20
19
  import "@uppy/core/css/style.min.css";
21
20
  import "@uppy/dashboard/css/style.min.css";
22
21
  import "@uppy/audio/css/style.min.css";
@@ -33,8 +32,8 @@ import Dashboard from "@uppy/dashboard";
33
32
  import ImageEditor from "@uppy/image-editor";
34
33
  import prettyBytes from "pretty-bytes";
35
34
  import PdfViewerModal from "./pdf-viewer/PdfViewerModal.vue";
36
-
37
35
  import {
36
+ ElMessageBox,
38
37
  ElTable,
39
38
  ElTableColumn,
40
39
  ElButton,
@@ -43,12 +42,13 @@ import {
43
42
  ElDropdownMenu,
44
43
  ElIcon,
45
44
  ElTag,
46
- ElTooltip
45
+ ElTooltip,
46
+ ElPopover
47
47
  } from "element-plus";
48
48
  import type { AceFile } from "./types";
49
49
  import { fa } from "element-plus/es/locales.mjs";
50
50
 
51
- const props = defineProps<{
51
+ const props = withDefaults(defineProps<{
52
52
  /**
53
53
  * 应用名
54
54
  */
@@ -89,7 +89,13 @@ const props = defineProps<{
89
89
  * 是否允许预览,为空表示采用应用里的附件设置
90
90
  */
91
91
  allowPreview?: boolean,
92
- }>();
92
+ /**
93
+ * 布局方式: list-列表布局(默认), inline-行内布局
94
+ */
95
+ layout?: 'list' | 'inline'
96
+ }>(), {
97
+ layout: 'list'
98
+ });
93
99
  const attachId = defineModel<string>({
94
100
  required: false
95
101
  });
@@ -512,6 +518,36 @@ watch(() => props.attachToken, () => {
512
518
 
513
519
  watch(()=> props.classificationLevel, updateAllowedClassificationLevels)
514
520
 
521
+ function getFileIcon(fileName: string) {
522
+ if (!fileName) return Document;
523
+ const ext = fileName.split('.').pop()?.toLowerCase();
524
+ switch (ext) {
525
+ case 'jpg':
526
+ case 'jpeg':
527
+ case 'png':
528
+ case 'gif':
529
+ case 'bmp':
530
+ case 'webp':
531
+ case 'svg':
532
+ return Picture;
533
+ case 'mp4':
534
+ case 'mkv':
535
+ case 'avi':
536
+ case 'mov':
537
+ case 'wmv':
538
+ case 'webm':
539
+ return VideoPlay;
540
+ case 'mp3':
541
+ case 'wav':
542
+ case 'ogg':
543
+ case 'flac':
544
+ case 'm4a':
545
+ return Headset;
546
+ default:
547
+ return Document;
548
+ }
549
+ }
550
+
515
551
  </script>
516
552
 
517
553
  <template>
@@ -546,40 +582,79 @@ watch(()=> props.classificationLevel, updateAllowedClassificationLevels)
546
582
  <span class="loader-shimmer">正在上传,已完成{{ uploadingProgress }}%...</span>
547
583
  </p>
548
584
  </div>
585
+
586
+ <div v-if="layout === 'inline'" class="inline-files">
587
+ <div v-for="file in files" :key="file.id" class="inline-file-item">
588
+ <el-popover placement="top" :width="300" trigger="hover">
589
+ <template #reference>
590
+ <div class="inline-file-icon-wrapper">
591
+ <el-icon class="file-icon" size="20"><component :is="getFileIcon(file.fileName)" /></el-icon>
592
+ </div>
593
+ </template>
594
+ <div class="file-popover-content">
595
+ <div class="popover-row">
596
+ <span class="label">文件名:</span>
597
+ <span class="value">{{ file.fileName }}</span>
598
+ </div>
599
+ <div class="popover-row">
600
+ <span class="label">大小:</span>
601
+ <span class="value">{{ prettyBytes(file.fileSize) }}</span>
602
+ </div>
603
+ <div class="popover-row">
604
+ <span class="label">密级:</span>
605
+ <span class="value">
606
+ <el-tag size="small"
607
+ :type="file.classifiedLevel < 50 ? (file.classifiedLevel < 30 ? 'danger' : 'warning') : 'info'">
608
+ {{ classificationLevelMap?.get(file.classifiedLevel) }}
609
+ </el-tag>
610
+ </span>
611
+ </div>
612
+ <div class="popover-actions">
613
+ <el-button link type="primary" @click="previewFile(file.token)"
614
+ v-if="checkAllowPreview(file)">预览
615
+ </el-button>
616
+ <el-button link type="primary" @click="downloadFile(file.token)" v-if="checkAllowDownload()">下载
617
+ </el-button>
618
+ <el-button link type="danger" @click="delUploadedFile(file)" v-if="checkAllowDelete()">删除
619
+ </el-button>
620
+ </div>
621
+ </div>
622
+ </el-popover>
623
+ </div>
624
+ </div>
625
+ </div>
626
+ <div v-if="layout === 'list'" class="file-list" :style="{ height: typeof props.height === 'number' ? props.height + 'px' : props.height, maxHeight: typeof props.maxHeight === 'number' ? props.maxHeight + 'px' : props.maxHeight }">
627
+ <div v-if="files.length === 0" class="empty-text">暂无文件</div>
628
+ <div v-for="file in files" :key="file.id" class="file-item">
629
+ <div class="file-main">
630
+ <el-icon class="file-icon"><component :is="getFileIcon(file.fileName)" /></el-icon>
631
+ <span class="file-name" :title="file.fileName">{{ file.fileName }}</span>
632
+ </div>
633
+ <div class="file-info-right">
634
+ <span class="file-size">{{ prettyBytes(file.fileSize) }}</span>
635
+ <div class="file-tag">
636
+ <el-tag size="small"
637
+ :type="file.classifiedLevel < 50 ? (file.classifiedLevel < 30 ? 'danger' : 'warning') : 'info'">
638
+ {{ classificationLevelMap?.get(file.classifiedLevel) }}
639
+ </el-tag>
640
+ <el-tooltip v-if="file.classifiedLevel < highestClassificationLevel" content="文件密级已高于当前许可范围,请立即删除">
641
+ <el-icon color="#F56C6C" class="warning-icon">
642
+ <warning-filled/>
643
+ </el-icon>
644
+ </el-tooltip>
645
+ </div>
646
+ <div class="file-actions">
647
+ <el-button link type="primary" @click="previewFile(file.token)"
648
+ v-if="checkAllowPreview(file)">预览
649
+ </el-button>
650
+ <el-button link type="primary" @click="downloadFile(file.token)" v-if="checkAllowDownload()">下载
651
+ </el-button>
652
+ <el-button link type="danger" @click="delUploadedFile(file)" v-if="checkAllowDelete()">删除
653
+ </el-button>
654
+ </div>
655
+ </div>
656
+ </div>
549
657
  </div>
550
- <el-table :data="files" :show-header="true" style="width: 100%" empty-text="暂无文件" :height="props.height"
551
- :max-height="props.maxHeight">
552
- <el-table-column prop="fileName" />
553
- <el-table-column prop="fileSize" width="100">
554
- <template #default="scope">
555
- {{ prettyBytes(scope.row.fileSize) }}
556
- </template>
557
- </el-table-column>
558
- <el-table-column prop="classifiedLevel" width="80">
559
- <template #default="scope">
560
- <el-tag
561
- :type="scope.row.classifiedLevel < 50 ? (scope.row.classifiedLevel < 30 ? 'danger' : 'warning') : 'info'">
562
- {{ classificationLevelMap?.get(scope.row.classifiedLevel) }}
563
- </el-tag>
564
- <el-tooltip v-if="scope.row.classifiedLevel < highestClassificationLevel" content="文件密级已高于当前许可范围,请立即删除">
565
- <el-icon color="#F56C6C">
566
- <warning-filled/>
567
- </el-icon>
568
- </el-tooltip>
569
- </template>
570
- </el-table-column>
571
- <el-table-column align="right" width="150" fixed="right">
572
- <template #default="scope">
573
- <el-button link type="warning" @click="previewFile(scope.row.token)"
574
- v-if="checkAllowPreview(scope.row)">预览
575
- </el-button>
576
- <el-button link type="primary" @click="downloadFile(scope.row.token)" v-if="checkAllowDownload()">下载
577
- </el-button>
578
- <el-button link type="danger" @click="delUploadedFile(scope.row)" v-if="checkAllowDelete()">删除
579
- </el-button>
580
- </template>
581
- </el-table-column>
582
- </el-table>
583
658
  </div>
584
659
  <pdf-viewer-modal :src="pdfSrc" v-model="pdfViewerVisible"></pdf-viewer-modal>
585
660
  </template>
@@ -601,6 +676,34 @@ watch(()=> props.classificationLevel, updateAllowedClassificationLevels)
601
676
 
602
677
  &-tools {
603
678
  display: flex;
679
+ align-items: center;
680
+ flex-wrap: wrap;
681
+ gap: 8px;
682
+ }
683
+
684
+ .inline-files {
685
+ display: flex;
686
+ align-items: center;
687
+ flex-wrap: wrap;
688
+ gap: 8px;
689
+ margin-left: 8px;
690
+
691
+ .inline-file-item {
692
+ .inline-file-icon-wrapper {
693
+ cursor: pointer;
694
+ display: flex;
695
+ align-items: center;
696
+ justify-content: center;
697
+ padding: 4px;
698
+ border-radius: 4px;
699
+ color: var(--el-text-color-regular);
700
+
701
+ &:hover {
702
+ background-color: var(--el-fill-color-light);
703
+ color: var(--el-color-primary);
704
+ }
705
+ }
706
+ }
604
707
  }
605
708
 
606
709
  .container {
@@ -654,4 +757,120 @@ watch(()=> props.classificationLevel, updateAllowedClassificationLevels)
654
757
  }
655
758
  }
656
759
  }
760
+
761
+ .file-popover-content {
762
+ display: flex;
763
+ flex-direction: column;
764
+ gap: 8px;
765
+ font-size: 14px;
766
+
767
+ .popover-row {
768
+ display: flex;
769
+ align-items: flex-start;
770
+
771
+ .label {
772
+ color: var(--el-text-color-secondary);
773
+ width: 60px;
774
+ flex-shrink: 0;
775
+ }
776
+
777
+ .value {
778
+ color: var(--el-text-color-primary);
779
+ word-break: break-all;
780
+ }
781
+ }
782
+
783
+ .popover-actions {
784
+ display: flex;
785
+ justify-content: flex-end;
786
+ gap: 8px;
787
+ margin-top: 8px;
788
+ border-top: 1px solid var(--el-border-color-lighter);
789
+ padding-top: 8px;
790
+ }
791
+ }
792
+
793
+ .file-list {
794
+ overflow-y: auto;
795
+ border: 1px solid var(--el-border-color-lighter);
796
+ border-radius: 4px;
797
+
798
+ .empty-text {
799
+ text-align: center;
800
+ padding: 20px;
801
+ color: var(--el-text-color-secondary);
802
+ font-size: 14px;
803
+ }
804
+
805
+ .file-item {
806
+ display: flex;
807
+ justify-content: space-between;
808
+ align-items: center;
809
+ padding: 8px 12px;
810
+ border-bottom: 1px solid var(--el-border-color-lighter);
811
+ font-size: 14px;
812
+
813
+ &:last-child {
814
+ border-bottom: none;
815
+ }
816
+
817
+ &:hover {
818
+ background-color: var(--el-fill-color-light);
819
+ }
820
+
821
+ .file-main {
822
+ display: flex;
823
+ align-items: center;
824
+ flex: 1;
825
+ overflow: hidden;
826
+ margin-right: 16px;
827
+
828
+ .file-icon {
829
+ margin-right: 8px;
830
+ color: var(--el-text-color-secondary);
831
+ font-size: 16px;
832
+ }
833
+
834
+ .file-name {
835
+ overflow: hidden;
836
+ text-overflow: ellipsis;
837
+ white-space: nowrap;
838
+ color: var(--el-text-color-regular);
839
+ }
840
+ }
841
+
842
+ .file-info-right {
843
+ display: flex;
844
+ align-items: center;
845
+ gap: 16px;
846
+
847
+ .file-size {
848
+ color: var(--el-text-color-secondary);
849
+ min-width: 60px;
850
+ text-align: right;
851
+ }
852
+
853
+ .file-tag {
854
+ display: flex;
855
+ align-items: center;
856
+ gap: 4px;
857
+
858
+ .warning-icon {
859
+ margin-left: 4px;
860
+ cursor: help;
861
+ }
862
+ }
863
+
864
+ .file-actions {
865
+ display: flex;
866
+ gap: 8px;
867
+
868
+ .el-button {
869
+ padding: 0;
870
+ height: auto;
871
+ }
872
+ }
873
+ }
874
+ }
875
+ }
657
876
  </style>
@@ -255,7 +255,6 @@ onUnmounted(() => {
255
255
  <Check v-if="userSelected(u)"/>
256
256
  </el-icon>
257
257
  <ja-user-info-tag :user-id="u.id" :full-name="u.fullName"
258
- :has-avatar="u.hasAvatar"
259
258
  placement="left-start"
260
259
  :theme="userTagTheme(u)"></ja-user-info-tag>
261
260
  </li>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import {onUnmounted, type Ref, ref} from "vue";
2
+ import {onUnmounted, type Ref, ref, type StyleValue} from "vue";
3
3
  import {Close, Star, StarFilled} from "@element-plus/icons-vue";
4
4
  import {type IAceAxios, useLoading, type User, useUserApi} from "@jari-ace/app-bolts";
5
5
  import {JaAvatar} from "../avatar";
@@ -29,13 +29,18 @@ const props = withDefaults(defineProps<{
29
29
  realm?: string,
30
30
  username?: string,
31
31
  theme?: keyof typeof themeClass,
32
- hasAvatar?: boolean,
33
- placement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end'
32
+ showAvatarInTag?: boolean,
33
+ placement?: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end',
34
+ displayType?: 'tag' | 'text',
35
+ textStyle?: StyleValue,
36
+ width?: string | number
34
37
  }>(), {
35
38
  closable: false,
36
39
  fullName: "无名氏",
37
40
  theme: "skyGray",
38
- placement: "bottom"
41
+ placement: "bottom",
42
+ displayType: "tag",
43
+ textStyle: () => ({})
39
44
  })
40
45
 
41
46
  const user = ref<User>();
@@ -103,10 +108,11 @@ function doUnbookmark() {
103
108
  <el-popover width="auto" :hide-after="200" @before-enter="onPop" :placement="placement"
104
109
  v-model:visible="visible">
105
110
  <template #reference>
106
- <div :class="themeClass[props.theme]">
111
+ <div v-if="displayType === 'tag'" :class="themeClass[props.theme]"
112
+ :style="{ width: typeof width === 'number' ? width + 'px' : width }">
107
113
  <div class="portrait">
108
114
  <ja-avatar :size="24" :user-id="userId" :realm="realm"
109
- :username="username" :has-avatar="false"></ja-avatar>
115
+ :username="username" :has-avatar="showAvatarInTag"></ja-avatar>
110
116
  </div>
111
117
  <div class="user-info">
112
118
  {{ fullName }}
@@ -117,6 +123,10 @@ function doUnbookmark() {
117
123
  </div>
118
124
  </div>
119
125
  </div>
126
+ <span v-else class="user-info-text"
127
+ :style="[textStyle, width ? { width: typeof width === 'number' ? width + 'px' : width, display: 'inline-block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', verticalAlign: 'bottom' } : {}]">
128
+ {{ fullName }}
129
+ </span>
120
130
  </template>
121
131
  <template #default>
122
132
  <div
@@ -275,6 +285,8 @@ function doUnbookmark() {
275
285
  white-space: nowrap;
276
286
  text-overflow: ellipsis;
277
287
  overflow: hidden;
288
+ flex: 1;
289
+ min-width: 0;
278
290
  }
279
291
 
280
292
  .close-btn {
@@ -394,4 +406,14 @@ function doUnbookmark() {
394
406
  }
395
407
  }
396
408
 
409
+ .user-info-text {
410
+ cursor: pointer;
411
+ color: var(--el-color-primary);
412
+ display: inline-block;
413
+
414
+ &:hover {
415
+ opacity: 0.8;
416
+ }
417
+ }
418
+
397
419
  </style>