基础框架 兼容视频格式 修改 \src\components\Upload\src\BasicUpload.vue 数据库新增 vue
< template> < div class = "w-full" > < div class = "upload" > < div class = "upload-card" > < ! --图片列表--> < divclass = "upload-card-item" :style= "getCSSProperties" v-for= "(item, index) in imgList" :key= "` img_${ index} ` " > < div v-if= "type == 'video'" class = "upload-card-item-info upload-card-item-info2" > < video style = "width: 100%; height: 100%;" controls :src= "item" > < /video> < div class = "img-box-actions2" > < n-icon size = "18" class = "mx-2 action-icon" @click= "remove(index)" > < DeleteOutlined /> < /n-icon> < /div> < /div> < div v-else-if= "type=='singleGraph'||type=='multiGraph'" class = "upload-card-item-info" > < div class = "img-box" > < img :src= "item" /> < /div> < div class = "img-box-actions" > < n-icon size = "18" class = "mx-2 action-icon" @click= "preview(item)" > < EyeOutlined /> < /n-icon> < n-icon size = "18" class = "mx-2 action-icon" @click= "remove(index)" > < DeleteOutlined /> < /n-icon> < /div> < /div> < div v-else class = "upload-card-item-info" > < div style = "width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;" > < n-icon size = "40" :depth= "4" > < FileOutlined /> < /n-icon> < /div> < div class = "img-box-actions" > < n-icon size = "18" class = "mx-2 action-icon" @click= "remove(index)" > < DeleteOutlined /> < /n-icon> < /div> < /div> < /div> < ! --上传图片 v-if= "imgList.length < maxNumber" --> < div v-if= "imgList.length < maxNumber" class = "upload-card-item upload-card-item-select-picture" :style= "getCSSProperties" > < n-uploadv-bind= "$props " :file-list-style= "{ display: 'none' }" @before-upload= "beforeUpload" @finish= "finish" style = "display:flex;justify-content: center;" > < div class = "flex flex-col justify-center" > < n-icon size = "18" class = "m-auto" > < PlusOutlined /> < /n-icon> < span class = "upload-title" > 点击上传< /span> < /div> < /n-upload> < /div> < /div> < /div> < ! --上传图片--> < div > < n-alert title = "提醒" type = "info" closable v-if= "helpText" class = "flex w-full" > { { helpText } } < /n-alert> < /div> < /div> < ! --预览图片--> < n-modalv-model:show= "showModal" preset = "card" title = "预览" :bordered= "false" :style= "{ width: '520px' }" > < img :src= "previewUrl" /> < /n-modal>
< /template> < script lang = "ts" > import { defineComponent, toRefs, reactive, computed, watch } from 'vue' ; import { EyeOutlined, DeleteOutlined, PlusOutlined,FileOutlined } from '@vicons/antd' ; import { basicProps } from './props' ; import { useMessage, useDialog } from 'naive-ui' ; import { ResultEnum } from '@/enums/httpEnum' ; import componentSetting from '@/settings/componentSetting' ; import { useGlobSetting } from '@/hooks/setting' ; import { isString } from '@/utils/is' ; const globSetting = useGlobSetting( ) ; export default defineComponent( { name: 'BasicUpload' ,components: { EyeOutlined, DeleteOutlined, PlusOutlined,FileOutlined } ,props: { .. .basicProps,} ,emits: [ 'uploadChange' , 'delete' ] ,setup( props, { emit } ) { const getCSSProperties = computed(( ) = > {return {width: `${props.width}px`, height: `${props.height}px`, max: `${props.max}`, }; }) ; console.log( 'props: ', props) const message = useMessage( ) ; const dialog = useDialog( ) ; const state = reactive( {showModal: false, previewUrl: '', originalImgList: [] as string[], imgList: [] as string[], }) ; / / 赋值默认图片显示watch( ( ) = > props.value, ( ) = > {if( props.value) {state.imgList = props.value.map(( item) = > {return getImgUrl( item) ; }) ; state.originalImgList = props.value; }}, { immediate: true }) ; / / 预览function preview( url: string) {state.showModal = true; state.previewUrl = url; }/ / 删除function remove( index: number) {dialog.info( {title: '提示', content: '你确定要删除吗?', positiveText: '确定', negativeText: '取消', onPositiveClick: ( ) = > {state.imgList.splice( index, 1 ) ; state.originalImgList.splice( index, 1 ) ; emit( 'uploadChange', state.originalImgList) ; emit( 'delete', state.originalImgList) ; }, onNegativeClick: ( ) = > {}, }) ; }/ / 组装完整图片地址function getImgUrl( url: string) : string {const { imgUrl } = globSetting; return / ( ^ http| https: \/ \/ ) / g.test( url) ? url : `${imgUrl}${url}`; }function checkFileType( fileType: string[], filetype: string) {if( filetype.indexOf( '/ ') != - 1 ) {return fileType.includes( `.${filetype}`) || fileType.includes( `.${filetype.split( '/ ') [1 ]}`) ; }return fileType.includes( filetype) ; / / return componentSetting.upload.fileType.includes( fileType) ; }/ / 上传之前function beforeUpload( { file }) {const fileInfo = file.file; const { maxSize, accept } = props; const acceptRef = ( isString( accept) && accept.split( ', ')) || [ ] ; // 设置最大值,则判断if ( maxSize && fileInfo.size / 1024 / 1024 >= maxSize) { message.error( ` 上传文件最大值不能超过${ maxSize} M` ) ; return false ; } // 设置类型,则判断// let fileType : string[ ] = componentSetting.upload.fileType; // fileType = [ .. .fileType,.. .acceptRef] ; // if ( acceptRef.length > 0 && ! checkFileType( fileInfo.type)) { if ( ! checkFileType( acceptRef,fileInfo.type)) { message.error( ` 您上传的格式为:${ fileInfo.type.split( '/' ) [ 1 ] } ,只能上传文件类型为${ acceptRef.join( ',' ) } ` ) ; return false ; } return true ; } //上传结束function finish( { event: Event } ) { const res = eval( '(' + ( Event.target?Event.target.response:event.target.response) + ')' ) ; const infoField = componentSetting.upload.apiSetting.infoField; const { code } = res; const message = res.msg || res.message || '上传失败' ; const result = res[ infoField] ; //成功if ( code == = ResultEnum.SUCCESS) { let imgUrl: string = getImgUrl( result) ; state.imgList.push( imgUrl) ; state.originalImgList.push( result) ; emit( 'uploadChange' , state.originalImgList) ; } else message.error( message) ; } return { .. .toRefs( state) ,finish,preview,remove,beforeUpload,getCSSProperties,} ; } ,} ) ;
< /script> < style lang = "less" > .upload { width: 100 %; overflow: hidden; & -card { width: auto; height: auto; display: flex; flex-wrap: wrap; align-items: center; & -item { margin: 0 8px 8px 0 ; position: relative; padding: 8px; border: 1px solid border-radius: 2px; display: flex; justify-content: center; flex-direction: column ; align-items: center; & :hover { background: 0 0 ; .upload-card-item-info::before { opacity: 1 ; } .upload-card-item-info2::before { content: normal; } & -info::before { opacity: 1 ; } } & -info { position: relative; height: 100 %; width: 100 %; padding: 0 ; overflow: hidden; & :hover { .img-box-actions { opacity: 1 ; } } & ::before { position: absolute; z-index: 1 ; width: 100 %; height: 100 %; background-color: rgba( 0 , 0 , 0 , 0.5 ) ; opacity: 0 ; transition: all 0 .3s; content: ' ' ; } .img-box { position: relative; //padding: 8px; //border: 1px solid border-radius: 2px; } .img-box-actions { position: absolute; top: 50 %; left: 50 %; z-index: 10 ; white-space: nowrap; transform: translate( -50%, -50%) ; opacity: 0 ; transition: all 0 .3s; display: flex; align-items: center; justify-content: space-between; & :hover { background: 0 0 ; } .action-icon { color: rgba( 255 , 255 , 255 , 0.85 ) ; & :hover { cursor: pointer; color: } } } .img-box-actions2 { position: absolute; top: 0 ; right: 0 ; z-index: 10 ; background: rgba( 0 , 0 , 0 , 0.5 ) ; .action-icon { color: rgba( 255 , 255 , 255 , 0.85 ) ; & :hover { cursor: pointer; color: } } } } } & -item-select-picture { border: 1px dashed border-radius: 2px; cursor: pointer; background: color: .upload-title { color: } } } }
< /style>