2525 </div >
2626 <div class =" m-feedback-actions" >
2727 <div class =" m-feedback-attachment" >
28+ <div class =" u-attachment-tip" >支持图片和视频,单个文件最大 30MB,最多上传 {{ max }} 个附件</div >
2829 <el-upload
2930 ref =" upload"
3031 class =" u-upload avatar-uploader"
3637 :on-change =" change"
3738 :on-exceed =" exceed"
3839 :limit =" max"
39- title =" 上传图片 "
40+ title =" 上传图片或视频 "
4041 with-credentials
41- accept =" image/jpg, image/jpeg, image/gif, image/png, image/bmp"
42+ accept =" image/jpg, image/jpeg, image/gif, image/png, image/bmp, video/mp4, video/quicktime, video/webm, video/ogg, video/x-m4v "
4243 multiple
4344 >
45+ <template #file =" { file } " >
46+ <div class =" u-upload-item" @click.stop =" handlePictureCardPreview(file)" >
47+ <img v-if =" !isVideoFile(file)" class =" el-upload-list__item-thumbnail" :src =" file.url" alt =" " />
48+ <div v-else class =" u-upload-video" >
49+ <video class =" u-upload-video__player" :src =" file.url" muted preload =" metadata" ></video >
50+ <i class =" el-icon-video-play u-upload-video__icon" ></i >
51+ </div >
52+ </div >
53+ </template >
4454 <i class =" el-icon-plus avatar-uploader-icon" ></i >
4555 </el-upload >
46- <el-dialog v-model =" dialogVisible" >
47- <img width =" 100%" :src =" dialogImageUrl" alt =" " />
56+ <el-dialog v-model =" dialogVisible" class =" m-media-preview" >
57+ <video
58+ v-if =" dialogFileType === 'video'"
59+ class =" u-preview-video"
60+ :src =" dialogImageUrl"
61+ controls
62+ :autoplay =" false"
63+ ></video >
64+ <img v-else width =" 100%" :src =" dialogImageUrl" alt =" " />
4865 </el-dialog >
4966 </div >
5067 <div class =" m-feedback-visible" >
5168 <span class =" u-label" >是否公开:</span >
52- <el-checkbox class =" u-checkbox" :true-value =" 1" :fasle -value =" 0" v-model =" form.public" ></el-checkbox >
69+ <el-checkbox class =" u-checkbox" :true-value =" 1" :false -value =" 0" v-model =" form.public" ></el-checkbox >
5370 <!-- <el-tooltip v-show="!canSubmit" content="必须先填写类型,子类和内容">
5471 <i class="el-icon-question"></i>
5572 </el-tooltip> -->
@@ -104,6 +121,7 @@ export default {
104121 uploadedMap: {},
105122 loading: false ,
106123 dialogImageUrl: " " ,
124+ dialogFileType: " image" ,
107125 dialogVisible: false ,
108126 };
109127 },
@@ -119,7 +137,38 @@ export default {
119137 },
120138 },
121139 methods: {
140+ isVideoFile (file ) {
141+ const type = file? .raw ? .type || file? .type || " " ;
142+ if (type .startsWith (" video/" )) return true ;
143+ return this .isVideoUrl (file? .url || file? .response ? .data ? .[0 ] || " " );
144+ },
145+ isVideoUrl (url ) {
146+ return / \. (mp4| mov| m4v| webm| ogg)(\? . * )? $ / i .test (url || " " );
147+ },
148+ validateFile (file ) {
149+ const raw = file? .raw || file;
150+ const type = raw? .type || " " ;
151+ const size = raw? .size || 0 ;
152+ const isImage = type .startsWith (" image/" );
153+ const isVideo = type .startsWith (" video/" );
154+
155+ if (! isImage && ! isVideo) {
156+ this .$message .warning (" 仅支持上传图片或视频文件" );
157+ return false ;
158+ }
159+
160+ if (size > 30 * 1024 * 1024 ) {
161+ this .$message .warning (" 单个附件大小不能超过 30MB" );
162+ return false ;
163+ }
164+
165+ return true ;
166+ },
122167 change (file ) {
168+ if (! this .validateFile (file)) {
169+ this .$refs .upload ? .handleRemove (file);
170+ return ;
171+ }
123172 if (file .status === " success" || this .uploadedMap [file .uid ]) return ;
124173 const fdata = new FormData ();
125174 fdata .append (" file" , file .raw );
@@ -147,6 +196,7 @@ export default {
147196 this .uploadedMap [file .uid ] = imageUrl;
148197 this .imgs = [... this .imgs , imageUrl];
149198 file .url = imageUrl;
199+ file .name = file .name || imageUrl .split (" /" ).pop ();
150200 file .status = " success" ;
151201 })
152202 .catch ((err ) => {
@@ -159,15 +209,16 @@ export default {
159209 }
160210 });
161211 },
162- // 图片上限
212+ // 附件上限
163213 exceed: function () {
164- this .$message .warning (` 上传的图片个数最多为 ${ this .max } 个` );
214+ this .$message .warning (` 上传的附件个数最多为 ${ this .max } 个` );
165215 },
166216 handlePictureCardPreview: function (file ) {
167217 this .dialogImageUrl = file .url ;
218+ this .dialogFileType = this .isVideoFile (file) ? " video" : " image" ;
168219 this .dialogVisible = true ;
169220 },
170- // 移除图片
221+ // 移除附件
171222 remove: function (file ) {
172223 const imageUrl = this .uploadedMap [file? .uid ] || file? .response ? .data ? .[0 ] || file? .url ;
173224 this .imgs = this .imgs .filter ((img ) => img !== imageUrl);
@@ -185,15 +236,23 @@ export default {
185236 .then ((res ) => {
186237 this .$message .success (" 提交成功" );
187238 this .$refs .upload .clearFiles ();
188- this .form = this .$options .data ().form ;
189- this .imgs = [];
190- this .uploadedMap = {};
239+ this .resetForm ();
191240 })
192241 .finally (() => {
193242 this .loading = false ;
194243 });
195244 },
245+ resetForm () {
246+ this .form = this .$options .data ().form ;
247+ this .imgs = [];
248+ this .uploadedMap = {};
249+ },
196250 addFile (file ) {
251+ if (! this .validateFile (file)) return false ;
252+ if ((this .$refs .upload ? .uploadFiles ? .length || 0 ) >= this .max ) {
253+ this .exceed ();
254+ return false ;
255+ }
197256 this .$refs .upload .handleStart (file);
198257 return false ;
199258 },
@@ -233,16 +292,52 @@ export default {
233292 .mt (20px );
234293 // .mb(10px);
235294 .u - upload {
295+ .el - upload- list {
296+ display: flex;
297+ flex- wrap: wrap;
298+ gap: 10px ;
299+ }
236300 .el - upload-- picture- card,
237301 .el - upload- list__item {
238- height: 40px ;
239- width: 40px ;
240- line- height: 40px ;
302+ height: 72px ;
303+ width: 72px ;
304+ line- height: 72px ;
241305 }
242306 .el - icon- plus {
243307 .fz (16px );
244308 }
245309 }
310+ .u - attachment- tip {
311+ color: #909399 ;
312+ .fz (12px , 1.6 );
313+ .mb (8px );
314+ }
315+ .u - upload- item {
316+ width: 100 % ;
317+ height: 100 % ;
318+ cursor: pointer;
319+ overflow: hidden;
320+ }
321+ .u - upload- video {
322+ position: relative;
323+ width: 100 % ;
324+ height: 100 % ;
325+ background: #111 ;
326+ & __player {
327+ width: 100 % ;
328+ height: 100 % ;
329+ object- fit: cover;
330+ }
331+ & __icon {
332+ position: absolute;
333+ top: 50 % ;
334+ left: 50 % ;
335+ color: #fff;
336+ .fz (20px );
337+ transform: translate (- 50 % , - 50 % );
338+ text- shadow: 0 2px 8px rgb (0 0 0 / 35 % );
339+ }
340+ }
246341 }
247342 .m - public {
248343 .mb (10px );
@@ -275,14 +370,31 @@ export default {
275370 padding- left: 40px ;
276371 padding- right: 40px ;
277372}
373+ .m - media- preview {
374+ .u - preview- video {
375+ width: 100 % ;
376+ max- height: 70vh ;
377+ background: #000 ;
378+ }
379+ }
278380
279381@media screen and (max - width : @phone ) {
280382 .m - add- feedback {
281- .type - box {
282- .el - form- item {
283- margin- bottom: 10px ;
383+ .type - box {
384+ .el - form- item {
385+ margin- bottom: 10px ;
386+ }
387+ }
388+ .m - feedback- actions {
389+ .u - upload {
390+ .el - upload-- picture- card,
391+ .el - upload- list__item {
392+ height: 64px ;
393+ width: 64px ;
394+ line- height: 64px ;
395+ }
396+ }
284397 }
285398 }
286399}
287- }
288400< / style>
0 commit comments