名称:usePreview
含义:
打开新页面,预览文档(excel、word等)
封装原因:
业务侧功能开发过程中,需要打开课件文档,但是不能让页面编码,充斥着大量的
window.open(jumpUrl, '_blank');
虽然一句编码很简单,只需要提供URL地址即可,但是场景使用不一样,需要做的操作也不太一样。
静态文件:
只需要提供服务器地址即可,相对比较简单
文档服务器:
打开相应文档,需要提供文件ID和文件名称,从文档服务器提取后打开
Hooks设计方式
usePreview.js
import { Config, Service } from '@basic-library'
import { Base64,uuid } from '@basic-utils'
const proxyConfig = "fileResource"
const getProxyUrl = (url) => {
const protocol = window.location.protocol
const host = window.location.host
return `${protocol}//${host}/${proxyConfig}/onlinePreview?url=${url}`
}
/**
* 获取字符串的哈希值
* @param {String} str
* @param {Boolean} caseSensitive
* @return {Number} hashCode
*/
const getHashCode =(str,caseSensitive)=>{
if(!caseSensitive){
str = str.toLowerCase();
}
// 1315423911=b'1001110011001111100011010100111'
var hash = 1315423911,i,ch;
for (i = str.length - 1; i >= 0; i--) {
ch = str.charCodeAt(i);
hash ^= ((hash << 5) + ch + (hash >> 2));
}
return (hash & 0x7FFFFFFF);
}
/**
* @description: 获取下载文件地址
* @param {*} item 文件相关对象信息
* @return {*}
*/
const getFilePath = (item) => {
const fileSeverIp = Config.BSConfig?.FilePreview
const { fileId, fullfilename, oName } = item
return fileSeverIp + Service.HParse('innerDownloadFile', {
fileId,
fullfilename,
oName
},false)
}
/**
* @description: 文件地址 base64加密、转义
* @param {*} path
* @return {*}
*/
const formatPath = (path) => {
return encodeURIComponent(Base64.toBase64(path))
}
/**
* @description: 根据文件名称生成UUID文件名称
* @param {*} fileId 文件id
* @return {*}
*/
const genFileName= (fileName,fileId) => {
if(!fileName && fileName.lastIndexOf('.') == -1) return
const getFileSuffix = name => name.split('.').pop()
return `${getHashCode(fileId)}.${getFileSuffix(fileName)}`
}
/**
* @description: 根据文件Id查找文件名称
* @param {*} fileId 文件id
* @return {*}
*/
const findFileName = async (fileId) => {
const { returnObj } = await Service.useHttp('queryServiceFileDetail', { fileId })
return returnObj.oFileName ?? ''
}
const usePreview = async (fileId, options) => {
let fileName = ''
let mode = ''
if(!fileId) {
new Error('文件ID为空!')
return
}
if(typeof options == 'object' ){
fileName = options.fileName ?? ''
mode = options?.mode || ''
}else{
fileName = options
}
const fullfilename = !fileName ? await findFileName(fileId) : fileName
if(!fullfilename) {
new Error('查找文件名称为空!')
return
}
const docPath = getFilePath({ fileId, fullfilename: genFileName(fullfilename,fileId), oName: fullfilename })
const jumpUrl = getProxyUrl(formatPath(docPath))
if(mode == 'path'){
return jumpUrl
}
window.open(jumpUrl, '_blank');
};
export default usePreview
上述过程中,其实业务逻辑挺饶的
- 需要支持获取解析拼装后的URL地址,主要目的是可能会给某个iframe用,页面内进行预览的情况
- 基于打开浏览器新页签方式,采用window.open方式,对于请求的预览服务,后端直接采用第三方开源插件,支持图片、视频、各类文档等,暂未进行封装,所以请求预览服务时,参数会携带一个url参数,这个url参数指向内部文件服务器的文件地址,就像套娃一样。稍微感觉有点麻烦,但是现阶段没有办法。
业务使用
1、浏览器打开,最简单方式
usePreview('文件id')
这种方式,不传文件名称,内部会根据文件id,去文件服务查找文件名称,然后拼装参数,在请求预览服务进行展示
2、浏览器打开,传递文件名称
usePreview('文件id','文件1.doc')
或者
usePreview('文件id',{fileName:'文件1.doc'})
这种方式,传递文件名称,内部会直接使用,不在进行二次请求接口查找文件名称,后续逻辑和第1种一样
3、获取预览服务地址
usePreview('文件id',{mode:'path'})
返回是一个 URL地址,注意,文件名称,和第2种一样,如果不传递,会进行二次查找