<!-- * @Description: * @Autor: renchao * @LastEditTime: 2023-12-15 14:42:12 --> <template> <div class="rlPopup"> <div class="prev handle-btn" v-if="!isScan" @click="prev()"> <i class="el-icon-arrow-left"></i> </div> <div class="next handle-btn" v-if="!isScan" @click="next()"> <i class="el-icon-arrow-right"></i> </div> <div class="img-list-wrap" v-Loading="loading"> <img id="photo" src="" v-show="isScan && this.BASE_API.gaopaiyi=='jy'" alt="高拍仪捷宇"> <img src="http://127.0.0.1:38088/video=stream&camidx=0" v-if="isScan && this.BASE_API.gaopaiyi=='lt'" alt="高拍仪"> <div v-for="(img, i) in previewImg.imgList" :key="i" v-else> <photo-zoom :url="img.fjurl" :bigWidth="165" v-if="i === previewImg.index" :scale="2" overlayStyle="width: 100%;height:100%"> </photo-zoom> </div> </div> <!--缩略图--> <div class="thumb-wrap"> <div class="thumb-wrap-button"> <el-button type="primary" @click="clickImage" v-if="previewImg.imgList.length>0">(放大) 显示(缩小)</el-button> <el-upload class="fileUpdate" ref="upload" :key="key" action="" :show-file-list="false" :multiple="true" :auto-upload="false" :on-change="handleChange" accept=".JPG, .PNG, .JPEG,.jpg, .png, .jpeg"> <el-button icon="el-icon-upload" type="primary" :loading="upDateloading" v-if="ableOperation">上传</el-button> </el-upload> <!-- 左移右移 --> <el-button type="primary" @click="handleMove('left')" v-if="ableOperation && thumbnailImages.length>0">左移</el-button> <el-button type="primary" @click="handleMove('right')" v-if="ableOperation && thumbnailImages.length>0">右移</el-button> <el-button type="primary" icon="el-icon-delete-solid" @click="handleDelete" v-if="thumbnailImages.length>0 && ableOperation">删除</el-button> <div v-if="ableOperation" class="pl-5"> <el-button type="primary" @click="handleOpenScan" v-if="ableOperation" :loading="loading">{{scanTitle}}</el-button> <el-button type="primary" @click="handleViewScan" v-if="isScan && ableOperation">拍照</el-button> </div> </div> <ul> <li v-for="(img, index) in thumbnailImages" :key="index" :class="{ active: previewImg.index === index }" @click="showCurrent(index)"> <img :src="img.fjurl"> </li> </ul> </div> <!-- 点开后的视图 --> <publicPicture v-if="showViewer" :url-list="allLi" :initialIndex="initialIndex" @close-viewer="closeViewer"> </publicPicture> </div> </template> <script> import PhotoZoom from '@/components/PhotoZoom' import { getAltimeterInfo, getUuid } from '@/utils/operation.js' import { uploadBatch, deleteClmx, move, uploadSjClmx } from "@/api/clxx.js"; import publicPicture from '@/components/publicPicture/index.vue' export default { name: 'PreviewImage', props: { previewImg: { type: Object, default: () => { } }, ableOperation: { type: Boolean, default: true } }, components: { PhotoZoom, publicPicture }, data () { return { upDateloading: false, loading: false, key: 0, isScan: false, // 打开高拍仪 scanTitle: '打开高拍仪', transform: { scale: 1, degree: 0 }, maxFileLength: 0, // 缩略图 thumbnailImages: [], showViewer: false, initialIndex: 0, allLi: [], webSocket: null } }, watch: { previewImg: { handler (newValue, oldValue) { if (newValue.imgList && newValue.imgList.length > 0) { this.allLi = _.cloneDeep(newValue.imgList).map(item => item.fjurl) this.thumbnailImages = newValue.imgList } else { this.allLi = [] this.thumbnailImages = [] } }, deep: true, immediate: true } }, created () { this.maxLength = 0; this.allLi = _.cloneDeep(this.previewImg.imgList).map(item => item.fjurl) this.thumbnailImages = this.previewImg.imgList }, computed: { isFirst () { return this.previewImg.index === 0 }, isLast () { return this.previewImg.index === this.previewImg.imgList.length - 1 } }, methods: { /** * @description: 打开高拍仪 * @author: renchao */ handleOpenScan () { let that = this this.isScan = !this.isScan if (this.isScan) { this.loading = true this.$message({ message: '正在启动程序请稍等', type: 'success' }) setTimeout(() => { this.scanTitle = '关闭高拍仪' this.loading = false }, 4000) } else { this.scanTitle = '打开高拍仪' } if (this.BASE_API.gaopaiyi == 'jy') { let webSocket = new WebSocket('ws://localhost:1818'); this.webSocket = webSocket webSocket.onopen = function (event) { webSocket.send('bStartPlay') webSocket.send('vSetPreviewRect(1600,1200)') } webSocket.onmessage = function (event) { let begin_data = "data:image/jpeg;base64,"; document.getElementById('photo').src = begin_data + event.data; if (event.data.indexOf('BeginsGetBase64') >= 0) { let blob = that.dataURLtoBlob('data:image/png;base64,' + event.data.replace('BeginsGetBase64', '').replace('EndsGetBase64', '')); let file = that.blobToFile(blob); var formData = new FormData(); formData.append('file', file) formData.append("bsmSj", that.previewImg.bsmSj); if (that.previewImg.imgList.length > 0) { formData.append("index", that.previewImg.imgList[that.previewImg.index].sxh); } uploadSjClmx(formData).then((res) => { if (res.code == 200) { that.$emit('updateList', { children: res.result, bsmSj: that.previewImg.bsmSj }) that.$message({ message: '上传成功!', type: 'success' }) } }) } } } }, // 左右移动 handleMove (direction) { move(direction, this.previewImg.imgList[this.previewImg.index].bsmClmx).then(res => { if (res.code == 200) { if (direction == 'left') { this.previewImg.index = this.previewImg.index - 1 } else { this.previewImg.index = this.previewImg.index + 1 } this.initialIndex = this.previewImg.index this.$emit('updateList', { children: res.result, bsmSj: this.previewImg.bsmSj }) this.$message({ message: '移动成功!', type: 'success' }) } else { this.$message.error(res.message); } }) }, /** * @description: 拍照 * @author: renchao */ dataURLtoBlob (base64String) { const arr = base64String.split(','); if (arr.length !== 2) { throw new Error('Invalid Base64 format'); } const mime = arr[0].match(/:(.*?);/)[1]; if (!mime) { throw new Error('Cannot retrieve MIME type'); } const bstr = atob(arr[1]); const n = bstr.length; const u8arr = new Uint8Array(n); for (let i = 0; i < n; i++) { u8arr[i] = bstr.charCodeAt(i); } return new Blob([u8arr], { type: mime }); }, blobToFile (blob) { let name = getUuid(8) + '.jpg' const file = new File([blob], name); return file; }, handleViewScan () { if (this.BASE_API.gaopaiyi == 'jy') { this.webSocket.send('sGetBase64'); return } getAltimeterInfo().then(res => { let blob = dataURLtoBlob('data:image/png;base64,' + res.data.photoBase64); let file = blobToFile(blob); var formData = new FormData(); formData.append('file', file) formData.append("bsmSj", this.previewImg.bsmSj); if (this.previewImg.imgList.length > 0) { formData.append("index", this.previewImg.imgList[this.previewImg.index].sxh); } uploadSjClmx(formData).then((res) => { if (res.code == 200) { this.$emit('updateList', { children: res.result, bsmSj: this.previewImg.bsmSj }) this.$message({ message: '上传成功!', type: 'success' }) } }) }) }, /** * @description: prev * @author: renchao */ prev () { let len = this.previewImg.imgList.length if (this.isFirst || len == 0) { this.$emit('prevPriview') } else { this.$parent.previewImg.index = (this.$parent.previewImg.index - 1 + len) % len } }, /** * @description: next * @author: renchao */ next () { let len = this.previewImg.imgList.length if (this.isLast || len == 0) { this.$emit('nextPriview') } else { this.$parent.previewImg.index = (this.$parent.previewImg.index + 1) % len } }, /** * @description: showCurrent * @param {*} index * @author: renchao */ showCurrent (index) { this.previewImg.index = index this.initialIndex = index }, /** * @description: closeViewer * @author: renchao */ closeViewer () { this.showViewer = false }, /** * @description: clickImage * @author: renchao */ clickImage () { this.showViewer = true }, /** * @description: handleChange * @param {*} file * @param {*} files * @author: renchao */ async handleChange (file, fileList) { let length = fileList.length; this.maxFileLength = Math.max(length, this.maxFileLength) var formData = new FormData(); setTimeout(() => { if (this.maxFileLength !== length) { return } let num = 0, max = 0; const isLt5M = file.size / 1024 / 1024 < 5; fileList.forEach(item => { if (!isLt5M) { max++ } if (!['image/jpeg', 'image/png', 'image/jpg', 'image/gif'].includes(item.raw.type)) { num++ } else { formData.append('file', item.raw) } }) if (num >= 1) { this.$message.error("请选择jpeg/png/jpg/bmp/gif格式的图片后重试") // 移除不支持的文件类型 this.key++ return; } if (max >= 1) { this.$message.error('上传图片大小不能超过 5MB!'); this.key++ return; } this.upDateloading = true formData.append("bsmSj", this.previewImg.bsmSj); formData.append("bsmSlsq", this.previewImg.bsmSlsq); if (this.previewImg.imgList.length > 0) { formData.append("index", this.previewImg.imgList[this.previewImg.index].sxh); } uploadBatch(formData).then((res) => { if (res.code == 200) { this.$emit('updateList', { children: res.result, bsmSj: this.previewImg.bsmSj }) this.$message({ message: '上传成功!', type: 'success' }) this.upDateloading = false this.$refs.upload.clearFiles(); this.maxFileLength = 0 } }) }, 0) }, /** * @description: handleDelete * @author: renchao */ handleDelete () { let that = this this.$confirm('此操作将永久删除, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(async () => { let bsmClmx = this.previewImg.imgList[this.previewImg.index].bsmClmx let bsmSj = this.previewImg.imgList[this.previewImg.index].bsmSj this.previewImg.imgList = this.previewImg.imgList.filter(item => item.bsmClmx != bsmClmx) deleteClmx(bsmClmx).then(res => { if (res.code == 200) { that.$emit('updateList', { children: this.previewImg.imgList, bsmSj: bsmSj }) that.initialIndex = that.previewImg.index that.$message({ message: '删除成功!', type: 'success' }) } }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }) }) } } } </script> <style lang="scss" scoped> // 查看大图 .rlPopup { position: relative; width: 100%; text-align: center; height: 100%; .handle-btn { position: absolute; top: 50%; transform: translateY(-100%); width: 66px; height: 66px; line-height: 75px; color: #fff; background-color: #ccc; border-radius: 50%; cursor: pointer; text-align: center; transition: all 0.3s; i { font-size: 24px; } } .handle-btn:hover { background-color: rgb(185, 183, 183); } .prev { left: 1%; } .next { right: 1%; } .img-list-wrap { width: 100%; display: flex; justify-content: center; height: calc(100% - 80px); align-items: center; background: rgba(194, 190, 190, 0.1); overflow: scroll; img { display: block; object-fit: scale-down; transition: all 0.3s; width: 100%; height: 100%; } } .thumb-wrap { &-button { display: flex; justify-content: center; .fileUpdate { margin: 0 10px; } } li { float: left; width: 60px; height: 45px; border: solid 1px #ececec; position: relative; margin-right: 5px; cursor: pointer; &:last-child { margin-right: 0; } img { max-width: 57px; max-height: 42px; display: block; object-fit: scale-down; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } } .active { border-color: #409eff; } } } </style> <style> .zoom-on-hover { position: relative; overflow: hidden; } .zoom-on-hover .normal { width: 100%; } .zoom-on-hover .zoom { position: absolute; opacity: 0; transform-origin: top left; } .zoom-on-hover.zoomed .zoom { opacity: 1; } .zoom-on-hover.zoomed .normal { opacity: 0; } </style>