index.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <div class="file-selector">
  3. <!-- 文件选择对话框 -->
  4. <el-dialog
  5. v-model="dialogVisible"
  6. :title="dialogTitle"
  7. width="90%"
  8. :close-on-click-modal="false"
  9. class="file-selector-dialog"
  10. top="5vh"
  11. :before-close="handleClose"
  12. append-to-body
  13. :z-index="9999"
  14. >
  15. <!-- 直接嵌入文件管理页面组件 -->
  16. <div class="file-manager-container">
  17. <FileManager
  18. ref="fileManagerRef"
  19. :select-mode="true"
  20. :file-type="getFileTypeString()"
  21. :multiple="multiple"
  22. @file-selected="handleFileSelected"
  23. @files-selected="handleFilesSelected"
  24. />
  25. </div>
  26. <template #footer>
  27. <div class="dialog-footer">
  28. <el-button @click="handleClose">取消</el-button>
  29. <el-button type="primary" @click="confirmSelection" :disabled="multiple ? selectedFiles.length === 0 : !selectedFile">
  30. 确认选择{{ multiple ? `(${selectedFiles.length})` : '' }}
  31. </el-button>
  32. </div>
  33. </template>
  34. </el-dialog>
  35. </div>
  36. </template>
  37. <script setup lang="ts">
  38. import { ref, computed, nextTick } from 'vue';
  39. import { ElMessage } from 'element-plus';
  40. import FileManager from '@/views/file/info/index.vue';
  41. // Props
  42. interface Props {
  43. modelValue: boolean;
  44. // 允许的文件类型 [1: 图片, 2: 视频, 3: 音频, 4: 文档, 5: 其他]
  45. // 例如:[1] 仅显示图片类型,[1,2] 显示图片和视频类型
  46. allowedTypes?: number[];
  47. // 是否允许多选(单选/多选文件)
  48. multiple?: boolean;
  49. // 是否允许上传新文件
  50. allowUpload?: boolean;
  51. // 对话框标题
  52. title?: string;
  53. }
  54. const props = withDefaults(defineProps<Props>(), {
  55. allowedTypes: () => [1], // 默认只允许图片
  56. multiple: false,
  57. allowUpload: true,
  58. title: '选择文件'
  59. });
  60. // Emits
  61. const emit = defineEmits<{
  62. 'update:modelValue': [value: boolean];
  63. 'confirm': [files: any[]];
  64. }>();
  65. // 响应式数据
  66. const dialogVisible = computed({
  67. get: () => props.modelValue,
  68. set: (value) => emit('update:modelValue', value)
  69. });
  70. const dialogTitle = computed(() => {
  71. const typeText = getTypeText();
  72. return props.title || `选择${typeText}${props.multiple ? '(多选)' : ''}`;
  73. });
  74. const selectedFile = ref<any>(null);
  75. const selectedFiles = ref<any[]>([]);
  76. const fileManagerRef = ref();
  77. // 方法
  78. const getFileTypeString = () => {
  79. // 如果只有一种类型,返回对应的类型字符串
  80. if (props.allowedTypes.length === 1) {
  81. switch (props.allowedTypes[0]) {
  82. case 1:
  83. return 'image';
  84. case 2:
  85. return 'video';
  86. case 3:
  87. return 'audio';
  88. case 4:
  89. return 'document';
  90. default:
  91. return '';
  92. }
  93. }
  94. // 多种类型时返回空字符串,表示不限制
  95. return '';
  96. };
  97. const getTypeText = () => {
  98. if (props.allowedTypes.length === 1) {
  99. switch (props.allowedTypes[0]) {
  100. case 1:
  101. return '图片';
  102. case 2:
  103. return '视频';
  104. case 3:
  105. return '音频';
  106. case 4:
  107. return '文档';
  108. case 5:
  109. return '文件';
  110. default:
  111. return '文件';
  112. }
  113. }
  114. return '文件';
  115. };
  116. const handleClose = () => {
  117. selectedFile.value = null;
  118. selectedFiles.value = [];
  119. // 重置FileManager组件的选择状态
  120. nextTick(() => {
  121. if (fileManagerRef.value && fileManagerRef.value.clearSelection) {
  122. fileManagerRef.value.clearSelection();
  123. }
  124. });
  125. emit('update:modelValue', false);
  126. };
  127. // 处理文件选择(单选模式)
  128. const handleFileSelected = (file: any) => {
  129. if (props.multiple) return;
  130. selectedFile.value = file;
  131. console.log('选择的文件:', file);
  132. };
  133. // 处理多文件选择
  134. const handleFilesSelected = (files: any[]) => {
  135. if (!props.multiple) return;
  136. selectedFiles.value = files;
  137. console.log('选择的文件列表:', files);
  138. };
  139. // 确认选择
  140. const confirmSelection = () => {
  141. if (props.multiple) {
  142. if (selectedFiles.value.length === 0) {
  143. ElMessage.warning(`请选择至少一个${getTypeText()}`);
  144. return;
  145. }
  146. emit('confirm', selectedFiles.value);
  147. emit('update:modelValue', false);
  148. ElMessage.success(`成功选择${selectedFiles.value.length}个${getTypeText()}`);
  149. } else {
  150. if (!selectedFile.value) {
  151. ElMessage.warning(`请选择一个${getTypeText()}`);
  152. return;
  153. }
  154. emit('confirm', [selectedFile.value]);
  155. emit('update:modelValue', false);
  156. ElMessage.success(`${getTypeText()}选择成功`);
  157. }
  158. // 清空选择
  159. selectedFile.value = null;
  160. selectedFiles.value = [];
  161. };
  162. </script>
  163. <style scoped>
  164. .file-selector {
  165. display: inline-block;
  166. }
  167. /* 文件选择器对话框样式 */
  168. .file-selector-dialog :deep(.el-dialog__body) {
  169. padding: 0;
  170. height: 80vh;
  171. overflow: hidden;
  172. }
  173. .file-manager-container {
  174. height: 100%;
  175. overflow: hidden;
  176. }
  177. .dialog-footer {
  178. text-align: right;
  179. }
  180. /* 确保对话框样式正常 */
  181. .file-selector-dialog :deep(.el-dialog) {
  182. display: flex;
  183. flex-direction: column;
  184. max-height: 90vh;
  185. }
  186. .file-selector-dialog :deep(.el-dialog__header) {
  187. flex-shrink: 0;
  188. }
  189. .file-selector-dialog :deep(.el-dialog__footer) {
  190. border-top: 1px solid #ebeef5;
  191. padding: 15px 20px;
  192. flex-shrink: 0;
  193. }
  194. </style>