Explorar o código

新增 文件管理新增图片预览、文件地址查看和复制、下载和删除功能
新增 test.ts新增判断文件是否为图片方法

zhontai %!s(int64=2) %!d(string=hai) anos
pai
achega
2acd2af5a5

+ 20 - 0
src/api/admin/File.ts

@@ -9,7 +9,9 @@
  * ---------------------------------------------------------------
  */
 
+import { AxiosResponse } from 'axios'
 import {
+  FileDeleteInput,
   PageInputFileGetPageDto,
   ResultOutputFileEntity,
   ResultOutputListFileEntity,
@@ -37,6 +39,24 @@ export class FileApi<SecurityDataType = unknown> extends HttpClient<SecurityData
       format: 'json',
       ...params,
     })
+  /**
+   * No description
+   *
+   * @tags file
+   * @name Delete
+   * @summary 删除文件
+   * @request POST:/api/admin/file/delete
+   * @secure
+   */
+  delete = (data: FileDeleteInput, params: RequestParams = {}) =>
+    this.request<AxiosResponse, any>({
+      path: `/api/admin/file/delete`,
+      method: 'POST',
+      body: data,
+      secure: true,
+      type: ContentType.Json,
+      ...params,
+    })
   /**
    * No description
    *

+ 17 - 2
src/api/admin/data-contracts.ts

@@ -666,6 +666,14 @@ export type DynamicFilterLogic = 0 | 1
  */
 export type DynamicFilterOperator = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18
 
+export interface FileDeleteInput {
+  /**
+   * 文件Id
+   * @format int64
+   */
+  id: number
+}
+
 /** 文件 */
 export interface FileEntity {
   /**
@@ -739,10 +747,17 @@ export interface FileGetPageDto {
 }
 
 export interface FileGetPageOutput {
-  /** Invalid=0,Minio=1,Aliyun=2,QCloud=3,Qiniu=4,HuaweiCloud=5 */
-  provider?: OSSProvider
+  /**
+   * 文件Id
+   * @format int64
+   */
+  id?: number
+  /** OSS供应商 */
+  providerName?: string | null
   /** 存储桶名称 */
   bucketName?: string | null
+  /** 文件目录 */
+  fileDirectory?: string | null
   /**
    * 文件Guid
    * @format uuid

+ 12 - 5
src/utils/test.ts

@@ -1,8 +1,8 @@
 import { verifyEmail } from '/@/utils/toolsValidate'
 /**
- * 手机号
+ * 是否手机号
  */
-export function mobile(value: string) {
+export function isMobile(value: string) {
   return /^1([3589]\d|4[5-9]|6[1-2,4-7]|7[0-8])\d{8}$/.test(value)
 }
 
@@ -13,7 +13,7 @@ export const testMobile = (rule: any, value: any, callback: any) => {
   if (!value) {
     callback()
   }
-  if (!mobile(value)) {
+  if (!isMobile(value)) {
     callback(new Error('请输入正确的手机号码'))
   } else {
     callback()
@@ -35,8 +35,15 @@ export const testEmail = (rule: any, value: any, callback: any) => {
 }
 
 /**
- * 外链
+ * 是否外链
  */
-export function externalLink(path: string) {
+export function isExternalLink(path: string) {
   return /^(http?:|https?:|mailto:|tel:)/.test(path)
 }
+
+/**
+ * 是否图片
+ */
+export function isImage(ext: string) {
+  return ['.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp', '.psd', '.svg', '.tiff'].indexOf(ext?.toLowerCase()) > -1
+}

+ 1 - 1
src/views/admin/file/components/file-upload.vue

@@ -1,6 +1,6 @@
 <template>
   <div>
-    <el-dialog v-model="state.showDialog" destroy-on-close :title="title" draggable width="600px">
+    <el-dialog v-model="state.showDialog" :title="title" draggable width="600px">
       <div>
         <el-upload
           ref="uploadRef"

+ 82 - 12
src/views/admin/file/index.vue

@@ -14,16 +14,56 @@
 
     <el-card shadow="never" style="margin-top: 8px">
       <el-table v-loading="state.loading" :data="state.fileListData" row-key="id" style="width: 100%">
-        <el-table-column prop="fileName" label="文件名" :formatter="formatterFileName" min-width="120" show-overflow-tooltip />
+        <el-table-column prop="fileName" label="文件名" min-width="220">
+          <template #default="{ row }">
+            <div class="my-flex">
+              <el-image
+                v-if="isImage(row.extension)"
+                :src="row.linkUrl"
+                :preview-src-list="previewImglist"
+                :initial-index="getInitialIndex(row.linkUrl)"
+                :lazy="true"
+                :hide-on-click-modal="true"
+                fit="scale-down"
+                preview-teleported
+                style="width: 80px; height: 80px"
+              />
+              <div class="ml10 my-flex-fill my-flex-y-center">
+                <div>{{ (row.fileName || '') + (row.extension || '') }}</div>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
         <el-table-column prop="sizeFormat" label="大小" width="120" />
         <el-table-column prop="providerName" label="供应商" width="80" />
         <el-table-column prop="bucketName" label="存储桶" width="80" />
-        <el-table-column prop="createdUserName" label="上传者" width="80" />
-        <el-table-column prop="createdTime" label="更新时间" :formatter="formatterTime" width="100" />
+        <el-table-column prop="fileDirectory" label="目录" width="120" />
+        <el-table-column prop="createdUserName" label="上传者" width="80">
+          <template #default="{ row }">
+            {{ row.modifiedUserName || row.createdUserName || '' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="createdTime" label="更新时间" width="100">
+          <template #default="{ row }">
+            {{ formatterTime(row.modifiedTime || row.createdTime || '') }}
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="180" fixed="right" header-align="center" align="center">
-          <!-- <template #default="{ row }">
-            
-          </template> -->
+          <template #default="{ row }">
+            <el-popover :width="220">
+              <p>{{ row.linkUrl }}</p>
+              <div style="text-align: right; margin: 0">
+                <el-button icon="ele-CopyDocument" size="small" type="primary" @click="copyText(row.linkUrl)">复制地址</el-button>
+              </div>
+              <template #reference>
+                <el-button size="small" text type="primary">地址</el-button>
+              </template>
+            </el-popover>
+            <el-link class="my-link mr12 ml12" :href="row.linkUrl" type="primary" icon="ele-Download" size="small" :underline="false" target="_blank"
+              >下载</el-link
+            >
+            <el-button v-auth="'api:admin:view:softdelete'" icon="ele-Delete" size="small" text type="danger" @click="onDelete(row)">删除</el-button>
+          </template>
         </el-table-column>
       </el-table>
       <div class="my-flex my-flex-end" style="margin-top: 20px">
@@ -46,11 +86,15 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted, onUnmounted, defineAsyncComponent } from 'vue'
+import { ref, reactive, onMounted, onUnmounted, defineAsyncComponent, computed, getCurrentInstance } from 'vue'
 import { PageInputFileGetPageDto, FileGetPageOutput } from '/@/api/admin/data-contracts'
 import { FileApi } from '/@/api/admin/File'
 import dayjs from 'dayjs'
 import eventBus from '/@/utils/mitt'
+import { isImage } from '/@/utils/test'
+import commonFunction from '/@/utils/commonFunction'
+
+const { proxy } = getCurrentInstance() as any
 
 const FileUpload = defineAsyncComponent(() => import('./components/file-upload.vue'))
 
@@ -71,6 +115,18 @@ const state = reactive({
   fileLogsTitle: '',
 })
 
+const { copyText } = commonFunction()
+
+const previewImglist = computed(() => {
+  let imgList = [] as string[]
+  state.fileListData.forEach((a) => {
+    if (isImage(a.extension as string) && a.linkUrl) {
+      imgList.push(a.linkUrl as string)
+    }
+  })
+  return imgList
+})
+
 onMounted(() => {
   onQuery()
   eventBus.on('refreshFile', async () => {
@@ -82,12 +138,12 @@ onUnmounted(() => {
   eventBus.off('refreshFile')
 })
 
-const formatterFileName = (row: FileGetPageOutput, column: any, cellValue: any) => {
-  return (row.fileName || '') + (row.extension || '')
+const formatterTime = (cellValue: any) => {
+  return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss')
 }
 
-const formatterTime = (row: FileGetPageOutput, column: any, cellValue: any) => {
-  return dayjs(cellValue).format('YYYY-MM-DD HH:mm:ss')
+const getInitialIndex = (imgUrl: string) => {
+  return previewImglist.value.indexOf(imgUrl)
 }
 
 const onQuery = async () => {
@@ -112,6 +168,16 @@ const onCurrentChange = (val: number) => {
 const onUpload = () => {
   fileUploadRef.value.open()
 }
+
+const onDelete = (row: FileGetPageOutput) => {
+  proxy.$modal
+    .confirmDelete(`确定要删除文件【${row.fileName}${row.extension}】?`)
+    .then(async () => {
+      await new FileApi().delete({ id: row.id as number }, { loading: true, showSuccessMessage: true })
+      onQuery()
+    })
+    .catch(() => {})
+}
 </script>
 
 <script lang="ts">
@@ -122,4 +188,8 @@ export default defineComponent({
 })
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.my-link {
+  font-size: 12px;
+}
+</style>