index.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <template>
  2. <ContentWrap>
  3. <!-- 列表 -->
  4. <XTable @register="registerTable">
  5. <template #toolbar_buttons>
  6. <XButton
  7. type="primary"
  8. preIcon="ep:upload"
  9. title="上传文件"
  10. @click="uploadDialogVisible = true"
  11. />
  12. </template>
  13. <template #actionbtns_default="{ row }">
  14. <XTextButton
  15. preIcon="ep:copy-document"
  16. :title="t('common.copy')"
  17. @click="handleCopy(row.url)"
  18. />
  19. <XTextButton preIcon="ep:view" :title="t('action.detail')" @click="handleDetail(row)" />
  20. <XTextButton
  21. preIcon="ep:delete"
  22. :title="t('action.del')"
  23. v-hasPermi="['infra:file:delete']"
  24. @click="deleteData(row.id)"
  25. />
  26. </template>
  27. </XTable>
  28. </ContentWrap>
  29. <XModal v-model="dialogVisible" :title="dialogTitle">
  30. <!-- 对话框(详情) -->
  31. <Descriptions :schema="allSchemas.detailSchema" :data="detailData">
  32. <template #url="{ row }">
  33. <el-image
  34. v-if="row.type === 'jpg' || 'png' || 'gif'"
  35. style="width: 100px; height: 100px"
  36. :src="row.url"
  37. :key="row.url"
  38. lazy
  39. />
  40. <span>{{ row.url }}</span>
  41. </template>
  42. </Descriptions>
  43. <!-- 操作按钮 -->
  44. <template #footer>
  45. <XButton :title="t('dialog.close')" @click="dialogVisible = false" />
  46. </template>
  47. </XModal>
  48. <XModal v-model="uploadDialogVisible" :title="uploadDialogTitle">
  49. <el-upload
  50. ref="uploadRef"
  51. :action="updateUrl + '?updateSupport=' + updateSupport"
  52. :headers="uploadHeaders"
  53. :drag="true"
  54. :limit="1"
  55. :multiple="true"
  56. :show-file-list="true"
  57. :disabled="uploadDisabled"
  58. :before-upload="beforeUpload"
  59. :on-exceed="handleExceed"
  60. :on-success="handleFileSuccess"
  61. :on-error="excelUploadError"
  62. :before-remove="beforeRemove"
  63. :auto-upload="false"
  64. accept=".jpg, .png, .gif"
  65. >
  66. <Icon icon="ep:upload-filled" />
  67. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  68. <template #tip>
  69. <div class="el-upload__tip">请上传 .jpg, .png, .gif 标准格式文件</div>
  70. </template>
  71. </el-upload>
  72. <template #footer>
  73. <!-- 按钮:保存 -->
  74. <XButton
  75. type="primary"
  76. preIcon="ep:upload-filled"
  77. :title="t('action.save')"
  78. @click="submitFileForm()"
  79. />
  80. <!-- 按钮:关闭 -->
  81. <XButton :title="t('dialog.close')" @click="uploadDialogVisible = false" />
  82. </template>
  83. </XModal>
  84. </template>
  85. <script setup lang="ts" name="FileList">
  86. import type { UploadInstance, UploadRawFile, UploadProps } from 'element-plus'
  87. // 业务相关的 import
  88. import { allSchemas } from './fileList.data'
  89. import * as FileApi from '@/api/infra/fileList'
  90. import { getAccessToken, getTenantId } from '@/utils/auth'
  91. import { useClipboard } from '@vueuse/core'
  92. const { t } = useI18n() // 国际化
  93. const message = useMessage() // 消息弹窗
  94. // 列表相关的变量
  95. const [registerTable, { reload, deleteData }] = useXTable({
  96. allSchemas: allSchemas,
  97. getListApi: FileApi.getFilePageApi,
  98. deleteApi: FileApi.deleteFileApi
  99. })
  100. const detailData = ref() // 详情 Ref
  101. const dialogVisible = ref(false) // 是否显示弹出层
  102. const dialogTitle = ref('') // 弹出层标题
  103. const uploadDialogVisible = ref(false)
  104. const uploadDialogTitle = ref('上传')
  105. const updateSupport = ref(0)
  106. const uploadDisabled = ref(false)
  107. const uploadRef = ref<UploadInstance>()
  108. let updateUrl = import.meta.env.VITE_UPLOAD_URL
  109. const uploadHeaders = ref()
  110. // 文件上传之前判断
  111. const beforeUpload = (file: UploadRawFile) => {
  112. const isImg = file.type === 'image/jpeg' || 'image/gif' || 'image/png'
  113. const isLt5M = file.size / 1024 / 1024 < 5
  114. if (!isImg) message.error('上传文件只能是 jpeg / gif / png 格式!')
  115. if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
  116. return isImg && isLt5M
  117. }
  118. // 处理上传的文件发生变化
  119. // const handleFileChange = (uploadFile: UploadFile): void => {
  120. // uploadRef.value.data.path = uploadFile.name
  121. // }
  122. // 文件上传
  123. const submitFileForm = () => {
  124. uploadHeaders.value = {
  125. Authorization: 'Bearer ' + getAccessToken(),
  126. 'tenant-id': getTenantId()
  127. }
  128. uploadDisabled.value = true
  129. uploadRef.value!.submit()
  130. }
  131. // 文件上传成功
  132. const handleFileSuccess = async (response: any): Promise<void> => {
  133. if (response.code !== 0) {
  134. message.error(response.msg)
  135. return
  136. }
  137. message.success('上传成功')
  138. uploadDialogVisible.value = false
  139. uploadDisabled.value = false
  140. await reload()
  141. }
  142. const beforeRemove: UploadProps['beforeRemove'] = () => {
  143. uploadDisabled.value = false
  144. }
  145. // 文件数超出提示
  146. const handleExceed = (): void => {
  147. message.error('最多只能上传一个文件!')
  148. }
  149. // 上传错误提示
  150. const excelUploadError = (): void => {
  151. message.error('导入数据失败,请您重新上传!')
  152. }
  153. // 详情操作
  154. const handleDetail = (row: FileApi.FileVO) => {
  155. // 设置数据
  156. detailData.value = row
  157. dialogTitle.value = t('action.detail')
  158. dialogVisible.value = true
  159. }
  160. // ========== 复制相关 ==========
  161. const handleCopy = async (text: string) => {
  162. const { copy, copied, isSupported } = useClipboard({ source: text })
  163. if (!isSupported) {
  164. message.error(t('common.copyError'))
  165. } else {
  166. await copy()
  167. if (unref(copied)) {
  168. message.success(t('common.copySuccess'))
  169. }
  170. }
  171. }
  172. </script>