index.vue 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <ContentWrap>
  3. <!-- 列表 -->
  4. <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar">
  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="handleDelete(row.id)"
  25. />
  26. </template>
  27. </vxe-grid>
  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. :auto-upload="false"
  63. accept=".jpg, .png, .gif"
  64. >
  65. <Icon icon="ep:upload-filled" />
  66. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  67. <template #tip>
  68. <div class="el-upload__tip">请上传 .jpg, .png, .gif 标准格式文件</div>
  69. </template>
  70. </el-upload>
  71. <template #footer>
  72. <!-- 按钮:保存 -->
  73. <XButton
  74. type="primary"
  75. preIcon="ep:upload-filled"
  76. :title="t('action.save')"
  77. @click="submitFileForm()"
  78. />
  79. <!-- 按钮:关闭 -->
  80. <XButton :title="t('dialog.close')" @click="uploadDialogVisible = false" />
  81. </template>
  82. </XModal>
  83. </template>
  84. <script setup lang="ts" name="FileList">
  85. import { ref, unref } from 'vue'
  86. import { useI18n } from '@/hooks/web/useI18n'
  87. import { useMessage } from '@/hooks/web/useMessage'
  88. import { useVxeGrid } from '@/hooks/web/useVxeGrid'
  89. import { VxeGridInstance } from 'vxe-table'
  90. import { ElUpload, ElImage, UploadInstance, UploadRawFile } from 'element-plus'
  91. // 业务相关的 import
  92. import { allSchemas } from './fileList.data'
  93. import * as FileApi from '@/api/infra/fileList'
  94. import { getAccessToken, getTenantId } from '@/utils/auth'
  95. import { useClipboard } from '@vueuse/core'
  96. const { t } = useI18n() // 国际化
  97. const message = useMessage() // 消息弹窗
  98. // 列表相关的变量
  99. const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref
  100. const { gridOptions, getList, deleteData } = useVxeGrid<FileApi.FileVO>({
  101. allSchemas: allSchemas,
  102. getListApi: FileApi.getFilePageApi,
  103. deleteApi: FileApi.deleteFileApi
  104. })
  105. const detailData = ref() // 详情 Ref
  106. const dialogVisible = ref(false) // 是否显示弹出层
  107. const dialogTitle = ref('') // 弹出层标题
  108. const uploadDialogVisible = ref(false)
  109. const uploadDialogTitle = ref('上传')
  110. const updateSupport = ref(0)
  111. const uploadDisabled = ref(false)
  112. const uploadRef = ref<UploadInstance>()
  113. let updateUrl = import.meta.env.VITE_UPLOAD_URL
  114. const uploadHeaders = ref()
  115. // 文件上传之前判断
  116. const beforeUpload = (file: UploadRawFile) => {
  117. const isImg = file.type === 'image/jpeg' || 'image/gif' || 'image/png'
  118. const isLt5M = file.size / 1024 / 1024 < 5
  119. if (!isImg) message.error('上传文件只能是 jpeg / gif / png 格式!')
  120. if (!isLt5M) message.error('上传文件大小不能超过 5MB!')
  121. return isImg && isLt5M
  122. }
  123. // 处理上传的文件发生变化
  124. // const handleFileChange = (uploadFile: UploadFile): void => {
  125. // uploadRef.value.data.path = uploadFile.name
  126. // }
  127. // 文件上传
  128. const submitFileForm = () => {
  129. uploadHeaders.value = {
  130. Authorization: 'Bearer ' + getAccessToken(),
  131. 'tenant-id': getTenantId()
  132. }
  133. uploadDisabled.value = true
  134. uploadRef.value!.submit()
  135. }
  136. // 文件上传成功
  137. const handleFileSuccess = async (response: any): Promise<void> => {
  138. if (response.code !== 0) {
  139. message.error(response.msg)
  140. return
  141. }
  142. message.success('上传成功')
  143. uploadDialogVisible.value = false
  144. uploadDisabled.value = false
  145. await getList(xGrid)
  146. }
  147. // 文件数超出提示
  148. const handleExceed = (): void => {
  149. message.error('最多只能上传一个文件!')
  150. }
  151. // 上传错误提示
  152. const excelUploadError = (): void => {
  153. message.error('导入数据失败,请您重新上传!')
  154. }
  155. // 详情操作
  156. const handleDetail = (row: FileApi.FileVO) => {
  157. // 设置数据
  158. detailData.value = row
  159. dialogTitle.value = t('action.detail')
  160. dialogVisible.value = true
  161. }
  162. // 删除操作
  163. const handleDelete = async (rowId: number) => {
  164. await deleteData(xGrid, rowId)
  165. }
  166. // ========== 复制相关 ==========
  167. const handleCopy = async (text: string) => {
  168. const { copy, copied, isSupported } = useClipboard({ source: text })
  169. if (!isSupported) {
  170. message.error(t('common.copyError'))
  171. } else {
  172. await copy()
  173. if (unref(copied)) {
  174. message.success(t('common.copySuccess'))
  175. }
  176. }
  177. }
  178. </script>