##文件预览组件
- 按照组件
解决展示pdf的问题 npm install pdfh5 npm install [email protected] --ignore-scripts npm install --save dommatrix npm install --save web-streams-polyfill 解决excel和docx预览的问题 npm install @vue-office/docx [email protected] npm install @vue-office/excel [email protected] npm install @vue/composition-api
- 使用方法
- 前端:
页面引入组件: import VueOfficeDocx from '@vue-office/docx' import Pdfh5 from "pdfh5"; import VueOfficeExcel from '@vue-office/excel' import '@vue-office/excel/lib/index.css' import '@vue-office/docx/lib/index.css' pdf预览: <div id="pdf" v-if="nowItem.fileFormat === '.pdf'" style="width: 100%; height: 100%; border: none;"></div> docx预览: <vue-office-docx :key="new Date().getTime()" v-if="nowItem.fileFormat === '.docx'" :src="preViewUrl" @rendered="rendered" /> excel预览: <vue-office-excel :key="new Date().getTime()" v-if="nowItem.fileFormat === '.xls' || nowItem.fileFormat === '.xlsx'" :src="preViewUrl" @rendered="rendered" /> txt预览: <iframe v-if="nowItem.fileFormat === '.txt'" :src="preViewUrl" style="width: 100%; height: 98%; border: none;"/>
js部分: downLoadLibrary(item.id).then(res => { //请求接口获取文件流 if (item.fileFormat === '.txt') { this.preViewUrl = window.URL.createObjectURL(res) //将文件流转化为url this.loading = false; } else if (item.fileFormat === '.pdf') { let prePdfUrl = window.URL.createObjectURL(res) //将文件流转化为url //使用id #pdf 获取pdfh5实例 this.pdfh5 = new Pdfh5('#pdf', { pdfurl: prePdfUrl, pageNum: false, //不显示页码 backTop: false, //不显示回到顶部 zoomEnable: false, //禁止缩放 maxZoom: 1, //点击屏幕缩放1倍 也就是禁止缩放的 }); //完成 let that = this; this.pdfh5.on('complete', function (status, msg, time) { that.rendered(); //渲染完成回调方法 可以自己定义业务逻辑 }); } else { this.preViewUrl = res //docx和excel } }) 请求接口: export function downLoadLibrary(id){ return request({ url: '/manager/library/downLoadLibrary/' + id, method: 'get', responseType: 'blob', }) }
- 后端:这里就是service层的接口,根据id获取文件流并返回给前端,前端根据文件格式进行不同的处理。
public void downLoadLibrary(Long id, HttpServletResponse response) { TInstructionResourceLibrary instructionResourceLibrary = this.selectInstructionResourceLibraryById(id); if (Objects.isNull(instructionResourceLibrary)) { throw new ServiceException("资源不存在"); } String configByKey = sysConfigService.selectConfigByKey("sys.upload.file"); String resourcePath = configByKey + instructionResourceLibrary.getResourcePath(); File file = new File(resourcePath); if (!file.exists()) { throw new ServiceException("文件不存在:" + resourcePath); } try { if (instructionResourceLibrary.getFileFormat().equals(".txt")) { response.setContentType("text/plain"); } else if (instructionResourceLibrary.getFileFormat().equals(".pdf")) { response.setContentType("application/pdf"); } else { response.setContentType("application/octet-stream"); } FileUtils.writeBytes(resourcePath, response.getOutputStream()); } catch (Exception e) { throw new ServiceException("下载文件失败:" + e.getMessage()); } }
视频预览组件
- 使用自带的video组件即可,无需额外的组件。
- 前端:
<video
ref="video"
:controls="true"
controlslist="nodownload noplaybackrate disablepictureinpicture"
:src="preViewUrl"
webkit-playsinline="true"
playsinline="true"
x-webkit-airplay="allow"
x5-playsinline
style="width: 100%"
@play="onPlayerPlay"
@pause="onPlayerPause"
@seeking="seeking"
@seeked="seeked"
@canplay="onPlayerCanPlay"
@timeupdate="onPlayerTimeUpdate"
:autoplay="false"/>
js部分:
playVideo(row) { // 打开视频弹出层 并且设置视频播放的src的url路径
this.videoName = row.videoName;
this.preViewOpen = true;
this.preViewUrl = "http://域名:端口/路径"
this.videoId = row.id;
},
handleClosePreView() { //关闭弹出层,并且清除播放记录 ,里面的字段可更具需要自定义
console.log("关闭弹出层");
this.addRecord("close")
this.recordId = null; //播放记录id
this.videoId = null; //播放的视频id
this.currentTime = 0; //视频的当前播放进度时间
this.tempTime = 0; //临时记录当前播放进度时间,防止拖动进度条时,时间不准确
this.viewDuration = 0; //播放时长,单位秒,是根据开始播放到关闭弹出层的视频非暂停时间的总时长
this.seconds = 0; //js计时器,大致计算播放时长 大概50多s 触发一次保存接口,之后清零
this.setIntervalId && clearInterval(this.setIntervalId); // 清除定时器
this.viewDurationInterval && clearInterval(this.viewDurationInterval); // 清除定时器
this.duration = 0; //视频实际的时长
this.videoName = ""; //视频每次
this.$refs.video.load(); //重新加载视频
this.preViewOpen = false; //关闭弹出层
},
//新增播放记录
addRecord(option) { //要记录播放的时长
let data = {
"id": this.recordId, // 记录id
"videoId": this.videoId, // 视频id
"viewDuration": this.viewDuration, // 播放时长
};
addTrainVideoRecord(data).then(response => {
console.log(response);
this.recordId = response.msg;
if (option === "close") {
this.recordId = null;
}
});
},
onPlayerCanPlay() { //回调函数 视频准备好可以播放
console.log("可以播放");
},
onPlayerPlay() { //回调函数 点击播放按钮,视频开始播放
if (this.playerPauseFlag) {
return;
}
//新增一条播放记录
this.addRecord();
this.setIntervalId = setInterval(() => {
this.tempTime = this.currentTime + 0.01;
this.seconds += 0.01;
}, 1); // 定时器,每隔1ms获取一次播放时间
this.viewDurationInterval = setInterval(() => {
this.viewDuration += 1;
}, 950)
},
onPlayerTimeUpdate(e) { //回调函数 视频播放进度变化 基本每秒触发一次
this.currentTime = e.target.currentTime;
this.duration = e.target.duration;
//每播放1左右分钟秒保存一次播放记录
if (this.seconds >= 140) {
this.addRecord()
this.seconds = 0;
}
},
onPlayerPause() { //回调函数 视频暂停播放
if (this.playerPauseFlag) {
return;
}
//记录一次 下次开始是新的记录
this.addRecord()
this.setIntervalId && clearInterval(this.setIntervalId);
this.viewDurationInterval && clearInterval(this.viewDurationInterval);
},
seeking() { //回调函数 拖动进度条
console.log("拖动进度条");
},
seeked() { //回调函数 拖动进度条结束
this.playerPauseFlag = true
setTimeout(function () {
this.playerPauseFlag = false
}, 1000)
// 只允许向后拖动
if (this.tempTime < this.currentTime) {
this.$refs.video.currentTime = this.tempTime;
}
},
后端接口:流式返回的 每次2m的视频流
@GetMapping(value = "/viewVideo/{id}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public void viewVideo(@PathVariable("id") Long id, HttpServletResponse response) throws IOException {
// 获取视频地址
File videoFile = videoService.findVideoUrl(id);
StreamingResponseBody stream = out -> {
try (InputStream inputStream = Files.newInputStream(videoFile.toPath())) {
byte[] bytes = new byte[1024 * 1024 * 2]; // 2M
int length;
while ((length = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, length);
}
System.out.println("视频下载成功");
out.flush();
} catch (final Exception e) {
throw new RuntimeException(e);
}
};
stream.writeTo(response.getOutputStream());
}