mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-10-31 02:08:45 +08:00 
			
		
		
		
	重构:基础设施 -> 文件管理 文件列表
This commit is contained in:
		| @@ -297,7 +297,8 @@ export default { | ||||
|     typeCreate: 'Dict Type Create', | ||||
|     typeUpdate: 'Dict Type Eidt', | ||||
|     dataCreate: 'Dict Data Create', | ||||
|     dataUpdate: 'Dict Data Eidt' | ||||
|     dataUpdate: 'Dict Data Eidt', | ||||
|     fileUpload: 'File Upload' | ||||
|   }, | ||||
|   dialog: { | ||||
|     dialog: 'Dialog', | ||||
|   | ||||
| @@ -297,7 +297,8 @@ export default { | ||||
|     typeCreate: '字典类型新增', | ||||
|     typeUpdate: '字典类型编辑', | ||||
|     dataCreate: '字典数据新增', | ||||
|     dataUpdate: '字典数据编辑' | ||||
|     dataUpdate: '字典数据编辑', | ||||
|     fileUpload: '上传文件' | ||||
|   }, | ||||
|   dialog: { | ||||
|     dialog: '弹窗', | ||||
|   | ||||
							
								
								
									
										82
									
								
								src/views/infra/file/form.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/views/infra/file/form.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| <template> | ||||
|   <Dialog :title="modelTitle" v-model="modelVisible"> | ||||
|     <el-upload | ||||
|       ref="uploadRef" | ||||
|       :limit="1" | ||||
|       accept=".jpg, .png, .gif" | ||||
|       :auto-upload="false" | ||||
|       drag | ||||
|       :headers="headers" | ||||
|       :action="url" | ||||
|       :data="data" | ||||
|       :disabled="formLoading" | ||||
|       :on-change="handleFileChange" | ||||
|       :on-progress="handleFileUploadProgress" | ||||
|       :on-success="handleFileSuccess" | ||||
|     > | ||||
|       <i class="el-icon-upload"></i> | ||||
|       <div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em> </div> | ||||
|       <template #tip> | ||||
|         <div class="el-upload__tip" style="color: red"> | ||||
|           提示:仅允许导入 jpg、png、gif 格式文件! | ||||
|         </div> | ||||
|       </template> | ||||
|     </el-upload> | ||||
|     <template #footer> | ||||
|       <div class="dialog-footer"> | ||||
|         <el-button @click="submitFileForm" type="primary" :disabled="formLoading">确 定</el-button> | ||||
|         <el-button @click="modelVisible = false">取 消</el-button> | ||||
|       </div> | ||||
|     </template> | ||||
|   </Dialog> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import { Dialog } from '@/components/Dialog' | ||||
| import { getAccessToken } from '@/utils/auth' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| const message = useMessage() // 消息弹窗 | ||||
|  | ||||
| const modelVisible = ref(false) // 弹窗的是否展示 | ||||
| const modelTitle = ref('') // 弹窗的标题 | ||||
| const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||||
| const url = import.meta.env.VITE_UPLOAD_URL | ||||
| const headers = { Authorization: 'Bearer ' + getAccessToken() } | ||||
| const data = ref({ path: '' }) | ||||
| const uploadRef = ref() | ||||
|  | ||||
| /** 打开弹窗 */ | ||||
| const openModal = async () => { | ||||
|   modelVisible.value = true | ||||
|   modelTitle.value = t('action.fileUpload') | ||||
| } | ||||
| defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗 | ||||
|  | ||||
| /** 提交表单 */ | ||||
| const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||||
| /** 处理上传的文件发生变化 */ | ||||
| const handleFileChange = (file) => { | ||||
|   data.value.path = file.name | ||||
| } | ||||
| /** 处理文件上传中 */ | ||||
| const handleFileUploadProgress = () => { | ||||
|   formLoading.value = true // 禁止修改 | ||||
| } | ||||
| /** 发起文件上传 */ | ||||
| const submitFileForm = () => { | ||||
|   unref(uploadRef)?.submit() | ||||
| } | ||||
| /** 文件上传成功处理 */ | ||||
| const handleFileSuccess = () => { | ||||
|   // 清理 | ||||
|   modelVisible.value = false | ||||
|   formLoading.value = false | ||||
|   unref(uploadRef)?.clearFiles() | ||||
|   // 提示成功,并刷新 | ||||
|   message.success(t('common.createSuccess')) | ||||
|   emit('success') | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style scoped></style> | ||||
							
								
								
									
										162
									
								
								src/views/infra/file/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/views/infra/file/index.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| <template> | ||||
|   <!-- 搜索 --> | ||||
|   <content-wrap> | ||||
|     <el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true"> | ||||
|       <el-form-item label="文件路径" prop="path"> | ||||
|         <el-input | ||||
|           v-model="queryParams.path" | ||||
|           placeholder="请输入文件路径" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="文件类型" prop="type" width="80"> | ||||
|         <el-input | ||||
|           v-model="queryParams.type" | ||||
|           placeholder="请输入文件类型" | ||||
|           clearable | ||||
|           @keyup.enter="handleQuery" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="创建时间" prop="createTime"> | ||||
|         <el-date-picker | ||||
|           v-model="queryParams.createTime" | ||||
|           value-format="YYYY-MM-DD HH:mm:ss" | ||||
|           type="daterange" | ||||
|           range-separator="-" | ||||
|           start-placeholder="开始日期" | ||||
|           end-placeholder="结束日期" | ||||
|           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" | ||||
|         /> | ||||
|       </el-form-item> | ||||
|       <el-form-item> | ||||
|         <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> | ||||
|         <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> | ||||
|         <el-button type="primary" @click="openModal"> | ||||
|           <Icon icon="ep:upload" class="mr-5px" /> 上传文件 | ||||
|         </el-button> | ||||
|       </el-form-item> | ||||
|     </el-form> | ||||
|   </content-wrap> | ||||
|  | ||||
|   <!-- 列表 --> | ||||
|   <content-wrap> | ||||
|     <el-table v-loading="loading" :data="list" align="center"> | ||||
|       <el-table-column label="文件名" align="center" prop="name" :show-overflow-tooltip="true" /> | ||||
|       <el-table-column label="文件路径" align="center" prop="path" :show-overflow-tooltip="true" /> | ||||
|       <el-table-column label="URL" align="center" prop="url" :show-overflow-tooltip="true" /> | ||||
|       <el-table-column | ||||
|         label="文件大小" | ||||
|         align="center" | ||||
|         prop="size" | ||||
|         width="120" | ||||
|         :formatter="sizeFormat" | ||||
|       /> | ||||
|       <el-table-column label="文件类型" align="center" prop="type" width="180px" /> | ||||
|       <el-table-column | ||||
|         label="上传时间" | ||||
|         align="center" | ||||
|         prop="createTime" | ||||
|         width="180" | ||||
|         :formatter="dateFormatter" | ||||
|       /> | ||||
|       <el-table-column label="操作" align="center"> | ||||
|         <template #default="scope"> | ||||
|           <el-button | ||||
|             link | ||||
|             type="danger" | ||||
|             @click="handleDelete(scope.row.id)" | ||||
|             v-hasPermi="['infra:config:delete']" | ||||
|           > | ||||
|             删除 | ||||
|           </el-button> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </el-table> | ||||
|     <!-- 分页 --> | ||||
|     <Pagination | ||||
|       :total="total" | ||||
|       v-model:page="queryParams.pageNo" | ||||
|       v-model:limit="queryParams.pageSize" | ||||
|       @pagination="getList" | ||||
|     /> | ||||
|   </content-wrap> | ||||
|  | ||||
|   <!-- 表单弹窗:添加/修改 --> | ||||
|   <file-upload-form ref="modalRef" @success="getList" /> | ||||
| </template> | ||||
| <script setup lang="ts" name="Config"> | ||||
| import { dateFormatter } from '@/utils/formatTime' | ||||
| import * as FileApi from '@/api/infra/fileList' | ||||
| import FileUploadForm from './form.vue' | ||||
| const message = useMessage() // 消息弹窗 | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| const loading = ref(true) // 列表的加载中 | ||||
| const total = ref(0) // 列表的总页数 | ||||
| const list = ref([]) // 列表的数据 | ||||
| const queryParams = reactive({ | ||||
|   pageNo: 1, | ||||
|   pageSize: 10, | ||||
|   name: undefined, | ||||
|   type: undefined, | ||||
|   createTime: [] | ||||
| }) | ||||
| const queryFormRef = ref() // 搜索的表单 | ||||
|  | ||||
| /** 查询参数列表 */ | ||||
| const getList = async () => { | ||||
|   loading.value = true | ||||
|   try { | ||||
|     const data = await FileApi.getFilePageApi(queryParams) | ||||
|     list.value = data.list | ||||
|     total.value = data.total | ||||
|   } finally { | ||||
|     loading.value = false | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** 搜索按钮操作 */ | ||||
| const handleQuery = () => { | ||||
|   queryParams.pageNo = 1 | ||||
|   getList() | ||||
| } | ||||
|  | ||||
| /** 重置按钮操作 */ | ||||
| const resetQuery = () => { | ||||
|   queryFormRef.value.resetFields() | ||||
|   handleQuery() | ||||
| } | ||||
|  | ||||
| /** 添加/修改操作 */ | ||||
| const modalRef = ref() | ||||
| const openModal = () => { | ||||
|   modalRef.value.openModal() | ||||
| } | ||||
|  | ||||
| /** 删除按钮操作 */ | ||||
| const handleDelete = async (id: number) => { | ||||
|   try { | ||||
|     // 删除的二次确认 | ||||
|     await message.delConfirm() | ||||
|     // 发起删除 | ||||
|     await FileApi.deleteFileApi(id) | ||||
|     message.success(t('common.delSuccess')) | ||||
|     // 刷新列表 | ||||
|     await getList() | ||||
|   } catch {} | ||||
| } | ||||
|  | ||||
| const sizeFormat = (row) => { | ||||
|   const unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] | ||||
|   const srcSize = parseFloat(row.size) | ||||
|   const index = Math.floor(Math.log(srcSize) / Math.log(1024)) | ||||
|   const size = srcSize / Math.pow(1024, index) | ||||
|   const sizeStr = size.toFixed(2) //保留的小数位数 | ||||
|   return sizeStr + ' ' + unitArr[index] | ||||
| } | ||||
| /** 初始化 **/ | ||||
| onMounted(() => { | ||||
|   getList() | ||||
| }) | ||||
| </script> | ||||
| @@ -1,52 +0,0 @@ | ||||
| import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas' | ||||
| const { t } = useI18n() // 国际化 | ||||
|  | ||||
| // CrudSchema | ||||
| const crudSchemas = reactive<VxeCrudSchema>({ | ||||
|   primaryKey: 'id', | ||||
|   primaryType: 'seq', | ||||
|   action: true, | ||||
|   columns: [ | ||||
|     { | ||||
|       title: '文件名', | ||||
|       field: 'name' | ||||
|     }, | ||||
|     { | ||||
|       title: '文件路径', | ||||
|       field: 'path', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: 'URL', | ||||
|       field: 'url', | ||||
|       table: { | ||||
|         cellRender: { | ||||
|           name: 'XPreview' | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       title: '文件大小', | ||||
|       field: 'size', | ||||
|       formatter: 'formatSize' | ||||
|     }, | ||||
|     { | ||||
|       title: '文件类型', | ||||
|       field: 'type', | ||||
|       isSearch: true | ||||
|     }, | ||||
|     { | ||||
|       title: t('common.createTime'), | ||||
|       field: 'createTime', | ||||
|       formatter: 'formatDate', | ||||
|       isForm: false, | ||||
|       search: { | ||||
|         show: true, | ||||
|         itemRender: { | ||||
|           name: 'XDataTimePicker' | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| }) | ||||
| export const { allSchemas } = useVxeCrudSchemas(crudSchemas) | ||||
| @@ -1,173 +0,0 @@ | ||||
| <template> | ||||
|   <ContentWrap> | ||||
|     <!-- 列表 --> | ||||
|     <XTable @register="registerTable"> | ||||
|       <template #toolbar_buttons> | ||||
|         <XButton | ||||
|           type="primary" | ||||
|           preIcon="ep:upload" | ||||
|           title="上传文件" | ||||
|           @click="uploadDialogVisible = true" | ||||
|         /> | ||||
|       </template> | ||||
|       <template #actionbtns_default="{ row }"> | ||||
|         <XTextButton | ||||
|           preIcon="ep:copy-document" | ||||
|           :title="t('common.copy')" | ||||
|           @click="handleCopy(row.url)" | ||||
|         /> | ||||
|         <XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" /> | ||||
|         <XTextButton | ||||
|           preIcon="ep:delete" | ||||
|           :title="t('action.del')" | ||||
|           v-hasPermi="['infra:file:delete']" | ||||
|           @click="deleteData(row.id)" | ||||
|         /> | ||||
|       </template> | ||||
|     </XTable> | ||||
|   </ContentWrap> | ||||
|   <XModal v-model="dialogVisible" :title="dialogTitle"> | ||||
|     <!-- 对话框(详情) --> | ||||
|     <Descriptions :schema="allSchemas.detailSchema" :data="detailData"> | ||||
|       <template #url="{ row }"> | ||||
|         <el-image | ||||
|           v-if="row.type === 'jpg' || 'png' || 'gif'" | ||||
|           style="width: 100px; height: 100px" | ||||
|           :src="row.url" | ||||
|           :key="row.url" | ||||
|           lazy | ||||
|         /> | ||||
|         <span>{{ row.url }}</span> | ||||
|       </template> | ||||
|     </Descriptions> | ||||
|     <!-- 操作按钮 --> | ||||
|     <template #footer> | ||||
|       <XButton :title="t('dialog.close')" @click="dialogVisible = false" /> | ||||
|     </template> | ||||
|   </XModal> | ||||
|   <XModal v-model="uploadDialogVisible" :title="uploadDialogTitle"> | ||||
|     <el-upload | ||||
|       ref="uploadRef" | ||||
|       :action="updateUrl + '?updateSupport=' + updateSupport" | ||||
|       :headers="uploadHeaders" | ||||
|       :drag="true" | ||||
|       :limit="1" | ||||
|       :multiple="true" | ||||
|       :show-file-list="true" | ||||
|       :disabled="uploadDisabled" | ||||
|       :before-upload="beforeUpload" | ||||
|       :on-exceed="handleExceed" | ||||
|       :on-success="handleFileSuccess" | ||||
|       :on-error="excelUploadError" | ||||
|       :auto-upload="false" | ||||
|       accept=".jpg, .png, .gif" | ||||
|     > | ||||
|       <Icon icon="ep:upload-filled" /> | ||||
|       <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> | ||||
|       <template #tip> | ||||
|         <div class="el-upload__tip">请上传 .jpg, .png, .gif 标准格式文件</div> | ||||
|       </template> | ||||
|     </el-upload> | ||||
|     <template #footer> | ||||
|       <!-- 按钮:保存 --> | ||||
|       <XButton | ||||
|         type="primary" | ||||
|         preIcon="ep:upload-filled" | ||||
|         :title="t('action.save')" | ||||
|         @click="submitFileForm()" | ||||
|       /> | ||||
|       <!-- 按钮:关闭 --> | ||||
|       <XButton :title="t('dialog.close')" @click="uploadDialogVisible = false" /> | ||||
|     </template> | ||||
|   </XModal> | ||||
| </template> | ||||
| <script setup lang="ts" name="FileList"> | ||||
| import type { UploadInstance, UploadRawFile } from 'element-plus' | ||||
| // 业务相关的 import | ||||
| import { allSchemas } from './fileList.data' | ||||
| import * as FileApi from '@/api/infra/fileList' | ||||
| import { getAccessToken, getTenantId } from '@/utils/auth' | ||||
| import { useClipboard } from '@vueuse/core' | ||||
|  | ||||
| const { t } = useI18n() // 国际化 | ||||
| const message = useMessage() // 消息弹窗 | ||||
|  | ||||
| // 列表相关的变量 | ||||
| const [registerTable, { reload, deleteData }] = useXTable({ | ||||
|   allSchemas: allSchemas, | ||||
|   getListApi: FileApi.getFilePageApi, | ||||
|   deleteApi: FileApi.deleteFileApi | ||||
| }) | ||||
|  | ||||
| const detailData = ref() // 详情 Ref | ||||
| const dialogVisible = ref(false) // 是否显示弹出层 | ||||
| const dialogTitle = ref('') // 弹出层标题 | ||||
| const uploadDialogVisible = ref(false) | ||||
| const uploadDialogTitle = ref('上传') | ||||
| const updateSupport = ref(0) | ||||
| const uploadDisabled = ref(false) | ||||
| const uploadRef = ref<UploadInstance>() | ||||
| let updateUrl = import.meta.env.VITE_UPLOAD_URL | ||||
| const uploadHeaders = ref() | ||||
| // 文件上传之前判断 | ||||
| const beforeUpload = (file: UploadRawFile) => { | ||||
|   const isImg = file.type === 'image/jpeg' || 'image/gif' || 'image/png' | ||||
|   const isLt5M = file.size / 1024 / 1024 < 5 | ||||
|   if (!isImg) message.error('上传文件只能是 jpeg / gif / png 格式!') | ||||
|   if (!isLt5M) message.error('上传文件大小不能超过 5MB!') | ||||
|   return isImg && isLt5M | ||||
| } | ||||
| // 处理上传的文件发生变化 | ||||
| // const handleFileChange = (uploadFile: UploadFile): void => { | ||||
| //   uploadRef.value.data.path = uploadFile.name | ||||
| // } | ||||
| // 文件上传 | ||||
| const submitFileForm = () => { | ||||
|   uploadHeaders.value = { | ||||
|     Authorization: 'Bearer ' + getAccessToken(), | ||||
|     'tenant-id': getTenantId() | ||||
|   } | ||||
|   uploadDisabled.value = true | ||||
|   uploadRef.value!.submit() | ||||
| } | ||||
| // 文件上传成功 | ||||
| const handleFileSuccess = async (response: any): Promise<void> => { | ||||
|   if (response.code !== 0) { | ||||
|     message.error(response.msg) | ||||
|     return | ||||
|   } | ||||
|   message.success('上传成功') | ||||
|   uploadDialogVisible.value = false | ||||
|   uploadDisabled.value = false | ||||
|   await reload() | ||||
| } | ||||
| // 文件数超出提示 | ||||
| const handleExceed = (): void => { | ||||
|   message.error('最多只能上传一个文件!') | ||||
| } | ||||
| // 上传错误提示 | ||||
| const excelUploadError = (): void => { | ||||
|   message.error('导入数据失败,请您重新上传!') | ||||
| } | ||||
|  | ||||
| // 详情操作 | ||||
| const handleDetail = (row: FileApi.FileVO) => { | ||||
|   // 设置数据 | ||||
|   detailData.value = row | ||||
|   dialogTitle.value = t('action.detail') | ||||
|   dialogVisible.value = true | ||||
| } | ||||
|  | ||||
| // ========== 复制相关 ========== | ||||
| const handleCopy = async (text: string) => { | ||||
|   const { copy, copied, isSupported } = useClipboard({ source: text }) | ||||
|   if (!isSupported) { | ||||
|     message.error(t('common.copyError')) | ||||
|   } else { | ||||
|     await copy() | ||||
|     if (unref(copied)) { | ||||
|       message.success(t('common.copySuccess')) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user
	 dlarmor
					dlarmor