<template>
<div :class="['ps-con',model].join(' ')">
<template v-if="model=='page'">
<div class="ps-page-con">
<!-- <div class="p-title-con">
<div class="title" :title="winConfig.title"></div>
<div class="btn-group">
<a-button v-if="vhas" v-has="`${vhas}`" type="dashed" icon="download" @click="uploads(1)" style="margin: 0 5px">下载无水印</a-button>
<a-button type="dashed" icon="download" @click="uploads" style="margin: 0 5px" >下 载</a-button >
</div>
</div> -->
<div
class="p-data-con">
<component
v-if="!showCarousel"
:is="componentNameList[mark + '0']"
:url="url"
:value="url"
:order="getKey(url)"
:setEvent="setWatermarkFile"
:isShowWatermark="isShowWatermark"
></component>
<SwiperCon
ref="previewShowcarousel"
v-if="showCarousel"
:onChange="onChange"
>
<div
class="item-con swiper-slide"
:key="'carousel-item-con-' + index"
v-for="(item, index) in url"
>
<component
:is="componentNameList[mark + index]"
:url="item"
:value="item"
:setEvent="setWatermarkFile"
:order="getKey(item) + index"
:isShowWatermark="isShowWatermark"
></component>
</div>
</SwiperCon>
</div>
</div>
</template>
<template v-if="model=='modal'">
<a-modal
:dialogClass="madalClass"
:visible="winConfig.visible"
:width="winConfig.width"
:confirm-loading="winConfig.loading"
:zIndex="10000000"
@ok="
() => {
modalEvent('ok');
}
"
@cancel="
() => {
modalEvent('cancel');
}
"
:footer="null"
>
<div slot="title" class="p-title-con">
<div class="title" :title="winConfig.title">{{ winConfig.title }}</div>
<div class="btn-group">
<a-button v-if="vhas" v-has="`${vhas}`" type="dashed" icon="download" @click="uploads(1)" style="margin: 0 5px">下载无水印</a-button>
<a-button type="dashed" icon="download" @click="uploads" style="margin: 0 5px" >下 载</a-button >
<a-button type="dashed" @click="enlarge" style="margin: 0 5px">{{ enlargeLabel }}</a-button>
</div>
</div>
<div
class="p-data-con"
:style="{ height: `calc(${winConfig.height} - 140px)` }"
>
<component
v-if="!showCarousel"
:is="componentNameList[mark + '0']"
:url="url"
:value="url"
:order="getKey(url)"
:setEvent="setWatermarkFile"
:isShowWatermark="isShowWatermark"
></component>
<SwiperCon
ref="previewShowcarousel"
v-if="showCarousel"
:onChange="onChange"
>
<div
class="item-con swiper-slide"
:key="'carousel-item-con-' + index"
v-for="(item, index) in url"
>
<component
:is="componentNameList[mark + index]"
:url="item"
:value="item"
:setEvent="setWatermarkFile"
:order="getKey(item) + index"
:isShowWatermark="isShowWatermark"
></component>
</div>
</SwiperCon>
</div>
</a-modal>
</template>
</div>
</template>
<script>
import { base64Img2Blob } from "../utils/Watermark.js";
import {addWatermark} from '../utils/addWatermark.js'
import { getCaptionFileName } from "../utils/util.js";
import SwiperCon from "../SwiperCon/index";
import * as IS from "../utils/is.js";
import DownLondBox from './component/downLondBox.vue'
import TextBox from './component/textBox.vue'
import PdfBox from './component/pdfBox.vue'
import IframeBox from './component/iframeBox.vue'
import ImgBox from './component/imgBox.vue'
import odfBox from './component/odfBox.vue'
import UUID from "../utils/uuid.js";
const getFileSuffix = (filePath) => {
const res = { suffix: "", name: "" };
let tempUrl = filePath
if(filePath.indexOf('?')>=0){
tempUrl = tempUrl.split('?')[0]
}
var startIndex = tempUrl.lastIndexOf(".");
const name = tempUrl.match(/[^//]+$/)[0];
res.name = name;
if (startIndex != -1) {
res.suffix = tempUrl.match(/[^.]+$/)[0];
} // filePath.substring(startIndex + 1, filePath.length).toLowerCase();
return res;
};
const downloadFile = (url,fileName) => {
fetch(url)
.then(response => response.blob())
.then(data => {
const fileURL = window.URL.createObjectURL(data); // 创建了一个URL,该URL表示了Blob对象的内容
const link = document.createElement('a'); // 创建一个链接元素并设置其属性
link.href = fileURL;
link.download = fileName;
link.click(); // 模拟点击下载链接
window.URL.revokeObjectURL(fileURL); // 释放创建的URL对象
})
.catch(error => {
// 处理错误
});
}
/**
* PPreviewShow 附件展示组件 可展示 图片 文档 pdf odf 等 使用方法 <p-PreviewShow :config="{}" :url="''" :event="()=>{}"></p-PreviewShow>
*
* @vue-prop {String} [model='modal'] - 当前组件以什么方式展示。默认值是:modal; modal 表示弹框模式;page 表示页面嵌入模式;
* @vue-prop {String} vhas - 下载无水印按钮的权限控制码 用于控制无水印下载按钮的权限标识
* @vue-prop {Object} config - 此参数必填 用于设置弹窗的 {title:'',visible: false, loading: false, width: '50vw',height: '60vh' }
* @vue-prop {String|Array<String>} url - 用于显示的文件的地址;值可以是数组
* @vue-prop {String|Array<String>} name - 此参数可选 文件名称; 值可以是数组,当值是数组时需要和url的顺序对应
* @vue-prop {String|Array<String>} suffix - 此参数可选 文件后缀; 值可以是数组,当值是数组时需要和url的顺序对应
* @vue-prop {Function} event - 此参数必填 执行的事件 关闭事件
* @vue-prop {Boolean} [isShowWatermark=false] - 是否显示水印 默认:true 表示显示水印(下载时有水印) false 表示不显示水印(下载时无水印)
* @vue-prop {Boolean} [isBatchDownload=false] - 下载按钮是否是批量下载 默认:false 表示单个下载; true 表示批量下载
*/
export default {
name: "PPreviewShow",
components: {
imgBox:ImgBox,
iframeBox:IframeBox,
pdfBox:PdfBox,
downLondBox:DownLondBox,
textBox:TextBox,
odfBox,
SwiperCon,
},
props: {
// modal 弹框模式 page 非弹框模式
model:{type:String,default:()=>{return 'modal'}},
vhas:{type:String},
/**
* 用于设置弹窗的
* @prop {Object} config - 用于设置弹窗的 {title:'',visible: false, loading: false, width: '50vw',height: '60vh' }
*/
config: { type: Object,required: true, }, // 用于设置弹窗的 {title:'',visible: false, loading: false, width: '50vw',height: '60vh' }
url: { type: [String, Array],required: true, }, // 用于显示的文件的地址
name: { type: [String, Array] }, // 文件名称
suffix: { type: [String, Array] }, // 文件后缀
event: { type: Function,required: true, }, // 执行的事件 关闭
isShowWatermark:{type:Boolean, default:true}, // 是否显示水印 默认:true
showHelp:{type:Boolean, default: () => { return false }},
// 下载按钮是否是批量下载 默认:false 表示单个下载; true 表示批量下载
isBatchDownload:{type:Boolean, default: () => { return false }},
},
data() {
return {
isSingleFile: true,
mark: "item",
currentIndex: 0,
componentConfig: {
componentName: "",
},
componentNameList: {},
// 是否启用多文件预览 false 表示单位件预览 true 表示多文件预览
showCarousel: false,
previewUrlList: [],
madalClass: "",
isEnlarge: false,
enlargeLabel: "全 屏",
winConfig: {
title: "",
visible: false,
loading: false,
width: "50vw",
height: "60vh",
},
dataUrl: {},
// 用于下载带有水印的文件
downLoadWatermarkFile: null,
fileName: {},
};
},
watch: {
config: {
handler(val_) {
const val = val_
if (Object.prototype.toString.call(val) === "[object Object]") {
this.winConfig = Object.assign(
{},
JSON.parse(JSON.stringify(this.winConfig)),
JSON.parse(JSON.stringify(val))
);
}
},
deep: true,
immediate: true,
},
url: {
handler(val_) {
const val = val_
// console.log('2222222222222', val, this.suffix, this.name)
if (IS.isEmpty(val)) {
return false;
}
this.dataUrl = {};
this.componentNameList = {};
this.currentIndex = 0;
let tempArr = [];
if (IS.isArray(val)) {
this.showCarousel = true;
this.isSingleFile = false;
tempArr = [...val];
}
if (IS.isString(val)) {
this.isSingleFile = true; // true
this.showCarousel = false;
tempArr = [val];
}
tempArr.forEach((item, index) => {
let tempUrl = item
if(tempUrl.indexOf('?')>=0){
tempUrl = tempUrl.split('?')[0]
}
this.dataHandling(tempUrl, this.mark + index, index);
});
this.$nextTick(() => {
tempArr.length>1 && this.$refs.previewShowcarousel && this.$refs.previewShowcarousel.goTo && this.$refs.previewShowcarousel.goTo(this.currentIndex);
this.setWinTitle();
});
},
deep: true,
immediate: true,
},
},
mounted(){
if(this.$isShowHelp == true &&this.showHelp === true){
console.log(`
组件名称:
PPreviewShow
使用方法:
<p-PreviewShow :config="{}" :url="''" :event="()=>{}"></p-PreviewShow>
props参数说明:
props: {
// 此参数必填 用于设置弹窗的 {title:'',visible: false, loading: false, width: '50vw',height: '60vh' }
config: { type: Object },
// 此参数必填 用于显示的文件的地址
url: { type: [String, Array] },
// 此参数可选 文件名称
name: { type: [String, Array] },
// 此参数可选 文件后缀
suffix: { type: [String, Array] },
// 此参数必填 执行的事件 关闭
event: { type: Function },
// 此参数可选 用于控制无水印下载按钮的权限标识
vhas:{type:String},
// 是否显示水印 默认:true 表示显示水印(下载时有水印) false 表示不显示水印(下载时无水印)
isShowWatermark:{type:Boolean, default:true},
// 下载按钮是否是批量下载 默认:false 表示单个下载; true 表示批量下载
isBatchDownload:{type:Boolean, default: () => { return false }},
},
`);
}
},
methods: {
onChange(a) {
// console.log(a)
this.currentIndex = a;
this.setWinTitle();
},
getKey(str){
return UUID('MDUUID',str+'')
},
setWinTitle() {
let currentTitle = "";
const key = this.mark + this.currentIndex;
const currentUrl = this.dataUrl[key]
if(!IS.isNullOrUnDef(currentUrl) && !IS.isEmpty(currentUrl)){
if (IS.isArray(this.name)) {
currentTitle =this.name[this.currentIndex] || getCaptionFileName(currentUrl);
}
if (IS.isString(this.name)) {
currentTitle = this.name || getCaptionFileName(currentUrl);
}
if (IS.isNullOrUnDef(currentTitle) || IS.isEmpty(currentTitle)) {
currentTitle = getCaptionFileName(currentUrl);
}
}
// console.log('title = ====>', currentTitle, key, this.name, this.dataUrl)
this.winConfig.title = currentTitle;
},
setWatermarkFile(data) {
// suffix url
const res = base64Img2Blob(data, window);
// console.log('setWatermarkFile====>', res)
this.downLoadWatermarkFile = res;
},
// 放大
enlarge() {
// madalClass
if (this.isEnlarge) {
// 还原
this.madalClass = "";
this.enlargeLabel = "全 屏";
this.winConfig.width = "50vw";
this.winConfig.height = "50vh";
} else {
// 放大
this.enlargeLabel = "还 原";
this.madalClass = "ps-con-modal";
this.winConfig.width = "100vw";
this.winConfig.height = "100vh";
}
this.isEnlarge = !this.isEnlarge;
},
modalEvent(type) {
// 关闭
this.winConfig.visible = false;
this.winConfig.width = "50vw";
this.winConfig.height = "60vh";
this.componentConfig.componentName = "";
this.dataUrl = "";
this.isEnlarge = false;
this.madalClass = "";
this.enlargeLabel = "全 屏";
this.event && this.event("close");
},
dataHandling(val, key, index) {
this.downLoadWatermarkFile = null;
const suffix_ = getFileSuffix(val);
this.fileName[key] = this.name || suffix_.name;
// console.log('suffix_===>',suffix_,this.suffix);
let currentSuffix = "";
let currentTitle = "";
if(IS.isUnDef(this.suffix) || IS.isEmpty(this.suffix)){
currentSuffix = suffix_.suffix;
}
if (IS.isArray(this.suffix)) {
currentSuffix = this.suffix[index] || suffix_.suffix;
}
if (IS.isString(this.suffix)) {
currentSuffix = this.suffix || suffix_.suffix;
}
// console.log('后缀========》',currentSuffix,this.suffix,index,suffix_.suffix);
if (IS.isArray(this.name)) {
currentTitle = this.name[index] || getCaptionFileName(val);
}
if (IS.isString(this.name)) {
currentTitle = this.name || getCaptionFileName(val);
}
// this.name || getCaptionFileName(url)
// console.log('@@@@@@@@@@@@',currentSuffix, val, key, currentTitle);
this.getComponentInfo(currentSuffix, val, key, currentTitle);
},
getComponentInfo(fileType, url, index, title_) {
// console.log('getComponentInfo====>', fileType, url, index)
const documentFun = (self) => {
self.componentNameList[index] = "iframeBox";
// `https://view.officeapps.live.com/op/view.aspx?src=${url}`
// self.dataUrl[index] = `https://view.officeapps.live.com/op/view.aspx?src=${url}`;
self.dataUrl[index] = url;
};
const imgFun = (self) => {
// console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2222',this.componentNameList,this.dataUrl);
self.componentNameList[index] = "imgBox";
self.dataUrl[index] = url;
};
const textFun = (self) => {
self.componentNameList[index] = "textBox";
self.dataUrl[index] = url;
fetch(self.dataUrl[index]).then((res) => {
res.blob().then((blob) => {
var reader = new FileReader(); //这是核心,读取操作就是由它完成.
reader.readAsText(blob, "utf8"); //读取文件的内容,也可以读取文件的URL
reader.onload = function () {
console.log("this.result===>", this.result);
//当读取完成后回调这个函数,然后此时文件的内容存储到了result中,直接操作即可
document.getElementById("txtBox").innerHTML = this.result;
};
});
});
};
const getInfo = {
xlsx: documentFun,
xls: documentFun,
pptx: documentFun,
ppt: documentFun,
doc: documentFun,
docx: documentFun,
jpg: imgFun,
png: imgFun,
jpeg: imgFun,
pdf: (self) => {
self.componentNameList[index] = "pdfBox";
// // this.dataUrl = 'https://zxcloud.oss-cn-hangzhou.aliyuncs.com/user/task/deliverables/1679882880287_%E6%9D%9C%E5%90%AF%E5%AE%97-%E6%84%8F%E5%A4%96%E9%99%A9%E7%94%B5%E5%AD%90%E4%BF%9D%E5%8D%9520221126-20231125-53.04.pdf' // url
// this.dataUrl = 'https://zxcloud-test.oss-cn-hangzhou.aliyuncs.com/qsb/businessLicense/1679968661043_%E5%B0%8F%E7%BA%A2%E4%B9%A6(%E7%AC%AC%E5%9B%9B%E7%89%88).pdf' // url
// this.AddWatermark.addWatermark(this.dataUrl).then(res=>{
// PDFObject.embed(res.url, "#pdfBox");
// })
self.dataUrl[index] = url;
// this.$nextTick(() => {
// PDFObject.embed(this.dataUrl[index], '#pdfBox')
// })
// console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3333',index,this.componentNameList,this.dataUrl);
},
txt: textFun,
ofd: (self) => {
self.dataUrl[index] = url;
self.componentNameList[index] = "odfBox";
},
};
// if (this.config && !this.config.title && this.config.title != '--') {
// this.winConfig.title = this.name || getCaptionFileName(url)
// }
let fileType_ = fileType;
const tempArr = ["xlsx", "xls"];
if (tempArr.indexOf(fileType_) >= 0) {
if (this.isSingleFile === true) {
getInfo[fileType_] && getInfo[fileType_](this);
} else {
fileType_ = "";
// getInfo[''] && getInfo[''](this)
}
} else {
getInfo[fileType_] && getInfo[fileType_](this);
}
this.setWinTitle();
// console.log('文件类型====》',fileType_,this.isSingleFile, this.componentNameList[index],index,this.componentNameList, getInfo[fileType_],getInfo);
if (!getInfo[fileType_]) {
// 下载 downLondBox
this.componentNameList[index] = "downLondBox";
this.dataUrl[index] = url;
}
},
getDownFileName(itemIndex, url){
let fileName = getCaptionFileName(url);
if(!IS.isNullOrUnDef(this.name)&&!IS.isEmpty(this.name)){
if(IS.isArray(this.name)){
fileName = this.name[itemIndex]
}
if(IS.isString(this.name)){
fileName = this.name
}
}
return fileName
},
async downItemFile(type,itemIndex,url){
//从链接上截取文件名
let fileName = this.getDownFileName(itemIndex,url)
if(type===1){
// 无水印下载
downloadFile(url,fileName)
return false
}else{
// 有水印下载
if(this.isShowWatermark == false){
// url = this.dataUrl[key] //this.downLoadWatermarkFile || this.url
downloadFile(url,fileName)
}else{
const res = await addWatermark(url,this,this.$watermarkConfig)
downloadFile(res.url,fileName)
}
}
},
//下载
async uploads(type) {
const key = this.mark + this.currentIndex;
let url = this.dataUrl[key]; //this.downLoadWatermarkFile || this.url
if(this.isBatchDownload == false){
this.downItemFile(type,this.currentIndex,url)
}
if(this.isBatchDownload == true){
const tempARr = Object.keys(this.dataUrl)
tempARr.forEach((key_,index)=>{
const url_ = this.dataUrl[key_];
this.downItemFile(type,index,url_)
})
}
},
},
};
</script>
<style lang="less">
.img-box {
width: auto;
height: 100%;
}
.p-data-con {
height: 60vh;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
.carousel-con {
.slick-slider {
width: 100%;
height: 100%;
.slick-list {
width: 100%;
height: 100%;
}
}
}
.dots-item {
li button {
background: #000000;
}
li {
&.slick-active button {
background: #3205f7;
}
}
.item-con {
height: 100%;
}
}
.custom-slick-arrow {
width: 25px;
height: 25px;
font-size: 25px;
// color: #f0f1f5;
// background-color: rgb(10, 10, 10);
opacity: 1;
z-index: 100;
}
// .custom-slick-arrow:before {
// display: none;
// }
// .custom-slick-arrow:hover {
// opacity: 1;
// }
.slick-track {
height: 100%;
.slick-slide div {
height: 100%;
display: flex !important;
justify-content: center;
align-items: center;
}
}
}
.p-title-con {
width: calc(100% - 50px);
display: flex;
justify-content: space-between;
align-items: center;
z-index: 100;
.title {
flex: 1;
display: flex;
overflow: hidden;
/*文本不会换行*/
white-space: nowrap;
/*当文本溢出包含元素时,以省略号表示超出的文本*/
text-overflow: ellipsis;
padding: 5px 0;
}
.btn-group {
// width: 200px;
}
}
.ps-con-modal {
top: 0px !important;
}
.ps-con{
&.page{
width: 100%;
height: 100%;
}
&.modal{}
.ps-page-con{
width: 100%;
height: 100%;
.p-title-con{
width: calc(100% - 50px);
display: flex;
justify-content: space-between;
align-items: center;
z-index: 100;
.title {
flex: 1;
display: flex;
overflow: hidden;
/*文本不会换行*/
white-space: nowrap;
/*当文本溢出包含元素时,以省略号表示超出的文本*/
text-overflow: ellipsis;
padding: 5px 0;
}
.btn-group {
// width: 200px;
}
}
.p-data-con{
width: 100%;
height: 100%;
}
}
}
</style>