整体思路(模型特殊不考虑,别人封装不具备参考性)
图片上传采用单独的组件,其他三种类型采用一个上传组件(仅仅文件格式不同) 文件上传采用前端直接上传阿里云的方式 图片预览使用elementUI自带的image预览 dwg预览采用 kkfileview 方式,需要后台部署,前端使用 npm install js-base64
,应该支持所有文件的预览,我们这里仅用作CAD文件的预览 文档类型的直接在浏览器打开预览,如果不支持需要拼接前缀 "https://view.officeapps.live.com/op/view.aspx?src="
图片下载为压缩包 文档类的相同方法下载
上传
< el- form
style= "width: 650px"
: model= "form"
: rules= "rules"
ref= "form"
label- width= "180px"
class = "demo-form"
: disabled= "type == 3"
>
< el- form- item label= "样板格式" prop= "modelType" >
< el- radio- group v- model= "form.modelType" >
< el- radio label= "1" > 图片样板< / el- radio>
< el- radio label= "2" > 三维样板< / el- radio>
< el- radio label= "3" > 图纸样板< / el- radio>
< el- radio label= "4" > 文档样板< / el- radio>
< / el- radio- group>
< / el- form- item>
< ! -- 1 图片样板 2 三维样板 3 图纸样板 4 文档样板 -- >
< el- form- item
v- if = "form.modelType == 1"
label= "样板文件上传"
prop= "url"
>
< ImageUpload
v- model= "form.url"
tip= "请上传图片:"
: limit= "10"
: showIcon= "type == 3 ? true : false"
> < / ImageUpload>
< / el- form- item>
< el- form- item
v- if = "form.modelType != 1"
label= "样板文件上传"
prop= "url"
>
< ModelUpload
v- if = "type != 3"
v- model= "form.url"
: limit= "1"
: fileSize= "
form. modelType == 3 ? 50 : form. modelType == 4 ? 10 : 5120
"
: isShowUploadModel= "true"
ref= "videoUploadRef"
@input= "uploadTemplate"
: fileType= "
form. modelType == 3
? [ '.dwg' ]
: form. modelType == 4
? [ '.doc' , '.docx' , '.xls' , '.xlsx' , '.ppt' , '.pptx' , '.pdf' ]
: [ '.rvt' , '.ifc' , '.obj' , '.stl' , '.fbx' , '.3DS' ]
"
> < / ModelUpload>
< div v- else class = "blue point" @click= "preview(form)" >
{ { form. url?. split ( "/" ) [ form. url?. split ( "/" ) . length - 1 ] } }
< / div>
< / el- form- item>
ModelUpload.vue
< template>
< div class = "component-upload-image" >
< el- upload
action= ""
: http- request= "beforeUpload"
class = "avatar-uploader"
: limit= "limit"
: on- remove= "handleDelete"
: on- error= "handleUploadError"
: on- exceed= "handleExceed"
name= "file"
: show- file- list= "true"
: file- list= "fileList"
ref= "uploadRef"
: on- preview= "handlePreview"
: data= "otherQuery"
>
< el- button
size= "small"
type= "primary"
v- if = "!modelFlag"
: disabled= "disabled"
> 点击上传< / el- button
>
< ! -- 上传提示 -- >
< div class = "el-upload__tip" slot= "tip" v- if = "showTip" >
< template v- if = "fileSize" >
大小不超过 < b style= "color: #f56c6c" > { { fileSize } } MB < / b>
< / template>
< template v- if = "fileType" >
文件类型支持
< b style= "color: #f56c6c" > { { fileType. join ( " / " ) } } < / b> 格式
< / template>
< / div>
< el- progress
v- if = "modelFlag == true"
type= "circle"
: percentage= "modelUploadPercent"
style= "margin-top: 7px"
> < / el- progress>
< / el- upload>
< / div>
< / template>
< script>
export default {
props: {
value: [ String, Object, Array] ,
limit: {
type: Number,
default : 1 ,
} ,
fileSize: {
type: Number,
default : 5120 ,
} ,
fileType: {
type: Array,
default : ( ) => [ ".rvt" , ".ifc" , ".dwg" , ".obj" , ".stl" , ".fbx" , ".3DS" ] ,
} ,
isShowTip: {
type: Boolean,
default : true ,
} ,
isShowUploadModel: {
type: Boolean,
default : false ,
} ,
isShowBtn: {
type: Boolean,
default : true ,
} ,
disabled: {
type: Boolean,
default : false ,
} ,
} ,
data ( ) {
return {
number: 0 ,
hideUpload: false ,
fileList: [ ] ,
otherQuery: { } ,
uploadList: [ ] ,
modelFlag: false ,
modelUploadPercent: 0 ,
isCancel: false ,
} ;
} ,
watch: {
value: {
handler ( val ) {
if ( val) {
console. log ( val, "val" ) ;
if ( typeof val == "string" ) {
const list = Array. isArray ( val) ? val : this . value. split ( "," ) ;
this . fileList = list. map ( ( item ) => {
if ( typeof item === "string" ) {
item = {
name: item. substring ( item. lastIndexOf ( "/" ) + 14 ) ,
url: item,
} ;
}
return item;
} ) ;
} else {
val. forEach ( ( el ) => {
el. name = el. fileName;
} ) ;
this . fileList = val;
}
} else {
this . fileList = [ ] ;
return [ ] ;
}
} ,
deep: true ,
immediate: true ,
} ,
} ,
computed: {
showTip ( ) {
return this . isShowTip && ( this . fileType || this . fileSize) ;
} ,
} ,
methods: {
Upload ( file, data ) {
console. log ( file) ;
let OSS = require ( "ali-oss" ) ;
let client = new OSS ( {
region: data. region,
accessKeyId: data. accessKeyId,
accessKeySecret: data. accessKeySecret,
bucket: "cscec83-openfile" ,
} ) ;
let cdnUrl = "https://cscec83-openfile.oss-cn-shanghai.aliyuncs.com/" ;
this . number++ ;
this . isCancel = false ;
const progress = ( p, _checkpoint ) => {
console. log ( p) ;
this . modelFlag = true ;
this . modelUploadPercent = Number ( ( Number ( p) * 100 ) . toFixed ( 1 ) ) ;
console. log ( this . isCancel) ;
if ( this . isCancel) {
client. cancel ( ) ;
}
} ;
let fileName = "model/" + new Date ( ) . getTime ( ) + file. file. name;
client
. multipartUpload ( fileName, file. file, {
progress,
partSize: 5 * 1024 * 1024 ,
} )
. then ( ( res ) => {
this . modelFlag = false ;
if ( res. name) {
let obj = {
fileName: res. name,
name: res. name,
size: this . otherQuery. size,
url: cdnUrl + res. name,
} ;
console. log ( cdnUrl + res. name) ;
this . uploadList. push ( obj) ;
if ( this . uploadList. length === this . number) {
this . fileList = this . fileList. concat ( this . uploadList) ;
this . uploadList = [ ] ;
this . number = 0 ;
this . $emit ( "input" , this . fileList) ;
}
} else {
this . $modal. msgError ( "上传失败,请重试" ) ;
this . cancel ( ) ;
}
} )
. catch ( ( err ) => {
console. log ( err) ;
if ( err. name == "cancel" ) {
this . $message ( "上传取消" ) ;
} else {
this . $modal. msgError ( err) ;
}
this . cancel ( ) ;
} ) ;
} ,
handleDelete ( file ) {
const findex = this . fileList
. map ( ( f ) => f. fileName)
. indexOf ( file. fileName) ;
if ( findex > - 1 ) {
this . fileList. splice ( findex, 1 ) ;
this . $emit ( "input" , this . fileList) ;
}
this . cancel ( ) ;
} ,
beforeUpload ( file ) {
console. log ( this . fileType, file. file. name) ;
this . otherQuery = { } ;
this . isCancel = false ;
var fileSize = file. file. size / 1024 / 1024 < this . fileSize;
let fileType = file. file. name. substring ( file. file. name. lastIndexOf ( "." ) ) ;
let isContinue = true ;
if (
this . fileType. indexOf ( fileType) == - 1
) {
this . $modal. msgError (
` 文件格式不正确, 请上传 ${ this . fileType. join ( "/" ) } 格式文件! `
) ;
this . fileList = [ ] ;
isContinue = false ;
}
if ( ! fileSize) {
this . $modal. msgError ( ` 上传视频大小不能超过 ${ this . fileSize} MB! ` ) ;
this . fileList = [ ] ;
isContinue = false ;
}
this . otherQuery. fileName = file. file. name;
this . otherQuery. size = ( file. file. size / 1024 / 1024 ) . toFixed ( 2 ) ;
if ( ! isContinue) return ;
this . $axios. get ( "/file/ossFile/getOssParameter" ) . then ( ( res ) => {
if ( res. code == 200 ) {
this . Upload ( file, res. data) ;
}
} ) ;
} ,
handlePreview ( file ) {
window. open ( file. url, "_blank" ) ;
} ,
handleExceed ( ) {
this . $message. error ( ` 上传文件数量不能超过 ${ this . limit} 个! ` ) ;
} ,
handleUploadError ( ) {
this . $modal. msgError ( "上传失败,请重试" ) ;
} ,
cancel ( type ) {
this . isCancel = true ;
this . modelFlag = false ;
} ,
} ,
} ;
< / script>
< style scoped lang= "css" >
: : v- deep. hideUpload . el- upload-- picture- card {
display: none;
}
: : v- deep . el- upload-- picture- card {
width: 104 px;
height: 104 px;
line- height: 104 px;
}
: : v- deep . el- upload- list-- picture- card . el- upload- list__item {
width: 104 px;
height: 104 px;
}
. avatar- uploader- icon {
border: 1 px dashed #d9d9d9 ! important;
}
. avatar- uploader . el- upload {
border: 1 px dashed #d9d9d9 ! important;
border- radius: 6 px ! important;
position: relative ! important;
overflow: hidden ! important;
}
. avatar- uploader . el- upload: hover {
border: 1 px dashed #d9d9d9 ! important;
border- color: #409 eff;
}
. avatar- uploader- icon {
font- size: 28 px;
color: #8 c939d;
width: 300 px;
height: 178 px;
line- height: 178 px;
text- align: center;
}
. avatar {
width: 300 px;
height: 178 px;
display: block;
}
< / style>
ImageUpload.vue
< template>
< div class = "component-upload-image" >
< el- upload
multiple
: action= "uploadImgUrl"
list- type= "picture-card"
: on- success= "handleUploadSuccess"
: before- upload= "handleBeforeUpload"
: limit= "limit"
: on- error= "handleUploadError"
: on- exceed= "handleExceed"
name= "file"
: disabled= "showIcon"
: on- remove= "handleRemove"
: show- file- list= "true"
: headers= "headers"
: file- list= "fileList"
: on- preview= "handlePictureCardPreview"
: class = "{
hideUpload: this . fileList. length >= this . limit || this . showIcon,
} "
>
< i class = "el-icon-plus" > < / i>
< / el- upload>
< ! -- 上传提示 -- >
< div class = "el-upload__tip" slot= "tip" v- if = "showTip" >
{ { tip } }
< template v- if = "fileSize" >
大小不超过 < b style= "color: #f56c6c" > { { fileSize } } MB < / b>
< / template>
< template v- if = "fileType" >
格式为 < b style= "color: #f56c6c" > { { fileType. join ( "/" ) } } < / b>
< / template>
< / div>
< el- dialog
: visible. sync= "dialogVisible"
title= "预览"
width= "800"
append- to- body
>
< img
: src= "dialogImageUrl"
style= "display: block; max-width: 100%; margin: 0 auto"
/ >
< / el- dialog>
< / div>
< / template>
< script>
export default {
props: {
value: [ String, Object, Array] ,
limit: {
type: Number,
default : 5 ,
} ,
fileSize: {
type: Number,
default : 10 ,
} ,
fileType: {
type: Array,
default : ( ) => [ "png" , "jpg" , "jpeg" ] ,
} ,
tip: {
type: String,
} ,
isShowTip: {
type: Boolean,
default : true ,
} ,
showIcon: {
type: Boolean,
default : false ,
} ,
} ,
data ( ) {
return {
number: 0 ,
uploadList: [ ] ,
dialogImageUrl: "" ,
dialogVisible: false ,
hideUpload: false ,
uploadImgUrl: "/prod-api" + "/file/upload" ,
headers: {
Authorization: this . $store. state. token,
} ,
fileList: [ ] ,
} ;
} ,
watch: {
value: {
handler ( val ) {
if ( val) {
const list = Array. isArray ( val) ? val : this . value. split ( "," ) ;
this . fileList = list. map ( ( item ) => {
if ( typeof item === "string" ) {
item = { name: item, url: item } ;
}
return item;
} ) ;
} else {
this . fileList = [ ] ;
return [ ] ;
}
} ,
deep: true ,
immediate: true ,
} ,
} ,
computed: {
showTip ( ) {
return this . isShowTip && ( this . fileType || this . fileSize) ;
} ,
} ,
methods: {
handleRemove ( file, fileList ) {
const findex = this . fileList. map ( ( f ) => f. name) . indexOf ( file. name) ;
if ( findex > - 1 ) {
this . fileList. splice ( findex, 1 ) ;
this . $emit ( "input" , this . listToString ( this . fileList) ) ;
}
} ,
handleUploadSuccess ( res ) {
this . uploadList. push ( { name: res. data. url, url: res. data. url } ) ;
if ( this . uploadList. length === this . number) {
this . fileList = this . fileList. concat ( this . uploadList) ;
this . uploadList = [ ] ;
this . number = 0 ;
this . $emit ( "input" , this . listToString ( this . fileList) ) ;
this . $modal. closeLoading ( ) ;
}
} ,
handleBeforeUpload ( file ) {
let isImg = false ;
if ( this . fileType. length) {
let fileExtension = "" ;
if ( file. name. lastIndexOf ( "." ) > - 1 ) {
fileExtension = file. name. slice ( file. name. lastIndexOf ( "." ) + 1 ) ;
}
isImg = this . fileType. some ( ( type ) => {
if ( file. type. indexOf ( type) > - 1 ) return true ;
if ( fileExtension && fileExtension. indexOf ( type) > - 1 ) return true ;
return false ;
} ) ;
} else {
isImg = file. type. indexOf ( "image" ) > - 1 ;
}
if ( ! isImg) {
this . $modal. msgError (
` 文件格式不正确, 请上传 ${ this . fileType. join ( "/" ) } 图片格式文件! `
) ;
return false ;
}
if ( this . fileSize) {
const isLt = file. size / 1024 / 1024 < this . fileSize;
if ( ! isLt) {
this . $modal. msgError ( ` 上传头像图片大小不能超过 ${ this . fileSize} MB! ` ) ;
return false ;
}
}
this . $modal. loading ( "正在上传图片,请稍候..." ) ;
this . number++ ;
} ,
handleExceed ( ) {
this . $modal. msgError ( ` 上传文件数量不能超过 ${ this . limit} 个! ` ) ;
} ,
handleUploadError ( ) {
this . $modal. msgError ( "上传图片失败,请重试" ) ;
this . $modal. closeLoading ( ) ;
} ,
handlePictureCardPreview ( file ) {
this . dialogImageUrl = file. url;
this . dialogVisible = true ;
} ,
listToString ( list, separator ) {
let strs = "" ;
separator = separator || "," ;
for ( let i in list) {
strs += list[ i] . url + separator;
}
return strs != "" ? strs. substr ( 0 , strs. length - 1 ) : "" ;
} ,
} ,
} ;
< / script>
< style scoped >
: : v- deep. hideUpload . el- upload-- picture- card {
display: none;
}
: : v- deep . el- upload-- picture- card {
width: 86 px;
height: 86 px;
line- height: 86 px;
}
: : v- deep . el- upload- list-- picture- card . el- upload- list__item {
width: 86 px;
height: 86 px;
}
: : v- deep . el- list- enter- active,
: : v- deep . el- list- leave- active {
transition: all 0 s;
}
: : v- deep . el- list- enter,
. el- list- leave- active {
opacity: 0 ;
transform: translateY ( 0 ) ;
}
< / style>
预览和下载
< template>
< div id= "index" >
< el- card shadow= "always" style= "margin-top: 20px" >
< div class = "model pd-16" >
< div class = "flex mb-20" >
< div class = "title-left bold size-22" > 工程样板< / div>
< div
class = "flex_r point border-blue blue plr-10 ptb-4 bg-white radius-4 size-14"
@click= "toTemplate"
>
查看更多 < i class = "el-icon-right" > < / i>
< / div>
< / div>
< div class = "flex_l" >
< div
class = "center mr-20 plr-20 ptb-10"
@click= "changeTab(1)"
: style= "
tab == 1
? 'background: linear-gradient(210.65deg, #5FA4FE 0%, #367EF8 100%);border-radius: 25px;color:#fff'
: ''
"
>
< img
: src= "` ${
tab == 1
? require ( '../../assets/img/zhi-tab-1-1.png' )
: require ( '../../assets/img/zhi-tab-1.png' )
} ` "
alt= ""
style= "width: 27px"
/ >
< div class = "ml-16 size-18" > 图片区< / div>
< / div>
< div
class = "center mr-20 plr-20 ptb-10"
@click= "changeTab(2)"
: style= "
tab == 2
? 'background: linear-gradient(210.65deg, #5FA4FE 0%, #367EF8 100%);border-radius: 25px;color:#fff'
: ''
"
>
< img
: src= "` ${
tab == 2
? require ( '../../assets/img/zhi-tab-4-1.png' )
: require ( '../../assets/img/zhi-tab-4.png' )
} ` "
alt= ""
style= "width: 27px"
/ >
< div class = "ml-16 size-18" > 三维模型区< / div>
< / div>
< div
class = "center mr-20 plr-20 ptb-10"
@click= "changeTab(3)"
: style= "
tab == 3
? 'background: linear-gradient(210.65deg, #5FA4FE 0%, #367EF8 100%);border-radius: 25px;color:#fff'
: ''
"
>
< img
: src= "` ${
tab == 3
? require ( '../../assets/img/zhi-tab-3-1.png' )
: require ( '../../assets/img/zhi-tab-3.png' )
} ` "
alt= ""
style= "width: 27px"
/ >
< div class = "ml-16 size-18" > 图纸区< / div>
< / div>
< div
class = "center mr-20 plr-20 ptb-10"
@click= "changeTab(4)"
: style= "
tab == 4
? 'background: linear-gradient(210.65deg, #5FA4FE 0%, #367EF8 100%);border-radius: 25px;color:#fff'
: ''
"
>
< img
: src= "` ${
tab == 4
? require ( '../../assets/img/zhi-tab-2-1.png' )
: require ( '../../assets/img/zhi-tab-2.png' )
} ` "
alt= ""
style= "width: 27px"
/ >
< div class = "ml-16 size-18" > 文档区< / div>
< / div>
< / div>
< el- row : gutter= "20" class = "mt-30" >
< div v- if = "templateList.length == 0" class = "text-center" >
< img src= "../../assets/img/null.png" alt= "" style= "width: 4rem" / >
< div> 暂无数据< / div>
< / div>
< el- col : span= "6" v- for = "(item, i) in templateList" : key= "i + 'c'" >
< el- card shadow= "hover" class = "point course mb-12" >
< el- image
v- if = "tab == 1"
style= "width: 100%; height: 170px; border-radius: 5px"
mode= "aspectFill"
: src= "item.pictureUrl"
: preview- src- list= "[item.url.split(',')]"
>
< / el- image>
< img
@click= "preview(item)"
v- if = "tab == 2 || tab == 3 || tab == 4"
: src= "
tab == 4
? require ( ` ../../assets/img/doc- ${
item. docType || 'word'
} .png ` )
: item. pictureUrl
"
style= "width: 100%; height: 170px; border-radius: 5px"
mode= "aspectFill"
/ >
< div class = "flex mtb-10 mlr-12" >
< div class = "line-1 mr-10" > { { item. modelName } } < / div>
< img
style= "width: 22px"
src= "../../assets/img/download.png"
alt= ""
@click. stop= "download(item)"
/ >
< / div>
< / el- card>
< / el- col>
< / el- row>
< / div>
< / el- card>
< modelPop ref= "modelPopRef" > < / modelPop>
< / div>
< / div>
< / template>
< script>
import { Base64 } from "js-base64" ;
export default {
data ( ) {
return {
tab: 1 ,
templateList: [ ] ,
} ;
} ,
mounted ( ) {
this . getTemplateList ( ) ;
} ,
methods: {
changeTab ( tab ) {
this . tab = tab;
this . getTemplateList ( ) ;
} ,
download ( item ) {
if ( this . tab == 1 ) {
this . $downloadZip. zip (
"/qualityTrain/sample/downloadAndZip?sampleId=" + item. sampleId,
item. modelName + "样板文件.zip"
) ;
} else if ( this . tab == 2 || this . tab == 3 ) {
window. open ( item. url) ;
} else if ( this . tab == 4 ) {
fetch ( item. url)
. then ( ( res ) => res. blob ( ) )
. then ( ( blob ) => {
const a = document. createElement ( "a" ) ;
const objectUrl = window. URL . createObjectURL ( blob) ;
a. download =
item. modelName +
( item. docType == "ppt"
? ".ppt"
: item. docType == "excel"
? ".xls"
: item. docType == "word"
? ".doc"
: ".pdf" ) ;
a. href = objectUrl;
a. click ( ) ;
} ) ;
}
} ,
getTemplateList ( ) {
this . $axios
. get ( "/qualityTrain/sample/homePage" , {
params: {
modelType: this . tab,
} ,
} )
. then ( ( res ) => {
this . templateList = res. data;
} ) ;
} ,
preview ( item ) {
if ( this . tab == 2 ) {
this . $refs. modelPopRef. init ( item. sampleId, item. modelName, false , true ) ;
} else if ( this . tab == 3 ) {
let base = location. protocol + "//" + location. hostname + ":8012" ;
let url =
( base. includes ( "192.168.2.89" ) ? "http://192.168.0.19:8012" : base) +
"/onlinePreview?url=" +
encodeURIComponent ( Base64. encode ( item. url) ) ;
window. open ( url, "_blank" ) ;
} else {
console. log ( item. docType) ;
window. open (
( item. docType != "pdf"
? "https://view.officeapps.live.com/op/view.aspx?src="
: "" ) + item. url
) ;
}
} ,
} ,
} ;
< / script>
downloadZip.js
import axios from 'axios'
import { saveAs } from 'file-saver'
import { Loading, Message } from 'element-ui' ;
export default ( { store } , inject) => {
const zip = ( url, name ) => {
let loadingInstance = Loading. service ( {
lock: true ,
text: '正在下载...' ,
spinner: 'el-icon-loading' ,
background: 'rgba(0, 0, 0, 0.7)'
} ) ;
const fullUrl = '/prod-api' + url;
axios ( {
method: 'get' ,
url: fullUrl,
responseType: 'blob' ,
timeout: 600000 ,
headers: { 'Authorization' : store. state. token }
} ) . then ( async ( res ) => {
const isLogin = await blobValidate ( res. data) ;
loadingInstance. close ( ) ;
if ( isLogin) {
const blob = new Blob ( [ res. data] , { type: 'application/zip' } )
saveAs ( blob, name)
} else {
printErrMsg ( res. data) ;
}
} ) . catch ( ( ) => {
loadingInstance. close ( ) ;
} ) ;
} ;
async function blobValidate ( data ) {
try {
const text = await data. text ( ) ;
JSON . parse ( text) ;
return false ;
} catch ( error) {
return true ;
}
}
let errorCode = {
'401' : '认证失败,无法访问系统资源' ,
'403' : '当前操作没有权限' ,
'404' : '访问资源不存在' ,
'default' : '系统未知错误,请反馈给管理员'
}
async function printErrMsg ( data ) {
const resText = await data. text ( ) ;
const rspObj = JSON . parse ( resText) ;
const errMsg = errorCode[ rspObj. code] || rspObj. msg || errorCode[ 'default' ]
Message. error ( errMsg) ;
}
inject ( 'downloadZip' , {
zip,
} ) ;
}