|
12 | 12 | > |
13 | 13 | <el-button type="primary">{{ $t('aiChat.uploadFile.label') }}</el-button> |
14 | 14 | </el-upload> |
15 | | - <el-space wrap class="w-full media-file-width upload_content mt-16"> |
| 15 | + <el-space wrap class="w-full media-file-width upload_content mt-16" v-if="!inputDisabled"> |
16 | 16 | <template v-for="(file, index) in model_value" :key="index"> |
17 | 17 | <el-card style="--el-card-padding: 0" shadow="never"> |
18 | 18 | <div |
|
37 | 37 | </el-card> |
38 | 38 | </template> |
39 | 39 | </el-space> |
| 40 | + <div class="mt-8 w-full" v-else> |
| 41 | + <div class="mb-8" v-if="download_list.length"> |
| 42 | + <el-space wrap class="w-full media-file-width upload_content"> |
| 43 | + <template v-for="(item, index) in download_list" :key="index"> |
| 44 | + <el-card shadow="never" style="--el-card-padding: 8px" class="download-file cursor"> |
| 45 | + <div class="download-button flex align-center" @click="downloadFile(item)"> |
| 46 | + <el-icon class="mr-4"> |
| 47 | + <Download /> |
| 48 | + </el-icon> |
| 49 | + {{ $t('aiChat.download') }} |
| 50 | + </div> |
| 51 | + <div class="show flex align-center"> |
| 52 | + <img :src="getImgUrl(item && item?.name)" alt="" width="24" /> |
| 53 | + <div class="ml-4 ellipsis-1" :title="item && item?.name"> |
| 54 | + {{ item && item?.name }} |
| 55 | + </div> |
| 56 | + </div> |
| 57 | + </el-card> |
| 58 | + </template> |
| 59 | + </el-space> |
| 60 | + </div> |
| 61 | + <div class="mb-8" v-if="image_list.length"> |
| 62 | + <el-space wrap> |
| 63 | + <template v-for="(item, index) in image_list" :key="index"> |
| 64 | + <div class="file cursor border-r-6" v-if="item.url"> |
| 65 | + <el-image |
| 66 | + :src="item.url" |
| 67 | + :zoom-rate="1.2" |
| 68 | + :max-scale="7" |
| 69 | + :min-scale="0.2" |
| 70 | + :preview-src-list="getAttrsArray(image_list, 'url')" |
| 71 | + :initial-index="index" |
| 72 | + alt="" |
| 73 | + fit="cover" |
| 74 | + style="width: 170px; height: 170px; display: block" |
| 75 | + class="border-r-6" |
| 76 | + /> |
| 77 | + </div> |
| 78 | + </template> |
| 79 | + </el-space> |
| 80 | + </div> |
| 81 | + <div class="mb-8" v-if="audio_list.length"> |
| 82 | + <el-space wrap> |
| 83 | + <template v-for="(item, index) in audio_list" :key="index"> |
| 84 | + <div class="file cursor border-r-6" v-if="item.url"> |
| 85 | + <audio :src="item.url" controls style="width: 350px; height: 43px" class="border-r-6" /> |
| 86 | + </div> |
| 87 | + </template> |
| 88 | + </el-space> |
| 89 | + </div> |
| 90 | + <div class="mb-8" v-if="video_list.length"> |
| 91 | + <el-space wrap> |
| 92 | + <template v-for="(item, index) in video_list" :key="index"> |
| 93 | + <div class="file cursor border-r-6" v-if="item.url"> |
| 94 | + <video :src="item.url" style="width: 170px; display: block" class="border-r-6" controls /> |
| 95 | + </div> |
| 96 | + </template> |
| 97 | + </el-space> |
| 98 | + </div> |
| 99 | + </div> |
40 | 100 | </template> |
41 | 101 | <script setup lang="ts"> |
42 | 102 | import { computed, inject, ref, useAttrs } from 'vue' |
43 | 103 | import { ElMessage } from 'element-plus' |
44 | 104 | import type { FormField } from '@/components/dynamics-form/type' |
45 | | -import { getImgUrl } from '@/utils/common' |
| 105 | +import { getImgUrl, downloadByURL, getFileUrl, fileType } from '@/utils/common' |
| 106 | +import { getAttrsArray } from '@/utils/array' |
46 | 107 | import { t } from '@/locales' |
47 | 108 | import { useFormDisabled } from 'element-plus' |
48 | 109 | const inputDisabled = useFormDisabled() |
@@ -86,6 +147,28 @@ const model_value = computed({ |
86 | 147 | }) |
87 | 148 | const fileArray = ref<any>([]) |
88 | 149 |
|
| 150 | +const imageExtensions = ['JPG', 'JPEG', 'PNG', 'GIF', 'BMP'] |
| 151 | +const videoExtensions = ['MP4', 'AVI', 'MKV', 'MOV', 'FLV', 'WMV'] |
| 152 | +const audioExtensions = ['MP3', 'WAV', 'OGG', 'AAC', 'M4A'] |
| 153 | +const ofType = (exts: string[]) => (f: any) => exts.includes(fileType(f?.name || '').toUpperCase()) |
| 154 | +
|
| 155 | +const files_with_url = computed(() => |
| 156 | + (model_value.value || []).map((f: any) => ({ ...f, url: f.url || getFileUrl(f.file_id) })), |
| 157 | +) |
| 158 | +const image_list = computed(() => files_with_url.value.filter(ofType(imageExtensions))) |
| 159 | +const audio_list = computed(() => files_with_url.value.filter(ofType(audioExtensions))) |
| 160 | +const video_list = computed(() => files_with_url.value.filter(ofType(videoExtensions))) |
| 161 | +// 非图片/音频/视频的(文档、压缩包等)统一走下载卡片 |
| 162 | +const download_list = computed(() => |
| 163 | + files_with_url.value.filter( |
| 164 | + (f: any) => !ofType([...imageExtensions, ...audioExtensions, ...videoExtensions])(f), |
| 165 | + ), |
| 166 | +) |
| 167 | +
|
| 168 | +function downloadFile(item: any) { |
| 169 | + downloadByURL(item.url, item.name) |
| 170 | +} |
| 171 | +
|
89 | 172 | const loading = ref<boolean>(false) |
90 | 173 |
|
91 | 174 | const uploadFile = async (file: any, fileList: Array<any>) => { |
@@ -116,6 +199,30 @@ const uploadFile = async (file: any, fileList: Array<any>) => { |
116 | 199 | } |
117 | 200 | </script> |
118 | 201 | <style lang="scss" scoped> |
| 202 | +/* hover 显示下载按钮,样式照抄 question-content/index.vue */ |
| 203 | +.download-file { |
| 204 | + height: 43px; |
| 205 | +
|
| 206 | + &:hover { |
| 207 | + color: var(--el-color-primary); |
| 208 | + border: 1px solid var(--el-color-primary); |
| 209 | +
|
| 210 | + .download-button { |
| 211 | + display: block; |
| 212 | + text-align: center; |
| 213 | + line-height: 26px; |
| 214 | + } |
| 215 | +
|
| 216 | + .show { |
| 217 | + display: none; |
| 218 | + } |
| 219 | + } |
| 220 | +
|
| 221 | + .download-button { |
| 222 | + display: none; |
| 223 | + } |
| 224 | +} |
| 225 | +
|
119 | 226 | .upload_content { |
120 | 227 | .is-disabled { |
121 | 228 | background-color: var(--el-fill-color-light); |
|
0 commit comments